Netdev List
 help / color / mirror / Atom feed
* [PATCH rc 09/15] RDMA/ocrdma: Don't NULL deref uctx on errors in ocrdma_copy_pd_uresp()
From: Jason Gunthorpe @ 2026-04-28 16:17 UTC (permalink / raw)
  To: Andrew Lunn, Broadcom internal kernel review list, Bryan Tan,
	Eric Dumazet, Junxian Huang, Konstantin Taranov, Jakub Kicinski,
	Leon Romanovsky, linux-hyperv, linux-rdma, netdev, Paolo Abeni,
	Selvin Xavier, Chengchang Tang, Tariq Toukan, Vishnu Dasa,
	Yishai Hadas
  Cc: Abhijit Gangurde, Adit Ranadive, Allen Hubbe, Andrew Boyer,
	Aditya Sarwade, Brad Spengler, Bryan Tan, David S. Miller,
	Dexuan Cui, Doug Ledford, George Zhang, Jorgen Hansen, Jianbo Liu,
	Kai Aizen, Leon Romanovsky, Leon Romanovsky, Yixian Liu, Long Li,
	Lijun Ou, Parav Pandit, patches, Roland Dreier, Roland Dreier,
	Sagi Grimberg, Ajay Sharma, stable, Tariq Toukan, Wei Hu (Xavier),
	Shaobo Xu, Nenglong Zhao
In-Reply-To: <0-v1-41f3135e5565+9d2-rdma_ai_fixes1_jgg@nvidia.com>

Sashiko points out that pd->uctx isn't initialized until late in the
function so all these error flow references are NULL and will crash. Use
the uctx that isn't NULL.

Cc: stable@vger.kernel.org
Fixes: fe2caefcdf58 ("RDMA/ocrdma: Add driver for Emulex OneConnect IBoE RDMA adapter")
Link: https://sashiko.dev/#/patchset/0-v1-e911b76a94d1%2B65d95-rdma_udata_rep_jgg%40nvidia.com?part=4
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/infiniband/hw/ocrdma/ocrdma_verbs.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
index 463c9a5703fc4e..a88cc5d84af828 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
@@ -620,9 +620,9 @@ static int ocrdma_copy_pd_uresp(struct ocrdma_dev *dev, struct ocrdma_pd *pd,
 
 ucopy_err:
 	if (pd->dpp_enabled)
-		ocrdma_del_mmap(pd->uctx, dpp_page_addr, PAGE_SIZE);
+		ocrdma_del_mmap(uctx, dpp_page_addr, PAGE_SIZE);
 dpp_map_err:
-	ocrdma_del_mmap(pd->uctx, db_page_addr, db_page_size);
+	ocrdma_del_mmap(uctx, db_page_addr, db_page_size);
 	return status;
 }
 
-- 
2.43.0


^ permalink raw reply related

* [PATCH rc 12/15] RDMA/mlx4: Fix mis-use of RCU in mlx4_srq_event()
From: Jason Gunthorpe @ 2026-04-28 16:17 UTC (permalink / raw)
  To: Andrew Lunn, Broadcom internal kernel review list, Bryan Tan,
	Eric Dumazet, Junxian Huang, Konstantin Taranov, Jakub Kicinski,
	Leon Romanovsky, linux-hyperv, linux-rdma, netdev, Paolo Abeni,
	Selvin Xavier, Chengchang Tang, Tariq Toukan, Vishnu Dasa,
	Yishai Hadas
  Cc: Abhijit Gangurde, Adit Ranadive, Allen Hubbe, Andrew Boyer,
	Aditya Sarwade, Brad Spengler, Bryan Tan, David S. Miller,
	Dexuan Cui, Doug Ledford, George Zhang, Jorgen Hansen, Jianbo Liu,
	Kai Aizen, Leon Romanovsky, Leon Romanovsky, Yixian Liu, Long Li,
	Lijun Ou, Parav Pandit, patches, Roland Dreier, Roland Dreier,
	Sagi Grimberg, Ajay Sharma, stable, Tariq Toukan, Wei Hu (Xavier),
	Shaobo Xu, Nenglong Zhao
In-Reply-To: <0-v1-41f3135e5565+9d2-rdma_ai_fixes1_jgg@nvidia.com>

Sashiko points out the radix_tree itself is RCU safe, but nothing ever
frees the mlx4_srq struct with RCU, and it isn't even accessed within the
RCU critical section. It also will crash if an event is delivered before
the srq object is finished initializing.

Use the spinlock since it isn't easy to make RCU work, use
refcount_inc_not_zero() to protect against partially initialized objects,
and order the refcount_set() to be after the srq is fully initialized.

Cc: stable@vger.kernel.org
Fixes: 30353bfc43a1 ("net/mlx4_core: Use RCU to perform radix tree lookup for SRQ")
Link: https://sashiko.dev/#/patchset/0-v2-1c49eeb88c48%2B91-rdma_udata_rep_jgg%40nvidia.com?part=5
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/net/ethernet/mellanox/mlx4/srq.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx4/srq.c b/drivers/net/ethernet/mellanox/mlx4/srq.c
index dd890f5d7b725c..8711689120f302 100644
--- a/drivers/net/ethernet/mellanox/mlx4/srq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/srq.c
@@ -44,13 +44,14 @@ void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type)
 {
 	struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
 	struct mlx4_srq *srq;
+	unsigned long flags;
 
-	rcu_read_lock();
+	spin_lock_irqsave(&srq_table->lock, flags);
 	srq = radix_tree_lookup(&srq_table->tree, srqn & (dev->caps.num_srqs - 1));
-	rcu_read_unlock();
-	if (srq)
-		refcount_inc(&srq->refcount);
-	else {
+	if (!srq || !refcount_inc_not_zero(&srq->refcount))
+		srq = NULL;
+	spin_unlock_irqrestore(&srq_table->lock, flags);
+	if (!srq) {
 		mlx4_warn(dev, "Async event for bogus SRQ %08x\n", srqn);
 		return;
 	}
@@ -203,8 +204,8 @@ int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, u32 cqn, u16 xrcd,
 	if (err)
 		goto err_radix;
 
-	refcount_set(&srq->refcount, 1);
 	init_completion(&srq->free);
+	refcount_set_release(&srq->refcount, 1);
 
 	return 0;
 
-- 
2.43.0


^ permalink raw reply related

* [PATCH rc 10/15] RDMA/vmw_pvrdma: Fix double free on pvrdma_alloc_ucontext() error path
From: Jason Gunthorpe @ 2026-04-28 16:17 UTC (permalink / raw)
  To: Andrew Lunn, Broadcom internal kernel review list, Bryan Tan,
	Eric Dumazet, Junxian Huang, Konstantin Taranov, Jakub Kicinski,
	Leon Romanovsky, linux-hyperv, linux-rdma, netdev, Paolo Abeni,
	Selvin Xavier, Chengchang Tang, Tariq Toukan, Vishnu Dasa,
	Yishai Hadas
  Cc: Abhijit Gangurde, Adit Ranadive, Allen Hubbe, Andrew Boyer,
	Aditya Sarwade, Brad Spengler, Bryan Tan, David S. Miller,
	Dexuan Cui, Doug Ledford, George Zhang, Jorgen Hansen, Jianbo Liu,
	Kai Aizen, Leon Romanovsky, Leon Romanovsky, Yixian Liu, Long Li,
	Lijun Ou, Parav Pandit, patches, Roland Dreier, Roland Dreier,
	Sagi Grimberg, Ajay Sharma, stable, Tariq Toukan, Wei Hu (Xavier),
	Shaobo Xu, Nenglong Zhao
In-Reply-To: <0-v1-41f3135e5565+9d2-rdma_ai_fixes1_jgg@nvidia.com>

Sashiko points out that pvrdma_uar_free() is already called within
pvrdma_dealloc_ucontext(), so calling it before triggers a double free.

Cc: stable@vger.kernel.org
Fixes: 29c8d9eba550 ("IB: Add vmw_pvrdma driver")
Link: https://sashiko.dev/#/patchset/0-v1-e911b76a94d1%2B65d95-rdma_udata_rep_jgg%40nvidia.com?part=4
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c
index bcd43dc30e21c6..c7c2b41060e526 100644
--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c
+++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c
@@ -322,7 +322,7 @@ int pvrdma_alloc_ucontext(struct ib_ucontext *uctx, struct ib_udata *udata)
 	uresp.qp_tab_size = vdev->dsr->caps.max_qp;
 	ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
 	if (ret) {
-		pvrdma_uar_free(vdev, &context->uar);
+		/* pvrdma_dealloc_ucontext() also frees the UAR */
 		pvrdma_dealloc_ucontext(&context->ibucontext);
 		return -EFAULT;
 	}
-- 
2.43.0


^ permalink raw reply related

* [PATCH rc 03/15] RDMA/mlx5: Add missing store/release for lock elision pattern
From: Jason Gunthorpe @ 2026-04-28 16:17 UTC (permalink / raw)
  To: Andrew Lunn, Broadcom internal kernel review list, Bryan Tan,
	Eric Dumazet, Junxian Huang, Konstantin Taranov, Jakub Kicinski,
	Leon Romanovsky, linux-hyperv, linux-rdma, netdev, Paolo Abeni,
	Selvin Xavier, Chengchang Tang, Tariq Toukan, Vishnu Dasa,
	Yishai Hadas
  Cc: Abhijit Gangurde, Adit Ranadive, Allen Hubbe, Andrew Boyer,
	Aditya Sarwade, Brad Spengler, Bryan Tan, David S. Miller,
	Dexuan Cui, Doug Ledford, George Zhang, Jorgen Hansen, Jianbo Liu,
	Kai Aizen, Leon Romanovsky, Leon Romanovsky, Yixian Liu, Long Li,
	Lijun Ou, Parav Pandit, patches, Roland Dreier, Roland Dreier,
	Sagi Grimberg, Ajay Sharma, stable, Tariq Toukan, Wei Hu (Xavier),
	Shaobo Xu, Nenglong Zhao
In-Reply-To: <0-v1-41f3135e5565+9d2-rdma_ai_fixes1_jgg@nvidia.com>

mlx5 has a common pattern implementing a device-global singleton resource
where it checks the resource pointer for !NULL and then skips obtaining
the lock.

This is not ordered properly as observing !NULL doesn't mean that all the
data under that pointer is also visible on this CPU when the lock is not
taken.

Use a release/acquire pairing to explicitly manage this.

Pointed out by sashiko, Codex found more cases.

Fixes: 5895e70f2e6e ("IB/mlx5: Allocate resources just before first QP/SRQ is created")
Fixes: 638420115cc4 ("IB/mlx5: Create UMR QP just before first reg_mr occurs")
Link: https://sashiko.dev/#/patchset/SYBPR01MB7881E1E0970268BD69C0BA75AF2B2%40SYBPR01MB7881.ausprd01.prod.outlook.com
Assisted-by: Codex:GPT-5.5
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/infiniband/hw/mlx5/main.c | 8 ++++----
 drivers/infiniband/hw/mlx5/umr.c  | 4 ++--
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index 109661c2ac12b0..73fab8a376933d 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -3310,7 +3310,7 @@ int mlx5_ib_dev_res_cq_init(struct mlx5_ib_dev *dev)
 	 * devr->c0 is set once, never changed until device unload.
 	 * Avoid taking the mutex if initialization is already done.
 	 */
-	if (devr->c0)
+	if (smp_load_acquire(&devr->c0))
 		return 0;
 
 	mutex_lock(&devr->cq_lock);
@@ -3336,7 +3336,7 @@ int mlx5_ib_dev_res_cq_init(struct mlx5_ib_dev *dev)
 	}
 
 	devr->p0 = pd;
-	devr->c0 = cq;
+	smp_store_release(&devr->c0, cq);
 
 unlock:
 	mutex_unlock(&devr->cq_lock);
@@ -3354,7 +3354,7 @@ int mlx5_ib_dev_res_srq_init(struct mlx5_ib_dev *dev)
 	 * devr->s1 is set once, never changed until device unload.
 	 * Avoid taking the mutex if initialization is already done.
 	 */
-	if (devr->s1)
+	if (smp_load_acquire(&devr->s1))
 		return 0;
 
 	mutex_lock(&devr->srq_lock);
@@ -3395,7 +3395,7 @@ int mlx5_ib_dev_res_srq_init(struct mlx5_ib_dev *dev)
 	}
 
 	devr->s0 = s0;
