Bluetooth: Fix channel check when binding RFCOMM sock
When binding RFCOMM socket with non-zero channel we're checking if there is already any other socket which has the same channel number assigned and then fail. This check does not consider situation where we have another socket connected to remote device on given channel number in which case we still should be able to bind local socket. This patch changes __rfcomm_get_sock_by_addr() to return only sockets in either BT_BOUND or BT_LISTEN states, also name is updated to better describe what this function does now. Signed-off-by: Andrzej Kaczmarek <andrzej.kaczmarek@tieto.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
7a4cd51dec
commit
b1765e7afe
|
@ -105,13 +105,18 @@ static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- Socket functions ---- */
|
/* ---- Socket functions ---- */
|
||||||
static struct sock *__rfcomm_get_sock_by_addr(u8 channel, bdaddr_t *src)
|
static struct sock *__rfcomm_get_listen_sock_by_addr(u8 channel, bdaddr_t *src)
|
||||||
{
|
{
|
||||||
struct sock *sk = NULL;
|
struct sock *sk = NULL;
|
||||||
|
|
||||||
sk_for_each(sk, &rfcomm_sk_list.head) {
|
sk_for_each(sk, &rfcomm_sk_list.head) {
|
||||||
if (rfcomm_pi(sk)->channel == channel &&
|
if (rfcomm_pi(sk)->channel != channel)
|
||||||
!bacmp(&rfcomm_pi(sk)->src, src))
|
continue;
|
||||||
|
|
||||||
|
if (bacmp(&rfcomm_pi(sk)->src, src))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (sk->sk_state == BT_BOUND || sk->sk_state == BT_LISTEN)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,6 +336,7 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr
|
||||||
{
|
{
|
||||||
struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
|
struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
|
||||||
struct sock *sk = sock->sk;
|
struct sock *sk = sock->sk;
|
||||||
|
int chan = sa->rc_channel;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
BT_DBG("sk %p %pMR", sk, &sa->rc_bdaddr);
|
BT_DBG("sk %p %pMR", sk, &sa->rc_bdaddr);
|
||||||
|
@ -352,12 +358,12 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr
|
||||||
|
|
||||||
write_lock(&rfcomm_sk_list.lock);
|
write_lock(&rfcomm_sk_list.lock);
|
||||||
|
|
||||||
if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) {
|
if (chan && __rfcomm_get_listen_sock_by_addr(chan, &sa->rc_bdaddr)) {
|
||||||
err = -EADDRINUSE;
|
err = -EADDRINUSE;
|
||||||
} else {
|
} else {
|
||||||
/* Save source address */
|
/* Save source address */
|
||||||
bacpy(&rfcomm_pi(sk)->src, &sa->rc_bdaddr);
|
bacpy(&rfcomm_pi(sk)->src, &sa->rc_bdaddr);
|
||||||
rfcomm_pi(sk)->channel = sa->rc_channel;
|
rfcomm_pi(sk)->channel = chan;
|
||||||
sk->sk_state = BT_BOUND;
|
sk->sk_state = BT_BOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,7 +445,7 @@ static int rfcomm_sock_listen(struct socket *sock, int backlog)
|
||||||
write_lock(&rfcomm_sk_list.lock);
|
write_lock(&rfcomm_sk_list.lock);
|
||||||
|
|
||||||
for (channel = 1; channel < 31; channel++)
|
for (channel = 1; channel < 31; channel++)
|
||||||
if (!__rfcomm_get_sock_by_addr(channel, src)) {
|
if (!__rfcomm_get_listen_sock_by_addr(channel, src)) {
|
||||||
rfcomm_pi(sk)->channel = channel;
|
rfcomm_pi(sk)->channel = channel;
|
||||||
err = 0;
|
err = 0;
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue