summaryrefslogtreecommitdiffstats
path: root/net/bluetooth/l2cap_core.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 21:00:51 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 21:00:51 +0000
commit6d03a247468059b0e59c821ef39e6762d4d6fc30 (patch)
tree17b9c00de2c62e68c965c742cdbc206f77a375da /net/bluetooth/l2cap_core.c
parentReleasing progress-linux version 6.8.12-1~progress7.99u1. (diff)
downloadlinux-6d03a247468059b0e59c821ef39e6762d4d6fc30.tar.xz
linux-6d03a247468059b0e59c821ef39e6762d4d6fc30.zip
Merging upstream version 6.9.2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'net/bluetooth/l2cap_core.c')
-rw-r--r--net/bluetooth/l2cap_core.c77
1 files changed, 24 insertions, 53 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 4a633c1b68..3f7a82f10f 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -457,9 +457,6 @@ struct l2cap_chan *l2cap_chan_create(void)
/* Set default lock nesting level */
atomic_set(&chan->nesting, L2CAP_NESTING_NORMAL);
- /* Available receive buffer space is initially unknown */
- chan->rx_avail = -1;
-
write_lock(&chan_list_lock);
list_add(&chan->global_l, &chan_list);
write_unlock(&chan_list_lock);
@@ -541,28 +538,6 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan)
}
EXPORT_SYMBOL_GPL(l2cap_chan_set_defaults);
-static __u16 l2cap_le_rx_credits(struct l2cap_chan *chan)
-{
- size_t sdu_len = chan->sdu ? chan->sdu->len : 0;
-
- if (chan->mps == 0)
- return 0;
-
- /* If we don't know the available space in the receiver buffer, give
- * enough credits for a full packet.
- */
- if (chan->rx_avail == -1)
- return (chan->imtu / chan->mps) + 1;
-
- /* If we know how much space is available in the receive buffer, give
- * out as many credits as would fill the buffer.
- */
- if (chan->rx_avail <= sdu_len)
- return 0;
-
- return DIV_ROUND_UP(chan->rx_avail - sdu_len, chan->mps);
-}
-
static void l2cap_le_flowctl_init(struct l2cap_chan *chan, u16 tx_credits)
{
chan->sdu = NULL;
@@ -571,7 +546,8 @@ static void l2cap_le_flowctl_init(struct l2cap_chan *chan, u16 tx_credits)
chan->tx_credits = tx_credits;
/* Derive MPS from connection MTU to stop HCI fragmentation */
chan->mps = min_t(u16, chan->imtu, chan->conn->mtu - L2CAP_HDR_SIZE);
- chan->rx_credits = l2cap_le_rx_credits(chan);
+ /* Give enough credits for a full packet */
+ chan->rx_credits = (chan->imtu / chan->mps) + 1;
skb_queue_head_init(&chan->tx_q);
}
@@ -583,7 +559,7 @@ static void l2cap_ecred_init(struct l2cap_chan *chan, u16 tx_credits)
/* L2CAP implementations shall support a minimum MPS of 64 octets */
if (chan->mps < L2CAP_ECRED_MIN_MPS) {
chan->mps = L2CAP_ECRED_MIN_MPS;
- chan->rx_credits = l2cap_le_rx_credits(chan);
+ chan->rx_credits = (chan->imtu / chan->mps) + 1;
}
}
@@ -3930,7 +3906,7 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn,
}
static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
- u8 *data, u8 rsp_code)
+ u8 *data, u8 rsp_code, u8 amp_id)
{
struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
struct l2cap_conn_rsp rsp;
@@ -4009,8 +3985,17 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
status = L2CAP_CS_AUTHOR_PEND;
chan->ops->defer(chan);
} else {
- l2cap_state_change(chan, BT_CONNECT2);
- result = L2CAP_CR_PEND;
+ /* Force pending result for AMP controllers.
+ * The connection will succeed after the
+ * physical link is up.
+ */
+ if (amp_id == AMP_ID_BREDR) {
+ l2cap_state_change(chan, BT_CONFIG);
+ result = L2CAP_CR_SUCCESS;
+ } else {
+ l2cap_state_change(chan, BT_CONNECT2);
+ result = L2CAP_CR_PEND;
+ }
status = L2CAP_CS_NO_INFO;
}
} else {
@@ -4075,7 +4060,7 @@ static int l2cap_connect_req(struct l2cap_conn *conn,
mgmt_device_connected(hdev, hcon, NULL, 0);
hci_dev_unlock(hdev);
- l2cap_connect(conn, cmd, data, L2CAP_CONN_RSP);
+ l2cap_connect(conn, cmd, data, L2CAP_CONN_RSP, 0);
return 0;
}
@@ -6528,7 +6513,9 @@ static void l2cap_chan_le_send_credits(struct l2cap_chan *chan)
{
struct l2cap_conn *conn = chan->conn;
struct l2cap_le_credits pkt;
- u16 return_credits = l2cap_le_rx_credits(chan);
+ u16 return_credits;
+
+ return_credits = (chan->imtu / chan->mps) + 1;
if (chan->rx_credits >= return_credits)
return;
@@ -6547,19 +6534,6 @@ static void l2cap_chan_le_send_credits(struct l2cap_chan *chan)
l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CREDITS, sizeof(pkt), &pkt);
}
-void l2cap_chan_rx_avail(struct l2cap_chan *chan, ssize_t rx_avail)
-{
- if (chan->rx_avail == rx_avail)
- return;
-
- BT_DBG("chan %p has %zd bytes avail for rx", chan, rx_avail);
-
- chan->rx_avail = rx_avail;
-
- if (chan->state == BT_CONNECTED)
- l2cap_chan_le_send_credits(chan);
-}
-
static int l2cap_ecred_recv(struct l2cap_chan *chan, struct sk_buff *skb)
{
int err;
@@ -6569,12 +6543,6 @@ static int l2cap_ecred_recv(struct l2cap_chan *chan, struct sk_buff *skb)
/* Wait recv to confirm reception before updating the credits */
err = chan->ops->recv(chan, skb);
- if (err < 0 && chan->rx_avail != -1) {
- BT_ERR("Queueing received LE L2CAP data failed");
- l2cap_send_disconn_req(chan, ECONNRESET);
- return err;
- }
-
/* Update credits whenever an SDU is received */
l2cap_chan_le_send_credits(chan);
@@ -6597,8 +6565,7 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
}
chan->rx_credits--;
- BT_DBG("chan %p: rx_credits %u -> %u",
- chan, chan->rx_credits + 1, chan->rx_credits);
+ BT_DBG("rx_credits %u -> %u", chan->rx_credits + 1, chan->rx_credits);
/* Update if remote had run out of credits, this should only happens
* if the remote is not using the entire MPS.
@@ -7486,6 +7453,10 @@ void l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
struct l2cap_conn *conn = hcon->l2cap_data;
int len;
+ /* For AMP controller do not create l2cap conn */
+ if (!conn && hcon->hdev->dev_type != HCI_PRIMARY)
+ goto drop;
+
if (!conn)
conn = l2cap_conn_add(hcon);