NFC: Purge LLCP socket Tx queues when being disconnected
authorSamuel Ortiz <sameo@linux.intel.com>
Fri, 26 Oct 2012 16:20:10 +0000 (18:20 +0200)
committerSamuel Ortiz <sameo@linux.intel.com>
Fri, 26 Oct 2012 16:26:53 +0000 (18:26 +0200)
The Tx queues are no longer valid when we receive a disconnection or when
the LLCP link goes down. In the later case we also purge the entire local
Tx queue.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
net/nfc/llcp/llcp.c

index c8b27af..2e23bd3 100644 (file)
@@ -45,12 +45,38 @@ void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *sk)
        write_unlock(&l->lock);
 }
 
+static void nfc_llcp_socket_purge(struct nfc_llcp_sock *sock)
+{
+       struct nfc_llcp_local *local = sock->local;
+       struct sk_buff *s, *tmp;
+
+       pr_debug("%p\n", &sock->sk);
+
+       skb_queue_purge(&sock->tx_queue);
+       skb_queue_purge(&sock->tx_pending_queue);
+       skb_queue_purge(&sock->tx_backlog_queue);
+
+       if (local == NULL)
+               return;
+
+       /* Search for local pending SKBs that are related to this socket */
+       skb_queue_walk_safe(&local->tx_queue, s, tmp) {
+               if (s->sk != &sock->sk)
+                       continue;
+
+               skb_unlink(s, &local->tx_queue);
+               kfree_skb(s);
+       }
+}
+
 static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen)
 {
        struct sock *sk;
        struct hlist_node *node, *tmp;
        struct nfc_llcp_sock *llcp_sock;
 
+       skb_queue_purge(&local->tx_queue);
+
        write_lock(&local->sockets.lock);
 
        sk_for_each_safe(sk, node, tmp, &local->sockets.head) {
@@ -58,6 +84,8 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen)
 
                bh_lock_sock(sk);
 
+               nfc_llcp_socket_purge(llcp_sock);
+
                if (sk->sk_state == LLCP_CONNECTED)
                        nfc_put_device(llcp_sock->dev);
 
@@ -1002,6 +1030,9 @@ static void nfc_llcp_recv_disc(struct nfc_llcp_local *local,
 
        sk = &llcp_sock->sk;
        lock_sock(sk);
+
+       nfc_llcp_socket_purge(llcp_sock);
+
        if (sk->sk_state == LLCP_CLOSED) {
                release_sock(sk);
                nfc_llcp_sock_put(llcp_sock);