Skip to content

Commit fb5845a

Browse files
jori-nordiccfriedt
authored andcommitted
Bluetooth: host: copy fragment data at the last minute
Only copy the data from the 'parent' buf into the segment buf if we successfully acquired the HCI semaphore (ie there are available controller buffers). This way we avoid pulling and pushing back the data in the case where there aren't any controller buffers available. Signed-off-by: Jonathan Rico <jonathan.rico@nordicsemi.no> (cherry picked from commit ca51439)
1 parent c0d6fad commit fb5845a

File tree

1 file changed

+49
-51
lines changed

1 file changed

+49
-51
lines changed

subsys/bluetooth/host/conn.c

Lines changed: 49 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -471,33 +471,32 @@ static int send_iso(struct bt_conn *conn, struct net_buf *buf, uint8_t flags)
471471
return bt_send(buf);
472472
}
473473

474-
static int send_frag(struct bt_conn *conn, struct net_buf *buf, uint8_t flags,
475-
bool always_consume)
474+
static inline uint16_t conn_mtu(struct bt_conn *conn)
475+
{
476+
#if defined(CONFIG_BT_BREDR)
477+
if (conn->type == BT_CONN_TYPE_BR || !bt_dev.le.acl_mtu) {
478+
return bt_dev.br.mtu;
479+
}
480+
#endif /* CONFIG_BT_BREDR */
481+
#if defined(CONFIG_BT_ISO)
482+
if (conn->type == BT_CONN_TYPE_ISO && bt_dev.le.iso_mtu) {
483+
return bt_dev.le.iso_mtu;
484+
}
485+
#endif /* CONFIG_BT_ISO */
486+
#if defined(CONFIG_BT_CONN)
487+
return bt_dev.le.acl_mtu;
488+
#else
489+
return 0;
490+
#endif /* CONFIG_BT_CONN */
491+
}
492+
493+
static int do_send_frag(struct bt_conn *conn, struct net_buf *buf, uint8_t flags)
476494
{
477495
struct bt_conn_tx *tx = tx_data(buf)->tx;
478-
uint32_t *pending_no_cb;
496+
uint32_t *pending_no_cb = NULL;
479497
unsigned int key;
480498
int err = 0;
481499

482-
/* Check if the controller can accept ACL packets */
483-
if (k_sem_take(bt_conn_get_pkts(conn), K_NO_WAIT)) {
484-
/* not `goto fail`, we don't want to free the tx context: in the
485-
* case where it is the original buffer, it will contain the
486-
* callback ptr.
487-
*/
488-
BT_DBG("no CTLR bufs");
489-
return -ENOBUFS;
490-
}
491-
492-
if (flags == FRAG_SINGLE || flags == FRAG_END) {
493-
/* De-queue the buffer now that we know we can send it.
494-
* Only applies if the buffer to be sent is the original buffer,
495-
* and not one of its fragments.
496-
* This buffer was fetched from the FIFO using a peek operation.
497-
*/
498-
buf = net_buf_get(&conn->tx_queue, K_NO_WAIT);
499-
}
500-
501500
/* Check for disconnection while waiting for pkts_sem */
502501
if (conn->state != BT_CONN_CONNECTED) {
503502
err = -ENOTCONN;
@@ -564,35 +563,41 @@ static int send_frag(struct bt_conn *conn, struct net_buf *buf, uint8_t flags,
564563
tx_free(tx);
565564
}
566565

567-
if (always_consume) {
568-
net_buf_unref(buf);
569-
}
570566
return err;
571567
}
572568

573-
static inline uint16_t conn_mtu(struct bt_conn *conn)
569+
static int send_frag(struct bt_conn *conn,
570+
struct net_buf *buf, struct net_buf *frag,
571+
uint8_t flags)
574572
{
575-
#if defined(CONFIG_BT_BREDR)
576-
if (conn->type == BT_CONN_TYPE_BR || !bt_dev.le.acl_mtu) {
577-
return bt_dev.br.mtu;
573+
/* Check if the controller can accept ACL packets */
574+
if (k_sem_take(bt_conn_get_pkts(conn), K_NO_WAIT)) {
575+
BT_DBG("no controller bufs");
576+
return -ENOBUFS;
578577
}
579-
#endif /* CONFIG_BT_BREDR */
580-
#if defined(CONFIG_BT_ISO)
581-
if (conn->type == BT_CONN_TYPE_ISO && bt_dev.le.iso_mtu) {
582-
return bt_dev.le.iso_mtu;
578+
579+
/* Add the data to the buffer */
580+
if (frag) {
581+
uint16_t frag_len = MIN(conn_mtu(conn), net_buf_tailroom(frag));
582+
583+
net_buf_add_mem(frag, buf->data, frag_len);
584+
net_buf_pull(buf, frag_len);
585+
} else {
586+
/* De-queue the buffer now that we know we can send it.
587+
* Only applies if the buffer to be sent is the original buffer,
588+
* and not one of its fragments.
589+
* This buffer was fetched from the FIFO using a peek operation.
590+
*/
591+
buf = net_buf_get(&conn->tx_queue, K_NO_WAIT);
592+
frag = buf;
583593
}
584-
#endif /* CONFIG_BT_ISO */
585-
#if defined(CONFIG_BT_CONN)
586-
return bt_dev.le.acl_mtu;
587-
#else
588-
return 0;
589-
#endif /* CONFIG_BT_CONN */
594+
595+
return do_send_frag(conn, frag, flags);
590596
}
591597

592598
static struct net_buf *create_frag(struct bt_conn *conn, struct net_buf *buf)
593599
{
594600
struct net_buf *frag;
595-
uint16_t frag_len;
596601

597602
switch (conn->type) {
598603
#if defined(CONFIG_BT_ISO)
@@ -618,11 +623,6 @@ static struct net_buf *create_frag(struct bt_conn *conn, struct net_buf *buf)
618623
tx_data(frag)->tx = NULL;
619624
tx_data(frag)->is_cont = false;
620625

621-
frag_len = MIN(conn_mtu(conn), net_buf_tailroom(frag));
622-
623-
net_buf_add_mem(frag, buf->data, frag_len);
624-
net_buf_pull(buf, frag_len);
625-
626626
return frag;
627627
}
628628

@@ -637,13 +637,13 @@ static int send_buf(struct bt_conn *conn, struct net_buf *buf)
637637
/* Send directly if the packet fits the ACL MTU */
638638
if (buf->len <= conn_mtu(conn) && !tx_data(buf)->is_cont) {
639639
BT_DBG("send single");
640-
return send_frag(conn, buf, FRAG_SINGLE, false);
640+
return send_frag(conn, buf, NULL, FRAG_SINGLE);
641641
}
642642

643643
BT_DBG("start fragmenting");
644644
/*
645645
* Send the fragments. For the last one simply use the original
646-
* buffer (which works since we've used net_buf_pull on it.
646+
* buffer (which works since we've used net_buf_pull on it).
647647
*/
648648
flags = FRAG_START;
649649
if (tx_data(buf)->is_cont) {
@@ -656,12 +656,10 @@ static int send_buf(struct bt_conn *conn, struct net_buf *buf)
656656
return -ENOMEM;
657657
}
658658

659-
err = send_frag(conn, frag, flags, false);
659+
err = send_frag(conn, buf, frag, flags);
660660
if (err) {
661661
BT_DBG("%p failed, mark as existing frag", buf);
662662
tx_data(buf)->is_cont = flags != FRAG_START;
663-
/* Put the frag back into the original buffer */
664-
net_buf_push_mem(buf, frag->data, frag->len);
665663
net_buf_unref(frag);
666664
return err;
667665
}
@@ -671,7 +669,7 @@ static int send_buf(struct bt_conn *conn, struct net_buf *buf)
671669

672670
BT_DBG("last frag");
673671
tx_data(buf)->is_cont = true;
674-
return send_frag(conn, buf, FRAG_END, false);
672+
return send_frag(conn, buf, NULL, FRAG_END);
675673
}
676674

677675
static struct k_poll_signal conn_change =

0 commit comments

Comments
 (0)