-	devr->s1 = s1;
+	smp_store_release(&devr->s1, s1);
 
 unlock:
 	mutex_unlock(&devr->srq_lock);
diff --git a/drivers/infiniband/hw/mlx5/umr.c b/drivers/infiniband/hw/mlx5/umr.c
index 29488fba21a034..f2139474be3751 100644
--- a/drivers/infiniband/hw/mlx5/umr.c
+++ b/drivers/infiniband/hw/mlx5/umr.c
@@ -147,7 +147,7 @@ int mlx5r_umr_resource_init(struct mlx5_ib_dev *dev)
 	 * UMR qp is set once, never changed until device unload.
 	 * Avoid taking the mutex if initialization is already done.
 	 */
-	if (dev->umrc.qp)
+	if (smp_load_acquire(&dev->umrc.qp))
 		return 0;
 
 	mutex_lock(&dev->umrc.init_lock);
@@ -185,7 +185,7 @@ int mlx5r_umr_resource_init(struct mlx5_ib_dev *dev)
 	sema_init(&dev->umrc.sem, MAX_UMR_WR);
 	mutex_init(&dev->umrc.lock);
 	dev->umrc.state = MLX5_UMR_STATE_ACTIVE;
-	dev->umrc.qp = qp;
+	smp_store_release(&dev->umrc.qp, qp);
 
 	mutex_unlock(&dev->umrc.init_lock);
 	return 0;
-- 
2.43.0


^ permalink raw reply related

* [PATCH rc 11/15] RDMA/mlx4: Fix resource leak on error in mlx4_ib_create_srq()
From: Jason Gunthorpe @ 2026-04-28 16:17 UTC (permalink / raw)
  To: Andrew Lunn, Broadcom internal kernel review list, Bryan Tan,
	Eric Dumazet, Junxian Huang, Konstantin Taranov, Jakub Kicinski,
	Leon Romanovsky, linux-hyperv, linux-rdma, netdev, Paolo Abeni,
	Selvin Xavier, Chengchang Tang, Tariq Toukan, Vishnu Dasa,
	Yishai Hadas
  Cc: Abhijit Gangurde, Adit Ranadive, Allen Hubbe, Andrew Boyer,
	Aditya Sarwade, Brad Spengler, Bryan Tan, David S. Miller,
	Dexuan Cui, Doug Ledford, George Zhang, Jorgen Hansen, Jianbo Liu,
	Kai Aizen, Leon Romanovsky, Leon Romanovsky, Yixian Liu, Long Li,
	Lijun Ou, Parav Pandit, patches, Roland Dreier, Roland Dreier,
	Sagi Grimberg, Ajay Sharma, stable, Tariq Toukan, Wei Hu (Xavier),
	Shaobo Xu, Nenglong Zhao
In-Reply-To: <0-v1-41f3135e5565+9d2-rdma_ai_fixes1_jgg@nvidia.com>

Sashiko points out that mlx4_srq_alloc() was not undone during error
unwind, add the missing call to mlx4_srq_free().

