net: qrtr: Do not do DEL_SERVER broadcast after DEL_CLIENT
authorSricharan Ramabadhran <quic_srichara@quicinc.com>
Mon, 3 Apr 2023 06:58:51 +0000 (12:28 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 13 Apr 2023 14:55:21 +0000 (16:55 +0200)
[ Upstream commit 839349d13905927d8a567ca4d21d88c82028e31d ]

On the remote side, when QRTR socket is removed, af_qrtr will call
qrtr_port_remove() which broadcasts the DEL_CLIENT packet to all neighbours
including local NS. NS upon receiving the DEL_CLIENT packet, will remove
the lookups associated with the node:port and broadcasts the DEL_SERVER
packet.

But on the host side, due to the arrival of the DEL_CLIENT packet, the NS
would've already deleted the server belonging to that port. So when the
remote's NS again broadcasts the DEL_SERVER for that port, it throws below
error message on the host:

"failed while handling packet from 2:-2"

So fix this error by not broadcasting the DEL_SERVER packet when the
DEL_CLIENT packet gets processed."

Fixes: 0c2204a4ad71 ("net: qrtr: Migrate nameservice to kernel from userspace")
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Ram Kumar Dharuman <quic_ramd@quicinc.com>
Signed-off-by: Sricharan Ramabadhran <quic_srichara@quicinc.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/qrtr/ns.c

index e595079..3e40a1b 100644 (file)
@@ -273,7 +273,7 @@ err:
        return NULL;
 }
 
-static int server_del(struct qrtr_node *node, unsigned int port)
+static int server_del(struct qrtr_node *node, unsigned int port, bool bcast)
 {
        struct qrtr_lookup *lookup;
        struct qrtr_server *srv;
@@ -286,7 +286,7 @@ static int server_del(struct qrtr_node *node, unsigned int port)
        radix_tree_delete(&node->servers, port);
 
        /* Broadcast the removal of local servers */
-       if (srv->node == qrtr_ns.local_node)
+       if (srv->node == qrtr_ns.local_node && bcast)
                service_announce_del(&qrtr_ns.bcast_sq, srv);
 
        /* Announce the service's disappearance to observers */
@@ -372,7 +372,7 @@ static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
                }
                slot = radix_tree_iter_resume(slot, &iter);
                rcu_read_unlock();
-               server_del(node, srv->port);
+               server_del(node, srv->port, true);
                rcu_read_lock();
        }
        rcu_read_unlock();
@@ -458,10 +458,13 @@ static int ctrl_cmd_del_client(struct sockaddr_qrtr *from,
                kfree(lookup);
        }
 
-       /* Remove the server belonging to this port */
+       /* Remove the server belonging to this port but don't broadcast
+        * DEL_SERVER. Neighbours would've already removed the server belonging
+        * to this port due to the DEL_CLIENT broadcast from qrtr_port_remove().
+        */
        node = node_get(node_id);
        if (node)
-               server_del(node, port);
+               server_del(node, port, false);
 
        /* Advertise the removal of this client to all local servers */
        local_node = node_get(qrtr_ns.local_node);
@@ -566,7 +569,7 @@ static int ctrl_cmd_del_server(struct sockaddr_qrtr *from,
        if (!node)
                return -ENOENT;
 
-       return server_del(node, port);
+       return server_del(node, port, true);
 }
 
 static int ctrl_cmd_new_lookup(struct sockaddr_qrtr *from,