diff options
author | Szymon Janc <ext.szymon.janc@tieto.com> | 2016-09-16 17:34:33 +0200 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@intel.com> | 2016-10-16 09:00:57 +0300 |
commit | cb24f7d53b057cde448ac4fc8e960ed7c9b3c94b (patch) | |
tree | 1c27c2e5a43fb17a3acb82ce88146b934ed4f4b2 /net | |
parent | 27731ce222f7baf81d897d378c9785fa056b9fdc (diff) |
Bluetooth: L2CAP: Connect optional fixed channel only if supported
Only connect BR/EDR fixed channel if remote indicates support for it.
Core Specification Vol 3. Part A. 4.11:
"An L2CAP entity shall not transmit on any fixed channel (with the
exception of the L2CAP signaling channel) until it has received a Fixed
Channels Supported InfoType from the peer L2CAP entity indicating
support for the channel, or has received a valid signaling packet from
the remote device on the Fixed channel."
If data on fixed channel was received before Information Response then
we connect this channel immediately.
Change-Id: Ifef142c4eb3c14ecffb4abe4836912e2f2aba3c9
Signed-off-by: Szymon Janc <ext.szymon.janc@tieto.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/l2cap_br.c | 48 |
1 files changed, 42 insertions, 6 deletions
diff --git a/net/bluetooth/l2cap_br.c b/net/bluetooth/l2cap_br.c index 15f640d1a..cb98dfd59 100644 --- a/net/bluetooth/l2cap_br.c +++ b/net/bluetooth/l2cap_br.c @@ -93,6 +93,9 @@ enum { /* Signaling channel flags */ L2CAP_FLAG_SIG_INFO_PENDING, /* retrieving remote l2cap info */ L2CAP_FLAG_SIG_INFO_DONE, /* remote l2cap info is done */ + + /* fixed channels flags */ + L2CAP_FLAG_FIXED_CONNECTED, /* fixed connected */ }; static struct bt_l2cap_server *br_servers; @@ -411,6 +414,31 @@ static void l2cap_br_get_info(struct bt_l2cap_br *l2cap, uint16_t info_type) l2cap_br_chan_send_req(&l2cap->chan, buf, L2CAP_BR_INFO_TIMEOUT); } +static void connect_fixed_channel(struct bt_l2cap_br_chan *chan) +{ + if (atomic_test_and_set_bit(chan->flags, L2CAP_FLAG_FIXED_CONNECTED)) { + return; + } + + if (chan->chan.ops && chan->chan.ops->connected) { + chan->chan.ops->connected(&chan->chan); + } +} + +static void connect_optional_fixed_channels(struct bt_l2cap_br *l2cap) +{ + /* can be change to loop if more BR/EDR fixed channels are added */ + if (l2cap->info_fixed_chan & BIT(BT_L2CAP_CID_BR_SMP)) { + struct bt_l2cap_chan *chan; + + chan = bt_l2cap_br_lookup_rx_cid(l2cap->chan.chan.conn, + BT_L2CAP_CID_BR_SMP); + if (chan) { + connect_fixed_channel(BR_CHAN(chan)); + } + } +} + static int l2cap_br_info_rsp(struct bt_l2cap_br *l2cap, uint8_t ident, struct net_buf *buf) { @@ -468,6 +496,9 @@ static int l2cap_br_info_rsp(struct bt_l2cap_br *l2cap, uint8_t ident, l2cap->info_fixed_chan = net_buf_pull_u8(buf); BT_DBG("remote fixed channel mask 0x%02x", l2cap->info_fixed_chan); + + connect_optional_fixed_channels(l2cap); + break; default: BT_WARN("type 0x%04x unsupported", type); @@ -555,7 +586,6 @@ void bt_l2cap_br_connected(struct bt_conn *conn) { struct bt_l2cap_fixed_chan *fchan; struct bt_l2cap_chan *chan; - struct bt_l2cap_br *l2cap; for (fchan = br_fixed_channels; fchan; fchan = fchan->_next) { struct bt_l2cap_br_chan *ch; @@ -577,13 +607,19 @@ void bt_l2cap_br_connected(struct bt_conn *conn) return; } - if (chan->ops && chan->ops->connected) { - chan->ops->connected(chan); + /* + * other fixed channels will be connected after Information + * Response is received + */ + if (fchan->cid == BT_L2CAP_CID_BR_SIG) { + struct bt_l2cap_br *sig_ch; + + connect_fixed_channel(ch); + + sig_ch = CONTAINER_OF(ch, struct bt_l2cap_br, chan); + l2cap_br_get_info(sig_ch, BT_L2CAP_INFO_FEAT_MASK); } } - - l2cap = CONTAINER_OF(chan, struct bt_l2cap_br, chan.chan); - l2cap_br_get_info(l2cap, BT_L2CAP_INFO_FEAT_MASK); } static struct bt_l2cap_server *l2cap_br_server_lookup_psm(uint16_t psm) |