Netdev List
 help / color / mirror / Atom feed
* [PATCH net-next] sctp: replace cb->args[4] with a local variable in sctp_diag_dump()
From: Xin Long @ 2026-07-09 21:28 UTC (permalink / raw)
  To: network dev, linux-sctp
  Cc: davem, kuba, Eric Dumazet, Paolo Abeni, Simon Horman,
	Marcelo Ricardo Leitner

cb->args[4] is currently used as a temporary counter to track the assoc
index while traversing ep->asocs in sctp_sock_dump(). However, this
state is only needed locally within a single dump iteration and does not
need to be preserved across callbacks.

Replace cb->args[4] with a local idx variable in sctp_sock_dump(), and
update cb->args[1] directly when the dump is interrupted due to skb
space exhaustion.

This simplifies the dump state handling and removes the dependency on an
extra cb->args[] slot, making the traversal logic easier to follow.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
 net/sctp/diag.c | 45 ++++++++++++++++++++++-----------------------
 1 file changed, 22 insertions(+), 23 deletions(-)

diff --git a/net/sctp/diag.c b/net/sctp/diag.c
index c2a0de2adf6f..a9bb31303613 100644
--- a/net/sctp/diag.c
+++ b/net/sctp/diag.c
@@ -299,18 +299,21 @@ static int sctp_sock_dump_one(struct sctp_endpoint *ep, struct sctp_transport *t
 static int sctp_sock_dump(struct sctp_endpoint *ep, struct sctp_transport *tsp, void *p)
 {
 	struct sctp_comm_param *commp = p;
-	struct sock *sk = ep->base.sk;
+	struct sock *sk = ep->base.sk, *nsk;
 	struct sk_buff *skb = commp->skb;
 	struct netlink_callback *cb = commp->cb;
 	const struct inet_diag_req_v2 *r = commp->r;
+	u32 portid = NETLINK_CB(cb->skb).portid;
 	struct sctp_association *assoc;
-	int err = 0;
+	int err = 0, idx = 0;
+
+	nsk = NETLINK_CB(cb->skb).sk;
 
 	lock_sock(sk);
 	if (ep != tsp->asoc->ep)
 		goto release;
 	list_for_each_entry(assoc, &ep->asocs, asocs) {
-		if (cb->args[4] < cb->args[1])
+		if (idx < cb->args[1])
 			goto next;
 
 		if (r->id.idiag_sport != htons(assoc->base.bind_addr.port) &&
@@ -320,32 +323,31 @@ static int sctp_sock_dump(struct sctp_endpoint *ep, struct sctp_transport *tsp,
 		    r->id.idiag_dport)
 			goto next;
 
-		if (!cb->args[3] &&
-		    inet_sctp_diag_fill(sk, NULL, skb, r,
-					sk_user_ns(NETLINK_CB(cb->skb).sk),
-					NETLINK_CB(cb->skb).portid,
-					cb->nlh->nlmsg_seq,
-					NLM_F_MULTI, cb->nlh,
-					commp->net_admin) < 0) {
-			err = 1;
-			goto release;
+		if (!cb->args[3]) {
+			err = inet_sctp_diag_fill(sk, NULL, skb, r,
+						  sk_user_ns(nsk), portid,
+						  cb->nlh->nlmsg_seq,
+						  NLM_F_MULTI, cb->nlh,
+						  commp->net_admin);
+			if (err < 0) {
+				cb->args[1] = idx;
+				goto release;
+			}
 		}
 		cb->args[3] = 1;
 
-		if (inet_sctp_diag_fill(sk, assoc, skb, r,
-					sk_user_ns(NETLINK_CB(cb->skb).sk),
-					NETLINK_CB(cb->skb).portid,
-					cb->nlh->nlmsg_seq, 0, cb->nlh,
-					commp->net_admin) < 0) {
-			err = 1;
+		err = inet_sctp_diag_fill(sk, assoc, skb, r, sk_user_ns(nsk),
+					  portid, cb->nlh->nlmsg_seq, 0,
+					  cb->nlh, commp->net_admin);
+		if (err < 0) {
+			cb->args[1] = idx;
 			goto release;
 		}
 next:
-		cb->args[4]++;
+		idx++;
 	}
 	cb->args[1] = 0;
 	cb->args[3] = 0;
-	cb->args[4] = 0;
 release:
 	release_sock(sk);
 	return err;
@@ -505,14 +507,11 @@ static void sctp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
 	 * 1 : to record the assoc pos of this time's traversal
 	 * 2 : to record the transport pos of this time's traversal
 	 * 3 : to mark if we have dumped the ep info of the current asoc
-	 * 4 : to track position within ep->asocs list in sctp_sock_dump()
 	 */
 	pos = cb->args[2];
 	sctp_transport_traverse_process(sctp_sock_filter, sctp_sock_dump,
 					net, &pos, &commp);
 	cb->args[2] = pos;
-	cb->args[1] = cb->args[4];
-	cb->args[4] = 0;
 }
 
 static const struct inet_diag_handler sctp_diag_handler = {
-- 
2.47.1


^ permalink raw reply related

* [PATCH] ieee802154: hwsim: serialize pib updates to fix double-free
From: David Carlier @ 2026-07-09 22:18 UTC (permalink / raw)
  To: alex.aring
  Cc: stable, syzbot+60332fd095f8bb2946ad, David Carlier,
	Stefan Schmidt, Miquel Raynal, Andrew Lunn, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-wpan, netdev,
	linux-kernel

hwsim_update_pib() does an unserialized read-swap-free of phy->pib:

	pib_old = rtnl_dereference(phy->pib);
	...
	rcu_assign_pointer(phy->pib, pib);
	kfree_rcu(pib_old, rcu);

It assumes the RTNL is held, but ->set_channel is not always called
under it: the mac802154 scan worker changes channels via
drv_set_channel() without the RTNL. Such an update can race an
RTNL-held one on the same phy; both read the same pib_old and both
kfree_rcu() it, double-freeing the object. With SLUB percpu sheaves
batching kfree_rcu(), this surfaces as a KASAN invalid-free in
rcu_free_sheaf().

struct hwsim_phy has no lock for pib. Add one and make the swap atomic
with rcu_replace_pointer() under it, dropping the misleading
rtnl_dereference().

Reported-by: syzbot+60332fd095f8bb2946ad@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=60332fd095f8bb2946ad
Fixes: f25da51fdc38 ("ieee802154: hwsim: add replacement for fakelb")
Signed-off-by: David Carlier <devnexen@gmail.com>
Cc: <stable@vger.kernel.org>
---
 drivers/net/ieee802154/mac802154_hwsim.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ieee802154/mac802154_hwsim.c b/drivers/net/ieee802154/mac802154_hwsim.c
index 6daa0f198b9f..a9bd1555d2dc 100644
--- a/drivers/net/ieee802154/mac802154_hwsim.c
+++ b/drivers/net/ieee802154/mac802154_hwsim.c
@@ -72,6 +72,8 @@ struct hwsim_phy {
 	struct ieee802154_hw *hw;
 	u32 idx;
 
+	/* Serializes phy->pib_updates. */
+	spinlock_t pib_lock;
 	struct hwsim_pib __rcu *pib;
 
 	bool suspended;
@@ -102,8 +104,6 @@ static int hwsim_update_pib(struct ieee802154_hw *hw, u8 page, u8 channel,
 	if (!pib)
 		return -ENOMEM;
 
-	pib_old = rtnl_dereference(phy->pib);
-
 	pib->page = page;
 	pib->channel = channel;
 	pib->filt.short_addr = filt->short_addr;
@@ -112,7 +112,10 @@ static int hwsim_update_pib(struct ieee802154_hw *hw, u8 page, u8 channel,
 	pib->filt.pan_coord = filt->pan_coord;
 	pib->filt_level = filt_level;
 
-	rcu_assign_pointer(phy->pib, pib);
+	spin_lock_bh(&phy->pib_lock);
+	pib_old = rcu_replace_pointer(phy->pib, pib,
+				      lockdep_is_held(&phy->pib_lock));
+	spin_unlock_bh(&phy->pib_lock);
 	kfree_rcu(pib_old, rcu);
 	return 0;
 }
@@ -952,6 +955,7 @@ static int hwsim_add_one(struct genl_info *info, struct device *dev,
 		goto err_pib;
 	}
 
+	spin_lock_init(&phy->pib_lock);
 	pib->channel = 13;
 	pib->filt.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
 	pib->filt.pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
-- 
2.53.0


^ permalink raw reply related

* [PATCH net 0/1] tls: device: push pending open record on splice EOF
From: Rishikesh Jethwani @ 2026-07-09 22:44 UTC (permalink / raw)
  To: netdev
  Cc: john.fastabend, kuba, sd, davem, pabeni, edumazet, leon,
	nils.juenemann, Rishikesh Jethwani

Hi all,

  A kTLS socket with device (HW) TX offload can leave its final
  record unsent when sendfile(2) is called with count > bytes-
  remaining in the file and the connection is closed without a
  trailing write. fs/splice.c fires ->splice_eof on the socket in
  this case, and tls_device_splice_eof() pre-patch only pushed
  partially-sent records - a fully-assembled but still-open record
  stayed pending until the next write, which an abrupt close()
  never provides. TLS_SW is unaffected; tls_sw_splice_eof() already
  handles pending open records.

  Report and discussion:
  https://lore.kernel.org/netdev/CAMPsyauZ+jzG9AysO0FWv6ZY0kvCUpjX_U7o=oOjCuOQ87BCgg@mail.gmail.com/

Rishikesh

Rishikesh Jethwani (1):
  tls: device: push pending open record on splice EOF

 net/tls/tls_device.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

-- 
2.25.1


^ permalink raw reply

* [PATCH 1/1] tls: device: push pending open record on splice EOF
From: Rishikesh Jethwani @ 2026-07-09 22:44 UTC (permalink / raw)
  To: netdev
  Cc: john.fastabend, kuba, sd, davem, pabeni, edumazet, leon,
	nils.juenemann, Rishikesh Jethwani
In-Reply-To: <20260709224436.1608993-1-rjethwani@purestorage.com>

On kTLS device-offload sockets, sendfile() with count > EOF can reach
->splice_eof() with a fully assembled but still-open TLS record left
pending. tls_device_splice_eof() only flushes partially sent records,
so an abrupt close() can drop the final record and the peer receives
a short file.

Fix tls_device_splice_eof() to also push pending open records.
This matches the software path, where splice EOF already flushes
pending open records.

Fixes: d4c1e80b0d1b ("tls/device: Use splice_eof() to flush")
Link: https://lore.kernel.org/netdev/CAMPsyauZ+jzG9AysO0FWv6ZY0kvCUpjX_U7o=oOjCuOQ87BCgg@mail.gmail.com/
Reported-by: Nils Juenemann <nils.juenemann@gmail.com>
Signed-off-by: Rishikesh Jethwani <rjethwani@purestorage.com>
---
 net/tls/tls_device.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c
index 741aef09bfd3..37bb06a8e8f5 100644
--- a/net/tls/tls_device.c
+++ b/net/tls/tls_device.c
@@ -595,13 +595,15 @@ void tls_device_splice_eof(struct socket *sock)
 	struct tls_context *tls_ctx = tls_get_ctx(sk);
 	struct iov_iter iter = {};
 
-	if (!tls_is_partially_sent_record(tls_ctx))
+	if (!tls_is_partially_sent_record(tls_ctx) &&
+	    !tls_is_pending_open_record(tls_ctx))
 		return;
 
 	mutex_lock(&tls_ctx->tx_lock);
 	lock_sock(sk);
 
-	if (tls_is_partially_sent_record(tls_ctx)) {
+	if (tls_is_partially_sent_record(tls_ctx) ||
+	    tls_is_pending_open_record(tls_ctx)) {
 		iov_iter_bvec(&iter, ITER_SOURCE, NULL, 0, 0);
 		tls_push_data(sk, &iter, 0, 0, TLS_RECORD_TYPE_DATA);
 	}
-- 
2.25.1


^ permalink raw reply related

* Re: [PATCH net] amd-xgbe: fix MAC_AUTO_SW handling in CL37 AN
From: Patrick Oppenlander @ 2026-07-09 23:16 UTC (permalink / raw)
  To: Prashanth Kumar KR
  Cc: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, netdev, linux-kernel, stable, Shyam Sundar S K,
	Thorsten Leemhuis
In-Reply-To: <20260709095006.3683940-1-prashanthkumar.k.r@amd.com>

Hi Prashanth,

thank you for addressing the bug. I will test your patch on our
hardware next week.

On Thu, 9 Jul 2026 at 19:50, Prashanth Kumar KR
<prashanthkumar.k.r@amd.com> wrote:
>
> From: Prashanth Kumar KR <PrashanthKumar.K.R@amd.com>
>
> MAC_AUTO_SW (VR_MII_DIG_CTRL1 bit 9) enables automatic XPCS speed
> mode switching after CL37 auto-negotiation and is only meaningful in
> SGMII MAC mode. The original code unconditionally set this bit on
> every call to xgbe_an37_set(), including when called from
> xgbe_an37_disable() with enable=false. This left MAC_AUTO_SW=1 after
> AN was disabled, causing the XPCS to autonomously switch speed from
> stale AN state during subsequent mode changes, breaking SGMII speed
> negotiation on 1G copper SFP modules.

In my testing this was breaking negotiation for all 1G SFP modules,
not just copper modules.

Patrick

> Fixes: 42fd432fe6d3 ("amd-xgbe: align CL37 AN sequence as per databook")
> Reported-by: Patrick Oppenlander <patrick.oppenlander@gmail.com>
> Link: https://lore.kernel.org/netdev/CAEg67GmFS0Q4oSZkz8zWdOzckSth9_vBPiOy6a7-d697C2w2Xg@mail.gmail.com
> Signed-off-by: Prashanth Kumar KR <PrashanthKumar.K.R@amd.com>
> ---
>  drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 11 ++++++++---
>  1 file changed, 8 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
> index fa0df6181207..12770af031eb 100644
> --- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
> +++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
> @@ -267,9 +267,14 @@ static void xgbe_an37_set(struct xgbe_prv_data *pdata, bool enable,
>
>         XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_CTRL1, reg);
>
> -       reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_PCS_DIG_CTRL);
> -       reg |= XGBE_VEND2_MAC_AUTO_SW;
> -       XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_PCS_DIG_CTRL, reg);
> +       if (pdata->an_mode == XGBE_AN_MODE_CL37_SGMII) {
> +               reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_PCS_DIG_CTRL);
> +               if (enable)
> +                       reg |= XGBE_VEND2_MAC_AUTO_SW;
> +               else
> +                       reg &= ~XGBE_VEND2_MAC_AUTO_SW;
> +               XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_PCS_DIG_CTRL, reg);
> +       }
>  }
>
>  static void xgbe_an37_restart(struct xgbe_prv_data *pdata)
> --
> 2.34.1
>

^ permalink raw reply

* [PATCH net v2 0/2] net: dsa: mv88e6xxx: 6141/6341 workarounds
From: Luke Howard @ 2026-07-09 23:29 UTC (permalink / raw)
  To: Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Vivien Didelot, Gregory CLEMENT, Andrew Lunn,
	Richard Cochran
  Cc: Cedric Jehasse, Kieran Tyrrell, Max Holtmann, Max Hunter,
	Christoph Mellauner, Simon Gapp, netdev, linux-kernel,
	Luke Howard

This patch series addresses two issues I found with the 88E6341
switch, which likely also apply to the 88E6141 (which is the same
chip without AVB/TSN support).

The first was a genuine bug, which assumed the chip did not have
a dedicated ATU FID register (it does).

The other is an issue I noticed with hash collisions in the ATU
on the 6341 when using multiple FIDs. Different algorithms could
be selected using devlink, but the FDB was not flushed which
resulted in a corrupted FDB.

Signed-off-by: Luke Howard <lukeh@padl.com>
---
Changes in v2:
- Rather than special casing ATU hash algorithm for the 6341, simply
  ensure the ATU is flushed when changing it via devlink.
- Retartget net instead of net-next, as this is a bugfix
- Link to v1: https://patch.msgid.link/20260703-mv88e6x41-fixes-v1-0-fbd3a1bf8965@padl.com

To: Andrew Lunn <andrew@lunn.ch>
To: Vladimir Oltean <olteanv@gmail.com>
To: "David S. Miller" <davem@davemloft.net>
To: Eric Dumazet <edumazet@google.com>
To: Jakub Kicinski <kuba@kernel.org>
To: Paolo Abeni <pabeni@redhat.com>
To: Richard Cochran <richardcochran@gmail.com>
To: Vivien Didelot <vivien.didelot@gmail.com>
To: Gregory CLEMENT <gregory.clement@bootlin.com>
Cc: netdev@vger.kernel.org
Cc: linux-kernel@vger.kernel.org

---
Luke Howard (2):
      net: dsa: mv88e6xxx: write the ATU FID register on 88E6141/88E6341
      net: dsa: mv88e6xxx: flush the ATU when the hash algorithm changes

 drivers/net/dsa/mv88e6xxx/chip.c        | 29 ++++++++++++++++++++++++++++-
 drivers/net/dsa/mv88e6xxx/chip.h        | 12 +++++++++---
 drivers/net/dsa/mv88e6xxx/devlink.c     |  6 ++++++
 drivers/net/dsa/mv88e6xxx/global1_atu.c |  4 ++--
 4 files changed, 45 insertions(+), 6 deletions(-)
---
base-commit: fe3e786ef4eb6e47d2901f568a27bd920477bbe9
change-id: 20260624-mv88e6x41-fixes-d4c84f955ebc

Best regards,
--  
Luke Howard <lukeh@padl.com>


^ permalink raw reply

* [PATCH net v2 2/2] net: dsa: mv88e6xxx: flush the ATU when the hash algorithm changes
From: Luke Howard @ 2026-07-09 23:29 UTC (permalink / raw)
  To: Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Vivien Didelot, Gregory CLEMENT, Andrew Lunn,
	Richard Cochran
  Cc: Cedric Jehasse, Kieran Tyrrell, Max Holtmann, Max Hunter,
	Christoph Mellauner, Simon Gapp, netdev, linux-kernel,
	Luke Howard
In-Reply-To: <20260710-mv88e6x41-fixes-v2-0-e23654c65aa0@padl.com>

Changing the ATU hash algorithm invalidates existing entries: those
loaded under the previous algorithm end up in different bins and read
back corrupted.

Flush the ATU whenever the hash algorithm is changed through devlink
and reload the default broadcast entries. Per-VLAN ATU entries and
any static addresses are not replayed, so the hash must be selected
before the FDB or MDB are configured.

Fixes: 23e8b470c778 ("net: dsa: mv88e6xxx: Add devlink param for ATU hash algorithm.")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Luke Howard <lukeh@padl.com>
---
 drivers/net/dsa/mv88e6xxx/chip.c    | 2 +-
 drivers/net/dsa/mv88e6xxx/chip.h    | 2 ++
 drivers/net/dsa/mv88e6xxx/devlink.c | 6 ++++++
 3 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 7938e50900ca8..6faae74de04a9 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -2523,7 +2523,7 @@ static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port,
 	return mv88e6xxx_port_db_load_purge(chip, port, broadcast, vid, state);
 }
 
-static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid)
+int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid)
 {
 	int port;
 	int err;
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index aca64fd4cb95c..6fda3f83c8885 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -894,4 +894,6 @@ int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
 				 void *priv),
 		       void *priv);
 
