summaryrefslogtreecommitdiff
path: root/net/bluetooth/l2cap_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/bluetooth/l2cap_core.c')
-rw-r--r--net/bluetooth/l2cap_core.c40
1 files changed, 34 insertions, 6 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 5deb6c4f1e41..3de3e3c8e966 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -926,16 +926,39 @@ int l2cap_chan_check_security(struct l2cap_chan *chan, bool initiator)
static int l2cap_get_ident(struct l2cap_conn *conn)
{
+ u8 max;
+ int ident;
+
/* LE link does not support tools like l2ping so use the full range */
if (conn->hcon->type == LE_LINK)
- return ida_alloc_range(&conn->tx_ida, 1, 255, GFP_ATOMIC);
-
+ max = 255;
/* Get next available identificator.
* 1 - 128 are used by kernel.
* 129 - 199 are reserved.
* 200 - 254 are used by utilities like l2ping, etc.
*/
- return ida_alloc_range(&conn->tx_ida, 1, 128, GFP_ATOMIC);
+ else
+ max = 128;
+
+ /* Allocate ident using min as last used + 1 (cyclic) */
+ ident = ida_alloc_range(&conn->tx_ida, READ_ONCE(conn->tx_ident) + 1,
+ max, GFP_ATOMIC);
+ /* Force min 1 to start over */
+ if (ident <= 0) {
+ ident = ida_alloc_range(&conn->tx_ida, 1, max, GFP_ATOMIC);
+ if (ident <= 0) {
+ /* If all idents are in use, log an error, this is
+ * extremely unlikely to happen and would indicate a bug
+ * in the code that idents are not being freed properly.
+ */
+ BT_ERR("Unable to allocate ident: %d", ident);
+ return 0;
+ }
+ }
+
+ WRITE_ONCE(conn->tx_ident, ident);
+
+ return ident;
}
static void l2cap_send_acl(struct l2cap_conn *conn, struct sk_buff *skb,
@@ -5081,14 +5104,14 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
cmd_len -= sizeof(*req);
num_scid = cmd_len / sizeof(u16);
- /* Always respond with the same number of scids as in the request */
- rsp_len = cmd_len;
-
if (num_scid > L2CAP_ECRED_MAX_CID) {
result = L2CAP_CR_LE_INVALID_PARAMS;
goto response;
}
+ /* Always respond with the same number of scids as in the request */
+ rsp_len = cmd_len;
+
mtu = __le16_to_cpu(req->mtu);
mps = __le16_to_cpu(req->mps);
@@ -6690,6 +6713,11 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
if (!chan->sdu) {
u16 sdu_len;
+ if (!pskb_may_pull(skb, L2CAP_SDULEN_SIZE)) {
+ err = -EINVAL;
+ goto failed;
+ }
+
sdu_len = get_unaligned_le16(skb->data);
skb_pull(skb, L2CAP_SDULEN_SIZE);