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; struct bt_conn *conn;
/** Channel operations reference */ /** Channel operations reference */
struct bt_l2cap_chan_ops *ops; struct bt_l2cap_chan_ops *ops;
struct bt_l2cap_chan *_next; sys_snode_t node;
bt_l2cap_chan_destroy_t destroy; bt_l2cap_chan_destroy_t destroy;
/* Response Timeout eXpired (RTX) timer */ /* Response Timeout eXpired (RTX) timer */
struct k_delayed_work rtx_work; 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_fifo_init(&conn->tx_queue);
k_poll_signal(&conn_change, 0); k_poll_signal(&conn_change, 0);
sys_slist_init(&conn->channels);
bt_l2cap_connected(conn); bt_l2cap_connected(conn);
notify_connected(conn); notify_connected(conn);
break; break;

View file

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

View file

@ -53,12 +53,6 @@
#define l2cap_remove_ident(conn, ident) __l2cap_lookup_ident(conn, ident, true) #define l2cap_remove_ident(conn, ident) __l2cap_lookup_ident(conn, ident, true)
#endif /* CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL */ #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; static struct bt_l2cap_fixed_chan *le_channels;
#if defined(CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL) #if defined(CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL)
static struct bt_l2cap_server *servers; 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; le_channels = chan;
} }
#if defined(CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL)
static struct bt_l2cap_le_chan *l2cap_chan_alloc_cid(struct bt_conn *conn, static struct bt_l2cap_le_chan *l2cap_chan_alloc_cid(struct bt_conn *conn,
struct bt_l2cap_chan *chan) 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; return NULL;
} }
#if defined(CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL)
static struct bt_l2cap_le_chan * static struct bt_l2cap_le_chan *
__l2cap_lookup_ident(struct bt_conn *conn, uint16_t ident, bool remove) __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; SYS_SLIST_FOR_EACH_CONTAINER(&conn->channels, chan, node) {
prev = chan, chan = chan->_next) { if (chan->ident == ident) {
if (chan->ident != ident) { if (remove) {
continue; sys_slist_remove(&conn->channels, prev,
} &chan->node);
}
if (!remove) {
return BT_L2CAP_LE_CHAN(chan); return BT_L2CAP_LE_CHAN(chan);
} }
if (!prev) { prev = &chan->node;
conn->channels = chan->_next;
} else {
prev->_next = chan->_next;
}
return BT_L2CAP_LE_CHAN(chan);
} }
return NULL; return NULL;
} }
#endif /* CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL */ #endif /* CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL */
static struct bt_l2cap_le_chan *__l2cap_chan(struct bt_conn *conn, void bt_l2cap_chan_remove(struct bt_conn *conn, struct bt_l2cap_chan *ch)
struct bt_l2cap_chan *ch,
enum l2cap_conn_list_action action)
{ {
struct bt_l2cap_chan *chan, *prev; struct bt_l2cap_chan *chan;
sys_snode_t *prev = NULL;
for (chan = conn->channels, prev = NULL; chan; SYS_SLIST_FOR_EACH_CONTAINER(&conn->channels, chan, node) {
prev = chan, chan = chan->_next) { if (chan == ch) {
if (chan != ch) { sys_slist_remove(&conn->channels, prev, &chan->node);
continue; return;
} }
switch (action) { prev = &chan->node;
case BT_L2CAP_CHAN_DETACH:
if (!prev) {
conn->channels = chan->_next;
} else {
prev->_next = chan->_next;
}
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) #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); 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); 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) bt_l2cap_chan_destroy_t destroy)
{ {
/* Attach channel to the connection */ /* Attach channel to the connection */
chan->_next = conn->channels; sys_slist_append(&conn->channels, &chan->node);
conn->channels = chan;
chan->conn = conn; chan->conn = conn;
chan->destroy = destroy; 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, static bool l2cap_chan_add(struct bt_conn *conn, struct bt_l2cap_chan *chan,
bt_l2cap_chan_destroy_t destroy) 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) { if (!ch) {
BT_ERR("Unable to allocate L2CAP CID"); 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) void bt_l2cap_disconnected(struct bt_conn *conn)
{ {
struct bt_l2cap_chan *chan; struct bt_l2cap_chan *chan, *next;
for (chan = conn->channels; chan;) {
struct bt_l2cap_chan *next;
/* prefetch since disconnected callback may cleanup */
next = chan->_next;
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&conn->channels, chan, next, node) {
bt_l2cap_chan_del(chan); 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, 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) { if (status) {
l2cap_detach_chan(chan->conn, chan); bt_l2cap_chan_remove(chan->conn, chan);
bt_l2cap_chan_del(chan); bt_l2cap_chan_del(chan);
return; return;
} }
@ -468,7 +437,7 @@ void bt_l2cap_encrypt_change(struct bt_conn *conn, uint8_t hci_status)
return; 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) #if defined(CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL)
l2cap_le_encrypt_change(chan, hci_status); l2cap_le_encrypt_change(chan, hci_status);
#endif #endif
@ -576,6 +545,34 @@ static void le_conn_param_update_req(struct bt_l2cap *l2cap, uint8_t ident,
} }
#endif /* CONFIG_BLUETOOTH_CENTRAL */ #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) #if defined(CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL)
static struct bt_l2cap_server *l2cap_server_lookup_psm(uint16_t psm) 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, static struct bt_l2cap_le_chan *l2cap_remove_tx_cid(struct bt_conn *conn,
uint16_t cid) 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 */ /* Protect fixed channels against accidental removal */
if (!L2CAP_LE_CID_IS_DYN(cid)) { if (!L2CAP_LE_CID_IS_DYN(cid)) {
return NULL; return NULL;
} }
for (chan = conn->channels, prev = NULL; chan; SYS_SLIST_FOR_EACH_CONTAINER(&conn->channels, chan, node) {
prev = chan, chan = chan->_next) { if (BT_L2CAP_LE_CHAN(chan)->rx.cid == cid) {
/* get the app's l2cap object wherein this chan is contained */ sys_slist_remove(&conn->channels, prev, &chan->node);
struct bt_l2cap_le_chan *ch = BT_L2CAP_LE_CHAN(chan); return BT_L2CAP_LE_CHAN(chan);
if (ch->tx.cid != cid) {
continue;
} }
if (!prev) { prev = &chan->node;
conn->channels = chan->_next;
} else {
prev->_next = chan->_next;
}
return ch;
} }
return NULL; 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) { if (l2cap_change_security(chan, result) == 0) {
return; return;
} }
l2cap_detach_chan(conn, &chan->chan); bt_l2cap_chan_remove(conn, &chan->chan);
default: default:
bt_l2cap_chan_del(&chan->chan); 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) #if defined(CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL)
static int l2cap_le_connect(struct bt_conn *conn, struct bt_l2cap_le_chan *ch, static int l2cap_le_connect(struct bt_conn *conn, struct bt_l2cap_le_chan *ch,
uint16_t psm) uint16_t psm)

View file

@ -60,12 +60,6 @@
*/ */
#define L2CAP_FEAT_FIXED_CHAN_MASK 0x00000080 #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 { enum {
/* Connection oriented channels flags */ /* Connection oriented channels flags */
L2CAP_FLAG_CONN_LCONF_DONE, /* local config accepted by remote */ 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; struct bt_l2cap_chan *chan;
for (chan = conn->channels; chan; chan = chan->_next) { SYS_SLIST_FOR_EACH_CONTAINER(&conn->channels, chan, node) {
struct bt_l2cap_br_chan *ch = BR_CHAN(chan); if (BR_CHAN(chan)->rx.cid == cid) {
if (ch->rx.cid == cid) {
return chan; return chan;
} }
} }
@ -116,15 +108,13 @@ struct bt_l2cap_chan *bt_l2cap_br_lookup_rx_cid(struct bt_conn *conn,
return NULL; 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) uint16_t cid)
{ {
struct bt_l2cap_chan *chan; struct bt_l2cap_chan *chan;
for (chan = conn->channels; chan; chan = chan->_next) { SYS_SLIST_FOR_EACH_CONTAINER(&conn->channels, chan, node) {
struct bt_l2cap_br_chan *ch = BR_CHAN(chan); if (BR_CHAN(chan)->tx.cid == cid) {
if (ch->tx.cid == cid) {
return chan; return chan;
} }
} }
@ -160,40 +150,9 @@ l2cap_br_chan_alloc_cid(struct bt_conn *conn, struct bt_l2cap_chan *chan)
return NULL; 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) 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); 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, static struct bt_l2cap_br_chan *l2cap_br_remove_tx_cid(struct bt_conn *conn,
uint16_t cid) 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 */ /* Protect fixed channels against accidental removal */
if (!L2CAP_BR_CID_IS_DYN(cid)) { if (!L2CAP_BR_CID_IS_DYN(cid)) {
return NULL; return NULL;
} }
for (chan = conn->channels, prev = NULL; chan; SYS_SLIST_FOR_EACH_CONTAINER(&conn->channels, chan, node) {
prev = chan, chan = chan->_next) { if (BR_CHAN(chan)->rx.cid == cid) {
/* get the app's l2cap object wherein this chan is contained */ sys_slist_remove(&conn->channels, prev, &chan->node);
struct bt_l2cap_br_chan *ch = BR_CHAN(chan); return BR_CHAN(chan);
if (ch->tx.cid != cid) {
continue;
} }
if (!prev) { prev = &chan->node;
conn->channels = chan->_next;
} else {
prev->_next = chan->_next;
}
return ch;
} }
return NULL; return NULL;
@ -1518,7 +1469,7 @@ void l2cap_br_encrypt_change(struct bt_conn *conn, uint8_t hci_status)
{ {
struct bt_l2cap_chan *chan; 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); l2cap_br_conn_pend(chan, hci_status);
if (chan->ops && chan->ops->encrypt_change) { 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, void bt_l2cap_chan_add(struct bt_conn *conn, struct bt_l2cap_chan *chan,
bt_l2cap_chan_destroy_t destroy); 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 */ /* Delete channel */
void bt_l2cap_chan_del(struct bt_l2cap_chan *chan); void bt_l2cap_chan_del(struct bt_l2cap_chan *chan);