+int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid);
+
 #endif /* _MV88E6XXX_CHIP_H */
diff --git a/drivers/net/dsa/mv88e6xxx/devlink.c b/drivers/net/dsa/mv88e6xxx/devlink.c
index 6f034841883c6..5168335f52289 100644
--- a/drivers/net/dsa/mv88e6xxx/devlink.c
+++ b/drivers/net/dsa/mv88e6xxx/devlink.c
@@ -61,6 +61,12 @@ int mv88e6xxx_devlink_param_set(struct dsa_switch *ds, u32 id,
 	switch (id) {
 	case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH:
 		err = mv88e6xxx_atu_set_hash(chip, ctx->val.vu8);
+		if (err)
+			break;
+		err = mv88e6xxx_g1_atu_flush(chip, 0, true);
+		if (err)
+			break;
+		err = mv88e6xxx_broadcast_setup(chip, 0);
 		break;
 	default:
 		err = -EOPNOTSUPP;

-- 
2.43.0


^ permalink raw reply related

* [PATCH net v2 1/2] net: dsa: mv88e6xxx: write the ATU FID register on 88E6141/88E6341
From: Luke Howard @ 2026-07-09 23:29 UTC (permalink / raw)
  To: Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Vivien Didelot, Gregory CLEMENT, Andrew Lunn,
	Richard Cochran
  Cc: Cedric Jehasse, Kieran Tyrrell, Max Holtmann, Max Hunter,
	Christoph Mellauner, Simon Gapp, netdev, linux-kernel,
	Luke Howard
In-Reply-To: <20260710-mv88e6x41-fixes-v2-0-e23654c65aa0@padl.com>

The driver decided whether a device has a dedicated ATU FID register
from its database count, taking the register path only when there were
more than 256 databases. The 88E6141/88E6341 have 256 databases but do
have the register, so they fell back to the legacy path and the FID
register was never written. Every FDB entry was then loaded into FID 0,
breaking VLAN aware bridging.

The number of databases does not imply whether the register is present.
Add an explicit atu_fid_reg flag, set it on every device that has the
register (all that previously matched the >256 heuristic, plus the
88E6141/88E6341), and key the register access off the flag instead of
the database count.

Fixes: a75961d0ebfd ("net: dsa: mv88e6xxx: Add support for ethernet switch 88E6341")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Luke Howard <lukeh@padl.com>
---
 drivers/net/dsa/mv88e6xxx/chip.c        | 27 +++++++++++++++++++++++++++
 drivers/net/dsa/mv88e6xxx/chip.h        | 10 +++++++---
 drivers/net/dsa/mv88e6xxx/global1_atu.c |  4 ++--
 3 files changed, 36 insertions(+), 5 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 80b877c74513d..7938e50900ca8 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -5747,6 +5747,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6097,
 		.name = "Marvell 88E6085",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_macs = 8192,
 		.num_ports = 10,
 		.num_internal_phys = 5,
@@ -5792,6 +5793,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6097,
 		.name = "Marvell 88E6097/88E6097F",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_macs = 8192,
 		.num_ports = 11,
 		.num_internal_phys = 8,
@@ -5817,6 +5819,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6165,
 		.name = "Marvell 88E6123",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_macs = 1024,
 		.num_ports = 3,
 		.num_internal_phys = 5,
@@ -5863,6 +5866,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6341,
 		.name = "Marvell 88E6141",
 		.num_databases = 256,
+		.atu_fid_reg = true,
 		.num_macs = 2048,
 		.num_ports = 6,
 		.num_internal_phys = 5,
@@ -5889,6 +5893,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6165,
 		.name = "Marvell 88E6161",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_macs = 1024,
 		.num_ports = 6,
 		.num_internal_phys = 5,
@@ -5915,6 +5920,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6165,
 		.name = "Marvell 88E6165",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_macs = 8192,
 		.num_ports = 6,
 		.num_internal_phys = 0,
@@ -5940,6 +5946,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6351,
 		.name = "Marvell 88E6171",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_macs = 8192,
 		.num_ports = 7,
 		.num_internal_phys = 5,
@@ -5965,6 +5972,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6352,
 		.name = "Marvell 88E6172",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_macs = 8192,
 		.num_ports = 7,
 		.num_internal_phys = 5,
@@ -5991,6 +5999,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6351,
 		.name = "Marvell 88E6175",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_macs = 8192,
 		.num_ports = 7,
 		.num_internal_phys = 5,
@@ -6016,6 +6025,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6352,
 		.name = "Marvell 88E6176",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_macs = 8192,
 		.num_ports = 7,
 		.num_internal_phys = 5,
@@ -6064,6 +6074,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6390,
 		.name = "Marvell 88E6190",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_macs = 16384,
 		.num_ports = 11,	/* 10 + Z80 */
 		.num_internal_phys = 9,
@@ -6089,6 +6100,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6390,
 		.name = "Marvell 88E6190X",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_macs = 16384,
 		.num_ports = 11,	/* 10 + Z80 */
 		.num_internal_phys = 9,
@@ -6114,6 +6126,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6390,
 		.name = "Marvell 88E6191",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_macs = 16384,
 		.num_ports = 11,	/* 10 + Z80 */
 		.num_internal_phys = 9,
@@ -6139,6 +6152,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6393,
 		.name = "Marvell 88E6191X",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_ports = 11,	/* 10 + Z80 */
 		.num_internal_phys = 8,
 		.internal_phys_offset = 1,
@@ -6164,6 +6178,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6393,
 		.name = "Marvell 88E6193X",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_ports = 11,	/* 10 + Z80 */
 		.num_internal_phys = 8,
 		.num_tcam_entries = 256,
@@ -6218,6 +6233,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6352,
 		.name = "Marvell 88E6240",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_macs = 8192,
 		.num_ports = 7,
 		.num_internal_phys = 5,
@@ -6267,6 +6283,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6390,
 		.name = "Marvell 88E6290",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_ports = 11,	/* 10 + Z80 */
 		.num_internal_phys = 9,
 		.num_gpio = 16,
@@ -6294,6 +6311,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6320,
 		.name = "Marvell 88E6320",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_macs = 8192,
 		.num_ports = 7,
 		.num_internal_phys = 2,
@@ -6322,6 +6340,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6320,
 		.name = "Marvell 88E6321",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_macs = 8192,
 		.num_ports = 7,
 		.num_internal_phys = 2,
@@ -6350,6 +6369,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6341,
 		.name = "Marvell 88E6341",
 		.num_databases = 256,
+		.atu_fid_reg = true,
 		.num_macs = 2048,
 		.num_internal_phys = 5,
 		.num_ports = 6,
@@ -6377,6 +6397,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6351,
 		.name = "Marvell 88E6350",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_macs = 8192,
 		.num_ports = 7,
 		.num_internal_phys = 5,
@@ -6402,6 +6423,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6351,
 		.name = "Marvell 88E6351",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_macs = 8192,
 		.num_ports = 7,
 		.num_internal_phys = 5,
@@ -6427,6 +6449,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6352,
 		.name = "Marvell 88E6352",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_macs = 8192,
 		.num_ports = 7,
 		.num_internal_phys = 5,
@@ -6453,6 +6476,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6393,
 		.name = "Marvell 88E6361",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_macs = 16384,
 		.num_ports = 11,
 		/* Ports 1, 2 and 8 are not routed */
@@ -6480,6 +6504,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6390,
 		.name = "Marvell 88E6390",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_macs = 16384,
 		.num_ports = 11,	/* 10 + Z80 */
 		.num_internal_phys = 9,
@@ -6508,6 +6533,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6390,
 		.name = "Marvell 88E6390X",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_macs = 16384,
 		.num_ports = 11,	/* 10 + Z80 */
 		.num_internal_phys = 9,
@@ -6535,6 +6561,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6393,
 		.name = "Marvell 88E6393X",
 		.num_databases = 4096,
+		.atu_fid_reg = true,
 		.num_ports = 11,	/* 10 + Z80 */
 		.num_internal_phys = 8,
 		.num_tcam_entries = 256,
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index e966e7c4cc5de..aca64fd4cb95c 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -165,16 +165,20 @@ struct mv88e6xxx_info {
 	 */
 	bool dual_chip;
 
+	/* Has a dedicated ATU FID register. */
+	bool atu_fid_reg;
+
+	/* Supports PTP */
+	bool ptp_support;
+
 	enum mv88e6xxx_edsa_support edsa_support;
 
 	/* Mask for FromPort and ToPort value of PortVec used in ATU Move
 	 * operation. 0 means that the ATU Move operation is not supported.
 	 */
 	u8 atu_move_port_mask;
-	const struct mv88e6xxx_ops *ops;
 
-	/* Supports PTP */
-	bool ptp_support;
+	const struct mv88e6xxx_ops *ops;
 
 	/* Internal PHY start index. 0 means that internal PHYs range starts at
 	 * port 0, 1 means internal PHYs range starts at port 1, etc
diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c
index c47f068f56b32..522978f638e2f 100644
--- a/drivers/net/dsa/mv88e6xxx/global1_atu.c
+++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c
@@ -135,7 +135,7 @@ static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op)
 	int err;
 
 	/* FID bits are dispatched all around gradually as more are supported */
-	if (mv88e6xxx_num_databases(chip) > 256) {
+	if (chip->info->atu_fid_reg) {
 		err = mv88e6xxx_g1_atu_fid_write(chip, fid);
 		if (err)
 			return err;
@@ -179,7 +179,7 @@ static int mv88e6xxx_g1_atu_fid_read(struct mv88e6xxx_chip *chip, u16 *fid)
 	u16 val = 0, upper = 0, op = 0;
 	int err = -EOPNOTSUPP;
 
-	if (mv88e6xxx_num_databases(chip) > 256) {
+	if (chip->info->atu_fid_reg) {
 		err = mv88e6xxx_g1_read(chip, MV88E6352_G1_ATU_FID, &val);
 		val &= 0xfff;
 		if (err)

-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH net] net: dpaa: always set a valid mode I/F mode
From: Sean Anderson @ 2026-07-09 23:45 UTC (permalink / raw)
  To: Michael Walle, Madalin Bucur, Andrew Lunn, David S . Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni
  Cc: netdev, linux-kernel
In-Reply-To: <20260706121011.1948906-1-mwalle@kernel.org>

On 7/6/26 08:08, Michael Walle wrote:
> Before converting to the phylink interface, the init function would have
> set the correct mode in the maccfg2.

So for reference, the old logic is

        if (iface_speed < SPEED_1000)
                tmp |= MACCFG2_NIBBLE_MODE;
        else if (iface_speed == SPEED_1000)
                tmp |= MACCFG2_BYTE_MODE;

which changes between nibble/byte mode depending on the max link speed
(e.g. phylink_interface_max_speed). Notably, neither is set for 2.5G.

Can you try moving this write to dtsec_mac_config? And check in the RM
whether this is configured based on the interface (in which case we should
remove it from dtsec_link_up) or the link speed. And please also check what
the correct behavior for 2.5G should be.

At one point I had the P-series RMs downloaded, but it appears I've misplaced
them...

--Sean

> After converting, init will just
> set 0 as the mode. According to the "QorIQ Data Path Acceleration
> Architecture (DPAA) Reference Manual", this is a reserved value. In
> fact, this will prevent the PCS to establish a link to a connected SGMII
> PHY. In turn, mac_link_up() is never called. Fix it by setting a
> non-reserved mode; mac_link_up() will then set the correct mode later.
> 
> Fixes: 5d93cfcf7360 ("net: dpaa: Convert to phylink")
> Signed-off-by: Michael Walle <mwalle@kernel.org>
> ---
> FWIW, I've tested this with a Marvell 88E1112 PHY.
> 
>   drivers/net/ethernet/freescale/fman/fman_dtsec.c | 5 ++++-
>   1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/ethernet/freescale/fman/fman_dtsec.c b/drivers/net/ethernet/freescale/fman/fman_dtsec.c
> index fe35703c509e..566921d3a884 100644
> --- a/drivers/net/ethernet/freescale/fman/fman_dtsec.c
> +++ b/drivers/net/ethernet/freescale/fman/fman_dtsec.c
> @@ -402,7 +402,10 @@ static int init(struct dtsec_regs __iomem *regs, struct dtsec_cfg *cfg,
>   	tmp |= MACCFG1_TX_FLOW;
>   	iowrite32be(tmp, &regs->maccfg1);
>   
> -	tmp = 0;
> +	/* write a non-reserved mode, otherwise the PCS won't establish a link
> +	 * and .mac_link_up() is never called.
> +	 */
> +	tmp = MACCFG2_NIBBLE_MODE;
>   
>   	tmp |= (cfg->preamble_len << MACCFG2_PREAMBLE_LENGTH_SHIFT) &
>   		MACCFG2_PREAMBLE_LENGTH_MASK;


^ permalink raw reply

* Re: [PATCH] net: mvneta: bm: fix device reference leak on failed lookup
From: Harshitha Ramamurthy @ 2026-07-09 23:53 UTC (permalink / raw)
  To: Johan Hovold
  Cc: Marcin Wojtas, Andrew Lunn, David S Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Gregory CLEMENT, netdev, stable
In-Reply-To: <20260709082713.829446-1-johan@kernel.org>

On Thu, Jul 9, 2026 at 1:32 AM Johan Hovold <johan@kernel.org> wrote:
>
> Make sure to drop the reference taken to the buffer manager device when
> attempting to look up its driver data before the driver has been bound.
>
> Note that holding a reference to a device does not prevent its driver
> data from going away.
>
> Fixes: 965cbbec7f20 ("net: mvneta: remove data pointer usage from device_node structure")
> Cc: stable@vger.kernel.org      # 4.19
> Cc: Gregory CLEMENT <gregory.clement@bootlin.com>
> Signed-off-by: Johan Hovold <johan@kernel.org>

Okay, platform_device_put() has to be called directly instead of
mvneta_bm_put() because that takes in the priv structure.

Reviewed-by: Harshitha Ramamurthy <hramamurthy@google.com>

> ---
>  drivers/net/ethernet/marvell/mvneta_bm.c | 15 +++++++++++++--
>  1 file changed, 13 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/ethernet/marvell/mvneta_bm.c b/drivers/net/ethernet/marvell/mvneta_bm.c
> index 6bb380494919..128fe1f512b4 100644
> --- a/drivers/net/ethernet/marvell/mvneta_bm.c
> +++ b/drivers/net/ethernet/marvell/mvneta_bm.c
> @@ -395,9 +395,20 @@ static void mvneta_bm_put_sram(struct mvneta_bm *priv)
>
>  struct mvneta_bm *mvneta_bm_get(struct device_node *node)
>  {
> -       struct platform_device *pdev = of_find_device_by_node(node);
> +       struct platform_device *pdev;
> +       struct mvneta_bm *priv;
> +
> +       pdev = of_find_device_by_node(node);
> +       if (!pdev)
> +               return NULL;
> +
> +       priv = platform_get_drvdata(pdev);
> +       if (!priv) {
> +               platform_device_put(pdev);
> +               return NULL;
> +       }
>
> -       return pdev ? platform_get_drvdata(pdev) : NULL;
> +       return priv;
>  }
>  EXPORT_SYMBOL_GPL(mvneta_bm_get);
>
> --
> 2.54.0
>
>

^ permalink raw reply

* Re: [PATCH bpf-next v11 1/5] bpf: add bpf_icmp_send kfunc
From: Stanislav Fomichev @ 2026-07-10  0:12 UTC (permalink / raw)
  To: Mahe Tardy
  Cc: bpf, andrii, ast, daniel, john.fastabend, jordan, martin.lau,
	yonghong.song, emil, netdev, edumazet, kuba, pabeni, davem, horms
In-Reply-To: <20260709144900.245904-2-mahe.tardy@gmail.com>

On 07/09, Mahe Tardy wrote:
> This is needed in the context of Tetragon to provide improved feedback
> (in contrast to just dropping packets) to east-west traffic when blocked
> by policies using cgroup_skb programs.
> 
> This reuses concepts from netfilter reject target codepath with the
> differences that:
> * Packets are cloned since the BPF user can still let the packet pass
>   (SK_PASS from the cgroup_skb progs for example) and the current skb
>   need to stay untouched (cgroup_skb hooks only allow read-only skb
>   payload).
> * We protect against recursion since the kfunc, by generating an ICMP
>   error message, could retrigger the BPF prog that invoked it.
> 
> Only ICMP_DEST_UNREACH and ICMPV6_DEST_UNREACH are currently supported.
> The interface accepts a type parameter to facilitate future extension to
> other ICMP control message types.
> 
> For normal cgroup_skb paths, the skb dst route should already be set.
> However, bpf_prog_test_run_skb can create synthetic IPv4/IPv6 skbs
> without an attached route. In that case, icmp_send returns early, and
> the kfunc would otherwise report success despite no ICMP reply being
> sent. This check also reject metadata dsts, which are not valid struct
> rtable instances. While IPv6 would stricly require only rejecting
> metadata dsts, same check is applied for API consistency.
> 
> Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
> Reviewed-by: Jordan Rife <jordan@jrife.io>
> Signed-off-by: Mahe Tardy <mahe.tardy@gmail.com>
> ---
>  net/core/filter.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 90 insertions(+)
> 
> diff --git a/net/core/filter.c b/net/core/filter.c
> index 4f5cbcac3e78..e4697036c67b 100644
> --- a/net/core/filter.c
> +++ b/net/core/filter.c
> @@ -84,6 +84,9 @@
>  #include <linux/un.h>
>  #include <net/xdp_sock_drv.h>
>  #include <net/inet_dscp.h>
> +#include <linux/icmpv6.h>
> +#include <net/icmp.h>
> +#include <net/ip6_route.h>
> 
>  #include "dev.h"
> 
> @@ -12548,6 +12551,83 @@ __bpf_kfunc int bpf_xdp_pull_data(struct xdp_md *x, u32 len)
>  	return 0;
>  }
> 
> +/**
> + * bpf_icmp_send - Send an ICMP control message
> + * @skb_ctx: Packet that triggered the control message
> + * @type: ICMP type (only ICMP_DEST_UNREACH/ICMPV6_DEST_UNREACH supported)
> + * @code: ICMP code (0-15 except ICMP_FRAG_NEEDED for IPv4, 0-6 for IPv6)
> + *
> + * Sends an ICMP control message in response to the packet. The original packet
> + * is cloned before sending the ICMP message, so the BPF program can still let
> + * the packet pass if desired.
> + *
> + * Currently only ICMP_DEST_UNREACH (IPv4) and ICMPV6_DEST_UNREACH (IPv6) are
> + * supported.
> + *
> + * Return: 0 on success (send attempt), negative error code on failure:
> + *         -EBUSY: Recursion detected
> + *         -EPROTONOSUPPORT: Non-IP protocol
> + *         -EOPNOTSUPP: Unsupported ICMP type
> + *         -EINVAL: Invalid code parameter
> + *         -ENETUNREACH: No usable route/dst for the ICMP reply
> + *         -ENOMEM: Memory allocation failed
> + */
> +__bpf_kfunc int bpf_icmp_send(struct __sk_buff *skb_ctx, int type, int code)
> +{
> +	struct sk_buff *skb = (struct sk_buff *)skb_ctx;
> +	struct sk_buff *nskb;
> +	struct sock *sk;
> +
> +	sk = skb_to_full_sk(skb);
> +	if (sk && sk->sk_kern_sock &&
> +	    (sk->sk_protocol == IPPROTO_ICMP || sk->sk_protocol == IPPROTO_ICMPV6))
> +		return -EBUSY;
> +
> +	if (!skb_valid_dst(skb))
> +		return -ENETUNREACH;

This looks much better, thanks!

Acked-by: Stanislav Fomichev <sdf@fomichev.me>

^ permalink raw reply

* Re: [PATCH bpf-next v11 2/5] selftests/bpf: add bpf_icmp_send kfunc cgroup_skb tests
From: Stanislav Fomichev @ 2026-07-10  0:12 UTC (permalink / raw)
  To: Mahe Tardy
  Cc: bpf, andrii, ast, daniel, john.fastabend, jordan, martin.lau,
	yonghong.song, emil, netdev, edumazet, kuba, pabeni, davem, horms
In-Reply-To: <20260709144900.245904-3-mahe.tardy@gmail.com>

On 07/09, Mahe Tardy wrote:
> This test opens a server and client, enters a new cgroup, attach a
> cgroup_skb program on egress and calls the bpf_icmp_send function from
> the client egress so that an ICMP unreach control message is sent back
> to the client. It then fetches the message from the error queue to
> confirm the correct ICMP unreach code has been sent.
> 
> Note that, for the client, we have to connect in non-blocking mode to
> let the test execute faster. Otherwise, we need to wait for the TCP
> three-way handshake to timeout in the kernel before reading the errno.
> 
> Also note that we don't set IP_RECVERR on the socket in
> connect_to_fd_nonblock since the error will be transferred anyway in our
> test because the connection is rejected at the beginning of the TCP
> handshake. See in net/ipv4/tcp_ipv4.c:tcp_v4_err for more details.
> 
> Reviewed-by: Jordan Rife <jordan@jrife.io>
> Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
> Signed-off-by: Mahe Tardy <mahe.tardy@gmail.com>

Acked-by: Stanislav Fomichev <sdf@fomichev.me>

^ permalink raw reply

* Re: [PATCH bpf-next v11 3/5] selftests/bpf: add bpf_icmp_send kfunc cgroup_skb IPv6 tests
From: Stanislav Fomichev @ 2026-07-10  0:12 UTC (permalink / raw)
  To: Mahe Tardy
  Cc: bpf, andrii, ast, daniel, john.fastabend, jordan, martin.lau,
	yonghong.song, emil, netdev, edumazet, kuba, pabeni, davem, horms
In-Reply-To: <20260709144900.245904-4-mahe.tardy@gmail.com>

On 07/09, Mahe Tardy wrote:
> This test extends the existing cgroup_skb tests with IPv6 support.
> 
> Note that we need to set IPV6_RECVERR on the socket for IPv6 in
> connect_to_fd_nonblock otherwise the error will be ignored even if we
> are in the middle of the TCP handshake. See in
> net/ipv6/datagram.c:ipv6_icmp_error for more details.
> 
> Reviewed-by: Jordan Rife <jordan@jrife.io>
> Signed-off-by: Mahe Tardy <mahe.tardy@gmail.com>

Acked-by: Stanislav Fomichev <sdf@fomichev.me>

^ permalink raw reply

* Re: [PATCH bpf-next v11 4/5] selftests/bpf: add bpf_icmp_send recursion test
From: Stanislav Fomichev @ 2026-07-10  0:13 UTC (permalink / raw)
  To: Mahe Tardy
  Cc: bpf, andrii, ast, daniel, john.fastabend, jordan, martin.lau,
	yonghong.song, emil, netdev, edumazet, kuba, pabeni, davem, horms
In-Reply-To: <20260709144900.245904-5-mahe.tardy@gmail.com>

On 07/09, Mahe Tardy wrote:
> This test is similar to test_icmp_send_unreach_cgroup but checks that,
> in case of recursion, meaning that the BPF program calling the kfunc was
> re-triggered by the icmp_send done by the kfunc, the kfunc will stop
> early and return -EBUSY.
> 
> The test attaches to the root cgroup to ensure the ICMP packet generated
> by the kfunc re-triggers the BPF program.
> 
> Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
> Reviewed-by: Jordan Rife <jordan@jrife.io>
> Signed-off-by: Mahe Tardy <mahe.tardy@gmail.com>

Acked-by: Stanislav Fomichev <sdf@fomichev.me>

^ permalink raw reply

* Re: [PATCH bpf-next v11 5/5] selftests/bpf: add bpf_icmp_send no route test
From: Stanislav Fomichev @ 2026-07-10  0:13 UTC (permalink / raw)
  To: Mahe Tardy
  Cc: bpf, andrii, ast, daniel, john.fastabend, jordan, martin.lau,
	yonghong.song, emil, netdev, edumazet, kuba, pabeni, davem, horms
In-Reply-To: <20260709144900.245904-6-mahe.tardy@gmail.com>

On 07/09, Mahe Tardy wrote:
> For normal live cgroup_skb paths, the skb should already be routed. The
> exception is for test run via BPF_PROG_TEST_RUN with packets created
> via bpf_prog_test_run_skb. Those lack dst route and thus the icmp_send
> would quietly fail by returning early.
> 
> This test exercises this and makes sure the kfunc returns -ENETUNREACH.
> 
> Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
> Reviewed-by: Jordan Rife <jordan@jrife.io>
> Signed-off-by: Mahe Tardy <mahe.tardy@gmail.com>

Acked-by: Stanislav Fomichev <sdf@fomichev.me>

^ permalink raw reply

* Re: [PATCH] wifi: brcmfmac: drain bus_reset work on device removal
From: Eddie Phillips @ 2026-07-10  0:23 UTC (permalink / raw)
  To: eddiephillips, Fan Wu
  Cc: Arend van Spriel, Kalle Valo, Franky Lin, Hante Meuleman,
	Chi-Hsien Lin, Wright Feng, Chung-Hsien Hsu, David S . Miller,
	Jakub Kicinski, linux-wireless, brcm80211-dev-list.pdl,
	SHA-cyfmac-dev-list, netdev, linux-kernel, stable
In-Reply-To: <20260709101635.103005-1-fanwu01@zju.edu.cn>

On Thu,  9 Jul 2026 10:16:35 +0000 Fan Wu <fanwu01@zju.edu.cn> wrote:

> brcmf_fw_crashed() and the debugfs "reset" entry both schedule
> drvr->bus_reset, whose callback recovers drvr through container_of()
> and dereferences it.  The teardown paths free drvr (brcmf_free ->
> wiphy_free) without draining the work, so a bus_reset callback pending
> or running during removal can outlive drvr.
> 
> Cancellation cannot live in brcmf_detach() or brcmf_free(): the work
> callback reaches teardown through the bus .reset op (PCIe
> brcmf_pcie_reset -> brcmf_detach; SDIO brcmf_sdio_bus_reset ->
> brcmf_sdiod_remove -> brcmf_free), so cancelling there would wait for
> the running work and deadlock.  Arming and the drain must also be
> mutually exclusive: a debugfs writer can otherwise schedule bus_reset
> after the drain and before the debugfs file is removed in
> brcmf_cfg80211_detach(), re-opening the window.
> 
> Add a per-bus mutex and route all arming through
> brcmf_bus_schedule_reset(), which under the lock skips when the bus is
> marked removing.  Each bus remove entry calls
> brcmf_bus_cancel_reset_work(), which under the same lock sets removing
> and cancels the work.  Where applicable the remove entry first stops
> the firmware-crash producer: on PCIe mask the mailbox and
> synchronize_irq; on SDIO unregister the bus interrupt and cancel the
> data worker, which also reports firmware halts through
> brcmf_fw_crashed().  The mutex is initialized at bus allocation so it
> is ready before any firmware-probe or removal path can reach it.  The
> SDIO suspend power-off path frees drvr through the same
> brcmf_sdiod_remove() and takes the same lock; resume re-allows the work
> only on a successful re-probe.
> 
> This issue was found by an in-house static analysis tool.
> 
> Fixes: 4684997d9eea ("brcmfmac: reset PCIe bus on a firmware crash")
> Cc: stable@vger.kernel.org
> Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
> Assisted-by: Codex:gpt-5.5
> ---
>  .../broadcom/brcm80211/brcmfmac/bcmsdh.c      | 13 ++++++++
>  .../broadcom/brcm80211/brcmfmac/bus.h         |  6 ++++
>  .../broadcom/brcm80211/brcmfmac/core.c        | 33 +++++++++++++++++--
>  .../broadcom/brcm80211/brcmfmac/pcie.c        |  6 ++++
>  .../broadcom/brcm80211/brcmfmac/sdio.c        |  6 ++++
>  .../broadcom/brcm80211/brcmfmac/sdio.h        |  1 +
>  .../broadcom/brcm80211/brcmfmac/usb.c         |  3 ++
>  7 files changed, 66 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
> index ac02244a6..c4bb32aec 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
> @@ -1043,6 +1043,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
>  	bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL);
>  	if (!bus_if)
>  		return -ENOMEM;
> +	mutex_init(&bus_if->bus_reset_lock);
>  	sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL);
>  	if (!sdiodev) {
>  		kfree(bus_if);
> @@ -1102,6 +1103,14 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func)
>  		if (func->num != 1)
>  			return;
>  
> +		/* Drain bus_reset before the shared brcmf_sdiod_remove()
> +		 * teardown, which the SDIO reset callback also reaches.  The
> +		 * data worker can arm bus_reset via brcmf_fw_crashed(); cancel
> +		 * it first.
> +		 */
> +		brcmf_sdio_cancel_datawork(sdiodev->bus);
> +		brcmf_bus_cancel_reset_work(bus_if);
> +
>  		/* only proceed with rest of cleanup if func 1 */
>  		brcmf_sdiod_remove(sdiodev);
>  
> @@ -1163,6 +1172,8 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
>  	} else {
>  		/* power will be cut so remove device, probe again in resume */
>  		brcmf_sdiod_intr_unregister(sdiodev);
> +		brcmf_sdio_cancel_datawork(sdiodev->bus);
> +		brcmf_bus_cancel_reset_work(bus_if);
>  		ret = brcmf_sdiod_remove(sdiodev);
>  		if (ret)
>  			brcmf_err("Failed to remove device on suspend\n");
> @@ -1188,6 +1199,8 @@ static int brcmf_ops_sdio_resume(struct device *dev)
>  		ret = brcmf_sdiod_probe(sdiodev);
>  		if (ret)
>  			brcmf_err("Failed to probe device on resume\n");
> +		else
> +			brcmf_bus_allow_reset_work(bus_if);
>  	} else {
>  		if (sdiodev->wowl_enabled &&
>  		    sdiodev->settings->bus.sdio.oob_irq_supported)
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
> index 3f5da3bb6..b606094af 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
> @@ -6,6 +6,7 @@
>  #ifndef BRCMFMAC_BUS_H
>  #define BRCMFMAC_BUS_H
>  
> +#include <linux/mutex.h>
>  #include "debug.h"
>  
>  /* IDs of the 6 default common rings of msgbuf protocol */
> @@ -149,11 +150,16 @@ struct brcmf_bus {
>  	u32 chiprev;
>  	bool always_use_fws_queue;
>  	bool wowl_supported;
> +	bool removing;		/* device removal in progress; quiesce async work */
> +	struct mutex bus_reset_lock;
>  
>  	const struct brcmf_bus_ops *ops;
>  	struct brcmf_bus_msgbuf *msgbuf;
>  };
>  
> +void brcmf_bus_cancel_reset_work(struct brcmf_bus *bus_if);
> +void brcmf_bus_allow_reset_work(struct brcmf_bus *bus_if);
> +
>  /*
>   * callback wrappers
>   */
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
> index fed9cd5f2..b934feb9b 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
> @@ -1164,6 +1164,35 @@ static int brcmf_revinfo_read(struct seq_file *s, void *data)
>  	return 0;
>  }
>  
> +/* Serialize bus_reset arming (debugfs reset write, brcmf_fw_crashed) against the
> + * teardown drain: the remove path takes bus_reset_lock, sets ->removing and cancels
> + * the work under it, so a racing armer either schedules before the cancel (and is
> + * drained) or observes ->removing and desists.
> + */
> +static void brcmf_bus_schedule_reset(struct brcmf_bus *bus_if)
> +{
> +	mutex_lock(&bus_if->bus_reset_lock);
> +	if (bus_if->drvr && bus_if->drvr->bus_reset.func && !bus_if->removing)
> +		schedule_work(&bus_if->drvr->bus_reset);
> +	mutex_unlock(&bus_if->bus_reset_lock);
> +}

Is this safe in a softIRQ context?                                                                                                        
mutex_lock() sleeps until it can get the lock.

> +
> +void brcmf_bus_cancel_reset_work(struct brcmf_bus *bus_if)
> +{
> +	mutex_lock(&bus_if->bus_reset_lock);
> +	bus_if->removing = true;
> +	if (bus_if->drvr)
> +		cancel_work_sync(&bus_if->drvr->bus_reset);
> +	mutex_unlock(&bus_if->bus_reset_lock);
> +}

How about if brcmf_pcie_remove() calls brcmf_bus_cancel_reset_work(),
takes the lock and calls cancel_work_sync(), sleeps. If debugfs
path is already running, it can invoke the worker thread. Is there
potential that both try to reset?

> +
> +void brcmf_bus_allow_reset_work(struct brcmf_bus *bus_if)
> +{
> +	mutex_lock(&bus_if->bus_reset_lock);
> +	bus_if->removing = false;
> +	mutex_unlock(&bus_if->bus_reset_lock);
> +}
> +
>  static void brcmf_core_bus_reset(struct work_struct *work)
>  {
>  	struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
> @@ -1184,7 +1213,7 @@ static ssize_t bus_reset_write(struct file *file, const char __user *user_buf,
>  	if (value != 1)
>  		return -EINVAL;
>  
> -	schedule_work(&drvr->bus_reset);
> +	brcmf_bus_schedule_reset(drvr->bus_if);
>  
>  	return count;
>  }
> @@ -1408,7 +1437,7 @@ void brcmf_fw_crashed(struct device *dev)
>  
>  	brcmf_dev_coredump(dev);
>  
> -	schedule_work(&drvr->bus_reset);
> +	brcmf_bus_schedule_reset(bus_if);
>  }
>  
>  void brcmf_detach(struct device *dev)
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
> index 8b149996f..3c6775166 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
> @@ -1914,6 +1914,7 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>  		ret = -ENOMEM;
>  		goto fail;
>  	}
> +	mutex_init(&bus->bus_reset_lock);
>  	bus->msgbuf = kzalloc(sizeof(*bus->msgbuf), GFP_KERNEL);
>  	if (!bus->msgbuf) {
>  		ret = -ENOMEM;
> @@ -1985,6 +1986,11 @@ brcmf_pcie_remove(struct pci_dev *pdev)
>  	if (devinfo->ci)
>  		brcmf_pcie_intr_disable(devinfo);
>  
> +	if (devinfo->irq_allocated)
> +		synchronize_irq(pdev->irq);
> +
> +	brcmf_bus_cancel_reset_work(bus);
> +
>  	brcmf_detach(&pdev->dev);
>  	brcmf_free(&pdev->dev);
>  
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
> index 8effeb7a7..31e37b0d4 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
> @@ -4541,6 +4541,12 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
>  	return NULL;
>  }
>  
> +void brcmf_sdio_cancel_datawork(struct brcmf_sdio *bus)
> +{
> +	if (bus)
> +		cancel_work_sync(&bus->datawork);
> +}
> +
>  /* Detach and free everything */
>  void brcmf_sdio_remove(struct brcmf_sdio *bus)
>  {
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
> index 15d2c02fa..3c68ebf8e 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
> @@ -373,6 +373,7 @@ int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev);
>  struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev);
>  void brcmf_sdio_remove(struct brcmf_sdio *bus);
>  void brcmf_sdio_isr(struct brcmf_sdio *bus, bool in_isr);
> +void brcmf_sdio_cancel_datawork(struct brcmf_sdio *bus);
>  
>  void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, bool active);
>  void brcmf_sdio_wowl_config(struct device *dev, bool enabled);
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
> index 9fb68c2dc..97d65ba36 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
> @@ -1271,6 +1271,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
>  		ret = -ENOMEM;
>  		goto fail;
>  	}
> +	mutex_init(&bus->bus_reset_lock);
>  
>  	bus->dev = dev;
>  	bus_pub->bus = bus;
> @@ -1336,6 +1337,8 @@ brcmf_usb_disconnect_cb(struct brcmf_usbdev_info *devinfo)
>  		return;
>  	brcmf_dbg(USB, "Enter, bus_pub %p\n", devinfo);
>  
> +	brcmf_bus_cancel_reset_work(devinfo->bus_pub.bus);
> +
>  	brcmf_detach(devinfo->dev);
>  	brcmf_free(devinfo->dev);
>  	kfree(devinfo->bus_pub.bus);
> -- 
> 2.34.1

