diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 21:00:51 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 21:00:51 +0000 |
commit | 6d03a247468059b0e59c821ef39e6762d4d6fc30 (patch) | |
tree | 17b9c00de2c62e68c965c742cdbc206f77a375da /net/bluetooth/l2cap_core.c | |
parent | Releasing progress-linux version 6.8.12-1~progress7.99u1. (diff) | |
download | linux-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.c | 77 |
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); |