Bluetooth: Restrict to one SCO listening socket
authorMarcel Holtmann <marcel@holtmann.org>
Thu, 19 Apr 2012 12:37:58 +0000 (14:37 +0200)
committerGustavo Padovan <gustavo@padovan.org>
Wed, 9 May 2012 04:40:39 +0000 (01:40 -0300)
The SCO sockets are only identified by its address. So only allow one
SCO socket in listening state per address or BDADDR_ANY.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Gustavo Padovan <gustavo@padovan.org>
net/bluetooth/sco.c

index c75cd7b07d18742fe5b55ba8596f214386e0640c..bf1af0b1497ef725564f5a3e206fe36680c3c753 100644 (file)
@@ -273,17 +273,20 @@ drop:
 }
 
 /* -------- Socket interface ---------- */
-static struct sock *__sco_get_sock_by_addr(bdaddr_t *ba)
+static struct sock *__sco_get_sock_listen_by_addr(bdaddr_t *ba)
 {
-       struct sock *sk;
        struct hlist_node *node;
+       struct sock *sk;
+
+       sk_for_each(sk, node, &sco_sk_list.head) {
+               if (sk->sk_state != BT_LISTEN)
+                       continue;
 
-       sk_for_each(sk, node, &sco_sk_list.head)
                if (!bacmp(&bt_sk(sk)->src, ba))
-                       goto found;
-       sk = NULL;
-found:
-       return sk;
+                       return sk;
+       }
+
+       return NULL;
 }
 
 /* Find socket listening on source bdaddr.
@@ -529,6 +532,7 @@ done:
 static int sco_sock_listen(struct socket *sock, int backlog)
 {
        struct sock *sk = sock->sk;
+       bdaddr_t *src = &bt_sk(sk)->src;
        int err = 0;
 
        BT_DBG("sk %p backlog %d", sk, backlog);
@@ -545,10 +549,21 @@ static int sco_sock_listen(struct socket *sock, int backlog)
                goto done;
        }
 
+       write_lock(&sco_sk_list.lock);
+
+       if (__sco_get_sock_listen_by_addr(src)) {
+               err = -EADDRINUSE;
+               goto unlock;
+       }
+
        sk->sk_max_ack_backlog = backlog;
        sk->sk_ack_backlog = 0;
+
        sk->sk_state = BT_LISTEN;
 
+unlock:
+       write_unlock(&sco_sk_list.lock);
+
 done:
        release_sock(sk);
        return err;