Sent using hkml (https://github.com/sjp38/hackermail)

^ permalink raw reply

* Re: [PATCH net-next] net: ipv4: clear dev->ip_ptr before destroying inetdev
From: Yuyang Huang @ 2026-07-10  0:28 UTC (permalink / raw)
  To: Ido Schimmel
  Cc: David S. Miller, David Ahern, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, linux-kernel, netdev,
	Kuniyuki Iwashima
In-Reply-To: <20260709171709.GA1749979@shredder>

On Fri, Jul 10, 2026 at 2:17 AM Ido Schimmel <idosch@nvidia.com> wrote:
>
> On Tue, Jul 07, 2026 at 01:30:39PM +0900, Yuyang Huang wrote:
> > To prevent RCU readers from accessing a partially destroyed in_device,
> > clear dev->ip_ptr early in inetdev_destroy() before freeing the
> > multicast list and individual IP addresses. This aligns the IPv4 teardown
> > sequence with the IPv6 implementation.
> >
> > Cc: Ido Schimmel <idosch@nvidia.com>
> > Cc: Kuniyuki Iwashima <kuniyu@google.com>
> > Signed-off-by: Yuyang Huang <yuyanghuang@google.com>
>
> I believe that sashiko-gemini [1] is right and you need to teach
> prestera to ignore NETDEV_DOWN notifications in the inetaddr chain when
> a RIF doesn't exist. Something like [2].
>
> Regarding ieee80211_ifa_changed(), the net device is being tore down, so
> failing to update the firmware ARP filter probably doesn't matter, but
> you can do something like [3] to avoid it completely.
>
> So, three patches where the last one aligns IPv4 with IPv6. Please check
> if other listeners need to be adjusted (mlxsw is OK).
>
> Thanks
>
> [1] https://sashiko.dev/#/patchset/20260707043039.101983-1-yuyanghuang%40google.com
>
> [2]
> diff --git a/drivers/net/ethernet/marvell/prestera/prestera_router.c b/drivers/net/ethernet/marvell/prestera/prestera_router.c
> index b036b173a308..0c4f462baa6e 100644
> --- a/drivers/net/ethernet/marvell/prestera/prestera_router.c
> +++ b/drivers/net/ethernet/marvell/prestera/prestera_router.c
> @@ -1302,10 +1302,8 @@ static int __prestera_inetaddr_port_event(struct net_device *port_dev,
>                 dev_hold(port_dev);
>                 break;
>         case NETDEV_DOWN:
> -               if (!re) {
> -                       NL_SET_ERR_MSG_MOD(extack, "Can't find RIF");
> -                       return -EEXIST;
> -               }
> +               if (!re)
> +                       return 0;
>                 prestera_rif_entry_destroy(port->sw, re);
>                 dev_put(port_dev);
>                 break;
>
> [3]
> diff --git a/net/mac80211/main.c b/net/mac80211/main.c
> index 90d295cc364f..0e7a60dd1d8d 100644
> --- a/net/mac80211/main.c
> +++ b/net/mac80211/main.c
> @@ -588,9 +588,7 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
>         if (sdata->vif.type != NL80211_IFTYPE_STATION)
>                 return NOTIFY_DONE;
>
> -       idev = __in_dev_get_rtnl(sdata->dev);
> -       if (!idev)
> -               return NOTIFY_DONE;
> +       idev = ifa->ifa_dev;
>
>         ifmgd = &sdata->u.mgd;

Thanks for the review comments; I will update prestera and ieee80211,
as well as go through other listeners to confirm the sequence and send
out stacked patches as suggested.

Thanks,

Yuyang

^ permalink raw reply

* [PATCH net v2] sctp: validate stream count in sctp_process_strreset_inreq()
From: Cen Zhang (Microsoft) @ 2026-07-10  1:07 UTC (permalink / raw)
  To: marcelo.leitner, lucien.xin, davem, edumazet, kuba, pabeni
  Cc: horms, linux-sctp, netdev, linux-kernel, AutonomousCodeSecurity,
	tgopinath, kys, blbllhy

When processing a RESET_IN_REQUEST from a peer,
sctp_process_strreset_inreq() derives the stream count from the
parameter length but does not check whether the resulting
RESET_OUT_REQUEST would exceed SCTP_MAX_CHUNK_LEN.

The OUT request header (sctp_strreset_outreq, 16 bytes) is 8 bytes
larger than the IN request header (sctp_strreset_inreq, 8 bytes).
Generally, the IP payload is bounded to 65535 bytes, so the stream
list cannot be large enough to trigger the overflow. However, on
interfaces with MTU > 65535 (e.g., loopback with IPv6 jumbograms), a
stream list that fits within the incoming IN parameter can cause a
__u16 overflow in sctp_make_strreset_req() when computing the OUT
request size, leading to an undersized skb allocation and a kernel
BUG:

  net/core/skbuff.c:207         skb_panic
  net/core/skbuff.c:2625        skb_put
  net/sctp/sm_make_chunk.c:1535 sctp_addto_chunk
  net/sctp/sm_make_chunk.c:3695 sctp_make_strreset_req
  net/sctp/stream.c:655         sctp_process_strreset_inreq

The local setsockopt path validates the generated reset request size.
However, for an incoming-only reset, it accounts for the smaller IN
request even though the peer must generate an OUT request with the same
stream list. Such a request cannot be completed successfully by the
peer.

Reject peer IN requests whose corresponding OUT request would exceed
SCTP_MAX_CHUNK_LEN. Also tighten the local check so it does not send an
IN request that would require an oversized OUT request from the peer.

Fixes: 7f9d68ac944e ("sctp: implement sender-side procedures for SSN Reset Request Parameter")
Reported-by: AutonomousCodeSecurity@microsoft.com
Closes: https://lore.kernel.org/all/20260707203215.2752-1-blbllhy@gmail.com/
Suggested-by: Xin Long <lucien.xin@gmail.com>
Signed-off-by: Cen Zhang (Microsoft) <blbllhy@gmail.com>
---
v2: Add the OUT request length check to the send path, as suggested by Xin Long.

 net/sctp/stream.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/net/sctp/stream.c b/net/sctp/stream.c
index 5c2fdedea088..34ffe6c945a4 100644
--- a/net/sctp/stream.c
+++ b/net/sctp/stream.c
@@ -308,7 +308,8 @@ int sctp_send_reset_streams(struct sctp_association *asoc,
 					goto out;
 
 			param_len += str_nums * sizeof(__u16) +
-				     sizeof(struct sctp_strreset_inreq);
+				     (out ? sizeof(struct sctp_strreset_inreq)
+					  : sizeof(struct sctp_strreset_outreq));
 		}
 
 		if (param_len > SCTP_MAX_CHUNK_LEN -
@@ -639,6 +640,9 @@ struct sctp_chunk *sctp_process_strreset_inreq(
 
 	nums = (ntohs(param.p->length) - sizeof(*inreq)) / sizeof(__u16);
 	str_p = inreq->list_of_streams;
+	if (nums * sizeof(__u16) + sizeof(struct sctp_strreset_outreq) >
+	    SCTP_MAX_CHUNK_LEN - sizeof(struct sctp_reconf_chunk))
+		goto out;
 	for (i = 0; i < nums; i++) {
 		if (ntohs(str_p[i]) >= stream->outcnt) {
 			result = SCTP_STRRESET_ERR_WRONG_SSN;
-- 
2.53.0


^ permalink raw reply related

* [PATCH iproute2-next v5 0/2] rdma: display resource limits in curr/max format
From: Tao Cui @ 2026-07-10  1:17 UTC (permalink / raw)
  To: dsahern, leonro; +Cc: linux-rdma, netdev, cui.tao, cuitao

From: Tao Cui <cuitao@kylinos.cn>

This series adds support for displaying RDMA device resource limits in
curr/max format in the rdma tool, building on the kernel uapi attribute
RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_MAX which has landed in linux-next
(kernel commit 5911f6d6e7ce [1]).

Patch 1 syncs the rdma_netlink.h uapi header from the kernel.
Patch 2 updates the rdma tool to parse the new attribute and display
resource usage in curr/max format:

  $ rdma resource show
  0: mlx5_0: qp 123/131072  cq 45/65536  mr 200/1000000  pd 10/32768

[1]: 
Link: https://lore.kernel.org/all/20260615003646.168704-1-cui.tao@linux.dev/

Tao Cui (2):
  rdma: update uapi headers
  rdma: display resource limits in curr/max format

 rdma/include/uapi/rdma/rdma_netlink.h |  5 +++++
 rdma/res.c                            | 21 ++++++++++++++++++++-
 rdma/utils.c                          |  1 +
 3 files changed, 26 insertions(+), 1 deletion(-)

---
Changes in v5:
- Split the rdma_netlink.h update into its own commit following the
  uapi headers sync format ("rdma: update uapi headers").
Changes in v4:
- Add a Link: reference to the kernel patch; re-send now that the
  kernel side has landed in linux-next.
-- 
2.43.0


^ permalink raw reply

* [PATCH iproute2-next v5 1/2] rdma: update uapi headers
From: Tao Cui @ 2026-07-10  1:17 UTC (permalink / raw)
  To: dsahern, leonro; +Cc: linux-rdma, netdev, cui.tao, cuitao
In-Reply-To: <20260710011759.378893-1-cui.tao@linux.dev>

From: Tao Cui <cuitao@kylinos.cn>

Update rdma_netlink.h file upto kernel commit 5911f6d6e7ce
("RDMA/nldev: Add resource summary max values for usage display")

Signed-off-by: Tao Cui <cuitao@kylinos.cn>
---
 rdma/include/uapi/rdma/rdma_netlink.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/rdma/include/uapi/rdma/rdma_netlink.h b/rdma/include/uapi/rdma/rdma_netlink.h
index 4356ec4a..e5b8b065 100644
--- a/rdma/include/uapi/rdma/rdma_netlink.h
+++ b/rdma/include/uapi/rdma/rdma_netlink.h
@@ -604,6 +604,11 @@ enum rdma_nldev_attr {
 	RDMA_NLDEV_ATTR_FRMR_POOL_PINNED_HANDLES,	/* u32 */
 	RDMA_NLDEV_ATTR_FRMR_POOL_KEY_KERNEL_VENDOR_KEY,	/* u64 */
 
+	/*
+	 * Resource summary entry maximum value.
+	 */
+	RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_MAX,		/* u64 */
+
 	/*
 	 * Always the end
 	 */
-- 
2.43.0


^ permalink raw reply related

* [PATCH iproute2-next v5 2/2] rdma: display resource limits in curr/max format
From: Tao Cui @ 2026-07-10  1:17 UTC (permalink / raw)
  To: dsahern, leonro; +Cc: linux-rdma, netdev, cui.tao, cuitao
In-Reply-To: <20260710011759.378893-1-cui.tao@linux.dev>

From: Tao Cui <cuitao@kylinos.cn>

Parse the new RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_MAX netlink attribute
to show resource limits alongside current counts in curr/max format:

  Before: 0: mlx5_0: qp 123  cq 45  mr 200  pd 10
  After:  0: mlx5_0: qp 123/131072  cq 45/65536  mr 200/1000000  pd 10/32768

JSON output provides both current and max fields per resource type
(e.g. "qp": 123, "qp-max": 131072). Backward compatible: no output
change when kernel lacks the new attribute.

Signed-off-by: Tao Cui <cuitao@kylinos.cn>
Link: https://lore.kernel.org/all/20260615003646.168704-1-cui.tao@linux.dev/
---
 rdma/res.c   | 21 ++++++++++++++++++++-
 rdma/utils.c |  1 +
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/rdma/res.c b/rdma/res.c
index 062f0007..046935e2 100644
--- a/rdma/res.c
+++ b/rdma/res.c
@@ -55,7 +55,26 @@ static int res_print_summary(struct nlattr **tb)
 
 		name = mnl_attr_get_str(nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME]);
 		curr = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR]);
-		res_print_u64(name, curr, nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR]);
+		if (nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_MAX]) {
+			uint64_t max;
+			char max_name[64];
+
+			max = mnl_attr_get_u64(
+				nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_MAX]);
+			snprintf(max_name, sizeof(max_name), "%s-max", name);
+			print_u64(PRINT_JSON, name, NULL, curr);
+			print_u64(PRINT_JSON, max_name, NULL, max);
+			if (!is_json_context()) {
+				char buf[64];
+
+				snprintf(buf, sizeof(buf), "%s %" PRIu64 "/%" PRIu64 " ",
+					 name, curr, max);
+				pr_out("%s", buf);
+			}
+		} else {
+			res_print_u64(name, curr,
+				      nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR]);
+		}
 	}
 	return 0;
 }
