From bb300aedea872033326b0d52703c4df69b299de2 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Tue, 17 Jul 2018 14:08:33 -0700 Subject: [PATCH] net: qrtr: Send BYE message for all nodes on ept An ept can represent multiple nodes in a system. If an ept unregisters, qrtr should send a BYE control message for all the nodes that it represents. Iterate through the node tree to find all the nodes that belong to the ept. Change-Id: I641bba615e689f59acecc9ac87fec61c3eecc0d1 Signed-off-by: Chris Lew --- net/qrtr/qrtr.c | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c index 70e722932538..b93c9ea38480 100644 --- a/net/qrtr/qrtr.c +++ b/net/qrtr/qrtr.c @@ -638,28 +638,49 @@ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid) } EXPORT_SYMBOL_GPL(qrtr_endpoint_register); +static void qrtr_notify_bye(u32 nid) +{ + struct sockaddr_qrtr src = {AF_QIPCRTR, nid, QRTR_PORT_CTRL}; + struct sockaddr_qrtr dst = {AF_QIPCRTR, qrtr_local_nid, QRTR_PORT_CTRL}; + struct qrtr_ctrl_pkt *pkt; + struct sk_buff *skb; + + skb = qrtr_alloc_ctrl_packet(&pkt); + if (!skb) + return; + + pkt->cmd = cpu_to_le32(QRTR_TYPE_BYE); + qrtr_local_enqueue(NULL, skb, QRTR_TYPE_BYE, &src, &dst); +} + /** * qrtr_endpoint_unregister - unregister endpoint * @ep: endpoint to unregister */ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep) { + struct radix_tree_iter iter; struct qrtr_node *node = ep->node; - struct sockaddr_qrtr src = {AF_QIPCRTR, node->nid, QRTR_PORT_CTRL}; - struct sockaddr_qrtr dst = {AF_QIPCRTR, qrtr_local_nid, QRTR_PORT_CTRL}; - struct qrtr_ctrl_pkt *pkt; - struct sk_buff *skb; + unsigned long flags; + void __rcu **slot; mutex_lock(&node->ep_lock); node->ep = NULL; mutex_unlock(&node->ep_lock); /* Notify the local controller about the event */ - skb = qrtr_alloc_ctrl_packet(&pkt); - if (skb) { - pkt->cmd = cpu_to_le32(QRTR_TYPE_BYE); - qrtr_local_enqueue(NULL, skb, QRTR_TYPE_BYE, &src, &dst); + down_read(&qrtr_epts_lock); + spin_lock_irqsave(&qrtr_nodes_lock, flags); + radix_tree_for_each_slot(slot, &qrtr_nodes, &iter, 0) { + if (node != *slot) + continue; + + spin_unlock_irqrestore(&qrtr_nodes_lock, flags); + qrtr_notify_bye(iter.index); + spin_lock_irqsave(&qrtr_nodes_lock, flags); } + spin_unlock_irqrestore(&qrtr_nodes_lock, flags); + up_read(&qrtr_epts_lock); /* Wake up any transmitters waiting for resume-tx from the node */ wake_up_interruptible_all(&node->resume_tx);