Bluetooth: timer check sk is not owned before freeing
[pandora-kernel.git] / net / bluetooth / l2cap.c
index 4ed3827..18a802c 100644 (file)
@@ -83,6 +83,18 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
 static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
 
 /* ---- L2CAP timers ---- */
+static void l2cap_sock_set_timer(struct sock *sk, long timeout)
+{
+       BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout);
+       sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout);
+}
+
+static void l2cap_sock_clear_timer(struct sock *sk)
+{
+       BT_DBG("sock %p state %d", sk, sk->sk_state);
+       sk_stop_timer(sk, &sk->sk_timer);
+}
+
 static void l2cap_sock_timeout(unsigned long arg)
 {
        struct sock *sk = (struct sock *) arg;
@@ -92,6 +104,14 @@ static void l2cap_sock_timeout(unsigned long arg)
 
        bh_lock_sock(sk);
 
+       if (sock_owned_by_user(sk)) {
+               /* sk is owned by user. Try again later */
+               l2cap_sock_set_timer(sk, HZ / 5);
+               bh_unlock_sock(sk);
+               sock_put(sk);
+               return;
+       }
+
        if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG)
                reason = ECONNREFUSED;
        else if (sk->sk_state == BT_CONNECT &&
@@ -108,18 +128,6 @@ static void l2cap_sock_timeout(unsigned long arg)
        sock_put(sk);
 }
 
-static void l2cap_sock_set_timer(struct sock *sk, long timeout)
-{
-       BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout);
-       sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout);
-}
-
-static void l2cap_sock_clear_timer(struct sock *sk)
-{
-       BT_DBG("sock %p state %d", sk, sk->sk_state);
-       sk_stop_timer(sk, &sk->sk_timer);
-}
-
 /* ---- L2CAP channels ---- */
 static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid)
 {