Skip to content

Commit

Permalink
Bluetooth: L2CAP: Derive rx credits from MTU and MPS
Browse files Browse the repository at this point in the history
Give enough rx credits for a full packet instead of using an arbitrary
number which may not be enough depending on the MTU and MPS which can
cause interruptions while waiting for more credits, also remove
debugfs entry for l2cap_le_max_credits.

With these changes the credits are restored after each SDU is received
instead of using fixed threshold, this way it is garanteed that there
will always be enough credits to send a packet without waiting more
credits to arrive.

Signed-off-by: Luiz Augusto von Dentz <[email protected]>
Signed-off-by: Marcel Holtmann <[email protected]>
  • Loading branch information
Vudentz authored and holtmann committed Sep 27, 2018
1 parent fe14931 commit 96cd8ea
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 17 deletions.
2 changes: 0 additions & 2 deletions include/net/bluetooth/l2cap.h
Original file line number Diff line number Diff line change
Expand Up @@ -455,8 +455,6 @@ struct l2cap_conn_param_update_rsp {
#define L2CAP_CONN_PARAM_ACCEPTED 0x0000
#define L2CAP_CONN_PARAM_REJECTED 0x0001

#define L2CAP_LE_MAX_CREDITS 10

struct l2cap_le_conn_req {
__le16 psm;
__le16 scid;
Expand Down
42 changes: 27 additions & 15 deletions net/bluetooth/l2cap_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN | L2CAP_FEAT_UCD;
static LIST_HEAD(chan_list);
static DEFINE_RWLOCK(chan_list_lock);

static u16 le_max_credits = L2CAP_LE_MAX_CREDITS;

static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
u8 code, u8 ident, u16 dlen, void *data);
static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
Expand Down Expand Up @@ -518,9 +516,10 @@ static void l2cap_le_flowctl_init(struct l2cap_chan *chan)
chan->sdu_last_frag = NULL;
chan->sdu_len = 0;
chan->tx_credits = 0;
chan->rx_credits = le_max_credits;
/* Derive MPS from connection MTU to stop HCI fragmentation */
chan->mps = min_t(u16, chan->imtu, chan->conn->mtu - L2CAP_HDR_SIZE);
/* Give enough credits for a full packet */
chan->rx_credits = (chan->imtu / chan->mps) + 1;

skb_queue_head_init(&chan->tx_q);
}
Expand Down Expand Up @@ -6702,13 +6701,10 @@ static void l2cap_chan_le_send_credits(struct l2cap_chan *chan)
struct l2cap_le_credits pkt;
u16 return_credits;

/* We return more credits to the sender only after the amount of
* credits falls below half of the initial amount.
*/
if (chan->rx_credits >= (le_max_credits + 1) / 2)
return;
return_credits = ((chan->imtu / chan->mps) + 1) - chan->rx_credits;

return_credits = le_max_credits - chan->rx_credits;
if (!return_credits)
return;

BT_DBG("chan %p returning %u credits to sender", chan, return_credits);

Expand All @@ -6722,6 +6718,21 @@ static void l2cap_chan_le_send_credits(struct l2cap_chan *chan)
l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CREDITS, sizeof(pkt), &pkt);
}

static int l2cap_le_recv(struct l2cap_chan *chan, struct sk_buff *skb)
{
int err;

BT_DBG("SDU reassemble complete: chan %p skb->len %u", chan, skb->len);

/* Wait recv to confirm reception before updating the credits */
err = chan->ops->recv(chan, skb);

/* Update credits whenever an SDU is received */
l2cap_chan_le_send_credits(chan);

return err;
}

static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
{
int err;
Expand All @@ -6740,7 +6751,11 @@ static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
chan->rx_credits--;
BT_DBG("rx_credits %u -> %u", chan->rx_credits + 1, chan->rx_credits);

l2cap_chan_le_send_credits(chan);
/* Update if remote had run out of credits, this should only happens
* if the remote is not using the entire MPS.
*/
if (!chan->rx_credits)
l2cap_chan_le_send_credits(chan);

err = 0;

Expand All @@ -6766,7 +6781,7 @@ static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
}

if (skb->len == sdu_len)
return chan->ops->recv(chan, skb);
return l2cap_le_recv(chan, skb);

chan->sdu = skb;
chan->sdu_len = sdu_len;
Expand All @@ -6788,7 +6803,7 @@ static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
skb = NULL;

if (chan->sdu->len == chan->sdu_len) {
err = chan->ops->recv(chan, chan->sdu);
err = l2cap_le_recv(chan, chan->sdu);
if (!err) {
chan->sdu = NULL;
chan->sdu_last_frag = NULL;
Expand Down Expand Up @@ -7647,9 +7662,6 @@ int __init l2cap_init(void)
l2cap_debugfs = debugfs_create_file("l2cap", 0444, bt_debugfs,
NULL, &l2cap_debugfs_fops);

debugfs_create_u16("l2cap_le_max_credits", 0644, bt_debugfs,
&le_max_credits);

return 0;
}

Expand Down

0 comments on commit 96cd8ea

Please sign in to comment.