diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c index d0d14511d413..9d7e8af02471 100644 --- a/net/qrtr/qrtr.c +++ b/net/qrtr/qrtr.c @@ -212,6 +212,8 @@ static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb, int type, struct sockaddr_qrtr *from, struct sockaddr_qrtr *to, unsigned int flags); static void qrtr_handle_del_proc(struct sk_buff *skb); +static void qrtr_cleanup_flow_control(struct qrtr_node *node, + struct sk_buff *skb); static void qrtr_log_tx_msg(struct qrtr_node *node, struct qrtr_hdr_v1 *hdr, struct sk_buff *skb) @@ -1047,6 +1049,10 @@ static void qrtr_node_rx_work(struct kthread_work *work) if (!ipc) { kfree_skb(skb); } else { + if (cb->type == QRTR_TYPE_DEL_SERVER || + cb->type == QRTR_TYPE_DEL_CLIENT) { + qrtr_cleanup_flow_control(node, skb); + } qrtr_sock_queue_skb(node, skb, ipc); qrtr_port_put(ipc); } @@ -1054,6 +1060,47 @@ static void qrtr_node_rx_work(struct kthread_work *work) } } +static void qrtr_cleanup_flow_control(struct qrtr_node *node, + struct sk_buff *skb) +{ + struct qrtr_ctrl_pkt *pkt; + unsigned long key; + struct sockaddr_qrtr src; + struct qrtr_tx_flow *flow; + struct qrtr_tx_flow_waiter *waiter; + struct qrtr_tx_flow_waiter *temp; + u32 cmd; + + pkt = (void *)skb->data; + cmd = le32_to_cpu(pkt->cmd); + + if (cmd == QRTR_TYPE_DEL_SERVER) { + src.sq_node = le32_to_cpu(pkt->server.node); + src.sq_port = le32_to_cpu(pkt->server.port); + } else { + src.sq_node = le32_to_cpu(pkt->client.node); + src.sq_port = le32_to_cpu(pkt->client.port); + } + + key = (u64)src.sq_node << 32 | src.sq_port; + + mutex_lock(&node->qrtr_tx_lock); + flow = radix_tree_lookup(&node->qrtr_tx_flow, key); + if (!flow) { + mutex_unlock(&node->qrtr_tx_lock); + return; + } + + list_for_each_entry_safe(waiter, temp, &flow->waiters, node) { + list_del(&waiter->node); + sock_put(waiter->sk); + kfree(waiter); + } + kfree(flow); + radix_tree_delete(&node->qrtr_tx_flow, key); + mutex_unlock(&node->qrtr_tx_lock); +} + static void qrtr_handle_del_proc(struct sk_buff *skb) { struct sockaddr_qrtr src = {AF_QIPCRTR, 0, QRTR_PORT_CTRL};