diff --git a/rdma/utils.c b/rdma/utils.c
index 87003b2c..90ea1c55 100644
--- a/rdma/utils.c
+++ b/rdma/utils.c
@@ -480,6 +480,7 @@ static const enum mnl_attr_data_type nldev_policy[RDMA_NLDEV_ATTR_MAX] = {
 	[RDMA_NLDEV_ATTR_EVENT_TYPE] = MNL_TYPE_U8,
 	[RDMA_NLDEV_SYS_ATTR_MONITOR_MODE] = MNL_TYPE_U8,
 	[RDMA_NLDEV_ATTR_STAT_OPCOUNTER_ENABLED] = MNL_TYPE_U8,
+	[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_MAX] = MNL_TYPE_U64,
 };
 
 static int rd_attr_check(const struct nlattr *attr, int *typep)
-- 
2.43.0


^ permalink raw reply related

* [PATCH net] amt: refresh cached IP header pointers after MLD/IGMP checks
From: Xiang Mei (Microsoft) @ 2026-07-10  1:41 UTC (permalink / raw)
  To: Jakub Kicinski, Taehee Yoo, Andrew Lunn, David S . Miller,
	Eric Dumazet, Paolo Abeni
  Cc: netdev, linux-kernel, AutonomousCodeSecurity, tgopinath, kys,
	Xiang Mei (Microsoft)

