diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2012-04-19 14:37:58 +0200 |
---|---|---|
committer | Gustavo Padovan <gustavo@padovan.org> | 2012-05-09 01:40:39 -0300 |
commit | fb3340594bd6630c27e31ddeff25b7002fb4558e (patch) | |
tree | 81908435e0842679398d8830f56d4395c81d76bd /net/bluetooth | |
parent | 8ed21f7eece54bb80eea5e31c3d9c6c7b6517e49 (diff) | |
download | blackbird-op-linux-fb3340594bd6630c27e31ddeff25b7002fb4558e.tar.gz blackbird-op-linux-fb3340594bd6630c27e31ddeff25b7002fb4558e.zip |
Bluetooth: Restrict to one SCO listening socket
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>
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/sco.c | 29 |
1 files changed, 22 insertions, 7 deletions
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index c75cd7b07d18..bf1af0b1497e 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -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; |