Cc: stable@vger.kernel.org
Fixes: 225c7b1feef1 ("IB/mlx4: Add a driver Mellanox ConnectX InfiniBand adapters")
Link: https://sashiko.dev/#/patchset/0-v1-e911b76a94d1%2B65d95-rdma_udata_rep_jgg%40nvidia.com?part=8
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/infiniband/hw/mlx4/srq.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c
index 5b23e5f8b84aca..767840736d583b 100644
--- a/drivers/infiniband/hw/mlx4/srq.c
+++ b/drivers/infiniband/hw/mlx4/srq.c
@@ -194,13 +194,15 @@ int mlx4_ib_create_srq(struct ib_srq *ib_srq,
 	if (udata)
 		if (ib_copy_to_udata(udata, &srq->msrq.srqn, sizeof (__u32))) {
 			err = -EFAULT;
-			goto err_wrid;
+			goto err_srq;
 		}
 
 	init_attr->attr.max_wr = srq->msrq.max - 1;
 
 	return 0;
 
+err_srq:
+	mlx4_srq_free(dev->dev, &srq->msrq);
 err_wrid:
 	if (udata)
 		mlx4_ib_db_unmap_user(ucontext, &srq->db);
-- 
2.43.0


^ permalink raw reply related

* [PATCH rc 05/15] RDMA/mana: Remove user triggerable WARN_ON() in mana_ib_create_qp_rss()
From: Jason Gunthorpe @ 2026-04-28 16:17 UTC (permalink / raw)
  To: Andrew Lunn, Broadcom internal kernel review list, Bryan Tan,
	Eric Dumazet, Junxian Huang, Konstantin Taranov, Jakub Kicinski,
	Leon Romanovsky, linux-hyperv, linux-rdma, netdev, Paolo Abeni,
	Selvin Xavier, Chengchang Tang, Tariq Toukan, Vishnu Dasa,
	Yishai Hadas
  Cc: Abhijit Gangurde, Adit Ranadive, Allen Hubbe, Andrew Boyer,
	Aditya Sarwade, Brad Spengler, Bryan Tan, David S. Miller,
	Dexuan Cui, Doug Ledford, George Zhang, Jorgen Hansen, Jianbo Liu,
	Kai Aizen, Leon Romanovsky, Leon Romanovsky, Yixian Liu, Long Li,
	Lijun Ou, Parav Pandit, patches, Roland Dreier, Roland Dreier,
	Sagi Grimberg, Ajay Sharma, stable, Tariq Toukan, Wei Hu (Xavier),
	Shaobo Xu, Nenglong Zhao
In-Reply-To: <0-v1-41f3135e5565+9d2-rdma_ai_fixes1_jgg@nvidia.com>

Sashiko points out that the user can specify WQs sharing the same CQ as a
part of the uAPI and this will trigger the WARN_ON() then go on to corrupt
the kernel.

Just reject it outright and fail the QP creation.

Cc: stable@vger.kernel.org
Fixes: c15d7802a424 ("RDMA/mana_ib: Add CQ interrupt support for RAW QP")
Link: https://sashiko.dev/#/patchset/0-v2-1c49eeb88c48%2B91-rdma_udata_rep_jgg%40nvidia.com?part=1
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/infiniband/hw/mana/cq.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/infiniband/hw/mana/cq.c b/drivers/infiniband/hw/mana/cq.c
index f4cbe21763bf11..2d682428ef202a 100644
--- a/drivers/infiniband/hw/mana/cq.c
+++ b/drivers/infiniband/hw/mana/cq.c
@@ -137,8 +137,9 @@ int mana_ib_install_cq_cb(struct mana_ib_dev *mdev, struct mana_ib_cq *cq)
 
 	if (cq->queue.id >= gc->max_num_cqs)
 		return -EINVAL;
-	/* Create CQ table entry */
-	WARN_ON(gc->cq_table[cq->queue.id]);
+	/* Create CQ table entry, sharing a CQ between WQs is not supported */
+	if (gc->cq_table[cq->queue.id])
+		return -EINVAL;
 	if (cq->queue.kmem)
 		gdma_cq = cq->queue.kmem;
 	else
-- 
2.43.0


^ permalink raw reply related

* [PATCH rc 15/15] RDMA/hns: Fix unlocked call to hns_roce_qp_remove()
From: Jason Gunthorpe @ 2026-04-28 16:17 UTC (permalink / raw)
  To: Andrew Lunn, Broadcom internal kernel review list, Bryan Tan,
	Eric Dumazet, Junxian Huang, Konstantin Taranov, Jakub Kicinski,
	Leon Romanovsky, linux-hyperv, linux-rdma, netdev, Paolo Abeni,
	Selvin Xavier, Chengchang Tang, Tariq Toukan, Vishnu Dasa,
	Yishai Hadas
  Cc: Abhijit Gangurde, Adit Ranadive, Allen Hubbe, Andrew Boyer,
	Aditya Sarwade, Brad Spengler, Bryan Tan, David S. Miller,
	Dexuan Cui, Doug Ledford, George Zhang, Jorgen Hansen, Jianbo Liu,
	Kai Aizen, Leon Romanovsky, Leon Romanovsky, Yixian Liu, Long Li,
	Lijun Ou, Parav Pandit, patches, Roland Dreier, Roland Dreier,
	Sagi Grimberg, Ajay Sharma, stable, Tariq Toukan, Wei Hu (Xavier),
	Shaobo Xu, Nenglong Zhao
In-Reply-To: <0-v1-41f3135e5565+9d2-rdma_ai_fixes1_jgg@nvidia.com>

Sashiko points out that hns_roce_qp_remove() requires the caller to hold
locks.  The error flow in hns_roce_create_qp_common() doesn't hold those
locks for the error unwind so it risks corrupting memory.

Grab the same locks the other two callers use.

Cc: stable@vger.kernel.org
Fixes: e088a685eae9 ("RDMA/hns: Support rq record doorbell for the user space")
Link: https://sashiko.dev/#/patchset/0-v2-1c49eeb88c48%2B91-rdma_udata_rep_jgg%40nvidia.com?part=9
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/infiniband/hw/hns/hns_roce_qp.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c
index f94ba98871f0d0..bf04ee84a94392 100644
--- a/drivers/infiniband/hw/hns/hns_roce_qp.c
+++ b/drivers/infiniband/hw/hns/hns_roce_qp.c
@@ -1171,6 +1171,7 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
 	struct hns_roce_ib_create_qp_resp resp = {};
 	struct ib_device *ibdev = &hr_dev->ib_dev;
 	struct hns_roce_ib_create_qp ucmd = {};
+	unsigned long flags;
 	int ret;
 
 	mutex_init(&hr_qp->mutex);
@@ -1257,7 +1258,13 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
 	return 0;
 
 err_flow_ctrl:
+	spin_lock_irqsave(&hr_dev->qp_list_lock, flags);
+	hns_roce_lock_cqs(init_attr->send_cq ? to_hr_cq(init_attr->send_cq) : NULL,
+			  init_attr->recv_cq ? to_hr_cq(init_attr->recv_cq) : NULL);
 	hns_roce_qp_remove(hr_dev, hr_qp);
+	hns_roce_unlock_cqs(init_attr->send_cq ? to_hr_cq(init_attr->send_cq) : NULL,
+			    init_attr->recv_cq ? to_hr_cq(init_attr->recv_cq) : NULL);
+	spin_unlock_irqrestore(&hr_dev->qp_list_lock, flags);
 err_store:
 	free_qpc(hr_dev, hr_qp);
 err_qpc:
-- 
2.43.0


^ permalink raw reply related

* [PATCH rc 08/15] RDMA/ocrdma: Clarify the mm_head searching
From: Jason Gunthorpe @ 2026-04-28 16:17 UTC (permalink / raw)
  To: Andrew Lunn, Broadcom internal kernel review list, Bryan Tan,
	Eric Dumazet, Junxian Huang, Konstantin Taranov, Jakub Kicinski,
	Leon Romanovsky, linux-hyperv, linux-rdma, netdev, Paolo Abeni,
	Selvin Xavier, Chengchang Tang, Tariq Toukan, Vishnu Dasa,
	Yishai Hadas
  Cc: Abhijit Gangurde, Adit Ranadive, Allen Hubbe, Andrew Boyer,
	Aditya Sarwade, Brad Spengler, Bryan Tan, David S. Miller,
	Dexuan Cui, Doug Ledford, George Zhang, Jorgen Hansen, Jianbo Liu,
	Kai Aizen, Leon Romanovsky, Leon Romanovsky, Yixian Liu, Long Li,
	Lijun Ou, Parav Pandit, patches, Roland Dreier, Roland Dreier,
	Sagi Grimberg, Ajay Sharma, stable, Tariq Toukan, Wei Hu (Xavier),
	Shaobo Xu, Nenglong Zhao
In-Reply-To: <0-v1-41f3135e5565+9d2-rdma_ai_fixes1_jgg@nvidia.com>

The intention of this code is to find matching entries exactly, the driver
never creates phys_addr's with different lens so the current expression is
not a bug, but it doesn't make sense and confuses review tooling.

Search for exact match instead.

Link: https://sashiko.dev/#/patchset/0-v1-e911b76a94d1%2B65d95-rdma_udata_rep_jgg%40nvidia.com?part=4
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/infiniband/hw/ocrdma/ocrdma_verbs.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
index c17e2a54dbcaf9..463c9a5703fc4e 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
@@ -215,7 +215,7 @@ static void ocrdma_del_mmap(struct ocrdma_ucontext *uctx, u64 phy_addr,
 
 	mutex_lock(&uctx->mm_list_lock);
 	list_for_each_entry_safe(mm, tmp, &uctx->mm_head, entry) {
-		if (len != mm->key.len && phy_addr != mm->key.phy_addr)
+		if (len != mm->key.len || phy_addr != mm->key.phy_addr)
 			continue;
 
 		list_del(&mm->entry);
@@ -233,7 +233,7 @@ static bool ocrdma_search_mmap(struct ocrdma_ucontext *uctx, u64 phy_addr,
 
 	mutex_lock(&uctx->mm_list_lock);
 	list_for_each_entry(mm, &uctx->mm_head, entry) {
-		if (len != mm->key.len && phy_addr != mm->key.phy_addr)
+		if (len != mm->key.len || phy_addr != mm->key.phy_addr)
 			continue;
 
 		found = true;
-- 
2.43.0


^ permalink raw reply related

* [PATCH rc 04/15] RDMA/mana: Validate rx_hash_key_len
From: Jason Gunthorpe @ 2026-04-28 16:17 UTC (permalink / raw)
  To: Andrew Lunn, Broadcom internal kernel review list, Bryan Tan,
	Eric Dumazet, Junxian Huang, Konstantin Taranov, Jakub Kicinski,
	Leon Romanovsky, linux-hyperv, linux-rdma, netdev, Paolo Abeni,
	Selvin Xavier, Chengchang Tang, Tariq Toukan, Vishnu Dasa,
	Yishai Hadas
  Cc: Abhijit Gangurde, Adit Ranadive, Allen Hubbe, Andrew Boyer,
	Aditya Sarwade, Brad Spengler, Bryan Tan, David S. Miller,
	Dexuan Cui, Doug Ledford, George Zhang, Jorgen Hansen, Jianbo Liu,
	Kai Aizen, Leon Romanovsky, Leon Romanovsky, Yixian Liu, Long Li,
	Lijun Ou, Parav Pandit, patches, Roland Dreier, Roland Dreier,
	Sagi Grimberg, Ajay Sharma, stable, Tariq Toukan, Wei Hu (Xavier),
	Shaobo Xu, Nenglong Zhao
In-Reply-To: <0-v1-41f3135e5565+9d2-rdma_ai_fixes1_jgg@nvidia.com>

Sashiko points out that rx_hash_key_len comes from a uAPI structure and is
blindly passed to memcpy, allowing the userspace to trash kernel
memory. Bounds check it so the memcpy cannot overflow.

Cc: stable@vger.kernel.org
Fixes: 0266a177631d ("RDMA/mana_ib: Add a driver for Microsoft Azure Network Adapter")
Link: https://sashiko.dev/#/patchset/0-v2-1c49eeb88c48%2B91-rdma_udata_rep_jgg%40nvidia.com?part=1
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/infiniband/hw/mana/qp.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/infiniband/hw/mana/qp.c b/drivers/infiniband/hw/mana/qp.c
index 645581359cee0b..f7bb0d1f0f8034 100644
--- a/drivers/infiniband/hw/mana/qp.c
+++ b/drivers/infiniband/hw/mana/qp.c
@@ -21,6 +21,9 @@ static int mana_ib_cfg_vport_steering(struct mana_ib_dev *dev,
 
 	gc = mdev_to_gc(dev);
 
+	if (rx_hash_key_len > sizeof(req->hashkey))
+		return -EINVAL;
+
 	req_buf_size = struct_size(req, indir_tab, MANA_INDIRECT_TABLE_DEF_SIZE);
 	req = kzalloc(req_buf_size, GFP_KERNEL);
 	if (!req)
-- 
2.43.0


^ permalink raw reply related

* [PATCH rc 07/15] RDMA/mana: Fix error unwind in mana_ib_create_qp_rss()
From: Jason Gunthorpe @ 2026-04-28 16:17 UTC (permalink / raw)
  To: Andrew Lunn, Broadcom internal kernel review list, Bryan Tan,
	Eric Dumazet, Junxian Huang, Konstantin Taranov, Jakub Kicinski,
	Leon Romanovsky, linux-hyperv, linux-rdma, netdev, Paolo Abeni,
	Selvin Xavier, Chengchang Tang, Tariq Toukan, Vishnu Dasa,
	Yishai Hadas
  Cc: Abhijit Gangurde, Adit Ranadive, Allen Hubbe, Andrew Boyer,
	Aditya Sarwade, Brad Spengler, Bryan Tan, David S. Miller,
	Dexuan Cui, Doug Ledford, George Zhang, Jorgen Hansen, Jianbo Liu,
	Kai Aizen, Leon Romanovsky, Leon Romanovsky, Yixian Liu, Long Li,
	Lijun Ou, Parav Pandit, patches, Roland Dreier, Roland Dreier,
	Sagi Grimberg, Ajay Sharma, stable, Tariq Toukan, Wei Hu (Xavier),
	Shaobo Xu, Nenglong Zhao
In-Reply-To: <0-v1-41f3135e5565+9d2-rdma_ai_fixes1_jgg@nvidia.com>

Sashiko points out that mana_ib_cfg_vport_steering() is leaked, the normal
destroy path cleans it up.

Cc: stable@vger.kernel.org
Fixes: 0266a177631d ("RDMA/mana_ib: Add a driver for Microsoft Azure Network Adapter")
Link: https://sashiko.dev/#/patchset/0-v1-e911b76a94d1%2B65d95-rdma_udata_rep_jgg%40nvidia.com?part=4
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/infiniband/hw/mana/qp.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/infiniband/hw/mana/qp.c b/drivers/infiniband/hw/mana/qp.c
index 8e1f052d0ec976..0fbcf449c134b5 100644
--- a/drivers/infiniband/hw/mana/qp.c
+++ b/drivers/infiniband/hw/mana/qp.c
@@ -217,13 +217,15 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd,
 		ibdev_dbg(&mdev->ib_dev,
 			  "Failed to copy to udata create rss-qp, %d\n",
 			  ret);
-		goto fail;
+		goto err_disable_vport_rx;
 	}
 
 	kfree(mana_ind_table);
 
 	return 0;
 
+err_disable_vport_rx:
+	mana_disable_vport_rx(mpc);
 fail:
 	while (i-- > 0) {
 		ibwq = ind_tbl->ind_tbl[i];
-- 
2.43.0


^ permalink raw reply related

* [PATCH rc 02/15] RDMA/mlx5: Restore zero-init to mlx5_ib_modify_qp() ucmd
From: Jason Gunthorpe @ 2026-04-28 16:17 UTC (permalink / raw)
  To: Andrew Lunn, Broadcom internal kernel review list, Bryan Tan,
	Eric Dumazet, Junxian Huang, Konstantin Taranov, Jakub Kicinski,
	Leon Romanovsky, linux-hyperv, linux-rdma, netdev, Paolo Abeni,
	Selvin Xavier, Chengchang Tang, Tariq Toukan, Vishnu Dasa,
	Yishai Hadas
  Cc: Abhijit Gangurde, Adit Ranadive, Allen Hubbe, Andrew Boyer,
	Aditya Sarwade, Brad Spengler, Bryan Tan, David S. Miller,
	Dexuan Cui, Doug Ledford, George Zhang, Jorgen Hansen, Jianbo Liu,
	Kai Aizen, Leon Romanovsky, Leon Romanovsky, Yixian Liu, Long Li,
	Lijun Ou, Parav Pandit, patches, Roland Dreier, Roland Dreier,
	Sagi Grimberg, Ajay Sharma, stable, Tariq Toukan, Wei Hu (Xavier),
	Shaobo Xu, Nenglong Zhao
In-Reply-To: <0-v1-41f3135e5565+9d2-rdma_ai_fixes1_jgg@nvidia.com>

Sashiko points out the check for inlen==0 got missed, the ={} was not
redundant, put it back.

Fixes: a9cd442a5347 ("RDMA: Remove redundant = {} for udata req structs")
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/infiniband/hw/mlx5/qp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c
index 8f50e7342a7694..76d4021475f49b 100644
--- a/drivers/infiniband/hw/mlx5/qp.c
+++ b/drivers/infiniband/hw/mlx5/qp.c
@@ -4692,7 +4692,7 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
 	struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
 	struct mlx5_ib_modify_qp_resp resp = {};
 	struct mlx5_ib_qp *qp = to_mqp(ibqp);
-	struct mlx5_ib_modify_qp ucmd;
+	struct mlx5_ib_modify_qp ucmd = {};
 	enum ib_qp_type qp_type;
 	enum ib_qp_state cur_state, new_state;
 	int err = -EINVAL;
-- 
2.43.0


^ permalink raw reply related

* [PATCH rc 06/15] RDMA/mana: Fix mana_destroy_wq_obj() cleanup in mana_ib_create_qp_rss()
From: Jason Gunthorpe @ 2026-04-28 16:17 UTC (permalink / raw)
  To: Andrew Lunn, Broadcom internal kernel review list, Bryan Tan,
	Eric Dumazet, Junxian Huang, Konstantin Taranov, Jakub Kicinski,
	Leon Romanovsky, linux-hyperv, linux-rdma, netdev, Paolo Abeni,
	Selvin Xavier, Chengchang Tang, Tariq Toukan, Vishnu Dasa,
	Yishai Hadas
  Cc: Abhijit Gangurde, Adit Ranadive, Allen Hubbe, Andrew Boyer,
	Aditya Sarwade, Brad Spengler, Bryan Tan, David S. Miller,
	Dexuan Cui, Doug Ledford, George Zhang, Jorgen Hansen, Jianbo Liu,
	Kai Aizen, Leon Romanovsky, Leon Romanovsky, Yixian Liu, Long Li,
	Lijun Ou, Parav Pandit, patches, Roland Dreier, Roland Dreier,
	Sagi Grimberg, Ajay Sharma, stable, Tariq Toukan, Wei Hu (Xavier),
	Shaobo Xu, Nenglong Zhao
In-Reply-To: <0-v1-41f3135e5565+9d2-rdma_ai_fixes1_jgg@nvidia.com>

Sashiko points out there are two bugs here in the error unwind flow, both
related to how the WQ table is unwound.

First there is a double i-- on the first failure path due to the while loop
having a i--, remove it.

Second if mana_ib_install_cq_cb() fails then mana_create_wq_obj() is not
undone due to the above i--.

Cc: stable@vger.kernel.org
Fixes: c15d7802a424 ("RDMA/mana_ib: Add CQ interrupt support for RAW QP")
Link: https://sashiko.dev/#/patchset/0-v2-1c49eeb88c48%2B91-rdma_udata_rep_jgg%40nvidia.com?part=1
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/infiniband/hw/mana/qp.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/infiniband/hw/mana/qp.c b/drivers/infiniband/hw/mana/qp.c
index f7bb0d1f0f8034..8e1f052d0ec976 100644
--- a/drivers/infiniband/hw/mana/qp.c
+++ b/drivers/infiniband/hw/mana/qp.c
@@ -176,11 +176,8 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd,
 
 		ret = mana_create_wq_obj(mpc, mpc->port_handle, GDMA_RQ,
 					 &wq_spec, &cq_spec, &wq->rx_object);
-		if (ret) {
-			/* Do cleanup starting with index i-1 */
-			i--;
+		if (ret)
 			goto fail;
-		}
 
 		/* The GDMA regions are now owned by the WQ object */
 		wq->queue.gdma_region = GDMA_INVALID_DMA_REGION;
@@ -200,8 +197,10 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd,
 
 		/* Create CQ table entry */
 		ret = mana_ib_install_cq_cb(mdev, cq);
-		if (ret)
+		if (ret) {
+			mana_destroy_wq_obj(mpc, GDMA_RQ, wq->rx_object);
 			goto fail;
+		}
 	}
 	resp.num_entries = i;
 
-- 
2.43.0


^ permalink raw reply related

* [PATCH rc 00/15] Various bug fixes for RDMA drivers in the uapi functions
From: Jason Gunthorpe @ 2026-04-28 16:17 UTC (permalink / raw)
  To: Andrew Lunn, Broadcom internal kernel review list, Bryan Tan,
	Eric Dumazet, Junxian Huang, Konstantin Taranov, Jakub Kicinski,
	Leon Romanovsky, linux-hyperv, linux-rdma, netdev, Paolo Abeni,
	Selvin Xavier, Chengchang Tang, Tariq Toukan, Vishnu Dasa,
	Yishai Hadas
  Cc: Abhijit Gangurde, Adit Ranadive, Allen Hubbe, Andrew Boyer,
	Aditya Sarwade, Brad Spengler, Bryan Tan, David S. Miller,
	Dexuan Cui, Doug Ledford, George Zhang, Jorgen Hansen, Jianbo Liu,
	Kai Aizen, Leon Romanovsky, Leon Romanovsky, Yixian Liu, Long Li,
	Lijun Ou, Parav Pandit, patches, Roland Dreier, Roland Dreier,
	Sagi Grimberg, Ajay Sharma, stable, Tariq Toukan, Wei Hu (Xavier),
	Shaobo Xu, Nenglong Zhao

All were found by Sashiko or Claude AI tools. They vary in severity, but
are all things that shouldn't be present.

Jason Gunthorpe (15):
  RDMA/ionic: Fix typo in format string
  RDMA/mlx5: Restore zero-init to mlx5_ib_modify_qp() ucmd
  RDMA/mlx5: Add missing store/release for lock elision pattern
  RDMA/mana: Validate rx_hash_key_len
  RDMA/mana: Remove user triggerable WARN_ON() in
    mana_ib_create_qp_rss()
  RDMA/mana: Fix mana_destroy_wq_obj() cleanup in
    mana_ib_create_qp_rss()
  RDMA/mana: Fix error unwind in mana_ib_create_qp_rss()
  RDMA/ocrdma: Clarify the mm_head searching
  RDMA/ocrdma: Don't NULL deref uctx on errors in ocrdma_copy_pd_uresp()
  RDMA/vmw_pvrdma: Fix double free on pvrdma_alloc_ucontext() error path
  RDMA/mlx4: Fix resource leak on error in mlx4_ib_create_srq()
  RDMA/mlx4: Fix mis-use of RCU in mlx4_srq_event()
  RDMA/hns: Fix xarray race in hns_roce_create_srq()
  RDMA/hns: Fix xarray race in hns_roce_create_qp_common()
  RDMA/hns: Fix unlocked call to hns_roce_qp_remove()

 drivers/infiniband/hw/hns/hns_roce_qp.c         | 13 ++++++++++---
 drivers/infiniband/hw/hns/hns_roce_srq.c        | 12 ++++++------
 drivers/infiniband/hw/ionic/ionic_ibdev.c       |  2 +-
 drivers/infiniband/hw/mana/cq.c                 |  5 +++--
 drivers/infiniband/hw/mana/qp.c                 | 16 ++++++++++------
 drivers/infiniband/hw/mlx4/srq.c                |  4 +++-
 drivers/infiniband/hw/mlx5/main.c               |  8 ++++----
 drivers/infiniband/hw/mlx5/qp.c                 |  2 +-
 drivers/infiniband/hw/mlx5/umr.c                |  4 ++--
 drivers/infiniband/hw/ocrdma/ocrdma_verbs.c     |  8 ++++----
 drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c |  2 +-
 drivers/net/ethernet/mellanox/mlx4/srq.c        | 13 +++++++------
 12 files changed, 52 insertions(+), 37 deletions(-)


base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
-- 
2.43.0


^ permalink raw reply

* [PATCH rc 13/15] RDMA/hns: Fix xarray race in hns_roce_create_srq()
From: Jason Gunthorpe @ 2026-04-28 16:17 UTC (permalink / raw)
  To: Andrew Lunn, Broadcom internal kernel review list, Bryan Tan,
	Eric Dumazet, Junxian Huang, Konstantin Taranov, Jakub Kicinski,
	Leon Romanovsky, linux-hyperv, linux-rdma, netdev, Paolo Abeni,
	Selvin Xavier, Chengchang Tang, Tariq Toukan, Vishnu Dasa,
	Yishai Hadas
  Cc: Abhijit Gangurde, Adit Ranadive, Allen Hubbe, Andrew Boyer,
	Aditya Sarwade, Brad Spengler, Bryan Tan, David S. Miller,
	Dexuan Cui, Doug Ledford, George Zhang, Jorgen Hansen, Jianbo Liu,
	Kai Aizen, Leon Romanovsky, Leon Romanovsky, Yixian Liu, Long Li,
	Lijun Ou, Parav Pandit, patches, Roland Dreier, Roland Dreier,
	Sagi Grimberg, Ajay Sharma, stable, Tariq Toukan, Wei Hu (Xavier),
	Shaobo Xu, Nenglong Zhao
In-Reply-To: <0-v1-41f3135e5565+9d2-rdma_ai_fixes1_jgg@nvidia.com>

Sashiko points out that once the srq memory is stored into the xarray by
alloc_srqc() it can immediately be looked up by:

	xa_lock(&srq_table->xa);
	srq = xa_load(&srq_table->xa, srqn & (hr_dev->caps.num_srqs - 1));
	if (srq)
		refcount_inc(&srq->refcount);
	xa_unlock(&srq_table->xa);

Which will fail refcount debug because the refcount is 0 and then crash:

	srq->event(srq, event_type);

Because event is NULL.

Use refcount_inc_not_zero() instead to ensure a partially prepared srq is
never retrieved from the event handler and fix the ordering of the
initialization so refcount becomes 1 only after it is fully ready.

All the initialization must be done before calling free_srqc() since it
depends on the completion and refcount.

Fixes: 9a4435375cd1 ("IB/hns: Add driver files for hns RoCE driver")
Link: https://sashiko.dev/#/patchset/0-v1-e911b76a94d1%2B65d95-rdma_udata_rep_jgg%40nvidia.com?part=3
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/infiniband/hw/hns/hns_roce_srq.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/infiniband/hw/hns/hns_roce_srq.c b/drivers/infiniband/hw/hns/hns_roce_srq.c
index cb848e8e6bbd76..8b94cbdfa54dfa 100644
--- a/drivers/infiniband/hw/hns/hns_roce_srq.c
+++ b/drivers/infiniband/hw/hns/hns_roce_srq.c
@@ -16,8 +16,8 @@ void hns_roce_srq_event(struct hns_roce_dev *hr_dev, u32 srqn, int event_type)
 
 	xa_lock(&srq_table->xa);
 	srq = xa_load(&srq_table->xa, srqn & (hr_dev->caps.num_srqs - 1));
-	if (srq)
-		refcount_inc(&srq->refcount);
+	if (srq && !refcount_inc_not_zero(&srq->refcount))
+		srq = NULL;
 	xa_unlock(&srq_table->xa);
 
 	if (!srq) {
@@ -470,6 +470,10 @@ int hns_roce_create_srq(struct ib_srq *ib_srq,
 	if (ret)
 		goto err_srqn;
 
+	srq->event = hns_roce_ib_srq_event;
+	init_completion(&srq->free);
+	refcount_set_release(&srq->refcount, 1);
+
 	if (udata) {
 		resp.cap_flags = srq->cap_flags;
 		resp.srqn = srq->srqn;
@@ -480,10 +484,6 @@ int hns_roce_create_srq(struct ib_srq *ib_srq,
 		}
 	}
 
-	srq->event = hns_roce_ib_srq_event;
-	refcount_set(&srq->refcount, 1);
-	init_completion(&srq->free);
-
 	return 0;
 
 err_srqc:
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH] net: Unify user-visible "Qualcomm" name
From: Simon Horman @ 2026-04-28 16:14 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Loic Poulain, Sergey Ryazanov, Johannes Berg, netdev,
	linux-kernel, =Bjorn Andersson, Konrad Dybcio, linux-arm-msm
In-Reply-To: <20260427070127.18471-2-krzysztof.kozlowski@oss.qualcomm.com>

On Mon, Apr 27, 2026 at 09:01:27AM +0200, Krzysztof Kozlowski wrote:
> Various names for Qualcomm as a company are used in user-visible config
> options: QCOM, Qualcomm and Qualcomm Technologies.  Switch to unified
> "Qualcomm" so it will be easier for users to identify the options when
> for example running menuconfig.
> 
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>

...

> diff --git a/drivers/net/wwan/Kconfig b/drivers/net/wwan/Kconfig
> index 88df55d78d90..958dbc7347fa 100644
> --- a/drivers/net/wwan/Kconfig
> +++ b/drivers/net/wwan/Kconfig
> @@ -38,7 +38,7 @@ config WWAN_HWSIM
>  	  called wwan_hwsim.  If unsure, say N.
>  
>  config MHI_WWAN_CTRL
> -	tristate "MHI WWAN control driver for QCOM-based PCIe modems"
> +	tristate "MHI WWAN control driver for Qualcomm-based PCIe modems"
>  	depends on MHI_BUS
>  	help
>  	  MHI WWAN CTRL allows QCOM-based PCIe modems to expose different modem

Hi Krzysztof,

Sashiko points out that QCOM is still used on the line above.

> @@ -51,7 +51,7 @@ config MHI_WWAN_CTRL
>  	  called mhi_wwan_ctrl.
>  
>  config MHI_WWAN_MBIM
> -        tristate "MHI WWAN MBIM network driver for QCOM-based PCIe modems"
> +        tristate "MHI WWAN MBIM network driver for Qualcomm-based PCIe modems"
>          depends on MHI_BUS
>          help
>            MHI WWAN MBIM is a WWAN network driver for QCOM-based PCIe modems.

And here too.

-- 
pw-bot: changes-requested

^ permalink raw reply

* Re: [PATCH net-next v2 00/13] net: lan966x: add support for PCIe FDMA
From: Herve Codina @ 2026-04-28 16:07 UTC (permalink / raw)
  To: Daniel Machon
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Horatiu Vultur, Steen Hegelund, UNGLinuxDriver,
	Alexei Starovoitov, Daniel Borkmann, Jesper Dangaard Brouer,
	John Fastabend, Stanislav Fomichev, Arnd Bergmann,
	Greg Kroah-Hartman, Mohsin Bashir, netdev, linux-kernel, bpf
In-Reply-To: <20260428-lan966x-pci-fdma-v2-0-d3ec66e06202@microchip.com>

Hi Daniel, all,

On Tue, 28 Apr 2026 15:06:49 +0200
Daniel Machon <daniel.machon@microchip.com> wrote:

> When lan966x operates as a PCIe endpoint, the driver currently uses
> register-based I/O for frame injection and extraction. This approach is
> functional but slow, topping out at around 33 Mbps on an Intel x86 host
> with a lan966x PCIe card.
> 
> This series adds FDMA (Frame DMA) support for the PCIe path. When
> operating as a PCIe endpoint, the internal FDMA engine on lan966x cannot
> directly access host memory, so DMA buffers are allocated as contiguous
> coherent memory and mapped through the PCIe Address Translation Unit
> (ATU). The ATU provides outbound windows that translate internal FDMA
> addresses to PCIe bus addresses, allowing the FDMA engine to read and
> write host memory. Because the ATU requires contiguous address regions,
> page_pool and normal per-page DMA mappings cannot be used. Instead,
> frames are transferred using memcpy between the ATU-mapped buffers and
> the network stack. With this, throughput increases from ~33 Mbps to
> ~620 Mbps for default MTU.
> 

I have applied the whole series and performed some tests.

Issues observed in v1 are no more present.

Tested-by: Herve Codina <herve.codina@bootlin.com>

Best regards,
Hervé

^ permalink raw reply

* Re: [PATCH net] bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst()
From: Simon Horman @ 2026-04-28 16:04 UTC (permalink / raw)
  To: bestswngs
  Cc: 'Simon Horman', andrew+netdev, davem, edumazet, kuba,
	pabeni, willemb, martin.varghese, netdev, xmei5
In-Reply-To: <20260426165350.1663137-2-bestswngs@gmail.com>

From: 'Simon Horman' <horms@kernel.org>

This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
Full review at: https://sashiko.dev
---
bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst()

This commit fixes a NULL pointer dereference in bareudp_fill_metadata_dst()
by adding a check for the socket in the IPv6 path. If the device is down
and the socket is NULL, it now returns -ESHUTDOWN.

> Add a NULL check returning -ESHUTDOWN, consistent with the xmit paths
> in the same driver.

Does the IPv4 path also need to be updated to remain consistent?

While the IPv4 path lookup doesn't use the socket pointer directly, if the
socket is NULL (meaning the device is down), shouldn't the IPv4 path also
return -ESHUTDOWN instead of successfully performing a route lookup?

> diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c
> index 0df3208783ad..da5866ba0699 100644
> --- a/drivers/net/bareudp.c
> +++ b/drivers/net/bareudp.c
> @@ -529,6 +529,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev,

Is it possible for an IPv6 tunnel key to be incorrectly processed as IPv4
earlier in this function?

Looking at the preceding condition in this function:

    if (!ipv6_mod_enabled() || ip_tunnel_info_af(info) == AF_INET) {
        struct rtable *rt;
        ...
        info->key.u.ipv4.src = saddr;
    }

If the IPv6 module is disabled at runtime, but an IPv6 tunnel key is provided
(e.g., via OVS or TC), the code falls back to the IPv4 branch.

Since key->u.ipv4.dst aliases exactly with bytes 4-7 of key->u.ipv6.src due
to the union layout in struct ip_tunnel_key, could this result in an invalid
IPv4 route lookup using portions of the IPv6 source address?

Would it be safer to explicitly reject IPv6 tunnel keys when the IPv6 module
is disabled?

>  		struct in6_addr saddr;
>  		struct socket *sock = rcu_dereference(bareudp->sock);
>  
> +		if (!sock)
> +			return -ESHUTDOWN;
> +
>  		dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock,
>  					     0, &saddr, &info->key,
>  					     sport, bareudp->port, info->key.tos,

^ permalink raw reply

* Re: [PATCH net-next 3/4] net/sched: switch tc_dump_qdisc() to for_each_netdev_dump()
From: Eric Dumazet @ 2026-04-28 15:57 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: David S . Miller, Paolo Abeni, Simon Horman, Jamal Hadi Salim,
	Jiri Pirko, Kuniyuki Iwashima, netdev, eric.dumazet
In-Reply-To: <20260427161335.500f80d3@kernel.org>

On Mon, Apr 27, 2026 at 4:13 PM Jakub Kicinski <kuba@kernel.org> wrote:
>
> On Mon, 27 Apr 2026 13:25:54 +0000 Eric Dumazet wrote:
> > +     for_each_netdev_dump(net, dev, ctx->ifindex) {
> >               struct netdev_queue *dev_queue;
> > +             struct Qdisc *q;
> >
> > -             if (idx < s_idx)
> > -                     goto cont;
> > -             if (idx > s_idx)
> > +             if (ctx->ifindex > s_ifindex)
> >                       s_q_idx = 0;
>
> I don't think we need this conditional now that we use for_each_netdev_dump()
> We can just add
>
>         s_q_idx = 0;
>
> right before closing bracket of the loop?

Ack thanks.

^ permalink raw reply

* Re: [PATCH net-next v4 3/3] gve: implement PTP gettimex64
From: Jordan Rhee @ 2026-04-28 15:49 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Harshitha Ramamurthy, netdev, joshwash, andrew+netdev, davem,
	edumazet, pabeni, richardcochran, willemb, nktgrg, jfraker,
	ziweixiao, maolson, thostet, jefrogers, alok.a.tiwari, yyd,
	jacob.e.keller, linux-kernel, Naman Gulati
In-Reply-To: <20260409201646.6af5235d@kernel.org>

On Thu, Apr 9, 2026 at 8:16 PM Jakub Kicinski <kuba@kernel.org> wrote:
>
> On Mon,  6 Apr 2026 23:40:02 +0000 Harshitha Ramamurthy wrote:
> > From: Jordan Rhee <jordanrhee@google.com>
> >
> > Enable chrony and phc2sys to synchronize system clock to NIC clock.
> >
> > The system cycle counters are sampled by the device to minimize the
> > uncertainty window. If the system times are sampled in the host, the
> > delta between pre and post readings is 100us or more due to AQ command
> > latency. The system times returned by the device have a delta of ~1us,
> > which enables significantly more accurate clock synchronization.
>
> Interesting. I'd like this looked over by David Woodhouse and tglx.
> Please repost after the merge window or send them an RFC.

Ack, will include comparison against ptp_read_system_prets/postts()
implementation.

>
> > +static int gve_ptp_read_timestamp(struct gve_ptp *ptp, cycles_t *pre_cycles,
> > +                               cycles_t *post_cycles,
> > +                               struct system_time_snapshot *snap)
> > +{
> > +     unsigned long delay_us = 1000;
> > +     int retry_count = 0;
> > +     int err;
> > +
> > +     lockdep_assert_held(&ptp->nic_ts_read_lock);
> > +
> > +     do {
>
> This can't be a for () loop with 5 iterations?

I've reformulated it to be in terms of total timeout, and kept it as a
do-while to guarantee that at least 1 iteration is run.

>
> > +             if (snap)
> > +                     ktime_get_snapshot(snap);
> > +
> > +             *pre_cycles = get_cycles();
> > +             err = gve_adminq_report_nic_ts(ptp->priv,
> > +                                            ptp->nic_ts_report_bus);
> > +
> > +             /* Prevent get_cycles() from being speculatively executed
> > +              * before the AdminQ command
> > +              */
> > +             rmb();
> > +             *post_cycles = get_cycles();
> > +             if (likely(err != -EAGAIN))
> > +                     return err;
> > +
> > +             fsleep(delay_us);
> > +
> > +             /* Exponential backoff */
> > +             delay_us *= 2;
> > +             retry_count++;
> > +     } while (retry_count < 5);
> > +
> > +     return -ETIMEDOUT;
> > +}
> > +
> >  /* Read the nic timestamp from hardware via the admin queue. */
> > -static int gve_clock_nic_ts_read(struct gve_ptp *ptp, u64 *nic_raw)
> > +static int gve_clock_nic_ts_read(struct gve_ptp *ptp, u64 *nic_raw,
> > +                              struct gve_sysclock_sample *sysclock)
> >  {
> > +     cycles_t host_pre_cycles, host_post_cycles;
> > +     struct gve_nic_ts_report *ts_report;
> >       int err;
> >
> >       mutex_lock(&ptp->nic_ts_read_lock);
> > -     err = gve_adminq_report_nic_ts(ptp->priv, ptp->nic_ts_report_bus);
> > -     if (err)
> > +     err = gve_ptp_read_timestamp(ptp, &host_pre_cycles, &host_post_cycles,
> > +                                  sysclock ? &sysclock->snapshot : NULL);
> > +     if (err) {
> > +             dev_err_ratelimited(&ptp->priv->pdev->dev,
> > +                                 "AdminQ timestamp read failed: %d\n", err);
> >               goto out;
> > +     }
> >
> > -     *nic_raw = be64_to_cpu(ptp->nic_ts_report->nic_timestamp);
> > +     ts_report = ptp->nic_ts_report;
> > +     *nic_raw = be64_to_cpu(ts_report->nic_timestamp);
> > +
> > +     if (sysclock) {
> > +             sysclock->nic_pre_cycles = be64_to_cpu(ts_report->pre_cycles);
> > +             sysclock->nic_post_cycles = be64_to_cpu(ts_report->post_cycles);
> > +             sysclock->host_pre_cycles = host_pre_cycles;
> > +             sysclock->host_post_cycles = host_post_cycles;
> > +     }
> >
> >  out:
> >       mutex_unlock(&ptp->nic_ts_read_lock);
> >       return err;
> >  }
> >
> > +struct gve_cycles_to_clock_callback_ctx {
> > +     u64 cycles;
> > +};
> > +
> > +static int gve_cycles_to_clock_fn(ktime_t *device_time,
> > +                               struct system_counterval_t *system_counterval,
> > +                               void *ctx)
>
> Does this do anything GVE specific??

No, however, I would caution against adding an API to the kernel to
convert TSC to ktime since this could invite further abuses of TSC.

>
> > +{
> > +     struct gve_cycles_to_clock_callback_ctx *context = ctx;
> > +
> > +     *device_time = 0;
> > +
> > +     system_counterval->cycles = context->cycles;
> > +     system_counterval->use_nsecs = false;
> > +
> > +     if (IS_ENABLED(CONFIG_X86))
> > +             system_counterval->cs_id = CSID_X86_TSC;
> > +     else if (IS_ENABLED(CONFIG_ARM64))
> > +             system_counterval->cs_id = CSID_ARM_ARCH_COUNTER;
> > +     else
> > +             return -EOPNOTSUPP;
> > +
> > +     return 0;
> > +}
> --
> pw-bot: cr

^ permalink raw reply

* [PATCH net-next 2/2] dpll: zl3073x: implement pin operational state reporting
From: Ivan Vecera @ 2026-04-28 15:49 UTC (permalink / raw)
  To: netdev
  Cc: Arkadiusz Kubalewski, David S. Miller, Donald Hunter,
	Eric Dumazet, Jakub Kicinski, Jiri Pirko, Jonathan Corbet,
	Michal Schmidt, Paolo Abeni, Pasi Vaananen, Petr Oros,
	Prathosh Satish, Shuah Khan, Simon Horman, Vadim Fedorenko,
	linux-doc, linux-kernel
In-Reply-To: <20260428154907.2820654-1-ivecera@redhat.com>

Implement operstate_on_dpll_get callback for input pins to report
the actual hardware status:

  - active: pin is the currently locked reference
  - standby: signal is valid but pin is not actively used
  - no-signal: reference monitor reports Loss of Signal (LOS)
  - qual-failed: reference monitor reports a qualification failure
    (SCM, CFM, GST, PFM, eSync or Split-XO)

Separate administrative state (state_on_dpll_get) from operational
state: admin state now reports purely the user-requested intent
(connected in reflock mode, selectable in auto mode).

Switch periodic monitoring to track operstate changes instead of
the mixed admin/oper state that was previously reported.

Add ref_mon_status bit definitions to regs.h.

Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
 drivers/dpll/zl3073x/dpll.c | 108 ++++++++++++++++++++++++------------
 drivers/dpll/zl3073x/regs.h |   9 ++-
 2 files changed, 79 insertions(+), 38 deletions(-)

diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c
index c95e93ef3ab04..6fd718696de0d 100644
--- a/drivers/dpll/zl3073x/dpll.c
+++ b/drivers/dpll/zl3073x/dpll.c
@@ -38,7 +38,7 @@
  * @prio: pin priority <0, 14>
  * @esync_control: embedded sync is controllable
  * @phase_gran: phase adjustment granularity
- * @pin_state: last saved pin state
+ * @operstate: last saved operational state
  * @phase_offset: last saved pin phase offset
  * @freq_offset: last saved fractional frequency offset
  * @measured_freq: last saved measured frequency
@@ -55,7 +55,7 @@ struct zl3073x_dpll_pin {
 	u8			prio;
 	bool			esync_control;
 	s32			phase_gran;
-	enum dpll_pin_state	pin_state;
+	enum dpll_pin_operstate	operstate;
 	s64			phase_offset;
 	s64			freq_offset;
 	u32			measured_freq;
@@ -500,46 +500,41 @@ zl3073x_dpll_input_pin_phase_adjust_set(const struct dpll_pin *dpll_pin,
 }
 
 /**
- * zl3073x_dpll_ref_state_get - get status for given input pin
+ * zl3073x_dpll_ref_operstate_get - get operational state for input pin
  * @pin: pointer to pin
- * @state: place to store status
+ * @operstate: place to store operational state
  *
- * Checks current status for the given input pin and stores the value
- * to @state.
+ * Returns the actual hardware state of the pin: whether it is actively
+ * used by the DPLL, has no signal, failed qualification, or is simply
+ * not in use.
  *
  * Return: 0 on success, <0 on error
  */
 static int
-zl3073x_dpll_ref_state_get(struct zl3073x_dpll_pin *pin,
-			   enum dpll_pin_state *state)
+zl3073x_dpll_ref_operstate_get(struct zl3073x_dpll_pin *pin,
+			       enum dpll_pin_operstate *operstate)
 {
 	struct zl3073x_dpll *zldpll = pin->dpll;
 	struct zl3073x_dev *zldev = zldpll->dev;
-	const struct zl3073x_chan *chan;
-	u8 ref;
-
-	chan = zl3073x_chan_state_get(zldev, zldpll->id);
-	ref = zl3073x_input_pin_ref_get(pin->id);
+	const struct zl3073x_ref *ref;
+	u8 ref_id;
 
-	/* Check if the pin reference is connected */
-	if (ref == zl3073x_dpll_connected_ref_get(zldpll)) {
-		*state = DPLL_PIN_STATE_CONNECTED;
-		return 0;
-	}
+	ref_id = zl3073x_input_pin_ref_get(pin->id);
 
-	/* If the DPLL is running in automatic mode and the reference is
-	 * selectable and its monitor does not report any error then report
-	 * pin as selectable.
-	 */
-	if (zl3073x_chan_mode_get(chan) == ZL_DPLL_MODE_REFSEL_MODE_AUTO &&
-	    zl3073x_dev_ref_is_status_ok(zldev, ref) &&
-	    zl3073x_chan_ref_is_selectable(chan, ref)) {
-		*state = DPLL_PIN_STATE_SELECTABLE;
+	/* Check if this pin is the currently locked reference */
+	if (ref_id == zl3073x_dpll_connected_ref_get(zldpll)) {
+		*operstate = DPLL_PIN_OPERSTATE_ACTIVE;
 		return 0;
 	}
 
-	/* Otherwise report the pin as disconnected */
-	*state = DPLL_PIN_STATE_DISCONNECTED;
+	/* Check reference monitor status */
+	ref = zl3073x_ref_state_get(zldev, ref_id);
+	if (ref->mon_status & ZL_REF_MON_STATUS_LOS)
+		*operstate = DPLL_PIN_OPERSTATE_NO_SIGNAL;
+	else if (!zl3073x_ref_is_status_ok(ref))
+		*operstate = DPLL_PIN_OPERSTATE_QUAL_FAILED;
+	else
+		*operstate = DPLL_PIN_OPERSTATE_STANDBY;
 
 	return 0;
 }
@@ -551,10 +546,48 @@ zl3073x_dpll_input_pin_state_on_dpll_get(const struct dpll_pin *dpll_pin,
 					 void *dpll_priv,
 					 enum dpll_pin_state *state,
 					 struct netlink_ext_ack *extack)
+{
+	struct zl3073x_dpll *zldpll = dpll_priv;
+	struct zl3073x_dpll_pin *pin = pin_priv;
+	const struct zl3073x_chan *chan;
+	u8 mode, ref;
+
+	chan = zl3073x_chan_state_get(zldpll->dev, zldpll->id);
+	ref = zl3073x_input_pin_ref_get(pin->id);
+	mode = zl3073x_chan_mode_get(chan);
+
+	switch (mode) {
+	case ZL_DPLL_MODE_REFSEL_MODE_REFLOCK:
+		if (ref == zl3073x_chan_ref_get(chan))
+			*state = DPLL_PIN_STATE_CONNECTED;
+		else
+			*state = DPLL_PIN_STATE_DISCONNECTED;
+		break;
+	case ZL_DPLL_MODE_REFSEL_MODE_AUTO:
+		if (zl3073x_chan_ref_is_selectable(chan, ref))
+			*state = DPLL_PIN_STATE_SELECTABLE;
+		else
+			*state = DPLL_PIN_STATE_DISCONNECTED;
+		break;
+	default:
+		*state = DPLL_PIN_STATE_DISCONNECTED;
+		break;
+	}
+
+	return 0;
+}
+
+static int
+zl3073x_dpll_input_pin_operstate_on_dpll_get(const struct dpll_pin *dpll_pin,
+					     void *pin_priv,
+					     const struct dpll_device *dpll,
+					     void *dpll_priv,
+					     enum dpll_pin_operstate *operstate,
+					     struct netlink_ext_ack *extack)
 {
 	struct zl3073x_dpll_pin *pin = pin_priv;
 
-	return zl3073x_dpll_ref_state_get(pin, state);
+	return zl3073x_dpll_ref_operstate_get(pin, operstate);
 }
 
 static int
@@ -1248,6 +1281,7 @@ static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = {
 	.frequency_get = zl3073x_dpll_input_pin_frequency_get,
 	.frequency_set = zl3073x_dpll_input_pin_frequency_set,
 	.measured_freq_get = zl3073x_dpll_input_pin_measured_freq_get,
+	.operstate_on_dpll_get = zl3073x_dpll_input_pin_operstate_on_dpll_get,
 	.phase_offset_get = zl3073x_dpll_input_pin_phase_offset_get,
 	.phase_adjust_get = zl3073x_dpll_input_pin_phase_adjust_get,
 	.phase_adjust_set = zl3073x_dpll_input_pin_phase_adjust_set,
@@ -1663,7 +1697,7 @@ zl3073x_dpll_pin_phase_offset_check(struct zl3073x_dpll_pin *pin)
 	 * 2) For other pins use appropriate ref_phase register if the phase
 	 *    monitor feature is enabled.
 	 */
-	if (pin->pin_state == DPLL_PIN_STATE_CONNECTED)
+	if (pin->operstate == DPLL_PIN_OPERSTATE_ACTIVE)
 		reg = ZL_REG_DPLL_PHASE_ERR_DATA(zldpll->id);
 	else if (zldpll->phase_monitor)
 		reg = ZL_REG_REF_PHASE(ref_id);
@@ -1828,7 +1862,7 @@ zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll)
 	}
 
 	list_for_each_entry(pin, &zldpll->pins, list) {
-		enum dpll_pin_state state;
+		enum dpll_pin_operstate operstate;
 		bool pin_changed = false;
 
 		/* Output pins change checks are not necessary because output
@@ -1837,18 +1871,18 @@ zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll)
 		if (!zl3073x_dpll_is_input_pin(pin))
 			continue;
 
-		rc = zl3073x_dpll_ref_state_get(pin, &state);
+		rc = zl3073x_dpll_ref_operstate_get(pin, &operstate);
 		if (rc) {
 			dev_err(dev,
-				"Failed to get %s on DPLL%u state: %pe\n",
+				"Failed to get %s on DPLL%u oper state: %pe\n",
 				pin->label, zldpll->id, ERR_PTR(rc));
 			return;
 		}
 
-		if (state != pin->pin_state) {
-			dev_dbg(dev, "%s state changed: %u->%u\n", pin->label,
-				pin->pin_state, state);
-			pin->pin_state = state;
+		if (operstate != pin->operstate) {
+			dev_dbg(dev, "%s oper state changed: %u->%u\n",
+				pin->label, pin->operstate, operstate);
+			pin->operstate = operstate;
 			pin_changed = true;
 		}
 
diff --git a/drivers/dpll/zl3073x/regs.h b/drivers/dpll/zl3073x/regs.h
index d425dc67250fe..8015808bdf548 100644
--- a/drivers/dpll/zl3073x/regs.h
+++ b/drivers/dpll/zl3073x/regs.h
@@ -98,7 +98,14 @@
 
 #define ZL_REG_REF_MON_STATUS(_idx)					\
 	ZL_REG_IDX(_idx, 2, 0x02, 1, ZL3073X_NUM_REFS, 1)
-#define ZL_REF_MON_STATUS_OK			0 /* all bits zeroed */
+#define ZL_REF_MON_STATUS_OK			0
+#define ZL_REF_MON_STATUS_LOS			BIT(0)
+#define ZL_REF_MON_STATUS_SCM			BIT(1)
+#define ZL_REF_MON_STATUS_CFM			BIT(2)
+#define ZL_REF_MON_STATUS_GST			BIT(3)
+#define ZL_REF_MON_STATUS_PFM			BIT(4)
+#define ZL_REF_MON_STATUS_ESYNC			BIT(6)
+#define ZL_REF_MON_STATUS_SPLIT_XO		BIT(7)
 
 #define ZL_REG_DPLL_MON_STATUS(_idx)					\
 	ZL_REG_IDX(_idx, 2, 0x10, 1, ZL3073X_MAX_CHANNELS, 1)
-- 
2.53.0


^ permalink raw reply related

* [PATCH net-next 1/2] dpll: add pin operational state
From: Ivan Vecera @ 2026-04-28 15:49 UTC (permalink / raw)
  To: netdev
  Cc: Arkadiusz Kubalewski, David S. Miller, Donald Hunter,
	Eric Dumazet, Jakub Kicinski, Jiri Pirko, Jonathan Corbet,
	Michal Schmidt, Paolo Abeni, Pasi Vaananen, Petr Oros,
	Prathosh Satish, Shuah Khan, Simon Horman, Vadim Fedorenko,
	linux-doc, linux-kernel
In-Reply-To: <20260428154907.2820654-1-ivecera@redhat.com>

Add pin-operstate enum and operstate_on_dpll_get callback to report
the actual hardware status of a pin with respect to its parent DPLL
device. Unlike pin-state (which reflects administrative intent set
by the user), operstate reflects what the hardware is actually doing.

Defined operational states:
  - active: pin is qualified and actively used by the DPLL
  - standby: pin is qualified but not actively used by the DPLL
  - no-signal: pin does not have a valid signal
  - qual-failed: pin signal failed qualification

The operstate is reported inside the pin-parent-device nested
attribute alongside the existing state and phase-offset attributes.

Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
 Documentation/driver-api/dpll.rst     | 38 ++++++++++++++++-----------
 Documentation/netlink/specs/dpll.yaml | 31 ++++++++++++++++++++++
 drivers/dpll/dpll_netlink.c           | 27 +++++++++++++++++++
 drivers/dpll/dpll_nl.c                |  3 ++-
 drivers/dpll/dpll_nl.h                |  2 +-
 include/linux/dpll.h                  |  6 +++++
 include/uapi/linux/dpll.h             | 23 ++++++++++++++++
 7 files changed, 113 insertions(+), 17 deletions(-)

diff --git a/Documentation/driver-api/dpll.rst b/Documentation/driver-api/dpll.rst
index 93c191b2d0898..37eaef785e304 100644
--- a/Documentation/driver-api/dpll.rst
+++ b/Documentation/driver-api/dpll.rst
@@ -65,35 +65,43 @@ request, where user provides attributes that result in single pin match.
 Pin selection
 =============
 
-In general, selected pin (the one which signal is driving the dpll
-device) can be obtained from ``DPLL_A_PIN_STATE`` attribute, and only
-one pin shall be in ``DPLL_PIN_STATE_CONNECTED`` state for any dpll
-device.
+Pin state (``DPLL_A_PIN_STATE``) reflects the administrative intent set
+by the user. Pin operational state (``DPLL_A_PIN_OPERSTATE``) reflects
+what the hardware is actually doing with the pin.
 
 Pin selection can be done either manually or automatically, depending
 on hardware capabilities and active dpll device work mode
 (``DPLL_A_MODE`` attribute). The consequence is that there are
-differences for each mode in terms of available pin states, as well as
-for the states the user can request for a dpll device.
+differences for each mode in terms of available pin states the user can
+request for a dpll device.
 
-In manual mode (``DPLL_MODE_MANUAL``) the user can request or receive
-one of following pin states:
+In manual mode (``DPLL_MODE_MANUAL``) the user can request one of
+following pin states:
 
-- ``DPLL_PIN_STATE_CONNECTED`` - the pin is used to drive dpll device
-- ``DPLL_PIN_STATE_DISCONNECTED`` - the pin is not used to drive dpll
+- ``DPLL_PIN_STATE_CONNECTED`` - the pin is selected to drive dpll
   device
+- ``DPLL_PIN_STATE_DISCONNECTED`` - the pin is not selected to drive
+  dpll device
 
-In automatic mode (``DPLL_MODE_AUTOMATIC``) the user can request or
-receive one of following pin states:
+In automatic mode (``DPLL_MODE_AUTOMATIC``) the user can request one of
+following pin states:
 
 - ``DPLL_PIN_STATE_SELECTABLE`` - the pin shall be considered as valid
   input for automatic selection algorithm
 - ``DPLL_PIN_STATE_DISCONNECTED`` - the pin shall be not considered as
   a valid input for automatic selection algorithm
 
-In automatic mode (``DPLL_MODE_AUTOMATIC``) the user can only receive
-pin state ``DPLL_PIN_STATE_CONNECTED`` once automatic selection
-algorithm locks a dpll device with one of the inputs.
+The actual hardware status of a pin is reported via the operational
+state (``DPLL_A_PIN_OPERSTATE``) attribute nested under the parent
+device:
+
+- ``DPLL_PIN_OPERSTATE_ACTIVE`` - pin is qualified and actively used
+  by the DPLL
+- ``DPLL_PIN_OPERSTATE_STANDBY`` - pin is qualified but not actively
+  used by the DPLL
+- ``DPLL_PIN_OPERSTATE_NO_SIGNAL`` - pin does not have a valid signal
+- ``DPLL_PIN_OPERSTATE_QUAL_FAILED`` - pin signal failed qualification
+  checks
 
 Shared pins
 ===========
diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml
index 40465a3d7fc20..c45de70a47ce6 100644
--- a/Documentation/netlink/specs/dpll.yaml
+++ b/Documentation/netlink/specs/dpll.yaml
@@ -212,6 +212,27 @@ definitions:
         name: selectable
         doc: pin enabled for automatic input selection
     render-max: true
+  -
+    type: enum
+    name: pin-operstate
+    doc: |
+      defines possible operational states of a pin with respect to its
+      parent DPLL device, valid values for DPLL_A_PIN_OPERSTATE attribute
+    entries:
+      -
+        name: active
+        doc: pin is qualified and actively used by the DPLL
+        value: 1
+      -
+        name: standby
+        doc: pin is qualified but not actively used by the DPLL
+      -
+        name: no-signal
+        doc: pin does not have a valid signal
+      -
+        name: qual-failed
+        doc: pin signal failed qualification (e.g. frequency or phase monitor)
+    render-max: true
   -
     type: flags
     name: pin-capabilities
@@ -488,6 +509,14 @@ attribute-sets:
           Value of (DPLL_A_PIN_MEASURED_FREQUENCY %
           DPLL_PIN_MEASURED_FREQUENCY_DIVIDER) is a fractional part
           of a measured frequency value.
+      -
+        name: operstate
+        type: u32
+        enum: pin-operstate
+        doc: |
+          Operational state of the pin with respect to its parent DPLL
+          device. Unlike state (which reflects the administrative intent),
+          operstate reflects the actual hardware status.
 
   -
     name: pin-parent-device
@@ -501,6 +530,8 @@ attribute-sets:
         name: prio
       -
         name: state
+      -
+        name: operstate
       -
         name: phase-offset
   -
diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c
index af7ce62ec55ca..05cf946b4be5e 100644
--- a/drivers/dpll/dpll_netlink.c
+++ b/drivers/dpll/dpll_netlink.c
@@ -324,6 +324,30 @@ dpll_msg_add_pin_on_dpll_state(struct sk_buff *msg, struct dpll_pin *pin,
 	return 0;
 }
 
+static int
+dpll_msg_add_pin_operstate(struct sk_buff *msg, struct dpll_pin *pin,
+			   struct dpll_pin_ref *ref,
+			   struct netlink_ext_ack *extack)
+{
+	const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
+	struct dpll_device *dpll = ref->dpll;
+	enum dpll_pin_operstate operstate;
+	int ret;
+
+	if (!ops->operstate_on_dpll_get)
+		return 0;
+	ret = ops->operstate_on_dpll_get(pin,
+					  dpll_pin_on_dpll_priv(dpll, pin),
+					  dpll, dpll_priv(dpll),
+					  &operstate, extack);
+	if (ret)
+		return ret;
+	if (nla_put_u32(msg, DPLL_A_PIN_OPERSTATE, operstate))
+		return -EMSGSIZE;
+
+	return 0;
+}
+
 static int
 dpll_msg_add_pin_direction(struct sk_buff *msg, struct dpll_pin *pin,
 			   struct dpll_pin_ref *ref,
@@ -650,6 +674,9 @@ dpll_msg_add_pin_dplls(struct sk_buff *msg, struct dpll_pin *pin,
 		if (ret)
 			goto nest_cancel;
 		ret = dpll_msg_add_pin_on_dpll_state(msg, pin, ref, extack);
+		if (ret)
+			goto nest_cancel;
+		ret = dpll_msg_add_pin_operstate(msg, pin, ref, extack);
 		if (ret)
 			goto nest_cancel;
 		ret = dpll_msg_add_pin_prio(msg, pin, ref, extack);
diff --git a/drivers/dpll/dpll_nl.c b/drivers/dpll/dpll_nl.c
index 1e652340a5d73..58235845fa3d5 100644
--- a/drivers/dpll/dpll_nl.c
+++ b/drivers/dpll/dpll_nl.c
@@ -12,11 +12,12 @@
 #include <uapi/linux/dpll.h>
 
 /* Common nested types */
-const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_PHASE_OFFSET + 1] = {
+const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_OPERSTATE + 1] = {
 	[DPLL_A_PIN_PARENT_ID] = { .type = NLA_U32, },
 	[DPLL_A_PIN_DIRECTION] = NLA_POLICY_RANGE(NLA_U32, 1, 2),
 	[DPLL_A_PIN_PRIO] = { .type = NLA_U32, },
 	[DPLL_A_PIN_STATE] = NLA_POLICY_RANGE(NLA_U32, 1, 3),
+	[DPLL_A_PIN_OPERSTATE] = NLA_POLICY_RANGE(NLA_U32, 1, 4),
 	[DPLL_A_PIN_PHASE_OFFSET] = { .type = NLA_S64, },
 };
 
diff --git a/drivers/dpll/dpll_nl.h b/drivers/dpll/dpll_nl.h
index 7419679b69779..fa8280e3dd14c 100644
--- a/drivers/dpll/dpll_nl.h
+++ b/drivers/dpll/dpll_nl.h
@@ -13,7 +13,7 @@
 #include <uapi/linux/dpll.h>
 
 /* Common nested types */
-extern const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_PHASE_OFFSET + 1];
+extern const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_OPERSTATE + 1];
 extern const struct nla_policy dpll_pin_parent_pin_nl_policy[DPLL_A_PIN_STATE + 1];
 extern const struct nla_policy dpll_reference_sync_nl_policy[DPLL_A_PIN_STATE + 1];
 
diff --git a/include/linux/dpll.h b/include/linux/dpll.h
index b7277a8b484d2..b6f16c884b99e 100644
--- a/include/linux/dpll.h
+++ b/include/linux/dpll.h
@@ -85,6 +85,12 @@ struct dpll_pin_ops {
 				 const struct dpll_device *dpll,
 				 void *dpll_priv, enum dpll_pin_state *state,
 				 struct netlink_ext_ack *extack);
+	int (*operstate_on_dpll_get)(const struct dpll_pin *pin,
+				     void *pin_priv,
+				     const struct dpll_device *dpll,
+				     void *dpll_priv,
+				     enum dpll_pin_operstate *operstate,
+				     struct netlink_ext_ack *extack);
 	int (*state_on_pin_set)(const struct dpll_pin *pin, void *pin_priv,
 				const struct dpll_pin *parent_pin,
 				void *parent_pin_priv,
diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h
index 871685f7c353b..cb363cccf2e2a 100644
--- a/include/uapi/linux/dpll.h
+++ b/include/uapi/linux/dpll.h
@@ -178,6 +178,28 @@ enum dpll_pin_state {
 	DPLL_PIN_STATE_MAX = (__DPLL_PIN_STATE_MAX - 1)
 };
 
+/**
+ * enum dpll_pin_operstate - defines possible operational states of a pin with
+ *   respect to its parent DPLL device, valid values for DPLL_A_PIN_OPERSTATE
+ *   attribute
+ * @DPLL_PIN_OPERSTATE_ACTIVE: pin is qualified and actively used by the DPLL
+ * @DPLL_PIN_OPERSTATE_STANDBY: pin is qualified but not actively used by the
+ *   DPLL
+ * @DPLL_PIN_OPERSTATE_NO_SIGNAL: pin does not have a valid signal
+ * @DPLL_PIN_OPERSTATE_QUAL_FAILED: pin signal failed qualification (e.g.
+ *   frequency or phase monitor)
+ */
+enum dpll_pin_operstate {
+	DPLL_PIN_OPERSTATE_ACTIVE = 1,
+	DPLL_PIN_OPERSTATE_STANDBY,
+	DPLL_PIN_OPERSTATE_NO_SIGNAL,
+	DPLL_PIN_OPERSTATE_QUAL_FAILED,
+
+	/* private: */
+	__DPLL_PIN_OPERSTATE_MAX,
+	DPLL_PIN_OPERSTATE_MAX = (__DPLL_PIN_OPERSTATE_MAX - 1)
+};
+
 /**
  * enum dpll_pin_capabilities - defines possible capabilities of a pin, valid
  *   flags on DPLL_A_PIN_CAPABILITIES attribute
@@ -257,6 +279,7 @@ enum dpll_a_pin {
 	DPLL_A_PIN_PHASE_ADJUST_GRAN,
 	DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET_PPT,
 	DPLL_A_PIN_MEASURED_FREQUENCY,
+	DPLL_A_PIN_OPERSTATE,
 
 	__DPLL_A_PIN_MAX,
 	DPLL_A_PIN_MAX = (__DPLL_A_PIN_MAX - 1)
-- 
2.53.0


^ permalink raw reply related

* [PATCH net-next 0/2] dpll: add pin operational state
From: Ivan Vecera @ 2026-04-28 15:49 UTC (permalink / raw)
  To: netdev
  Cc: Arkadiusz Kubalewski, David S. Miller, Donald Hunter,
	Eric Dumazet, Jakub Kicinski, Jiri Pirko, Jonathan Corbet,
	Michal Schmidt, Paolo Abeni, Pasi Vaananen, Petr Oros,
	Prathosh Satish, Shuah Khan, Simon Horman, Vadim Fedorenko,
	linux-doc, linux-kernel

Add pin operational state (operstate) to the DPLL subsystem to
separate administrative intent from actual hardware status.

Currently pin-state mixes what the user requested (connected,
selectable, disconnected) with what the hardware is actually doing.
This makes it difficult to diagnose situations where a user sets
a pin as selectable or connected but the hardware cannot use it
due to signal issues.

The new operstate attribute is reported inside the pin-parent-device
nest alongside the existing state and is read-only. Defined values:

  - active: pin is qualified and actively used by the DPLL
  - standby: pin is qualified but not actively used by the DPLL
  - no-signal: pin does not have a valid signal
  - qual-failed: pin signal failed qualification checks

Patch 1 adds the operstate enum, netlink attribute and the
operstate_on_dpll_get callback to the DPLL subsystem. It also
updates Documentation/driver-api/dpll.rst to describe the
separation between admin state and operational state.

Patch 2 implements the callback for ZL3073x input pins using the
reference monitor status register. It also refactors the existing
state_on_dpll_get to return purely administrative state and switches
periodic monitoring to track operstate changes.

Ivan Vecera (2):
  dpll: add pin operational state
  dpll: zl3073x: implement pin operational state reporting

 Documentation/driver-api/dpll.rst     |  38 +++++----
 Documentation/netlink/specs/dpll.yaml |  31 ++++++++
 drivers/dpll/dpll_netlink.c           |  27 +++++++
 drivers/dpll/dpll_nl.c                |   3 +-
 drivers/dpll/dpll_nl.h                |   2 +-
 drivers/dpll/zl3073x/dpll.c           | 108 +++++++++++++++++---------
 drivers/dpll/zl3073x/regs.h           |   9 ++-
 include/linux/dpll.h                  |   6 ++
 include/uapi/linux/dpll.h             |  23 ++++++
 9 files changed, 192 insertions(+), 55 deletions(-)


base-commit: 1f5ffc672165ff851063a5fd044b727ab2517ae3
-- 
2.53.0


^ permalink raw reply

* Re: [PATCH net-next 2/4] net/sched: tc_dump_qdisc_root() refactor
From: Eric Dumazet @ 2026-04-28 15:48 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: David S . Miller, Paolo Abeni, Simon Horman, Jamal Hadi Salim,
	Jiri Pirko, Kuniyuki Iwashima, netdev, eric.dumazet
In-Reply-To: <20260427160847.5dbf1915@kernel.org>

On Mon, Apr 27, 2026 at 4:08 PM Jakub Kicinski <kuba@kernel.org> wrote:
>
> On Mon, 27 Apr 2026 13:25:53 +0000 Eric Dumazet wrote:
> > -     if (q_idx < s_q_idx) {
> > -             q_idx++;
> > -     } else {
> > -             if (!tc_qdisc_dump_ignore(q, dump_invisible) &&
> > -                 tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).portid,
> > -                               cb->nlh->nlmsg_seq, NLM_F_MULTI,
> > -                               RTM_NEWQDISC, NULL) <= 0)
> > -                     goto done;
> > -             q_idx++;
> > +     if (!(q_idx < s_q_idx) &&
> > +         !tc_qdisc_dump_ignore(q, dump_invisible)) {
> > +             ret = tc_fill_qdisc(skb, q, q->parent,
> > +                                 NETLINK_CB(cb->skb).portid,
> > +                                 cb->nlh->nlmsg_seq, NLM_F_MULTI,
> > +                                 RTM_NEWQDISC, NULL);
> > +             if (ret < 0)
> > +                     goto out;
> >       }
> > +     q_idx++;
>
> Probably subjective but I'm not sure the
>
>         if (!(q_idx < s_q_idx) &&
>
> is more readable than the previous version?
>
> Especially for:
>
> >       hash_for_each(qdisc_dev(root)->qdisc_hash, b, q, hash) {
> > -             if (q_idx < s_q_idx) {
> > -                     q_idx++;
> > -                     continue;
> > +             if (!(q_idx < s_q_idx) &&
> > +                 !tc_qdisc_dump_ignore(q, dump_invisible)) {
> > +                     ret = tc_fill_qdisc(skb, q, q->parent,
> > +                                         NETLINK_CB(cb->skb).portid,
> > +                                         cb->nlh->nlmsg_seq, NLM_F_MULTI,
> > +                                         RTM_NEWQDISC, NULL);
> > +                     if (ret < 0)
> > +                             goto out;
> >               }
>
> I feel like checking the ID + continue in netlink dump loop is fairly
> idiomatic.

OK, this was removing one indent level.

I will keep the double q_idx++ then.

^ permalink raw reply

* Re: [PATCH net-next 4/4] net/sched: speedup tc_dump_qdisc() when tcm_ifindex is provided
From: Eric Dumazet @ 2026-04-28 15:40 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: David S . Miller, Paolo Abeni, Simon Horman, Jamal Hadi Salim,
	Jiri Pirko, Kuniyuki Iwashima, netdev, eric.dumazet
In-Reply-To: <20260427161830.78193ed9@kernel.org>

On Mon, Apr 27, 2026 at 4:18 PM Jakub Kicinski <kuba@kernel.org> wrote:
>
> On Mon, 27 Apr 2026 13:25:55 +0000 Eric Dumazet wrote:
> >  static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
> >  {
> >       const struct nlmsghdr *nlh = cb->nlh;
> > +     const struct tcmsg *tcm = nlmsg_data(nlh);
>
> nit: breaks reverse xmas tree
>
> I added this tcm assignment after parsing:
>
>         err = nlmsg_parse_deprecated(nlh, sizeof(struct tcmsg), tca, TCA_MAX,
>                                      rtm_tca_policy, cb->extack);
>         if (err < 0)
>                 return err;
> +       tcm = nlmsg_data(nlh);
>
> because nlmsg_parse validates the struct is in range of skb->len

Note tc_get_qdisc() and tc_ctl_tclass() use tcm = nlmsg_data(n) before
validation.

Do they need to be changed?

>
> >       struct net *net = sock_net(skb->sk);
> >       struct nlattr *tca[TCA_MAX + 1];
> >       struct {
> > @@ -1892,6 +1893,9 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
> >       if (err < 0)
> >               return err;
> >
> > +     if (!ctx->ifindex)
> > +             ctx->ifindex = tcm->tcm_ifindex;
> > +
> >       s_ifindex = ctx->ifindex;
> >       s_q_idx = ctx->q_idx;
> >
> > @@ -1899,8 +1903,13 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
> >               struct netdev_queue *dev_queue;
> >               struct Qdisc *q;
> >
> > -             if (ctx->ifindex > s_ifindex)
> > +             if (ctx->ifindex > s_ifindex) {
> > +                     if (tcm->tcm_ifindex) {
> > +                             ctx->ifindex = ULONG_MAX;
> > +                             break;
> > +                     }
> >                       s_q_idx = 0;
> > +             }
>
> nit2: personal preference but I had before the loop:
>
>         if (tcm->tcm_ifindex && !ctx->ifindex)
>                 ctx->ifindex = tcm->tcm_ifindex;
>
> in the loop:
>
>         if (tcm->tcm_ifindex && ctx->ifindex != tcm->tcm_ifindex)
>                 break;

^ permalink raw reply

* [PATCH net v4] ipv6: Implement limits on extension header parsing
From: Daniel Borkmann @ 2026-04-28 15:37 UTC (permalink / raw)
  To: kuba
  Cc: edumazet, dsahern, tom, willemdebruijn.kernel, idosch, pabeni,
	justin.iurman, netdev

ipv6_{skip_exthdr,find_hdr}() and ip6_{tnl_parse_tlv_enc_lim,
protocol_deliver_rcu}() iterate over IPv6 extension headers until they
find a non-extension-header protocol or run out of packet data. The
loops have no iteration counter, relying solely on the packet length
to bound them. For a crafted packet with 8-byte extension headers
filling a 64KB jumbogram, this means a worst case of up to ~8k
iterations with a skb_header_pointer call each. ipv6_skip_exthdr(),
for example, is used where it parses the inner quoted packet inside
an incoming ICMPv6 error:

  - icmpv6_rcv
    - checksum validation
    - case ICMPV6_DEST_UNREACH
      - icmpv6_notify
        - pskb_may_pull()       <- pull inner IPv6 header
        - ipv6_skip_exthdr()    <- iterates here
        - pskb_may_pull()
        - ipprot->err_handler() <- sk lookup

The per-iteration cost of ipv6_skip_exthdr itself is generally
light, but skb_header_pointer becomes more costly on reassembled
packets: the first ~1232 bytes of the inner packet are in the skb's
linear area, but the remaining ~63KB are in the frag_list where
skb_copy_bits is needed to read data.

Initially, the idea was to add a configurable limit via a new
sysctl knob with default 8, in line with knobs from commit
47d3d7ac656a ("ipv6: Implement limits on Hop-by-Hop and Destination
options"), but two reasons eventually argued against it:

- It adds to UAPI that needs to be maintained forever, and
  upcoming work is restricting extension header ordering anyway,
  leaving little reason for another sysctl knob
- exthdrs_core.c is always built-in even when CONFIG_IPV6=n,
  where struct net has no .ipv6 member, so the read site would
  need an ifdef'd fallback to a constant anyway

Therefore, just use a constant (IP6_MAX_EXT_HDRS_CNT). All four
extension header walking functions are now bound by this limit.

Note that the check in ip6_protocol_deliver_rcu() happens right
before the goto resubmit, such that we don't have to have a test
for ipv6_ext_hdr() in the fast-path.

There's an ongoing IETF draft-iurman-6man-eh-occurrences to enforce
IPv6 extension headers ordering and occurrence. The latter also
discusses security implications. As per RFC8200 section 4.1, the
occurrence rules for extension headers provide a practical upper
bound which is 8. In order to be conservative, let's define
IP6_MAX_EXT_HDRS_CNT as 4x that to leave enough room for quirky
setups. In the unlikely event that this is still not enough, then
we might need to reconsider a sysctl.

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
 v3->v4:
   - Switching to hard-coded define with 32 limit as discussed
     earlier, otherwise fixing the kbuild-bot error becomes
     to ugly.. was worth a try, but given the case of being
     built-in also with CONFIG_IPV6=n define seems better
     (Justin, Victor, kbuild-bot)
 v2->v3:
   - Adding IP6SKB_HOPBYHOP coverage (Justin)
   - I left the limit at 8 w/ sysctl, still feels the better
     option to me if we can keep the worst-case more tightened
 v1->v2:
   - Set the default to 8 (Justin)
   - Update IETF references (Justin)
   - Add core path coverage as well (Justin)

 include/net/dropreason-core.h | 6 ++++++
 include/net/ipv6.h            | 3 +++
 net/ipv6/exthdrs_core.c       | 7 +++++++
 net/ipv6/ip6_input.c          | 5 +++++
 net/ipv6/ip6_tunnel.c         | 4 ++++
 5 files changed, 25 insertions(+)

diff --git a/include/net/dropreason-core.h b/include/net/dropreason-core.h
index e0ca3904ff8e..2f312d1f67d6 100644
--- a/include/net/dropreason-core.h
+++ b/include/net/dropreason-core.h
@@ -99,6 +99,7 @@
 	FN(FRAG_TOO_FAR)		\
 	FN(TCP_MINTTL)			\
 	FN(IPV6_BAD_EXTHDR)		\
+	FN(IPV6_TOO_MANY_EXTHDRS)	\
 	FN(IPV6_NDISC_FRAG)		\
 	FN(IPV6_NDISC_HOP_LIMIT)	\
 	FN(IPV6_NDISC_BAD_CODE)		\
@@ -494,6 +495,11 @@ enum skb_drop_reason {
 	SKB_DROP_REASON_TCP_MINTTL,
 	/** @SKB_DROP_REASON_IPV6_BAD_EXTHDR: Bad IPv6 extension header. */
 	SKB_DROP_REASON_IPV6_BAD_EXTHDR,
+	/**
+	 * @SKB_DROP_REASON_IPV6_TOO_MANY_EXTHDRS: Number of IPv6 extension
+	 * headers in the packet exceeds IP6_MAX_EXT_HDRS_CNT.
+	 */
+	SKB_DROP_REASON_IPV6_TOO_MANY_EXTHDRS,
 	/** @SKB_DROP_REASON_IPV6_NDISC_FRAG: invalid frag (suppress_frag_ndisc). */
 	SKB_DROP_REASON_IPV6_NDISC_FRAG,
 	/** @SKB_DROP_REASON_IPV6_NDISC_HOP_LIMIT: invalid hop limit. */
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index d042afe7a245..118a24ac9e73 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -90,6 +90,9 @@ struct ip_tunnel_info;
 #define IP6_DEFAULT_MAX_DST_OPTS_LEN	 INT_MAX /* No limit */
 #define IP6_DEFAULT_MAX_HBH_OPTS_LEN	 INT_MAX /* No limit */
 
+/* Hard limit on traversed IPv6 extension headers */
+#define IP6_MAX_EXT_HDRS_CNT		 32
+
 /*
  *	Addr type
  *	
diff --git a/net/ipv6/exthdrs_core.c b/net/ipv6/exthdrs_core.c
index 49e31e4ae7b7..9d06d487e8b1 100644
--- a/net/ipv6/exthdrs_core.c
+++ b/net/ipv6/exthdrs_core.c
@@ -73,6 +73,7 @@ int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp,
 		     __be16 *frag_offp)
 {
 	u8 nexthdr = *nexthdrp;
+	int exthdr_cnt = 0;
 
 	*frag_offp = 0;
 
@@ -82,6 +83,8 @@ int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp,
 
 		if (nexthdr == NEXTHDR_NONE)
 			return -1;
+		if (unlikely(exthdr_cnt++ >= IP6_MAX_EXT_HDRS_CNT))
+			return -1;
 		hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
 		if (!hp)
 			return -1;
@@ -190,6 +193,7 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
 {
 	unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);
 	u8 nexthdr = ipv6_hdr(skb)->nexthdr;
+	int exthdr_cnt = 0;
 	bool found;
 
 	if (fragoff)
@@ -216,6 +220,9 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
 			return -ENOENT;
 		}
 
+		if (unlikely(exthdr_cnt++ >= IP6_MAX_EXT_HDRS_CNT))
+			return -EBADMSG;
+
 		hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
 		if (!hp)
 			return -EBADMSG;
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 967b07aeb683..8972863c93ee 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -403,6 +403,7 @@ INDIRECT_CALLABLE_DECLARE(int tcp_v6_rcv(struct sk_buff *));
 void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr,
 			      bool have_final)
 {
+	int exthdr_cnt = IP6CB(skb)->flags & IP6SKB_HOPBYHOP ? 1 : 0;
 	const struct inet6_protocol *ipprot;
 	struct inet6_dev *idev;
 	unsigned int nhoff;
@@ -487,6 +488,10 @@ void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr,
 				nexthdr = ret;
 				goto resubmit_final;
 			} else {
+				if (unlikely(exthdr_cnt++ >= IP6_MAX_EXT_HDRS_CNT)) {
+					SKB_DR_SET(reason, IPV6_TOO_MANY_EXTHDRS);
+					goto discard;
+				}
 				goto resubmit;
 			}
 		} else if (ret == 0) {
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index c468c83af0f2..9d1037ac082f 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -399,11 +399,15 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw)
 	unsigned int nhoff = raw - skb->data;
 	unsigned int off = nhoff + sizeof(*ipv6h);
 	u8 nexthdr = ipv6h->nexthdr;
+	int exthdr_cnt = 0;
 
 	while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) {
 		struct ipv6_opt_hdr *hdr;
 		u16 optlen;
 
+		if (unlikely(exthdr_cnt++ >= IP6_MAX_EXT_HDRS_CNT))
+			break;
+
 		if (!pskb_may_pull(skb, off + sizeof(*hdr)))
 			break;
 
-- 
2.43.0


^ 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