amt_dev_xmit() and amt_update_handler() cache iph/ip6h before calling
ip_mc_check_igmp() / ipv6_mc_check_mld(), which may pskb_may_pull() a
non-linear skb and reallocate skb->head. The stale pointers are then
read (amt_dev_xmit: group.ip{4,6} = iph/ip6h->daddr; amt_update_handler:
ip{,v6}_eth_mc_map()), a slab-use-after-free. tx is reachable by an
unprivileged user whose amt device has SG enabled; rx by a tunnel peer
sending a membership update fragmented across several IP fragments.

Reload iph/ip6h after the check returns, like commit f0e42f0c4337
("ipv6: sit: reload inner IPv6 header after GSO offloads").

tx path:
  BUG: KASAN: slab-use-after-free in amt_dev_xmit (drivers/net/amt.c:1238)
  Read of size 16 by task exploit
   amt_dev_xmit (drivers/net/amt.c:1238)
   dev_hard_start_xmit (net/core/dev.c:3905)
   __dev_queue_xmit (net/core/dev.c:4872)
   packet_sendmsg (net/packet/af_packet.c:3114)

rx path:
  BUG: KASAN: slab-use-after-free in amt_rcv (drivers/net/amt.c:2530)
  Read of size 4 by task exploit
   amt_rcv (drivers/net/amt.c:2530)
   udp_queue_rcv_one_skb (net/ipv4/udp.c:2388)
   ip_local_deliver (net/ipv4/ip_input.c:262)
   ip_rcv (net/ipv4/ip_input.c:612)

Fixes: cbc21dc1cfe9 ("amt: add data plane of amt interface")
Fixes: bc54e49c140b ("amt: add multicast(IGMP) report message handler")
Fixes: b75f7095d4d4 ("amt: add mld report message handler")
Reported-by: AutonomousCodeSecurity@microsoft.com
Signed-off-by: Xiang Mei (Microsoft) <xmei5@asu.edu>
---
 drivers/net/amt.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/amt.c b/drivers/net/amt.c
index 951dd10e192b..8bc61c539b0a 100644
--- a/drivers/net/amt.c
+++ b/drivers/net/amt.c
@@ -1210,6 +1210,7 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev)
 		} else {
 			data = true;
 		}
+		iph = ip_hdr(skb);
 		v6 = false;
 		group.ip4 = iph->daddr;
 #if IS_ENABLED(CONFIG_IPV6)
@@ -1234,6 +1235,7 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev)
 		} else {
 			data = true;
 		}
+		ip6h = ipv6_hdr(skb);
 		v6 = true;
 		group.ip6 = ip6h->daddr;
 #endif
@@ -2498,6 +2500,7 @@ static bool amt_update_handler(struct amt_dev *amt, struct sk_buff *skb)
 			netdev_dbg(amt->dev, "Invalid IGMP\n");
 			return true;
 		}
