diff --git a/package/firmware/wireless-regdb/Makefile b/package/firmware/wireless-regdb/Makefile index 4cce267f61..7d4cf63c47 100644 --- a/package/firmware/wireless-regdb/Makefile +++ b/package/firmware/wireless-regdb/Makefile @@ -1,14 +1,14 @@ include $(TOPDIR)/rules.mk PKG_NAME:=wireless-regdb -PKG_VERSION:=2024.07.04 +PKG_VERSION:=2024.10.07 PKG_RELEASE:=1 PKG_LICENSE:=ISC PKG_LICENSE_FILES:=LICENSE PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=@KERNEL/software/network/wireless-regdb/ -PKG_HASH:=9832a14e1be24abff7be30dee3c9a1afb5fdfcf475a0d91aafef039f8d85f5eb +PKG_HASH:=f76f2bd79a653e9f9dd50548d99d03a4a4eb157da056dfd5892f403ec28fb3d5 PKG_MAINTAINER:=Felix Fietkau diff --git a/package/firmware/wireless-regdb/patches/600-custom-change-txpower-and-dfs.patch b/package/firmware/wireless-regdb/patches/600-custom-change-txpower-and-dfs.patch index 1efdd19b23..2f464126da 100644 --- a/package/firmware/wireless-regdb/patches/600-custom-change-txpower-and-dfs.patch +++ b/package/firmware/wireless-regdb/patches/600-custom-change-txpower-and-dfs.patch @@ -1,17 +1,18 @@ --- a/db.txt +++ b/db.txt -@@ -415,8 +415,8 @@ country CL: DFS-JP +@@ -421,9 +421,8 @@ country CL: DFS-JP # https://www.miit.gov.cn/cms_files/filemanager/1226211233/attach/20236/d1dc19424d5a4cfe90d631adeee8dd58.pdf - # Note: The transmit power for 5150-5350MHz bands can be raised by 3dBm when TPC is implemented + # Note: The transmit power for 5250-5350MHz bands can be raised by 3dBm when TPC is implemented country CN: DFS-FCC - (2400 - 2483.5 @ 40), (20) -- (5150 - 5350 @ 80), (20), DFS, AUTO-BW, NO-OUTDOOR +- (5150 - 5250 @ 80), (23), NO-OUTDOOR, AUTO-BW +- (5250 - 5350 @ 80), (20), NO-OUTDOOR, DFS, AUTO-BW + (2400 - 2483.5 @ 40), (30) + (5150 - 5350 @ 160), (30) (5725 - 5850 @ 80), (33) # 60 GHz band channels 1,4: 28dBm, channels 2,3: 44dBm # ref: http://www.miit.gov.cn/n11293472/n11505629/n11506593/n11960250/n11960606/n11960700/n12330791.files/n12330790.pdf -@@ -1857,14 +1857,12 @@ country US: DFS-FCC +@@ -1916,14 +1915,12 @@ country US: DFS-FCC (920 - 928 @ 8), (30) (2400 - 2472 @ 40), (30) # 5.15 ~ 5.25 GHz: 30 dBm for master mode, 23 dBm for clients diff --git a/package/network/utils/iptables/Makefile b/package/network/utils/iptables/Makefile index d5511f33c1..8d2e257438 100644 --- a/package/network/utils/iptables/Makefile +++ b/package/network/utils/iptables/Makefile @@ -10,7 +10,7 @@ include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=iptables PKG_VERSION:=1.8.8 -PKG_RELEASE:=2 +PKG_RELEASE:=3 PKG_SOURCE_URL:=https://netfilter.org/projects/iptables/files PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2 diff --git a/package/network/utils/iptables/patches/104-nft-track-each-register-individually.patch b/package/network/utils/iptables/patches/104-nft-track-each-register-individually.patch new file mode 100644 index 0000000000..166dc86fa1 --- /dev/null +++ b/package/network/utils/iptables/patches/104-nft-track-each-register-individually.patch @@ -0,0 +1,1054 @@ +From f315af1cf88714702dcc51dc00b109df3d52e9e9 Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Fri, 23 Sep 2022 14:17:08 +0200 +Subject: nft: track each register individually + +Instead of assuming only one register is used, track all 16 regs +individually. + +This avoids need for the 'PREV_PAYLOAD' hack and also avoids the need to +clear out old flags: + +When we see that register 'x' will be written to, that register state is +reset automatically. + +Existing dissector decodes +ip saddr 1.2.3.4 meta l4proto tcp +... as +-s 6.0.0.0 -p tcp + +iptables-nft -s 1.2.3.4 -p tcp is decoded correctly because the expressions +are ordered like: + +meta l4proto tcp ip saddr 1.2.3.4 + | +... and 'meta l4proto' did clear the PAYLOAD flag. + +The simpler fix is: + ctx->flags &= ~NFT_XT_CTX_PAYLOAD; + +in nft_parse_cmp(), but that breaks dissection of '1-42', because +the second compare ('cmp lte 42') will not find the +payload expression anymore. + +Link: https://lore.kernel.org/netfilter-devel/20220922143544.GA22541@breakpoint.cc/T/#t +Signed-off-by: Florian Westphal +Reviewed-by: Phil Sutter +--- + iptables/nft-arp.c | 57 +++++++------- + iptables/nft-bridge.c | 102 +++++++++++++++---------- + iptables/nft-ipv4.c | 49 ++++++------ + iptables/nft-ipv6.c | 36 ++++----- + iptables/nft-shared.c | 205 +++++++++++++++++++++++++++++++++++--------------- + iptables/nft-shared.h | 110 ++++++++++++++++++++------- + 6 files changed, 360 insertions(+), 199 deletions(-) + +--- a/iptables/nft-arp.c ++++ b/iptables/nft-arp.c +@@ -160,25 +160,27 @@ static int nft_arp_add(struct nft_handle + return ret; + } + +-static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, ++static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, ++ const struct nft_xt_ctx_reg *reg, ++ struct nftnl_expr *e, + struct iptables_command_state *cs) + { + struct arpt_entry *fw = &cs->arp; + uint8_t flags = 0; + +- parse_meta(ctx, e, ctx->meta.key, fw->arp.iniface, fw->arp.iniface_mask, ++ parse_meta(ctx, e, reg->meta_dreg.key, fw->arp.iniface, fw->arp.iniface_mask, + fw->arp.outiface, fw->arp.outiface_mask, + &flags); + + fw->arp.invflags |= flags; + } + +-static void parse_mask_ipv4(struct nft_xt_ctx *ctx, struct in_addr *mask) ++static void parse_mask_ipv4(const struct nft_xt_ctx_reg *reg, struct in_addr *mask) + { +- mask->s_addr = ctx->bitwise.mask[0]; ++ mask->s_addr = reg->bitwise.mask[0]; + } + +-static bool nft_arp_parse_devaddr(struct nft_xt_ctx *ctx, ++static bool nft_arp_parse_devaddr(const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct arpt_devaddr_info *info) + { +@@ -192,18 +194,17 @@ static bool nft_arp_parse_devaddr(struct + + get_cmp_data(e, info->addr, ETH_ALEN, &inv); + +- if (ctx->flags & NFT_XT_CTX_BITWISE) { +- memcpy(info->mask, ctx->bitwise.mask, ETH_ALEN); +- ctx->flags &= ~NFT_XT_CTX_BITWISE; +- } else { ++ if (reg->bitwise.set) ++ memcpy(info->mask, reg->bitwise.mask, ETH_ALEN); ++ else + memset(info->mask, 0xff, +- min(ctx->payload.len, ETH_ALEN)); +- } ++ min(reg->payload.len, ETH_ALEN)); + + return inv; + } + + static void nft_arp_parse_payload(struct nft_xt_ctx *ctx, ++ const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct iptables_command_state *cs) + { +@@ -213,7 +214,7 @@ static void nft_arp_parse_payload(struct + uint8_t ar_hln; + bool inv; + +- switch (ctx->payload.offset) { ++ switch (reg->payload.offset) { + case offsetof(struct arphdr, ar_hrd): + get_cmp_data(e, &ar_hrd, sizeof(ar_hrd), &inv); + fw->arp.arhrd = ar_hrd; +@@ -243,43 +244,39 @@ static void nft_arp_parse_payload(struct + fw->arp.invflags |= IPT_INV_ARPOP; + break; + default: +- if (ctx->payload.offset == sizeof(struct arphdr)) { +- if (nft_arp_parse_devaddr(ctx, e, &fw->arp.src_devaddr)) ++ if (reg->payload.offset == sizeof(struct arphdr)) { ++ if (nft_arp_parse_devaddr(reg, e, &fw->arp.src_devaddr)) + fw->arp.invflags |= IPT_INV_SRCDEVADDR; +- } else if (ctx->payload.offset == sizeof(struct arphdr) + ++ } else if (reg->payload.offset == sizeof(struct arphdr) + + fw->arp.arhln) { + get_cmp_data(e, &addr, sizeof(addr), &inv); + fw->arp.src.s_addr = addr.s_addr; +- if (ctx->flags & NFT_XT_CTX_BITWISE) { +- parse_mask_ipv4(ctx, &fw->arp.smsk); +- ctx->flags &= ~NFT_XT_CTX_BITWISE; +- } else { ++ if (reg->bitwise.set) ++ parse_mask_ipv4(reg, &fw->arp.smsk); ++ else + memset(&fw->arp.smsk, 0xff, +- min(ctx->payload.len, ++ min(reg->payload.len, + sizeof(struct in_addr))); +- } + + if (inv) + fw->arp.invflags |= IPT_INV_SRCIP; +- } else if (ctx->payload.offset == sizeof(struct arphdr) + ++ } else if (reg->payload.offset == sizeof(struct arphdr) + + fw->arp.arhln + + sizeof(struct in_addr)) { +- if (nft_arp_parse_devaddr(ctx, e, &fw->arp.tgt_devaddr)) ++ if (nft_arp_parse_devaddr(reg, e, &fw->arp.tgt_devaddr)) + fw->arp.invflags |= IPT_INV_TGTDEVADDR; +- } else if (ctx->payload.offset == sizeof(struct arphdr) + ++ } else if (reg->payload.offset == sizeof(struct arphdr) + + fw->arp.arhln + + sizeof(struct in_addr) + + fw->arp.arhln) { + get_cmp_data(e, &addr, sizeof(addr), &inv); + fw->arp.tgt.s_addr = addr.s_addr; +- if (ctx->flags & NFT_XT_CTX_BITWISE) { +- parse_mask_ipv4(ctx, &fw->arp.tmsk); +- ctx->flags &= ~NFT_XT_CTX_BITWISE; +- } else { ++ if (reg->bitwise.set) ++ parse_mask_ipv4(reg, &fw->arp.tmsk); ++ else + memset(&fw->arp.tmsk, 0xff, +- min(ctx->payload.len, ++ min(reg->payload.len, + sizeof(struct in_addr))); +- } + + if (inv) + fw->arp.invflags |= IPT_INV_DSTIP; +--- a/iptables/nft-bridge.c ++++ b/iptables/nft-bridge.c +@@ -170,6 +170,7 @@ static int nft_bridge_add(struct nft_han + } + + static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, ++ const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct iptables_command_state *cs) + { +@@ -177,9 +178,9 @@ static void nft_bridge_parse_meta(struct + uint8_t invflags = 0; + char iifname[IFNAMSIZ] = {}, oifname[IFNAMSIZ] = {}; + +- parse_meta(ctx, e, ctx->meta.key, iifname, NULL, oifname, NULL, &invflags); ++ parse_meta(ctx, e, reg->meta_dreg.key, iifname, NULL, oifname, NULL, &invflags); + +- switch (ctx->meta.key) { ++ switch (reg->meta_dreg.key) { + case NFT_META_BRI_IIFNAME: + if (invflags & IPT_INV_VIA_IN) + cs->eb.invflags |= EBT_ILOGICALIN; +@@ -206,6 +207,7 @@ static void nft_bridge_parse_meta(struct + } + + static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, ++ const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct iptables_command_state *cs) + { +@@ -215,7 +217,7 @@ static void nft_bridge_parse_payload(str + bool inv; + int i; + +- switch (ctx->payload.offset) { ++ switch (reg->payload.offset) { + case offsetof(struct ethhdr, h_dest): + get_cmp_data(e, addr, sizeof(addr), &inv); + for (i = 0; i < ETH_ALEN; i++) +@@ -223,13 +225,11 @@ static void nft_bridge_parse_payload(str + if (inv) + fw->invflags |= EBT_IDEST; + +- if (ctx->flags & NFT_XT_CTX_BITWISE) { +- memcpy(fw->destmsk, ctx->bitwise.mask, ETH_ALEN); +- ctx->flags &= ~NFT_XT_CTX_BITWISE; +- } else { ++ if (reg->bitwise.set) ++ memcpy(fw->destmsk, reg->bitwise.mask, ETH_ALEN); ++ else + memset(&fw->destmsk, 0xff, +- min(ctx->payload.len, ETH_ALEN)); +- } ++ min(reg->payload.len, ETH_ALEN)); + fw->bitmask |= EBT_IDEST; + break; + case offsetof(struct ethhdr, h_source): +@@ -238,13 +238,11 @@ static void nft_bridge_parse_payload(str + fw->sourcemac[i] = addr[i]; + if (inv) + fw->invflags |= EBT_ISOURCE; +- if (ctx->flags & NFT_XT_CTX_BITWISE) { +- memcpy(fw->sourcemsk, ctx->bitwise.mask, ETH_ALEN); +- ctx->flags &= ~NFT_XT_CTX_BITWISE; +- } else { ++ if (reg->bitwise.set) ++ memcpy(fw->sourcemsk, reg->bitwise.mask, ETH_ALEN); ++ else + memset(&fw->sourcemsk, 0xff, +- min(ctx->payload.len, ETH_ALEN)); +- } ++ min(reg->payload.len, ETH_ALEN)); + fw->bitmask |= EBT_ISOURCE; + break; + case offsetof(struct ethhdr, h_proto): +@@ -294,28 +292,53 @@ lookup_check_iphdr_payload(uint32_t base + /* Make sure previous payload expression(s) is/are consistent and extract if + * matching on source or destination address and if matching on MAC and IP or + * only MAC address. */ +-static int lookup_analyze_payloads(const struct nft_xt_ctx *ctx, ++static int lookup_analyze_payloads(struct nft_xt_ctx *ctx, ++ enum nft_registers sreg, ++ uint32_t key_len, + bool *dst, bool *ip) + { ++ const struct nft_xt_ctx_reg *reg; ++ uint32_t sreg_count; + int val, val2 = -1; + +- if (ctx->flags & NFT_XT_CTX_PREV_PAYLOAD) { +- val = lookup_check_ether_payload(ctx->prev_payload.base, +- ctx->prev_payload.offset, +- ctx->prev_payload.len); ++ reg = nft_xt_ctx_get_sreg(ctx, sreg); ++ if (!reg) ++ return -1; ++ ++ if (reg->type != NFT_XT_REG_PAYLOAD) { ++ ctx->errmsg = "lookup reg is not payload type"; ++ return -1; ++ } ++ ++ sreg_count = sreg; ++ switch (key_len) { ++ case 12: /* ether + ipv4addr */ ++ val = lookup_check_ether_payload(reg->payload.base, ++ reg->payload.offset, ++ reg->payload.len); + if (val < 0) { + DEBUGP("unknown payload base/offset/len %d/%d/%d\n", +- ctx->prev_payload.base, ctx->prev_payload.offset, +- ctx->prev_payload.len); ++ reg->payload.base, reg->payload.offset, ++ reg->payload.len); + return -1; + } +- if (!(ctx->flags & NFT_XT_CTX_PAYLOAD)) { +- DEBUGP("Previous but no current payload?\n"); ++ ++ sreg_count += 2; ++ ++ reg = nft_xt_ctx_get_sreg(ctx, sreg_count); ++ if (!reg) { ++ ctx->errmsg = "next lookup register is invalid"; ++ return -1; ++ } ++ ++ if (reg->type != NFT_XT_REG_PAYLOAD) { ++ ctx->errmsg = "next lookup reg is not payload type"; + return -1; + } +- val2 = lookup_check_iphdr_payload(ctx->payload.base, +- ctx->payload.offset, +- ctx->payload.len); ++ ++ val2 = lookup_check_iphdr_payload(reg->payload.base, ++ reg->payload.offset, ++ reg->payload.len); + if (val2 < 0) { + DEBUGP("unknown payload base/offset/len %d/%d/%d\n", + ctx->payload.base, ctx->payload.offset, +@@ -325,18 +348,20 @@ static int lookup_analyze_payloads(const + DEBUGP("mismatching payload match offsets\n"); + return -1; + } +- } else if (ctx->flags & NFT_XT_CTX_PAYLOAD) { +- val = lookup_check_ether_payload(ctx->payload.base, +- ctx->payload.offset, +- ctx->payload.len); ++ break; ++ case 4: /* ipv4addr */ ++ val = lookup_check_ether_payload(reg->payload.base, ++ reg->payload.offset, ++ reg->payload.len); + if (val < 0) { + DEBUGP("unknown payload base/offset/len %d/%d/%d\n", + ctx->payload.base, ctx->payload.offset, + ctx->payload.len); + return -1; + } +- } else { +- DEBUGP("unknown LHS of lookup expression\n"); ++ break; ++ default: ++ ctx->errmsg = "unsupported lookup key length"; + return -1; + } + +@@ -413,14 +438,17 @@ static void nft_bridge_parse_lookup(stru + size_t poff, size; + uint32_t cnt; + +- if (lookup_analyze_payloads(ctx, &is_dst, &have_ip)) +- return; +- + s = set_from_lookup_expr(ctx, e); + if (!s) + xtables_error(OTHER_PROBLEM, + "BUG: lookup expression references unknown set"); + ++ if (lookup_analyze_payloads(ctx, ++ nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_SREG), ++ nftnl_set_get_u32(s, NFTNL_SET_KEY_LEN), ++ &is_dst, &have_ip)) ++ return; ++ + cnt = nftnl_set_get_u32(s, NFTNL_SET_DESC_SIZE); + + for (ematch = ctx->cs->match_list; ematch; ematch = ematch->next) { +@@ -468,8 +496,6 @@ static void nft_bridge_parse_lookup(stru + if (set_elems_to_among_pairs(among_data->pairs + poff, s, cnt)) + xtables_error(OTHER_PROBLEM, + "ebtables among pair parsing failed"); +- +- ctx->flags &= ~(NFT_XT_CTX_PAYLOAD | NFT_XT_CTX_PREV_PAYLOAD); + } + + static void parse_watcher(void *object, struct ebt_match **match_list, +--- a/iptables/nft-ipv4.c ++++ b/iptables/nft-ipv4.c +@@ -115,28 +115,28 @@ static bool nft_ipv4_is_same(const struc + b->fw.ip.iniface_mask, b->fw.ip.outiface_mask); + } + +-static void get_frag(struct nft_xt_ctx *ctx, struct nftnl_expr *e, bool *inv) ++static bool get_frag(const struct nft_xt_ctx_reg *reg, struct nftnl_expr *e) + { + uint8_t op; + + /* we assume correct mask and xor */ +- if (!(ctx->flags & NFT_XT_CTX_BITWISE)) +- return; ++ if (!reg->bitwise.set) ++ return false; + + /* we assume correct data */ + op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); + if (op == NFT_CMP_EQ) +- *inv = true; +- else +- *inv = false; ++ return true; + +- ctx->flags &= ~NFT_XT_CTX_BITWISE; ++ return false; + } + +-static void nft_ipv4_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, ++static void nft_ipv4_parse_meta(struct nft_xt_ctx *ctx, ++ const struct nft_xt_ctx_reg *reg, ++ struct nftnl_expr *e, + struct iptables_command_state *cs) + { +- switch (ctx->meta.key) { ++ switch (reg->meta_dreg.key) { + case NFT_META_L4PROTO: + cs->fw.ip.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); + if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) +@@ -146,17 +146,18 @@ static void nft_ipv4_parse_meta(struct n + break; + } + +- parse_meta(ctx, e, ctx->meta.key, cs->fw.ip.iniface, cs->fw.ip.iniface_mask, ++ parse_meta(ctx, e, reg->meta_dreg.key, cs->fw.ip.iniface, cs->fw.ip.iniface_mask, + cs->fw.ip.outiface, cs->fw.ip.outiface_mask, + &cs->fw.ip.invflags); + } + +-static void parse_mask_ipv4(struct nft_xt_ctx *ctx, struct in_addr *mask) ++static void parse_mask_ipv4(const struct nft_xt_ctx_reg *sreg, struct in_addr *mask) + { +- mask->s_addr = ctx->bitwise.mask[0]; ++ mask->s_addr = sreg->bitwise.mask[0]; + } + + static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx, ++ const struct nft_xt_ctx_reg *sreg, + struct nftnl_expr *e, + struct iptables_command_state *cs) + { +@@ -164,16 +165,15 @@ static void nft_ipv4_parse_payload(struc + uint8_t proto; + bool inv; + +- switch(ctx->payload.offset) { ++ switch (sreg->payload.offset) { + case offsetof(struct iphdr, saddr): + get_cmp_data(e, &addr, sizeof(addr), &inv); + cs->fw.ip.src.s_addr = addr.s_addr; +- if (ctx->flags & NFT_XT_CTX_BITWISE) { +- parse_mask_ipv4(ctx, &cs->fw.ip.smsk); +- ctx->flags &= ~NFT_XT_CTX_BITWISE; ++ if (sreg->bitwise.set) { ++ parse_mask_ipv4(sreg, &cs->fw.ip.smsk); + } else { + memset(&cs->fw.ip.smsk, 0xff, +- min(ctx->payload.len, sizeof(struct in_addr))); ++ min(sreg->payload.len, sizeof(struct in_addr))); + } + + if (inv) +@@ -182,13 +182,11 @@ static void nft_ipv4_parse_payload(struc + case offsetof(struct iphdr, daddr): + get_cmp_data(e, &addr, sizeof(addr), &inv); + cs->fw.ip.dst.s_addr = addr.s_addr; +- if (ctx->flags & NFT_XT_CTX_BITWISE) { +- parse_mask_ipv4(ctx, &cs->fw.ip.dmsk); +- ctx->flags &= ~NFT_XT_CTX_BITWISE; +- } else { ++ if (sreg->bitwise.set) ++ parse_mask_ipv4(sreg, &cs->fw.ip.dmsk); ++ else + memset(&cs->fw.ip.dmsk, 0xff, +- min(ctx->payload.len, sizeof(struct in_addr))); +- } ++ min(sreg->payload.len, sizeof(struct in_addr))); + + if (inv) + cs->fw.ip.invflags |= IPT_INV_DSTIP; +@@ -201,13 +199,12 @@ static void nft_ipv4_parse_payload(struc + break; + case offsetof(struct iphdr, frag_off): + cs->fw.ip.flags |= IPT_F_FRAG; +- inv = false; +- get_frag(ctx, e, &inv); ++ inv = get_frag(sreg, e); + if (inv) + cs->fw.ip.invflags |= IPT_INV_FRAG; + break; + default: +- DEBUGP("unknown payload offset %d\n", ctx->payload.offset); ++ DEBUGP("unknown payload offset %d\n", sreg->payload.offset); + break; + } + } +--- a/iptables/nft-ipv6.c ++++ b/iptables/nft-ipv6.c +@@ -104,10 +104,12 @@ static bool nft_ipv6_is_same(const struc + b->fw6.ipv6.outiface_mask); + } + +-static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, ++static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx, ++ const struct nft_xt_ctx_reg *reg, ++ struct nftnl_expr *e, + struct iptables_command_state *cs) + { +- switch (ctx->meta.key) { ++ switch (reg->meta_dreg.key) { + case NFT_META_L4PROTO: + cs->fw6.ipv6.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); + if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) +@@ -117,17 +119,19 @@ static void nft_ipv6_parse_meta(struct n + break; + } + +- parse_meta(ctx, e, ctx->meta.key, cs->fw6.ipv6.iniface, ++ parse_meta(ctx, e, reg->meta_dreg.key, cs->fw6.ipv6.iniface, + cs->fw6.ipv6.iniface_mask, cs->fw6.ipv6.outiface, + cs->fw6.ipv6.outiface_mask, &cs->fw6.ipv6.invflags); + } + +-static void parse_mask_ipv6(struct nft_xt_ctx *ctx, struct in6_addr *mask) ++static void parse_mask_ipv6(const struct nft_xt_ctx_reg *reg, ++ struct in6_addr *mask) + { +- memcpy(mask, ctx->bitwise.mask, sizeof(struct in6_addr)); ++ memcpy(mask, reg->bitwise.mask, sizeof(struct in6_addr)); + } + + static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx, ++ const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct iptables_command_state *cs) + { +@@ -135,17 +139,15 @@ static void nft_ipv6_parse_payload(struc + uint8_t proto; + bool inv; + +- switch (ctx->payload.offset) { ++ switch (reg->payload.offset) { + case offsetof(struct ip6_hdr, ip6_src): + get_cmp_data(e, &addr, sizeof(addr), &inv); + memcpy(cs->fw6.ipv6.src.s6_addr, &addr, sizeof(addr)); +- if (ctx->flags & NFT_XT_CTX_BITWISE) { +- parse_mask_ipv6(ctx, &cs->fw6.ipv6.smsk); +- ctx->flags &= ~NFT_XT_CTX_BITWISE; +- } else { ++ if (reg->bitwise.set) ++ parse_mask_ipv6(reg, &cs->fw6.ipv6.smsk); ++ else + memset(&cs->fw6.ipv6.smsk, 0xff, +- min(ctx->payload.len, sizeof(struct in6_addr))); +- } ++ min(reg->payload.len, sizeof(struct in6_addr))); + + if (inv) + cs->fw6.ipv6.invflags |= IP6T_INV_SRCIP; +@@ -153,13 +155,11 @@ static void nft_ipv6_parse_payload(struc + case offsetof(struct ip6_hdr, ip6_dst): + get_cmp_data(e, &addr, sizeof(addr), &inv); + memcpy(cs->fw6.ipv6.dst.s6_addr, &addr, sizeof(addr)); +- if (ctx->flags & NFT_XT_CTX_BITWISE) { +- parse_mask_ipv6(ctx, &cs->fw6.ipv6.dmsk); +- ctx->flags &= ~NFT_XT_CTX_BITWISE; +- } else { ++ if (reg->bitwise.set) ++ parse_mask_ipv6(reg, &cs->fw6.ipv6.dmsk); ++ else + memset(&cs->fw6.ipv6.dmsk, 0xff, +- min(ctx->payload.len, sizeof(struct in6_addr))); +- } ++ min(reg->payload.len, sizeof(struct in6_addr))); + + if (inv) + cs->fw6.ipv6.invflags |= IP6T_INV_DSTIP; +--- a/iptables/nft-shared.c ++++ b/iptables/nft-shared.c +@@ -295,6 +295,16 @@ nft_create_match(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + const char *name); + ++static uint32_t get_meta_mask(struct nft_xt_ctx *ctx, enum nft_registers sreg) ++{ ++ struct nft_xt_ctx_reg *reg = nft_xt_ctx_get_sreg(ctx, sreg); ++ ++ if (reg->bitwise.set) ++ return reg->bitwise.mask[0]; ++ ++ return ~0u; ++} ++ + static int parse_meta_mark(struct nft_xt_ctx *ctx, struct nftnl_expr *e) + { + struct xt_mark_mtinfo1 *mark; +@@ -312,12 +322,7 @@ static int parse_meta_mark(struct nft_xt + + value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA); + mark->mark = value; +- if (ctx->flags & NFT_XT_CTX_BITWISE) { +- memcpy(&mark->mask, &ctx->bitwise.mask, sizeof(mark->mask)); +- ctx->flags &= ~NFT_XT_CTX_BITWISE; +- } else { +- mark->mask = 0xffffffff; +- } ++ mark->mask = get_meta_mask(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG)); + + return 0; + } +@@ -451,20 +456,40 @@ void get_cmp_data(struct nftnl_expr *e, + *inv = false; + } + +-static void nft_meta_set_to_target(struct nft_xt_ctx *ctx) ++static void nft_meta_set_to_target(struct nft_xt_ctx *ctx, ++ struct nftnl_expr *e) + { + struct xtables_target *target; ++ struct nft_xt_ctx_reg *sreg; ++ enum nft_registers sregnum; + struct xt_entry_target *t; + unsigned int size; + const char *targname; + +- switch (ctx->meta.key) { ++ sregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_META_SREG); ++ sreg = nft_xt_ctx_get_sreg(ctx, sregnum); ++ if (!sreg) ++ return; ++ ++ if (sreg->meta_sreg.set == 0) ++ return; ++ ++ switch (sreg->meta_sreg.key) { + case NFT_META_NFTRACE: +- if (ctx->immediate.data[0] == 0) ++ if ((sreg->type != NFT_XT_REG_IMMEDIATE)) { ++ ctx->errmsg = "meta nftrace but reg not immediate"; + return; ++ } ++ ++ if (sreg->immediate.data[0] == 0) { ++ ctx->errmsg = "trace is cleared"; ++ return; ++ } ++ + targname = "TRACE"; + break; + default: ++ ctx->errmsg = "meta sreg key not supported"; + return; + } + +@@ -486,51 +511,74 @@ static void nft_meta_set_to_target(struc + + static void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e) + { +- ctx->meta.key = nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY); ++ struct nft_xt_ctx_reg *reg; + +- if (nftnl_expr_is_set(e, NFTNL_EXPR_META_SREG) && +- (ctx->flags & NFT_XT_CTX_IMMEDIATE) && +- nftnl_expr_get_u32(e, NFTNL_EXPR_META_SREG) == ctx->immediate.reg) { +- ctx->flags &= ~NFT_XT_CTX_IMMEDIATE; +- nft_meta_set_to_target(ctx); ++ if (nftnl_expr_is_set(e, NFTNL_EXPR_META_SREG)) { ++ nft_meta_set_to_target(ctx, e); + return; + } + +- ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG); +- ctx->flags |= NFT_XT_CTX_META; ++ reg = nft_xt_ctx_get_dreg(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG)); ++ if (!reg) ++ return; ++ ++ reg->meta_dreg.key = nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY); ++ reg->type = NFT_XT_REG_META_DREG; + } + + static void nft_parse_payload(struct nft_xt_ctx *ctx, struct nftnl_expr *e) + { +- if (ctx->flags & NFT_XT_CTX_PAYLOAD) { +- memcpy(&ctx->prev_payload, &ctx->payload, +- sizeof(ctx->prev_payload)); +- ctx->flags |= NFT_XT_CTX_PREV_PAYLOAD; +- } ++ enum nft_registers regnum = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_DREG); ++ struct nft_xt_ctx_reg *reg = nft_xt_ctx_get_dreg(ctx, regnum); + +- ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_DREG); +- ctx->payload.base = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_BASE); +- ctx->payload.offset = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET); +- ctx->payload.len = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_LEN); +- ctx->flags |= NFT_XT_CTX_PAYLOAD; ++ if (!reg) ++ return; ++ ++ reg->type = NFT_XT_REG_PAYLOAD; ++ reg->payload.base = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_BASE); ++ reg->payload.offset = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET); ++ reg->payload.len = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_LEN); + } + + static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e) + { +- uint32_t reg, len; ++ enum nft_registers sregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_SREG); ++ enum nft_registers dregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_DREG); ++ struct nft_xt_ctx_reg *sreg = nft_xt_ctx_get_sreg(ctx, sregnum); ++ struct nft_xt_ctx_reg *dreg = sreg; + const void *data; ++ uint32_t len; + +- reg = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_SREG); +- if (ctx->reg && reg != ctx->reg) ++ if (!sreg) + return; + +- reg = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_DREG); +- ctx->reg = reg; ++ if (sregnum != dregnum) { ++ dreg = nft_xt_ctx_get_sreg(ctx, dregnum); /* sreg, do NOT clear ... */ ++ if (!dreg) ++ return; ++ ++ *dreg = *sreg; /* .. and copy content instead */ ++ } ++ + data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_XOR, &len); +- memcpy(ctx->bitwise.xor, data, len); ++ ++ if (len > sizeof(dreg->bitwise.xor)) { ++ ctx->errmsg = "bitwise xor too large"; ++ return; ++ } ++ ++ memcpy(dreg->bitwise.xor, data, len); ++ + data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_MASK, &len); +- memcpy(ctx->bitwise.mask, data, len); +- ctx->flags |= NFT_XT_CTX_BITWISE; ++ ++ if (len > sizeof(dreg->bitwise.mask)) { ++ ctx->errmsg = "bitwise mask too large"; ++ return; ++ } ++ ++ memcpy(dreg->bitwise.mask, data, len); ++ ++ dreg->bitwise.set = true; + } + + static struct xtables_match * +@@ -835,6 +883,8 @@ static void nft_parse_transport(struct n + struct nftnl_expr *e, + struct iptables_command_state *cs) + { ++ struct nft_xt_ctx_reg *sreg; ++ enum nft_registers reg; + uint32_t sdport; + uint16_t port; + uint8_t proto, op; +@@ -855,7 +905,17 @@ static void nft_parse_transport(struct n + nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len); + op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); + +- switch(ctx->payload.offset) { ++ reg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG); ++ sreg = nft_xt_ctx_get_sreg(ctx, reg); ++ if (!sreg) ++ return; ++ ++ if (sreg->type != NFT_XT_REG_PAYLOAD) { ++ ctx->errmsg = "sgreg not payload"; ++ return; ++ } ++ ++ switch(sreg->payload.offset) { + case 0: /* th->sport */ + switch (len) { + case 2: /* load sport only */ +@@ -881,10 +941,9 @@ static void nft_parse_transport(struct n + uint8_t flags = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); + uint8_t mask = ~0; + +- if (ctx->flags & NFT_XT_CTX_BITWISE) { +- memcpy(&mask, &ctx->bitwise.mask, sizeof(mask)); +- ctx->flags &= ~NFT_XT_CTX_BITWISE; +- } ++ if (sreg->bitwise.set) ++ memcpy(&mask, &sreg->bitwise.mask, sizeof(mask)); ++ + nft_parse_tcp_flags(ctx, cs, op, flags, mask); + } + return; +@@ -892,6 +951,7 @@ static void nft_parse_transport(struct n + } + + static void nft_parse_transport_range(struct nft_xt_ctx *ctx, ++ const struct nft_xt_ctx_reg *sreg, + struct nftnl_expr *e, + struct iptables_command_state *cs) + { +@@ -921,7 +981,7 @@ static void nft_parse_transport_range(st + from = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_FROM_DATA)); + to = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_TO_DATA)); + +- switch(ctx->payload.offset) { ++ switch (sreg->payload.offset) { + case 0: + nft_parse_th_port_range(ctx, cs, proto, from, to, -1, -1, op); + return; +@@ -934,30 +994,40 @@ static void nft_parse_transport_range(st + + static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e) + { ++ struct nft_xt_ctx_reg *sreg; + uint32_t reg; + + reg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG); +- if (ctx->reg && reg != ctx->reg) ++ ++ sreg = nft_xt_ctx_get_sreg(ctx, reg); ++ if (!sreg) + return; + +- if (ctx->flags & NFT_XT_CTX_META) { +- ctx->h->ops->parse_meta(ctx, e, ctx->cs); +- ctx->flags &= ~NFT_XT_CTX_META; +- } +- /* bitwise context is interpreted from payload */ +- if (ctx->flags & NFT_XT_CTX_PAYLOAD) { +- switch (ctx->payload.base) { ++ switch (sreg->type) { ++ case NFT_XT_REG_UNDEF: ++ ctx->errmsg = "cmp sreg undef"; ++ break; ++ case NFT_XT_REG_META_DREG: ++ ctx->h->ops->parse_meta(ctx, sreg, e, ctx->cs); ++ break; ++ case NFT_XT_REG_PAYLOAD: ++ switch (sreg->payload.base) { + case NFT_PAYLOAD_LL_HEADER: + if (ctx->h->family == NFPROTO_BRIDGE) +- ctx->h->ops->parse_payload(ctx, e, ctx->cs); ++ ctx->h->ops->parse_payload(ctx, sreg, e, ctx->cs); + break; + case NFT_PAYLOAD_NETWORK_HEADER: +- ctx->h->ops->parse_payload(ctx, e, ctx->cs); ++ ctx->h->ops->parse_payload(ctx, sreg, e, ctx->cs); + break; + case NFT_PAYLOAD_TRANSPORT_HEADER: + nft_parse_transport(ctx, e, ctx->cs); + break; + } ++ ++ break; ++ default: ++ ctx->errmsg = "cmp sreg has unknown type"; ++ break; + } + } + +@@ -976,18 +1046,22 @@ static void nft_parse_immediate(struct n + int verdict; + + if (nftnl_expr_is_set(e, NFTNL_EXPR_IMM_DATA)) { ++ struct nft_xt_ctx_reg *dreg; + const void *imm_data; + uint32_t len; + + imm_data = nftnl_expr_get_data(e, NFTNL_EXPR_IMM_DATA, &len); ++ dreg = nft_xt_ctx_get_dreg(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_DREG)); ++ if (!dreg) ++ return; + +- if (len > sizeof(ctx->immediate.data)) ++ if (len > sizeof(dreg->immediate.data)) + return; + +- memcpy(ctx->immediate.data, imm_data, len); +- ctx->immediate.len = len; +- ctx->immediate.reg = nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_DREG); +- ctx->flags |= NFT_XT_CTX_IMMEDIATE; ++ memcpy(dreg->immediate.data, imm_data, len); ++ dreg->immediate.len = len; ++ dreg->type = NFT_XT_REG_IMMEDIATE; ++ + return; + } + +@@ -1124,20 +1198,29 @@ static void nft_parse_lookup(struct nft_ + + static void nft_parse_range(struct nft_xt_ctx *ctx, struct nftnl_expr *e) + { ++ struct nft_xt_ctx_reg *sreg; + uint32_t reg; + + reg = nftnl_expr_get_u32(e, NFTNL_EXPR_RANGE_SREG); +- if (reg != ctx->reg) +- return; ++ sreg = nft_xt_ctx_get_sreg(ctx, reg); + +- if (ctx->flags & NFT_XT_CTX_PAYLOAD) { +- switch (ctx->payload.base) { ++ switch (sreg->type) { ++ case NFT_XT_REG_UNDEF: ++ ctx->errmsg = "range sreg undef"; ++ break; ++ case NFT_XT_REG_PAYLOAD: ++ switch (sreg->payload.base) { + case NFT_PAYLOAD_TRANSPORT_HEADER: +- nft_parse_transport_range(ctx, e, ctx->cs); ++ nft_parse_transport_range(ctx, sreg, e, ctx->cs); + break; + default: ++ ctx->errmsg = "range with unknown payload base"; + break; + } ++ break; ++ default: ++ ctx->errmsg = "range sreg type unsupported"; ++ break; + } + } + +--- a/iptables/nft-shared.h ++++ b/iptables/nft-shared.h +@@ -38,13 +38,41 @@ struct xtables_args; + struct nft_handle; + struct xt_xlate; + +-enum { +- NFT_XT_CTX_PAYLOAD = (1 << 0), +- NFT_XT_CTX_META = (1 << 1), +- NFT_XT_CTX_BITWISE = (1 << 2), +- NFT_XT_CTX_IMMEDIATE = (1 << 3), +- NFT_XT_CTX_PREV_PAYLOAD = (1 << 4), +- NFT_XT_CTX_RANGE = (1 << 5), ++enum nft_ctx_reg_type { ++ NFT_XT_REG_UNDEF, ++ NFT_XT_REG_PAYLOAD, ++ NFT_XT_REG_IMMEDIATE, ++ NFT_XT_REG_META_DREG, ++}; ++ ++struct nft_xt_ctx_reg { ++ enum nft_ctx_reg_type type:8; ++ ++ union { ++ struct { ++ uint32_t base; ++ uint32_t offset; ++ uint32_t len; ++ } payload; ++ struct { ++ uint32_t data[4]; ++ uint8_t len; ++ } immediate; ++ struct { ++ uint32_t key; ++ } meta_dreg; ++ }; ++ ++ struct { ++ uint32_t mask[4]; ++ uint32_t xor[4]; ++ bool set; ++ } bitwise; ++ ++ struct { ++ uint32_t key; ++ bool set; ++ } meta_sreg; + }; + + struct nft_xt_ctx { +@@ -58,25 +86,51 @@ struct nft_xt_ctx { + struct xt_udp *udp; + } tcpudp; + +- uint32_t reg; +- struct { +- uint32_t base; +- uint32_t offset; +- uint32_t len; +- } payload, prev_payload; +- struct { +- uint32_t key; +- } meta; +- struct { +- uint32_t data[4]; +- uint32_t len, reg; +- } immediate; +- struct { +- uint32_t mask[4]; +- uint32_t xor[4]; +- } bitwise; ++ struct nft_xt_ctx_reg regs[1 + 16]; ++ ++ const char *errmsg; + }; + ++static inline struct nft_xt_ctx_reg *nft_xt_ctx_get_sreg(struct nft_xt_ctx *ctx, enum nft_registers reg) ++{ ++ switch (reg) { ++ case NFT_REG_VERDICT: ++ return &ctx->regs[0]; ++ case NFT_REG_1: ++ return &ctx->regs[1]; ++ case NFT_REG_2: ++ return &ctx->regs[5]; ++ case NFT_REG_3: ++ return &ctx->regs[9]; ++ case NFT_REG_4: ++ return &ctx->regs[13]; ++ case NFT_REG32_00...NFT_REG32_15: ++ return &ctx->regs[reg - NFT_REG32_00]; ++ default: ++ ctx->errmsg = "Unknown register requested"; ++ break; ++ } ++ ++ return NULL; ++} ++ ++static inline void nft_xt_reg_clear(struct nft_xt_ctx_reg *r) ++{ ++ r->type = 0; ++ r->bitwise.set = false; ++ r->meta_sreg.set = false; ++} ++ ++static inline struct nft_xt_ctx_reg *nft_xt_ctx_get_dreg(struct nft_xt_ctx *ctx, enum nft_registers reg) ++{ ++ struct nft_xt_ctx_reg *r = nft_xt_ctx_get_sreg(ctx, reg); ++ ++ if (r) ++ nft_xt_reg_clear(r); ++ ++ return r; ++} ++ + struct nft_family_ops { + int (*add)(struct nft_handle *h, struct nftnl_rule *r, + struct iptables_command_state *cs); +@@ -84,9 +138,13 @@ struct nft_family_ops { + const struct iptables_command_state *cs_b); + void (*print_payload)(struct nftnl_expr *e, + struct nftnl_expr_iter *iter); +- void (*parse_meta)(struct nft_xt_ctx *ctx, struct nftnl_expr *e, ++ void (*parse_meta)(struct nft_xt_ctx *ctx, ++ const struct nft_xt_ctx_reg *sreg, ++ struct nftnl_expr *e, + struct iptables_command_state *cs); +- void (*parse_payload)(struct nft_xt_ctx *ctx, struct nftnl_expr *e, ++ void (*parse_payload)(struct nft_xt_ctx *ctx, ++ const struct nft_xt_ctx_reg *sreg, ++ struct nftnl_expr *e, + struct iptables_command_state *cs); + void (*parse_lookup)(struct nft_xt_ctx *ctx, struct nftnl_expr *e); + void (*set_goto_flag)(struct iptables_command_state *cs); diff --git a/target/linux/generic/backport-5.15/893-v6.12-mtd-spinand-winbond-add-support-for-W25N01KV.patch b/target/linux/generic/backport-5.15/893-v6.12-mtd-spinand-winbond-add-support-for-W25N01KV.patch new file mode 100644 index 0000000000..49ac690a41 --- /dev/null +++ b/target/linux/generic/backport-5.15/893-v6.12-mtd-spinand-winbond-add-support-for-W25N01KV.patch @@ -0,0 +1,65 @@ +From e2a9fcb36e851adb5b25c4acea53a290fd48a636 Mon Sep 17 00:00:00 2001 +From: Robert Marko +Date: Mon, 5 Aug 2024 19:51:02 +0200 +Subject: [PATCH] mtd: spinand: winbond: add support for W25N01KV + +Add support for Winbond W25N01KV 1Gbit SPI-NAND. + +It has 4-bit on-die ECC. + +Signed-off-by: Robert Marko +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20240805175125.6658-1-robimarko@gmail.com +--- + drivers/mtd/nand/spi/winbond.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +--- a/drivers/mtd/nand/spi/winbond.c ++++ b/drivers/mtd/nand/spi/winbond.c +@@ -74,6 +74,18 @@ static int w25m02gv_select_target(struct + return spi_mem_exec_op(spinand->spimem, &op); + } + ++static int w25n01kv_ooblayout_ecc(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *region) ++{ ++ if (section > 3) ++ return -ERANGE; ++ ++ region->offset = 64 + (8 * section); ++ region->length = 7; ++ ++ return 0; ++} ++ + static int w25n02kv_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) + { +@@ -98,6 +110,11 @@ static int w25n02kv_ooblayout_free(struc + return 0; + } + ++static const struct mtd_ooblayout_ops w25n01kv_ooblayout = { ++ .ecc = w25n01kv_ooblayout_ecc, ++ .free = w25n02kv_ooblayout_free, ++}; ++ + static const struct mtd_ooblayout_ops w25n02kv_ooblayout = { + .ecc = w25n02kv_ooblayout_ecc, + .free = w25n02kv_ooblayout_free, +@@ -160,6 +177,15 @@ static const struct spinand_info winbond + &update_cache_variants), + 0, + SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)), ++ SPINAND_INFO("W25N01KV", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xae, 0x21), ++ NAND_MEMORG(1, 2048, 96, 64, 1024, 20, 1, 1, 1), ++ NAND_ECCREQ(4, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ++ &write_cache_variants, ++ &update_cache_variants), ++ 0, ++ SPINAND_ECCINFO(&w25n01kv_ooblayout, w25n02kv_ecc_get_status)), + SPINAND_INFO("W25N02KV", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), diff --git a/target/linux/mediatek/patches-5.15/341-mtd-spinand-winbond-Support-for-W25MxxGV-W25NxxKV-se.patch b/target/linux/mediatek/patches-5.15/341-mtd-spinand-winbond-Support-for-W25MxxGV-W25NxxKV-se.patch deleted file mode 100644 index 197c9af2b6..0000000000 --- a/target/linux/mediatek/patches-5.15/341-mtd-spinand-winbond-Support-for-W25MxxGV-W25NxxKV-se.patch +++ /dev/null @@ -1,161 +0,0 @@ -From 9471c6ebf176284108115f60e22a176e70b97c0b Mon Sep 17 00:00:00 2001 -From: Chen Minqiang -Date: Thu, 12 Oct 2023 06:51:40 +0800 -Subject: [PATCH] mtd: spinand: winbond: Support for W25MxxGV W25NxxKV series - ---- - drivers/mtd/nand/spi/winbond.c | 115 +++++++++++++++++++++++++++++++++ - 1 file changed, 115 insertions(+) - ---- a/drivers/mtd/nand/spi/winbond.c -+++ b/drivers/mtd/nand/spi/winbond.c -@@ -15,6 +15,23 @@ - - #define WINBOND_CFG_BUF_READ BIT(3) - -+#define W25N02_N04KV_STATUS_ECC_MASK (3 << 4) -+#define W25N02_N04KV_STATUS_ECC_NO_BITFLIPS (0 << 4) -+#define W25N02_N04KV_STATUS_ECC_1_4_BITFLIPS (1 << 4) -+#define W25N02_N04KV_STATUS_ECC_5_8_BITFLIPS (3 << 4) -+#define W25N02_N04KV_STATUS_ECC_UNCOR_ERROR (2 << 4) -+ -+#define W25N01_M02GV_STATUS_ECC_MASK (3 << 4) -+#define W25N01_M02GV_STATUS_ECC_NO_BITFLIPS (0 << 4) -+#define W25N01_M02GV_STATUS_ECC_1_BITFLIPS (1 << 4) -+#define W25N01_M02GV_STATUS_ECC_UNCOR_ERROR (2 << 4) -+ -+#define W25N01KV_STATUS_ECC_MASK (3 << 4) -+#define W25N01KV_STATUS_ECC_NO_BITFLIPS (0 << 4) -+#define W25N01KV_STATUS_ECC_1_3_BITFLIPS (1 << 4) -+#define W25N01KV_STATUS_ECC_4_BITFLIPS (3 << 4) -+#define W25N01KV_STATUS_ECC_UNCOR_ERROR (2 << 4) -+ - static SPINAND_OP_VARIANTS(read_cache_variants, - SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), -@@ -31,6 +48,29 @@ static SPINAND_OP_VARIANTS(update_cache_ - SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), - SPINAND_PROG_LOAD(false, 0, NULL, 0)); - -+static int w25n02kv_n04kv_ooblayout_ecc(struct mtd_info *mtd, int section, -+ struct mtd_oob_region *region) -+{ -+ return -ERANGE; -+} -+ -+static int w25n02kv_n04kv_ooblayout_free(struct mtd_info *mtd, int section, -+ struct mtd_oob_region *region) -+{ -+ if (section > 3) -+ return -ERANGE; -+ -+ region->offset = (16 * section) + 2; -+ region->length = 14; -+ -+ return 0; -+} -+ -+static const struct mtd_ooblayout_ops w25n02kv_n04kv_ooblayout = { -+ .ecc = w25n02kv_n04kv_ooblayout_ecc, -+ .free = w25n02kv_n04kv_ooblayout_free, -+}; -+ - static int w25m02gv_ooblayout_ecc(struct mtd_info *mtd, int section, - struct mtd_oob_region *region) - { -@@ -140,6 +180,58 @@ static int w25n02kv_ecc_get_status(struc - return -EINVAL; - } - -+static int w25n01kv_ecc_get_status(struct spinand_device *spinand, -+ u8 status) -+{ -+ switch (status & W25N01KV_STATUS_ECC_MASK) { -+ case W25N01KV_STATUS_ECC_NO_BITFLIPS: -+ return 0; -+ -+ case W25N01KV_STATUS_ECC_1_3_BITFLIPS: -+ return 3; -+ -+ case W25N01KV_STATUS_ECC_4_BITFLIPS: -+ return 4; -+ -+ case W25N01KV_STATUS_ECC_UNCOR_ERROR: -+ return -EBADMSG; -+ -+ default: -+ break; -+ } -+ -+ return -EINVAL; -+} -+ -+static int w25n02kv_n04kv_ecc_get_status(struct spinand_device *spinand, -+ u8 status) -+{ -+ switch (status & W25N02_N04KV_STATUS_ECC_MASK) { -+ case W25N02_N04KV_STATUS_ECC_NO_BITFLIPS: -+ return 0; -+ -+ case W25N02_N04KV_STATUS_ECC_1_4_BITFLIPS: -+ return 3; -+ -+ case W25N02_N04KV_STATUS_ECC_5_8_BITFLIPS: -+ return 4; -+ -+ /* W25N02_N04KV_use internal 8bit ECC algorithm. -+ * But the ECC strength is 4 bit requried. -+ * Return 3 if the bit bit flip count less than 5. -+ * Return 4 if the bit bit flip count more than 5 to 8. -+ */ -+ -+ case W25N02_N04KV_STATUS_ECC_UNCOR_ERROR: -+ return -EBADMSG; -+ -+ default: -+ break; -+ } -+ -+ return -EINVAL; -+} -+ - static const struct spinand_info winbond_spinand_table[] = { - SPINAND_INFO("W25M02GV", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21), -@@ -151,6 +243,16 @@ static const struct spinand_info winbond - 0, - SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL), - SPINAND_SELECT_TARGET(w25m02gv_select_target)), -+ SPINAND_INFO("W25N01KV", -+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xae, 0x21), -+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), -+ NAND_ECCREQ(4, 512), -+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, -+ &write_cache_variants, -+ &update_cache_variants), -+ 0, -+ SPINAND_ECCINFO(&w25n02kv_n04kv_ooblayout, -+ w25n01kv_ecc_get_status)), - SPINAND_INFO("W25N01GV", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x21), - NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), -@@ -169,6 +271,19 @@ static const struct spinand_info winbond - &update_cache_variants), - 0, - SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), -+ /* W25N04KV has 2-die(lun), however, it can select die automatically. -+ * Treat it as single die here and double block size. -+ */ -+ SPINAND_INFO("W25N04KV", -+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x23), -+ NAND_MEMORG(1, 2048, 128, 64, 4096, 40, 2, 1, 1), -+ NAND_ECCREQ(8, 512), -+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, -+ &write_cache_variants, -+ &update_cache_variants), -+ 0, -+ SPINAND_ECCINFO(&w25n02kv_n04kv_ooblayout, -+ w25n02kv_n04kv_ecc_get_status)), - }; - - static int winbond_spinand_init(struct spinand_device *spinand) diff --git a/target/linux/mpc85xx/p1010/config-default b/target/linux/mpc85xx/p1010/config-default index f00fb4d5fd..32f525aaf1 100644 --- a/target/linux/mpc85xx/p1010/config-default +++ b/target/linux/mpc85xx/p1010/config-default @@ -3,7 +3,9 @@ CONFIG_BR200_WP=y CONFIG_CMDLINE_OVERRIDE=y CONFIG_FIREBOX_T10=y # CONFIG_FSL_CORENET_CF is not set +CONFIG_FSL_IFC=y CONFIG_GPIO_74X164=y +CONFIG_MEMORY=y CONFIG_MTD_CFI=y CONFIG_MTD_NAND_FSL_IFC=y CONFIG_MTD_PHYSMAP=y