Skip to content

Commit 81d524d

Browse files
jori-nordiccarlescufi
authored andcommitted
Bluetooth: L2CAP: always send from workqueue
Always pull from the channel queue from the system workqueue context. This simplifies debugging. This also allows us to remove `sent` from the metadata struct. Signed-off-by: Jonathan Rico <[email protected]>
1 parent 2dcb91a commit 81d524d

2 files changed

Lines changed: 19 additions & 45 deletions

File tree

include/zephyr/bluetooth/l2cap.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan);
593593
* @note Buffer ownership is transferred to the stack in case of success, in
594594
* case of an error the caller retains the ownership of the buffer.
595595
*
596-
* @return Bytes sent in case of success or negative value in case of error.
596+
* @return 0 in case of success or negative value in case of error.
597597
*/
598598
int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf);
599599

subsys/bluetooth/host/l2cap.c

Lines changed: 18 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ NET_BUF_POOL_FIXED_DEFINE(disc_pool, 1,
7171
#define l2cap_remove_ident(conn, ident) __l2cap_lookup_ident(conn, ident, true)
7272

7373
struct l2cap_tx_meta_data {
74-
int sent;
7574
uint16_t cid;
7675
bt_conn_tx_cb_t cb;
7776
void *user_data;
@@ -924,32 +923,31 @@ static struct net_buf *l2cap_chan_le_get_tx_buf(struct bt_l2cap_le_chan *ch)
924923
}
925924

926925
static int l2cap_chan_le_send_sdu(struct bt_l2cap_le_chan *ch,
927-
struct net_buf **buf, uint16_t sent);
926+
struct net_buf **buf);
928927

929928
static void l2cap_chan_tx_process(struct k_work *work)
930929
{
931930
struct bt_l2cap_le_chan *ch;
932931
struct net_buf *buf;
932+
int ret;
933933

934934
ch = CONTAINER_OF(k_work_delayable_from_work(work), struct bt_l2cap_le_chan, tx_work);
935935

936936
/* Resume tx in case there are buffers in the queue */
937937
while ((buf = l2cap_chan_le_get_tx_buf(ch))) {
938-
int sent = l2cap_tx_meta_data(buf)->sent;
939-
940-
LOG_DBG("buf %p sent %u", buf, sent);
938+
LOG_DBG("buf %p", buf);
941939

942-
sent = l2cap_chan_le_send_sdu(ch, &buf, sent);
943-
if (sent < 0) {
944-
if (sent == -EAGAIN) {
940+
ret = l2cap_chan_le_send_sdu(ch, &buf);
941+
if (ret < 0) {
942+
if (ret == -EAGAIN) {
945943
ch->tx_buf = buf;
946944
/* If we don't reschedule, and the app doesn't nudge l2cap (e.g. by
947945
* sending another SDU), the channel will be stuck in limbo. To
948946
* prevent this, we reschedule with a configurable delay.
949947
*/
950948
k_work_schedule(&ch->tx_work, K_MSEC(CONFIG_BT_L2CAP_RESCHED_MS));
951949
} else {
952-
l2cap_tx_buf_destroy(ch->chan.conn, buf, sent);
950+
l2cap_tx_buf_destroy(ch->chan.conn, buf, ret);
953951
}
954952
break;
955953
}
@@ -2060,10 +2058,11 @@ static int l2cap_chan_le_send(struct bt_l2cap_le_chan *ch,
20602058
}
20612059

20622060
static int l2cap_chan_le_send_sdu(struct bt_l2cap_le_chan *ch,
2063-
struct net_buf **buf, uint16_t sent)
2061+
struct net_buf **buf)
20642062
{
20652063
int ret, total_len;
20662064
struct net_buf *frag;
2065+
int sent = 0;
20672066

20682067
total_len = net_buf_frags_len(*buf) + sent;
20692068

@@ -2081,10 +2080,6 @@ static int l2cap_chan_le_send_sdu(struct bt_l2cap_le_chan *ch,
20812080

20822081
ret = l2cap_chan_le_send(ch, frag, 0);
20832082
if (ret < 0) {
2084-
if (ret == -EAGAIN) {
2085-
/* Store sent data into user_data */
2086-
l2cap_tx_meta_data(frag)->sent = sent;
2087-
}
20882083
*buf = frag;
20892084
return ret;
20902085
}
@@ -3119,13 +3114,13 @@ int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan)
31193114
static int bt_l2cap_dyn_chan_send(struct bt_l2cap_le_chan *le_chan, struct net_buf *buf)
31203115
{
31213116
struct l2cap_tx_meta_data *data;
3122-
void *old_user_data = l2cap_tx_meta_data(buf);
3123-
uint16_t sdu_len;
3124-
int err;
3117+
uint16_t sdu_len = net_buf_frags_len(buf);
31253118

3126-
sdu_len = net_buf_frags_len(buf);
3119+
LOG_DBG("chan %p buf %p", le_chan, buf);
31273120

31283121
if (sdu_len > le_chan->tx.mtu) {
3122+
LOG_ERR("attempt to send %u bytes on %u MTU chan",
3123+
sdu_len, le_chan->tx.mtu);
31293124
return -EMSGSIZE;
31303125
}
31313126

@@ -3165,38 +3160,17 @@ static int bt_l2cap_dyn_chan_send(struct bt_l2cap_le_chan *le_chan, struct net_b
31653160
*/
31663161
net_buf_push_le16(buf, sdu_len);
31673162

3168-
data->sent = 0;
3163+
/* Put buffer on TX queue */
31693164
data->cid = le_chan->tx.cid;
31703165
data->cb = NULL;
31713166
data->user_data = NULL;
31723167
l2cap_tx_meta_data(buf) = data;
3168+
net_buf_put(&le_chan->tx_queue, buf);
31733169

3174-
/* Queue if there are pending segments left from previous packet or
3175-
* there are no credits available.
3176-
*/
3177-
if (le_chan->tx_buf || !k_fifo_is_empty(&le_chan->tx_queue) ||
3178-
!atomic_get(&le_chan->tx.credits)) {
3179-
l2cap_tx_meta_data(buf)->sent = 0;
3180-
net_buf_put(&le_chan->tx_queue, buf);
3181-
k_work_reschedule(&le_chan->tx_work, K_NO_WAIT);
3182-
return 0;
3183-
}
3184-
3185-
err = l2cap_chan_le_send_sdu(le_chan, &buf, 0);
3186-
if (err < 0) {
3187-
if (err == -EAGAIN && l2cap_tx_meta_data(buf)->sent) {
3188-
/* Queue buffer if at least one segment could be sent */
3189-
net_buf_put(&le_chan->tx_queue, buf);
3190-
return l2cap_tx_meta_data(buf)->sent;
3191-
}
3192-
3193-
LOG_ERR("failed to send message %d", err);
3170+
/* Always process the queue in the same context */
3171+
k_work_reschedule(&le_chan->tx_work, K_NO_WAIT);
31943172

3195-
l2cap_tx_meta_data(buf) = old_user_data;
3196-
free_tx_meta_data(data);
3197-
}
3198-
3199-
return err;
3173+
return 0;
32003174
}
32013175

32023176
int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf)

0 commit comments

Comments
 (0)