Commit c2287681 authored by Ido Yariv's avatar Ido Yariv Committed by Gustavo Padovan

Bluetooth: Search global l2cap channels by src/dst addresses

The cid or psm and the source address might not be enough to uniquely
identify a global channel, especially when the source address is our
own.

For instance, when trying to communicate with two LE devices in master
mode, data received from the both devices is sent to the same socket.

Fix this by taking the destination address into account when choosing
the socket.
Signed-off-by: default avatarIdo Yariv <ido@wizery.com>
Signed-off-by: default avatarArik Nemtsov <arik@wizery.com>
Tested-by: default avatarJoão Paulo Rechi Vita <jprvita@openbossa.org>
Signed-off-by: default avatarGustavo Padovan <gustavo@padovan.org>
parent d8ce9395
...@@ -1066,11 +1066,12 @@ static void l2cap_conn_start(struct l2cap_conn *conn) ...@@ -1066,11 +1066,12 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
mutex_unlock(&conn->chan_lock); mutex_unlock(&conn->chan_lock);
} }
/* Find socket with cid and source bdaddr. /* Find socket with cid and source/destination bdaddr.
* Returns closest match, locked. * Returns closest match, locked.
*/ */
static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid, static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid,
bdaddr_t *src) bdaddr_t *src,
bdaddr_t *dst)
{ {
struct l2cap_chan *c, *c1 = NULL; struct l2cap_chan *c, *c1 = NULL;
...@@ -1083,14 +1084,22 @@ static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid, ...@@ -1083,14 +1084,22 @@ static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid,
continue; continue;
if (c->scid == cid) { if (c->scid == cid) {
int src_match, dst_match;
int src_any, dst_any;
/* Exact match. */ /* Exact match. */
if (!bacmp(&bt_sk(sk)->src, src)) { src_match = !bacmp(&bt_sk(sk)->src, src);
dst_match = !bacmp(&bt_sk(sk)->dst, dst);
if (src_match && dst_match) {
read_unlock(&chan_list_lock); read_unlock(&chan_list_lock);
return c; return c;
} }
/* Closest match */ /* Closest match */
if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) src_any = !bacmp(&bt_sk(sk)->src, BDADDR_ANY);
dst_any = !bacmp(&bt_sk(sk)->dst, BDADDR_ANY);
if ((src_match && dst_any) || (src_any && dst_match) ||
(src_any && dst_any))
c1 = c; c1 = c;
} }
} }
...@@ -1109,7 +1118,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) ...@@ -1109,7 +1118,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
/* Check if we have socket listening on cid */ /* Check if we have socket listening on cid */
pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA, pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
conn->src); conn->src, conn->dst);
if (!pchan) if (!pchan)
return; return;
...@@ -1337,10 +1346,12 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) ...@@ -1337,10 +1346,12 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
/* ---- Socket interface ---- */ /* ---- Socket interface ---- */
/* Find socket with psm and source bdaddr. /* Find socket with psm and source / destination bdaddr.
* Returns closest match. * Returns closest match.
*/ */
static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src) static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm,
bdaddr_t *src,
bdaddr_t *dst)
{ {
struct l2cap_chan *c, *c1 = NULL; struct l2cap_chan *c, *c1 = NULL;
...@@ -1353,14 +1364,22 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr ...@@ -1353,14 +1364,22 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr
continue; continue;
if (c->psm == psm) { if (c->psm == psm) {
int src_match, dst_match;
int src_any, dst_any;
/* Exact match. */ /* Exact match. */
if (!bacmp(&bt_sk(sk)->src, src)) { src_match = !bacmp(&bt_sk(sk)->src, src);
dst_match = !bacmp(&bt_sk(sk)->dst, dst);
if (src_match && dst_match) {
read_unlock(&chan_list_lock); read_unlock(&chan_list_lock);
return c; return c;
} }
/* Closest match */ /* Closest match */
if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) src_any = !bacmp(&bt_sk(sk)->src, BDADDR_ANY);
dst_any = !bacmp(&bt_sk(sk)->dst, BDADDR_ANY);
if ((src_match && dst_any) || (src_any && dst_match) ||
(src_any && dst_any))
c1 = c; c1 = c;
} }
} }
...@@ -2887,7 +2906,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd ...@@ -2887,7 +2906,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
BT_DBG("psm 0x%2.2x scid 0x%4.4x", __le16_to_cpu(psm), scid); BT_DBG("psm 0x%2.2x scid 0x%4.4x", __le16_to_cpu(psm), scid);
/* Check if we have socket listening on psm */ /* Check if we have socket listening on psm */
pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src); pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src, conn->dst);
if (!pchan) { if (!pchan) {
result = L2CAP_CR_BAD_PSM; result = L2CAP_CR_BAD_PSM;
goto sendresp; goto sendresp;
...@@ -4627,7 +4646,7 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str ...@@ -4627,7 +4646,7 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str
{ {
struct l2cap_chan *chan; struct l2cap_chan *chan;
chan = l2cap_global_chan_by_psm(0, psm, conn->src); chan = l2cap_global_chan_by_psm(0, psm, conn->src, conn->dst);
if (!chan) if (!chan)
goto drop; goto drop;
...@@ -4653,7 +4672,7 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, u16 cid, ...@@ -4653,7 +4672,7 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, u16 cid,
{ {
struct l2cap_chan *chan; struct l2cap_chan *chan;
chan = l2cap_global_chan_by_scid(0, cid, conn->src); chan = l2cap_global_chan_by_scid(0, cid, conn->src, conn->dst);
if (!chan) if (!chan)
goto drop; goto drop;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment