Bluetooth: L2CAP: Use sys_slist_t for connection channels

This avoid having duplicated code for list manipulation in both LE and
BR channels.

Change-Id: I734635e8e51d4b826a3d45cda8551e1e509bd913
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
Luiz Augusto von Dentz 2017-03-21 15:48:03 +02:00
commit 41a55893f7
6 changed files with 89 additions and 175 deletions

View file

@ -74,7 +74,7 @@ struct bt_l2cap_chan {
struct bt_conn *conn;
/** Channel operations reference */
struct bt_l2cap_chan_ops *ops;
struct bt_l2cap_chan *_next;
sys_snode_t node;
bt_l2cap_chan_destroy_t destroy;
/* Response Timeout eXpired (RTX) timer */
struct k_delayed_work rtx_work;

View file

@ -1304,6 +1304,8 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state)
k_fifo_init(&conn->tx_queue);
k_poll_signal(&conn_change, 0);
sys_slist_init(&conn->channels);
bt_l2cap_connected(conn);
notify_connected(conn);
break;

View file

@ -94,7 +94,7 @@ struct bt_conn {
struct k_fifo tx_queue;
/* Active L2CAP channels */
struct bt_l2cap_chan *channels;
sys_slist_t channels;
atomic_t ref;

View file

@ -53,12 +53,6 @@
#define l2cap_remove_ident(conn, ident) __l2cap_lookup_ident(conn, ident, true)
#endif /* CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL */
/* Wrapper macros making action on channel's list assigned to connection */
#define l2cap_lookup_chan(conn, chan) \
__l2cap_chan(conn, chan, BT_L2CAP_CHAN_LOOKUP)
#define l2cap_detach_chan(conn, chan) \
__l2cap_chan(conn, chan, BT_L2CAP_CHAN_DETACH)
static struct bt_l2cap_fixed_chan *le_channels;
#if defined(CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL)
static struct bt_l2cap_server *servers;
@ -100,6 +94,7 @@ void bt_l2cap_le_fixed_chan_register(struct bt_l2cap_fixed_chan *chan)
le_channels = chan;
}
#if defined(CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL)
static struct bt_l2cap_le_chan *l2cap_chan_alloc_cid(struct bt_conn *conn,
struct bt_l2cap_chan *chan)
{
@ -124,63 +119,41 @@ static struct bt_l2cap_le_chan *l2cap_chan_alloc_cid(struct bt_conn *conn,
return NULL;
}
#if defined(CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL)
static struct bt_l2cap_le_chan *
__l2cap_lookup_ident(struct bt_conn *conn, uint16_t ident, bool remove)
{
struct bt_l2cap_chan *chan, *prev;
struct bt_l2cap_chan *chan;
sys_snode_t *prev = NULL;
for (chan = conn->channels, prev = NULL; chan;
prev = chan, chan = chan->_next) {
if (chan->ident != ident) {
continue;
SYS_SLIST_FOR_EACH_CONTAINER(&conn->channels, chan, node) {
if (chan->ident == ident) {
if (remove) {
sys_slist_remove(&conn->channels, prev,
&chan->node);
}
if (!remove) {
return BT_L2CAP_LE_CHAN(chan);
}
if (!prev) {
conn->channels = chan->_next;
} else {
prev->_next = chan->_next;
}
return BT_L2CAP_LE_CHAN(chan);
prev = &chan->node;
}
return NULL;
}
#endif /* CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL */
static struct bt_l2cap_le_chan *__l2cap_chan(struct bt_conn *conn,
struct bt_l2cap_chan *ch,
enum l2cap_conn_list_action action)
void bt_l2cap_chan_remove(struct bt_conn *conn, struct bt_l2cap_chan *ch)
{
struct bt_l2cap_chan *chan, *prev;
struct bt_l2cap_chan *chan;
sys_snode_t *prev = NULL;
for (chan = conn->channels, prev = NULL; chan;
prev = chan, chan = chan->_next) {
if (chan != ch) {
continue;
SYS_SLIST_FOR_EACH_CONTAINER(&conn->channels, chan, node) {
if (chan == ch) {
sys_slist_remove(&conn->channels, prev, &chan->node);
return;
}
switch (action) {
case BT_L2CAP_CHAN_DETACH:
if (!prev) {
conn->channels = chan->_next;
} else {
prev->_next = chan->_next;
prev = &chan->node;
}
return BT_L2CAP_LE_CHAN(chan);
case BT_L2CAP_CHAN_LOOKUP:
default:
return BT_L2CAP_LE_CHAN(chan);
}
}
return NULL;
}
#if defined(CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL)
@ -286,7 +259,7 @@ static void l2cap_rtx_timeout(struct k_work *work)
BT_ERR("chan %p timeout", chan);
l2cap_detach_chan(chan->chan.conn, &chan->chan);
bt_l2cap_chan_remove(chan->chan.conn, &chan->chan);
bt_l2cap_chan_del(&chan->chan);
}
@ -294,8 +267,7 @@ void bt_l2cap_chan_add(struct bt_conn *conn, struct bt_l2cap_chan *chan,
bt_l2cap_chan_destroy_t destroy)
{
/* Attach channel to the connection */
chan->_next = conn->channels;
conn->channels = chan;
sys_slist_append(&conn->channels, &chan->node);
chan->conn = conn;
chan->destroy = destroy;
@ -305,7 +277,13 @@ void bt_l2cap_chan_add(struct bt_conn *conn, struct bt_l2cap_chan *chan,
static bool l2cap_chan_add(struct bt_conn *conn, struct bt_l2cap_chan *chan,
bt_l2cap_chan_destroy_t destroy)
{
struct bt_l2cap_le_chan *ch = l2cap_chan_alloc_cid(conn, chan);
struct bt_l2cap_le_chan *ch;
#if defined(CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL)
ch = l2cap_chan_alloc_cid(conn, chan);
#else
ch = BT_L2CAP_LE_CHAN(chan);
#endif
if (!ch) {
BT_ERR("Unable to allocate L2CAP CID");
@ -364,20 +342,11 @@ void bt_l2cap_connected(struct bt_conn *conn)
void bt_l2cap_disconnected(struct bt_conn *conn)
{
struct bt_l2cap_chan *chan;
for (chan = conn->channels; chan;) {
struct bt_l2cap_chan *next;
/* prefetch since disconnected callback may cleanup */
next = chan->_next;
struct bt_l2cap_chan *chan, *next;
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&conn->channels, chan, next, node) {
bt_l2cap_chan_del(chan);
chan = next;
}
conn->channels = NULL;
}
static struct net_buf *l2cap_create_le_sig_pdu(uint8_t code, uint8_t ident,
@ -448,7 +417,7 @@ static void l2cap_le_encrypt_change(struct bt_l2cap_chan *chan, uint8_t status)
}
if (status) {
l2cap_detach_chan(chan->conn, chan);
bt_l2cap_chan_remove(chan->conn, chan);
bt_l2cap_chan_del(chan);
return;
}
@ -468,7 +437,7 @@ void bt_l2cap_encrypt_change(struct bt_conn *conn, uint8_t hci_status)
return;
}
for (chan = conn->channels; chan; chan = chan->_next) {
SYS_SLIST_FOR_EACH_CONTAINER(&conn->channels, chan, node) {
#if defined(CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL)
l2cap_le_encrypt_change(chan, hci_status);
#endif
@ -576,6 +545,34 @@ static void le_conn_param_update_req(struct bt_l2cap *l2cap, uint8_t ident,
}
#endif /* CONFIG_BLUETOOTH_CENTRAL */
struct bt_l2cap_chan *bt_l2cap_le_lookup_tx_cid(struct bt_conn *conn,
uint16_t cid)
{
struct bt_l2cap_chan *chan;
SYS_SLIST_FOR_EACH_CONTAINER(&conn->channels, chan, node) {
if (BT_L2CAP_LE_CHAN(chan)->tx.cid == cid) {
return chan;
}
}
return NULL;
}
struct bt_l2cap_chan *bt_l2cap_le_lookup_rx_cid(struct bt_conn *conn,
uint16_t cid)
{
struct bt_l2cap_chan *chan;
SYS_SLIST_FOR_EACH_CONTAINER(&conn->channels, chan, node) {
if (BT_L2CAP_LE_CHAN(chan)->rx.cid == cid) {
return chan;
}
}
return NULL;
}
#if defined(CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL)
static struct bt_l2cap_server *l2cap_server_lookup_psm(uint16_t psm)
{
@ -806,29 +803,21 @@ rsp:
static struct bt_l2cap_le_chan *l2cap_remove_tx_cid(struct bt_conn *conn,
uint16_t cid)
{
struct bt_l2cap_chan *chan, *prev;
struct bt_l2cap_chan *chan;
sys_snode_t *prev = NULL;
/* Protect fixed channels against accidental removal */
if (!L2CAP_LE_CID_IS_DYN(cid)) {
return NULL;
}
for (chan = conn->channels, prev = NULL; chan;
prev = chan, chan = chan->_next) {
/* get the app's l2cap object wherein this chan is contained */
struct bt_l2cap_le_chan *ch = BT_L2CAP_LE_CHAN(chan);
if (ch->tx.cid != cid) {
continue;
SYS_SLIST_FOR_EACH_CONTAINER(&conn->channels, chan, node) {
if (BT_L2CAP_LE_CHAN(chan)->rx.cid == cid) {
sys_slist_remove(&conn->channels, prev, &chan->node);
return BT_L2CAP_LE_CHAN(chan);
}
if (!prev) {
conn->channels = chan->_next;
} else {
prev->_next = chan->_next;
}
return ch;
prev = &chan->node;
}
return NULL;
@ -969,7 +958,7 @@ static void le_conn_rsp(struct bt_l2cap *l2cap, uint8_t ident,
if (l2cap_change_security(chan, result) == 0) {
return;
}
l2cap_detach_chan(conn, &chan->chan);
bt_l2cap_chan_remove(conn, &chan->chan);
default:
bt_l2cap_chan_del(&chan->chan);
}
@ -1564,37 +1553,6 @@ void bt_l2cap_init(void)
}
}
struct bt_l2cap_chan *bt_l2cap_le_lookup_tx_cid(struct bt_conn *conn,
uint16_t cid)
{
struct bt_l2cap_chan *chan;
for (chan = conn->channels; chan; chan = chan->_next) {
struct bt_l2cap_le_chan *ch = BT_L2CAP_LE_CHAN(chan);
if (ch->tx.cid == cid)
return chan;
}
return NULL;
}
struct bt_l2cap_chan *bt_l2cap_le_lookup_rx_cid(struct bt_conn *conn,
uint16_t cid)
{
struct bt_l2cap_chan *chan;
for (chan = conn->channels; chan; chan = chan->_next) {
struct bt_l2cap_le_chan *ch = BT_L2CAP_LE_CHAN(chan);
if (ch->rx.cid == cid) {
return chan;
}
}
return NULL;
}
#if defined(CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL)
static int l2cap_le_connect(struct bt_conn *conn, struct bt_l2cap_le_chan *ch,
uint16_t psm)

View file

@ -60,12 +60,6 @@
*/
#define L2CAP_FEAT_FIXED_CHAN_MASK 0x00000080
/* Wrapper macros making action on channel's list assigned to connection */
#define l2cap_br_lookup_chan(conn, chan) \
__l2cap_chan(conn, chan, BT_L2CAP_CHAN_LOOKUP)
#define l2cap_br_detach_chan(conn, chan) \
__l2cap_chan(conn, chan, BT_L2CAP_CHAN_DETACH)
enum {
/* Connection oriented channels flags */
L2CAP_FLAG_CONN_LCONF_DONE, /* local config accepted by remote */
@ -105,10 +99,8 @@ struct bt_l2cap_chan *bt_l2cap_br_lookup_rx_cid(struct bt_conn *conn,
{
struct bt_l2cap_chan *chan;
for (chan = conn->channels; chan; chan = chan->_next) {
struct bt_l2cap_br_chan *ch = BR_CHAN(chan);
if (ch->rx.cid == cid) {
SYS_SLIST_FOR_EACH_CONTAINER(&conn->channels, chan, node) {
if (BR_CHAN(chan)->rx.cid == cid) {
return chan;
}
}
@ -116,15 +108,13 @@ struct bt_l2cap_chan *bt_l2cap_br_lookup_rx_cid(struct bt_conn *conn,
return NULL;
}
static struct bt_l2cap_chan *bt_l2cap_br_lookup_tx_cid(struct bt_conn *conn,
struct bt_l2cap_chan *bt_l2cap_br_lookup_tx_cid(struct bt_conn *conn,
uint16_t cid)
{
struct bt_l2cap_chan *chan;
for (chan = conn->channels; chan; chan = chan->_next) {
struct bt_l2cap_br_chan *ch = BR_CHAN(chan);
if (ch->tx.cid == cid) {
SYS_SLIST_FOR_EACH_CONTAINER(&conn->channels, chan, node) {
if (BR_CHAN(chan)->tx.cid == cid) {
return chan;
}
}
@ -160,40 +150,9 @@ l2cap_br_chan_alloc_cid(struct bt_conn *conn, struct bt_l2cap_chan *chan)
return NULL;
}
static struct bt_l2cap_br_chan *__l2cap_chan(struct bt_conn *conn,
struct bt_l2cap_chan *ch,
enum l2cap_conn_list_action action)
{
struct bt_l2cap_chan *chan, *prev;
for (chan = conn->channels, prev = NULL; chan;
prev = chan, chan = chan->_next) {
if (chan != ch) {
continue;
}
switch (action) {
case BT_L2CAP_CHAN_DETACH:
if (!prev) {
conn->channels = chan->_next;
} else {
prev->_next = chan->_next;
}
return BR_CHAN(chan);
case BT_L2CAP_CHAN_LOOKUP:
default:
return BR_CHAN(chan);
}
}
return NULL;
}
static void l2cap_br_chan_cleanup(struct bt_l2cap_chan *chan)
{
l2cap_br_detach_chan(chan->conn, chan);
bt_l2cap_chan_remove(chan->conn, chan);
bt_l2cap_chan_del(chan);
}
@ -1090,29 +1049,21 @@ send_rsp:
static struct bt_l2cap_br_chan *l2cap_br_remove_tx_cid(struct bt_conn *conn,
uint16_t cid)
{
struct bt_l2cap_chan *chan, *prev;
struct bt_l2cap_chan *chan;
sys_snode_t *prev = NULL;
/* Protect fixed channels against accidental removal */
if (!L2CAP_BR_CID_IS_DYN(cid)) {
return NULL;
}
for (chan = conn->channels, prev = NULL; chan;
prev = chan, chan = chan->_next) {
/* get the app's l2cap object wherein this chan is contained */
struct bt_l2cap_br_chan *ch = BR_CHAN(chan);
if (ch->tx.cid != cid) {
continue;
SYS_SLIST_FOR_EACH_CONTAINER(&conn->channels, chan, node) {
if (BR_CHAN(chan)->rx.cid == cid) {
sys_slist_remove(&conn->channels, prev, &chan->node);
return BR_CHAN(chan);
}
if (!prev) {
conn->channels = chan->_next;
} else {
prev->_next = chan->_next;
}
return ch;
prev = &chan->node;
}
return NULL;
@ -1518,7 +1469,7 @@ void l2cap_br_encrypt_change(struct bt_conn *conn, uint8_t hci_status)
{
struct bt_l2cap_chan *chan;
for (chan = conn->channels; chan; chan = chan->_next) {
SYS_SLIST_FOR_EACH_CONTAINER(&conn->channels, chan, node) {
l2cap_br_conn_pend(chan, hci_status);
if (chan->ops && chan->ops->encrypt_change) {

View file

@ -215,6 +215,9 @@ void bt_l2cap_disconnected(struct bt_conn *conn);
void bt_l2cap_chan_add(struct bt_conn *conn, struct bt_l2cap_chan *chan,
bt_l2cap_chan_destroy_t destroy);
/* Remove channel from the connection */
void bt_l2cap_chan_remove(struct bt_conn *conn, struct bt_l2cap_chan *chan);
/* Delete channel */
void bt_l2cap_chan_del(struct bt_l2cap_chan *chan);