diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2012-04-19 08:37:58 -0400 |
---|---|---|
committer | Gustavo Padovan <gustavo@padovan.org> | 2012-05-09 00:40:39 -0400 |
commit | fb3340594bd6630c27e31ddeff25b7002fb4558e (patch) | |
tree | 81908435e0842679398d8830f56d4395c81d76bd /net | |
parent | 8ed21f7eece54bb80eea5e31c3d9c6c7b6517e49 (diff) |
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')
-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: | |||
273 | } | 273 | } |
274 | 274 | ||
275 | /* -------- Socket interface ---------- */ | 275 | /* -------- Socket interface ---------- */ |
276 | static struct sock *__sco_get_sock_by_addr(bdaddr_t *ba) | 276 | static struct sock *__sco_get_sock_listen_by_addr(bdaddr_t *ba) |
277 | { | 277 | { |
278 | struct sock *sk; | ||
279 | struct hlist_node *node; | 278 | struct hlist_node *node; |
279 | struct sock *sk; | ||
280 | |||
281 | sk_for_each(sk, node, &sco_sk_list.head) { | ||
282 | if (sk->sk_state != BT_LISTEN) | ||
283 | continue; | ||
280 | 284 | ||
281 | sk_for_each(sk, node, &sco_sk_list.head) | ||
282 | if (!bacmp(&bt_sk(sk)->src, ba)) | 285 | if (!bacmp(&bt_sk(sk)->src, ba)) |
283 | goto found; | 286 | return sk; |
284 | sk = NULL; | 287 | } |
285 | found: | 288 | |
286 | return sk; | 289 | return NULL; |
287 | } | 290 | } |
288 | 291 | ||
289 | /* Find socket listening on source bdaddr. | 292 | /* Find socket listening on source bdaddr. |
@@ -529,6 +532,7 @@ done: | |||
529 | static int sco_sock_listen(struct socket *sock, int backlog) | 532 | static int sco_sock_listen(struct socket *sock, int backlog) |
530 | { | 533 | { |
531 | struct sock *sk = sock->sk; | 534 | struct sock *sk = sock->sk; |
535 | bdaddr_t *src = &bt_sk(sk)->src; | ||
532 | int err = 0; | 536 | int err = 0; |
533 | 537 | ||
534 | BT_DBG("sk %p backlog %d", sk, backlog); | 538 | BT_DBG("sk %p backlog %d", sk, backlog); |
@@ -545,10 +549,21 @@ static int sco_sock_listen(struct socket *sock, int backlog) | |||
545 | goto done; | 549 | goto done; |
546 | } | 550 | } |
547 | 551 | ||
552 | write_lock(&sco_sk_list.lock); | ||
553 | |||
554 | if (__sco_get_sock_listen_by_addr(src)) { | ||
555 | err = -EADDRINUSE; | ||
556 | goto unlock; | ||
557 | } | ||
558 | |||
548 | sk->sk_max_ack_backlog = backlog; | 559 | sk->sk_max_ack_backlog = backlog; |
549 | sk->sk_ack_backlog = 0; | 560 | sk->sk_ack_backlog = 0; |
561 | |||
550 | sk->sk_state = BT_LISTEN; | 562 | sk->sk_state = BT_LISTEN; |
551 | 563 | ||
564 | unlock: | ||
565 | write_unlock(&sco_sk_list.lock); | ||
566 | |||
552 | done: | 567 | done: |
553 | release_sock(sk); | 568 | release_sock(sk); |
554 | return err; | 569 | return err; |