+		iph = ip_hdr(skb);
 
 		spin_lock_bh(&tunnel->lock);
 		amt_igmp_report_handler(amt, skb, tunnel);
@@ -2517,6 +2520,7 @@ static bool amt_update_handler(struct amt_dev *amt, struct sk_buff *skb)
 			netdev_dbg(amt->dev, "Invalid MLD\n");
 			return true;
 		}
+		ip6h = ipv6_hdr(skb);
 
 		spin_lock_bh(&tunnel->lock);
 		amt_mld_report_handler(amt, skb, tunnel);
-- 
2.43.0


^ permalink raw reply related

* [PATCH net] tipc: clear sock->sk on the failed-insert path in tipc_sk_create()
From: Daehyeon Ko @ 2026-07-10  1:44 UTC (permalink / raw)
  To: netdev
  Cc: Jon Maloy, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, tipc-discussion, linux-kernel,
	Daehyeon Ko, stable

When tipc_sk_create() fails to insert the new socket (tipc_sk_insert()
returns non-zero), its error path frees the sk with sk_free() but leaves
sock->sk pointing at the freed object:

	if (tipc_sk_insert(tsk)) {
		sk_free(sk);
		pr_warn("Socket create failed; port number exhausted\n");
		return -EINVAL;
	}

This is harmless for plain socket(): the syscall layer clears sock->ops
before releasing, so tipc_release() is never called. It is not harmless
on the accept() path. tipc_accept() creates the pre-allocated child
socket with tipc_sk_create(net, new_sock, 0, kern); on failure it leaves
new_sock->sk dangling and new_sock->ops non-NULL, and do_accept() then
fput()s the new file, so __sock_release() -> tipc_release() runs
lock_sock(new_sock->sk) on the freed sk -- a use-after-free write of the
sk_lock spinlock.

tipc_release() already guards this exact "failed accept() releases a
pre-allocated child" case with "if (sk == NULL) return 0;", but the
guard is bypassed because tipc_sk_create() left sock->sk non-NULL
(dangling) rather than NULL.

Clear sock->sk on the failed-insert path so the existing tipc_release()
NULL check fires and the use-after-free is avoided.

The tipc_sk_insert() failure is reached when the per-netns socket
rhashtable hits its max_size (tsk_rht_params.max_size = 1048576, ~2M
elements) -- i.e. once a netns holds ~2M TIPC sockets every insert
returns -E2BIG.

  BUG: KASAN: slab-use-after-free in lock_sock_nested+0x98/0x150
  Write of size 8 at addr ffff8880047cdc38 by task init/1
   lock_sock_nested+0x98/0x150
   tipc_release+0xa4/0x7a0
   __sock_release+0x61/0x120
   sock_close+0x10/0x20
   __fput+0x1d6/0x490
  Allocated by task 1:
   sk_alloc+0x2b/0x380
   tipc_sk_create+0x82/0xb90
   tipc_accept+0x14c/0x650
  Freed by task 1:
   __sk_destruct+0x22d/0x2d0
   tipc_sk_create+0x7b8/0xb90
   tipc_accept+0x14c/0x650
   do_accept+0x1d2/0x2a0

Fixes: 07f6c4bc048a ("tipc: convert tipc reference table to use generic rhashtable")
Cc: stable@vger.kernel.org
Signed-off-by: Daehyeon Ko <4ncienth@gmail.com>
---
This was reported to security@kernel.org (Cc: the TIPC maintainer) with no
response; posting the fix directly to netdev as it is a straightforward
one-line fix. Full C reproducer available on request.

 net/tipc/socket.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index e564341e0216..55e695748332 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -502,6 +502,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
 	tipc_set_sk_state(sk, TIPC_OPEN);
 	if (tipc_sk_insert(tsk)) {
 		sk_free(sk);
+		sock->sk = NULL;
 		pr_warn("Socket create failed; port number exhausted\n");
 		return -EINVAL;
 	}
-- 
2.54.0


^ permalink raw reply related

* [PATCH net v2] net: hip04: fix tx coalesce timer and IRQ teardown races
From: Fan Wu @ 2026-07-10  1:57 UTC (permalink / raw)
  To: netdev
  Cc: shenjian15, salil.mehta, dingtianhong, horms, andrew+netdev,
	davem, edumazet, kuba, pabeni, linux-kernel, stable, Fan Wu

The hip04 remove path frees the TX/RX rings before unregistering the
netdev. If the interface is still up, unregister_netdev() then runs
.ndo_stop, whose TX reclaim and NAPI poll touch the already-freed DMA
ring memory. The TX coalesce timer and the platform IRQ also outlive
the netdev private data they dereference.

Reorder hip04_remove() so the netdev is unregistered (which runs .ndo_stop
synchronously, stopping NAPI and the TX queue) before the rings are freed.
Free the devm-managed IRQ explicitly before free_netdev(), so
hip04_mac_interrupt() (whose dev_id is the netdev) cannot fire against
freed memory: devm would otherwise release it only after .remove returns.

hip04_mac_stop() must quiesce both arming sites of the coalesce timer.
The NAPI poll arms it, and napi_disable() returns once the poll calls
napi_complete_done(), not when the poll function returns, so move that
arm before napi_complete_done().  The existing early exits that jump to
done do not call napi_complete_done(), so they remain outside the
completion-after-arm window this change closes.  The TX xmit path also
arms it, and mac_stop() is reached directly from hip04_tx_timeout_task()
as well as via .ndo_stop, so use netif_tx_disable() rather than
netif_stop_queue() to wait for an in-flight hip04_mac_start_xmit() to
finish.  The timer is then drained with hrtimer_cancel().  A "closing"
flag, checked at the single arming site, guards against a later arm.

