Bluetooth: L2CAP: Make bt_l2cap_send_pdu()

This API replaces `bt_l2cap_send()` and `bt_l2cap_send_cb()`.

The difference is that it takes the `struct bt_l2cap_le_chan` object
directly instead of a connection + CID.

We need the channel object in order to put the PDU on the TX queue. It
is inefficient to do a search for every PDU when the caller knows the
channel object's address and can just pass it down.

Signed-off-by: Jonathan Rico <jonathan.rico@nordicsemi.no>
This commit is contained in:
Jonathan Rico 2024-04-23 10:31:34 +02:00 committed by Alberto Escolar
commit 38820efd8d
5 changed files with 34 additions and 40 deletions

View file

@ -353,7 +353,7 @@ static int chan_send(struct bt_att_chan *chan, struct net_buf *buf)
data->att_chan = chan;
err = bt_l2cap_send(chan->att->conn, BT_L2CAP_CID_ATT, buf);
err = bt_l2cap_send_pdu(&chan->chan, buf, NULL, NULL);
if (err) {
if (err == -ENOBUFS) {
LOG_ERR("Ran out of TX buffers or contexts.");

View file

@ -545,7 +545,10 @@ static struct net_buf *l2cap_create_le_sig_pdu(uint8_t code, uint8_t ident,
*/
static int l2cap_send_sig(struct bt_conn *conn, struct net_buf *buf)
{
int err = bt_l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf);
struct bt_l2cap_chan *ch = bt_l2cap_le_lookup_tx_cid(conn, BT_L2CAP_CID_LE_SIG);
struct bt_l2cap_le_chan *chan = BT_L2CAP_LE_CHAN(ch);
int err = bt_l2cap_send_pdu(chan, buf, NULL, NULL);
if (err) {
net_buf_unref(buf);
@ -771,46 +774,41 @@ static void cancel_data_ready(struct bt_l2cap_le_chan *le_chan)
atomic_set(&le_chan->_pdu_ready_lock, 0);
}
int bt_l2cap_send_cb(struct bt_conn *conn, uint16_t cid, struct net_buf *seg,
bt_conn_tx_cb_t cb, void *user_data)
int bt_l2cap_send_pdu(struct bt_l2cap_le_chan *le_chan, struct net_buf *pdu,
bt_conn_tx_cb_t cb, void *user_data)
{
struct bt_l2cap_hdr *hdr;
LOG_DBG("conn %p cid %u len %zu", conn, cid, seg->len);
LOG_DBG("chan %p len %zu", le_chan, pdu->len);
hdr = net_buf_push(seg, sizeof(*hdr));
hdr->len = sys_cpu_to_le16(seg->len - sizeof(*hdr));
hdr->cid = sys_cpu_to_le16(cid);
hdr = net_buf_push(pdu, sizeof(*hdr));
hdr->len = sys_cpu_to_le16(pdu->len - sizeof(*hdr));
hdr->cid = sys_cpu_to_le16(le_chan->tx.cid);
/* TODO: un-foreach this: ATT, SMP & L2CAP CoC _know_ the channel */
struct bt_l2cap_chan *ch = bt_l2cap_le_lookup_tx_cid(conn, cid);
struct bt_l2cap_le_chan *chan = CONTAINER_OF(ch, struct bt_l2cap_le_chan, chan);
if (seg->ref != 1) {
if (pdu->ref != 1) {
/* The host may alter the buf contents when fragmenting. Higher
* layers cannot expect the buf contents to stay intact. Extra
* refs suggests a silent data corruption would occur if not for
* this error.
*/
LOG_ERR("Expecting 1 ref, got %d", seg->ref);
LOG_ERR("Expecting 1 ref, got %d", pdu->ref);
return -EINVAL;
}
if (seg->user_data_size < sizeof(struct closure)) {
if (pdu->user_data_size < sizeof(struct closure)) {
LOG_DBG("not enough room in user_data %d < %d pool %u",
seg->user_data_size,
pdu->user_data_size,
CONFIG_BT_CONN_TX_USER_DATA_SIZE,
seg->pool_id);
pdu->pool_id);
return -EINVAL;
}
make_closure(seg->user_data, cb, user_data);
make_closure(pdu->user_data, cb, user_data);
LOG_DBG("push: cb %p userdata %p", cb, user_data);
net_buf_put(&chan->_pdu_tx_queue, seg);
net_buf_put(&le_chan->_pdu_tx_queue, pdu);
raise_data_ready(chan); /* tis just a flag */
raise_data_ready(le_chan); /* tis just a flag */
return 0; /* look ma, no failures */
}
@ -2210,8 +2208,7 @@ static int l2cap_chan_le_send_seg(struct bt_l2cap_le_chan *ch, struct net_buf *b
* considered lost, as the lower layers are free to re-use it as they
* see fit. Reading from it later is obviously a no-no.
*/
err = bt_l2cap_send_cb(ch->chan.conn, ch->tx.cid, seg,
cb, UINT_TO_POINTER(ch->tx.cid));
err = bt_l2cap_send_pdu(ch, seg, cb, UINT_TO_POINTER(ch->tx.cid));
/* The only possible error is enotconn, in that case the data will be discarded anyways */
__ASSERT_NO_MSG(!err || err == -ENOTCONN);
@ -2221,7 +2218,7 @@ static int l2cap_chan_le_send_seg(struct bt_l2cap_le_chan *ch, struct net_buf *b
atomic_inc(&ch->tx.credits);
/* The host takes ownership of the reference in seg when
* bt_l2cap_send_cb is successful. The call returned an error,
* bt_l2cap_send_pdu is successful. The call returned an error,
* so we must get rid of the reference that was taken above.
*/
LOG_DBG("unref %p (%s)", seg,
@ -3365,8 +3362,7 @@ int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf)
}
/* Sending over static channels is not supported by this fn. Use
* `bt_l2cap_send()` if external to this file, or `l2cap_send` if
* internal.
* `bt_l2cap_send_pdu()` instead.
*/
if (IS_ENABLED(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL)) {
struct bt_l2cap_le_chan *le_chan = BT_L2CAP_LE_CHAN(chan);

View file

@ -214,14 +214,8 @@ struct net_buf *bt_l2cap_create_pdu_timeout(struct net_buf_pool *pool,
*
* Buffer ownership is transferred to stack in case of success.
*/
int bt_l2cap_send_cb(struct bt_conn *conn, uint16_t cid, struct net_buf *buf,
bt_conn_tx_cb_t cb, void *user_data);
static inline int bt_l2cap_send(struct bt_conn *conn, uint16_t cid,
struct net_buf *buf)
{
return bt_l2cap_send_cb(conn, cid, buf, NULL, NULL);
}
int bt_l2cap_send_pdu(struct bt_l2cap_le_chan *le_chan, struct net_buf *pdu,
bt_conn_tx_cb_t cb, void *user_data);
/* Receive a new L2CAP PDU from a connection */
void bt_l2cap_recv(struct bt_conn *conn, struct net_buf *buf, bool complete);
@ -254,4 +248,6 @@ void bt_l2cap_register_ecred_cb(const struct bt_l2cap_ecred_cb *cb);
struct bt_l2cap_server *bt_l2cap_server_lookup_psm(uint16_t psm);
/* Pull data from the L2CAP layer */
struct net_buf *l2cap_data_pull(struct bt_conn *conn, size_t amount);
struct net_buf *l2cap_data_pull(struct bt_conn *conn,
size_t amount,
size_t *length);

View file

@ -1750,7 +1750,9 @@ static void smp_timeout(struct k_work *work)
static void smp_send(struct bt_smp *smp, struct net_buf *buf,
bt_conn_tx_cb_t cb, void *user_data)
{
int err = bt_l2cap_send_cb(smp->chan.chan.conn, BT_L2CAP_CID_SMP, buf, cb, NULL);
__ASSERT_NO_MSG(user_data == NULL);
int err = bt_l2cap_send_pdu(&smp->chan, buf, cb, NULL);
if (err) {
if (err == -ENOBUFS) {
@ -1805,7 +1807,7 @@ static int smp_error(struct bt_smp *smp, uint8_t reason)
rsp->reason = reason;
/* SMP timer is not restarted for PairingFailed so don't use smp_send */
if (bt_l2cap_send(smp->chan.chan.conn, BT_L2CAP_CID_SMP, buf)) {
if (bt_l2cap_send_pdu(&smp->chan, buf, NULL, NULL)) {
net_buf_unref(buf);
}
@ -2824,7 +2826,7 @@ static int smp_send_security_req(struct bt_conn *conn)
req->auth_req = get_auth(smp, BT_SMP_AUTH_DEFAULT);
/* SMP timer is not restarted for SecRequest so don't use smp_send */
err = bt_l2cap_send(conn, BT_L2CAP_CID_SMP, req_buf);
err = bt_l2cap_send_pdu(&smp->chan, req_buf, NULL, NULL);
if (err) {
net_buf_unref(req_buf);
return err;

View file

@ -41,7 +41,7 @@ int bt_smp_sign(struct bt_conn *conn, struct net_buf *buf)
static int bt_smp_recv(struct bt_l2cap_chan *chan, struct net_buf *req_buf)
{
struct bt_conn *conn = chan->conn;
struct bt_l2cap_le_chan *le_chan = BT_L2CAP_LE_CHAN(chan);
struct bt_smp_pairing_fail *rsp;
struct bt_smp_hdr *hdr;
struct net_buf *buf;
@ -63,7 +63,7 @@ static int bt_smp_recv(struct bt_l2cap_chan *chan, struct net_buf *req_buf)
rsp = net_buf_add(buf, sizeof(*rsp));
rsp->reason = BT_SMP_ERR_PAIRING_NOTSUPP;
if (bt_l2cap_send(conn, BT_L2CAP_CID_SMP, buf)) {
if (bt_l2cap_send_pdu(le_chan, buf, NULL, NULL)) {
net_buf_unref(buf);
}