hip04_tx_timeout_task() restarts the device with mac_stop() + mac_open();
serialize that restart against .ndo_stop with rtnl_lock(), matching the
netdev core's locking, skip it if the device is no longer running, and
emit an error if the restart fails instead of silently leaving it down.

This issue was found by an in-house static analysis tool.

Fixes: a41ea46a9a12 ("net: hisilicon: new hip04 ethernet driver")
Cc: stable@vger.kernel.org
Assisted-by: Codex:gpt-5.5
Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
---
v2:
  - Address review comments from Simon Horman. Use netif_tx_disable() rather
    than netif_stop_queue() in hip04_mac_stop() so that an in-flight
    hip04_mac_start_xmit() finishes before the TX ring is reclaimed;
    mac_stop() is also called directly from the tx-timeout work, not only
    via .ndo_stop.
  - Arm the coalesce timer in hip04_rx_poll() before napi_complete_done(), so
    that napi_disable() observes the final arm and the subsequent cancel
    cannot miss it.
  - Free the devm-managed IRQ explicitly in hip04_remove() before free_netdev()
    so that hip04_mac_interrupt() cannot run against freed memory, placing it
    after unregister_netdev() so that the device is stopped first.
  - Reorder hip04_remove() so that the netdev is unregistered (running .ndo_stop)
    before the PHY is disconnected and the TX/RX rings are freed.
  - Check the return value of hip04_mac_open() in the tx-timeout restart path.

v1: https://lore.kernel.org/netdev/20260703050133.2445155-1-fanwu01@zju.edu.cn/

 drivers/net/ethernet/hisilicon/hip04_eth.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c
--- a/drivers/net/ethernet/hisilicon/hip04_eth.c
+++ b/drivers/net/ethernet/hisilicon/hip04_eth.c
@@ -15,6 +15,7 @@
 #include <linux/of_net.h>
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
+#include <linux/rtnetlink.h>
 
 #define SC_PPE_RESET_DREQ		0x026C
 
@@ -232,6 +233,7 @@
 	int tx_coalesce_frames;
 	int tx_coalesce_usecs;
 	struct hrtimer tx_coalesce_timer;
+	bool closing;
 
 	unsigned char *rx_buf[RX_DESC_NUM];
 	dma_addr_t rx_phys[RX_DESC_NUM];
@@ -497,6 +499,12 @@
 {
 	unsigned long ns = priv->tx_coalesce_usecs * NSEC_PER_USEC / 2;
 
+	/* Do not (re-)arm the TX coalesce timer once teardown has begun.
+	 * Both arming sites (TX xmit and NAPI rx poll) go through here.
+	 */
+	if (smp_load_acquire(&priv->closing))
+		return;
+
 	/* allow timer to fire after half the time at the earliest */
 	hrtimer_start_range_ns(&priv->tx_coalesce_timer, ns_to_ktime(ns),
 			       ns, HRTIMER_MODE_REL);
@@ -649,12 +657,15 @@
 		priv->reg_inten |= RCV_INT;
 		writel_relaxed(priv->reg_inten, priv->base + PPE_INTEN);
 	}
+	/* Arm the coalesce timer BEFORE napi_complete_done(): napi_disable()
+	 * in hip04_mac_stop() returns once SCHED is cleared here, not when
+	 * the poll function returns, so arming afterwards can slip past the
+	 * stop path's hrtimer_cancel().
+	 */
+	if (tx_remaining)
+		hip04_start_tx_timer(priv);
 	napi_complete_done(napi, rx);
 done:
-	/* start a new timer if necessary */
-	if (rx < budget && tx_remaining)
-		hip04_start_tx_timer(priv);
-
 	return rx;
 }
 
@@ -729,6 +740,11 @@
 	priv->rx_cnt_remaining = 0;
 	priv->tx_head = 0;
 	priv->tx_tail = 0;
+	/* A plain write is sufficient here: mac_open() runs under RTNL, so it
+	 * cannot race mac_stop()'s store-release, and napi_enable() below orders
+	 * this reset before any TX/NAPI traffic can resume.
+	 */
+	WRITE_ONCE(priv->closing, false);
 	hip04_reset_ppe(priv);
 
 	for (i = 0; i < RX_DESC_NUM; i++) {
@@ -759,8 +775,26 @@
 	struct hip04_priv *priv = netdev_priv(ndev);
 	int i;
 
+	/* Stop new timer arms before draining: set the closing flag (checked
+	 * at the single arming site), wait for the NAPI poll and any in-flight
+	 * TX to finish, then cancel the timer.
+	 *
+	 * netif_tx_disable() (not netif_stop_queue()) is required because this
+	 * function is also called directly from hip04_tx_timeout_task(), not
+	 * only via .ndo_stop where the core has already deactivated TX;
+	 * netif_tx_disable() waits for an in-flight hip04_mac_start_xmit(),
+	 * which arms the timer, to finish.
+	 *
+	 * Because hip04_rx_poll() arms the timer before napi_complete_done(),
+	 * napi_disable() returning means that arm has happened, so the
+	 * hrtimer_cancel() below cannot miss it.  The store-release pairs
+	 * with the load in hip04_start_tx_timer().
+	 */
+	smp_store_release(&priv->closing, true);
+
 	napi_disable(&priv->napi);
-	netif_stop_queue(ndev);
+	netif_tx_disable(ndev);
+	hrtimer_cancel(&priv->tx_coalesce_timer);
 	hip04_mac_disable(ndev);
 	hip04_tx_reclaim(ndev, true);
 	hip04_reset_ppe(priv);
@@ -791,8 +825,21 @@
 	struct hip04_priv *priv;
 
 	priv = container_of(work, struct hip04_priv, tx_timeout_task);
+
+	/* Bail if the device was taken down (dev_close/unregister).  The
+	 * mac_stop() below is called directly and does not clear
+	 * __LINK_STATE_START, so this guard does not match the restart's
+	 * own stop; it exists only to avoid restarting a torn-down device.
+	 */
+	rtnl_lock();
+	if (!netif_running(priv->ndev))
+		goto out;
+
 	hip04_mac_stop(priv->ndev);
-	hip04_mac_open(priv->ndev);
+	if (hip04_mac_open(priv->ndev))
+		netdev_err(priv->ndev, "restart after tx timeout failed\n");
+out:
+	rtnl_unlock();
 }
 
 static int hip04_get_coalesce(struct net_device *netdev,
@@ -1026,13 +1073,24 @@
 	struct hip04_priv *priv = netdev_priv(ndev);
 	struct device *d = &pdev->dev;
 
+	unregister_netdev(ndev);
+
+	/* The IRQ is devm-managed and would otherwise be freed only after
+	 * this function returns.  Free it now, after unregister_netdev() has
+	 * run .ndo_stop to stop the device and mask its interrupt source, but
+	 * before the manual free_netdev() below, so that hip04_mac_interrupt()
+	 * (dev_id == ndev) cannot fire against freed memory.  free_irq() also
+	 * drains any in-flight handler.
+	 */
+	devm_free_irq(d, ndev->irq, ndev);
+	cancel_work_sync(&priv->tx_timeout_task);
+	hrtimer_cancel(&priv->tx_coalesce_timer);
+
 	if (priv->phy)
 		phy_disconnect(priv->phy);
 
 	hip04_free_ring(ndev, d);
-	unregister_netdev(ndev);
 	of_node_put(priv->phy_node);
-	cancel_work_sync(&priv->tx_timeout_task);
 	free_netdev(ndev);
 }
 


^ permalink raw reply

* [PATCH net-next v7 2/2] net: libwx: add support for set_coalesce in wx_ethtool_ops_vf
From: Mengyuan Lou @ 2026-07-10  1:59 UTC (permalink / raw)
  To: netdev; +Cc: jiawenwu, duanqiangwen, horms, kuba, pabeni, Mengyuan Lou
In-Reply-To: <20260710015925.34769-1-mengyuanlou@net-swift.com>

Add support for set_coalesce in wx_ethtool_ops_vf, which
is used to set interrupt coalescing parameters.

Update wx_write_eitr_vf() to use the same interrupt
moderation encoding as PF devices, since PF and VF share
the same register layout. And remove the now-unused
WX_VXITR_MASK definition.

Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com>
---
 drivers/net/ethernet/wangxun/libwx/wx_ethtool.c |  7 ++++++-
 drivers/net/ethernet/wangxun/libwx/wx_vf.h      |  1 -
 drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c  | 13 ++++++++++++-
 3 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
index eae038df6875..22037f015ded 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
@@ -10,6 +10,7 @@
 #include "wx_hw.h"
 #include "wx_lib.h"
 #include "wx_vf_common.h"
+#include "wx_vf_lib.h"
 
 struct wx_stats {
 	char stat_string[ETH_GSTRING_LEN];
@@ -488,7 +489,10 @@ int wx_set_coalesce(struct net_device *netdev,
 		else
 			/* rx only or mixed */
 			q_vector->itr = rx_itr_param;
-		wx_write_eitr(q_vector);
+		if (wx->pdev->is_virtfn)
+			wx_write_eitr_vf(q_vector);
+		else
+			wx_write_eitr(q_vector);
 	}
 
 	wx_update_rsc(wx);
@@ -845,6 +849,7 @@ static const struct ethtool_ops wx_ethtool_ops_vf = {
 	.set_ringparam		= wx_set_ringparam_vf,
 	.get_msglevel		= wx_get_msglevel,
 	.get_coalesce		= wx_get_coalesce,
+	.set_coalesce		= wx_set_coalesce,
 	.get_ts_info		= ethtool_op_get_ts_info,
 	.get_link_ksettings	= wx_get_link_ksettings_vf,
 };
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf.h b/drivers/net/ethernet/wangxun/libwx/wx_vf.h
index eb6ca3fe4e97..b64a4de089f2 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_vf.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_vf.h
@@ -41,7 +41,6 @@
 #define WX_VF_MAX_RX_QUEUES      4
 
 #define WX_VXITR(i)              (0x200 + (4 * (i))) /* i=[0,1] */
-#define WX_VXITR_MASK            GENMASK(8, 0)
 #define WX_VXITR_CNT_WDIS        BIT(31)
 #define WX_VXIVAR_MISC           0x260
 #define WX_VXIVAR(i)             (0x240 + (4 * (i))) /* i=[0,3] */
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c
index aa8be036956c..7325b475ee10 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c
@@ -16,7 +16,18 @@ void wx_write_eitr_vf(struct wx_q_vector *q_vector)
 	int v_idx = q_vector->v_idx;
 	u32 itr_reg;
 
-	itr_reg = q_vector->itr & WX_VXITR_MASK;
+	switch (wx->mac.type) {
+	case wx_mac_sp:
+		itr_reg = q_vector->itr & WX_SP_MAX_EITR;
+		break;
+	case wx_mac_aml:
+	case wx_mac_aml40:
+		itr_reg = (q_vector->itr >> 3) & WX_AML_MAX_EITR;
+		break;
+	default:
+		itr_reg = q_vector->itr & WX_EM_MAX_EITR;
+		break;
+	}
 
 	/* set the WDIS bit to not clear the timer bits and cause an
 	 * immediate assertion of the interrupt
-- 
2.30.1


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox