+++ /dev/null
-From a18146e51c874d5e9cfddb143e56023462004f3f Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 6 Apr 2021 21:55:52 +0200
-Subject: Bluetooth: Add support for reading AOSP vendor capabilities
-
-From: Marcel Holtmann <marcel@holtmann.org>
-
-[ Upstream commit f67743f9e03a67dbbf931d1787e6faf50766e521 ]
-
-When drivers indicate support for AOSP vendor extension, initialize them
-and read its capabilities.
-
-Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
-Stable-dep-of: 51eda36d33e4 ("Bluetooth: SCO: Fix not validating setsockopt user input")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- include/net/bluetooth/hci_core.h | 11 ++++++++++
- net/bluetooth/Kconfig | 7 +++++++
- net/bluetooth/Makefile | 1 +
- net/bluetooth/aosp.c | 35 ++++++++++++++++++++++++++++++++
- net/bluetooth/aosp.h | 16 +++++++++++++++
- net/bluetooth/hci_core.c | 3 +++
- 6 files changed, 73 insertions(+)
- create mode 100644 net/bluetooth/aosp.c
- create mode 100644 net/bluetooth/aosp.h
-
-diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
-index 33873266b2bc7..daafca376cb7c 100644
---- a/include/net/bluetooth/hci_core.h
-+++ b/include/net/bluetooth/hci_core.h
-@@ -569,6 +569,10 @@ struct hci_dev {
- void *msft_data;
- #endif
-
-+#if IS_ENABLED(CONFIG_BT_AOSPEXT)
-+ bool aosp_capable;
-+#endif
-+
- int (*open)(struct hci_dev *hdev);
- int (*close)(struct hci_dev *hdev);
- int (*flush)(struct hci_dev *hdev);
-@@ -1222,6 +1226,13 @@ static inline void hci_set_msft_opcode(struct hci_dev *hdev, __u16 opcode)
- #endif
- }
-
-+static inline void hci_set_aosp_capable(struct hci_dev *hdev)
-+{
-+#if IS_ENABLED(CONFIG_BT_AOSPEXT)
-+ hdev->aosp_capable = true;
-+#endif
-+}
-+
- int hci_dev_open(__u16 dev);
- int hci_dev_close(__u16 dev);
- int hci_dev_do_close(struct hci_dev *hdev);
-diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig
-index 64e669acd42f9..11a563d95e67b 100644
---- a/net/bluetooth/Kconfig
-+++ b/net/bluetooth/Kconfig
-@@ -99,6 +99,13 @@ config BT_MSFTEXT
- This options enables support for the Microsoft defined HCI
- vendor extensions.
-
-+config BT_AOSPEXT
-+ bool "Enable Android Open Source Project extensions"
-+ depends on BT
-+ help
-+ This options enables support for the Android Open Source
-+ Project defined HCI vendor extensions.
-+
- config BT_DEBUGFS
- bool "Export Bluetooth internals in debugfs"
- depends on BT && DEBUG_FS
-diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
-index 1c645fba8c493..cc0995301f93f 100644
---- a/net/bluetooth/Makefile
-+++ b/net/bluetooth/Makefile
-@@ -20,5 +20,6 @@ bluetooth-$(CONFIG_BT_BREDR) += sco.o
- bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o
- bluetooth-$(CONFIG_BT_LEDS) += leds.o
- bluetooth-$(CONFIG_BT_MSFTEXT) += msft.o
-+bluetooth-$(CONFIG_BT_AOSPEXT) += aosp.o
- bluetooth-$(CONFIG_BT_DEBUGFS) += hci_debugfs.o
- bluetooth-$(CONFIG_BT_SELFTEST) += selftest.o
-diff --git a/net/bluetooth/aosp.c b/net/bluetooth/aosp.c
-new file mode 100644
-index 0000000000000..a1b7762335a51
---- /dev/null
-+++ b/net/bluetooth/aosp.c
-@@ -0,0 +1,35 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/*
-+ * Copyright (C) 2021 Intel Corporation
-+ */
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+
-+#include "aosp.h"
-+
-+void aosp_do_open(struct hci_dev *hdev)
-+{
-+ struct sk_buff *skb;
-+
-+ if (!hdev->aosp_capable)
-+ return;
-+
-+ bt_dev_dbg(hdev, "Initialize AOSP extension");
-+
-+ /* LE Get Vendor Capabilities Command */
-+ skb = __hci_cmd_sync(hdev, hci_opcode_pack(0x3f, 0x153), 0, NULL,
-+ HCI_CMD_TIMEOUT);
-+ if (IS_ERR(skb))
-+ return;
-+
-+ kfree_skb(skb);
-+}
-+
-+void aosp_do_close(struct hci_dev *hdev)
-+{
-+ if (!hdev->aosp_capable)
-+ return;
-+
-+ bt_dev_dbg(hdev, "Cleanup of AOSP extension");
-+}
-diff --git a/net/bluetooth/aosp.h b/net/bluetooth/aosp.h
-new file mode 100644
-index 0000000000000..328fc6d39f703
---- /dev/null
-+++ b/net/bluetooth/aosp.h
-@@ -0,0 +1,16 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/*
-+ * Copyright (C) 2021 Intel Corporation
-+ */
-+
-+#if IS_ENABLED(CONFIG_BT_AOSPEXT)
-+
-+void aosp_do_open(struct hci_dev *hdev);
-+void aosp_do_close(struct hci_dev *hdev);
-+
-+#else
-+
-+static inline void aosp_do_open(struct hci_dev *hdev) {}
-+static inline void aosp_do_close(struct hci_dev *hdev) {}
-+
-+#endif
-diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
-index b9cf5bc9364c1..f4fc5a81ae928 100644
---- a/net/bluetooth/hci_core.c
-+++ b/net/bluetooth/hci_core.c
-@@ -44,6 +44,7 @@
- #include "smp.h"
- #include "leds.h"
- #include "msft.h"
-+#include "aosp.h"
-
- static void hci_rx_work(struct work_struct *work);
- static void hci_cmd_work(struct work_struct *work);
-@@ -1586,6 +1587,7 @@ static int hci_dev_do_open(struct hci_dev *hdev)
- ret = hdev->set_diag(hdev, true);
-
- msft_do_open(hdev);
-+ aosp_do_open(hdev);
-
- clear_bit(HCI_INIT, &hdev->flags);
-
-@@ -1788,6 +1790,7 @@ int hci_dev_do_close(struct hci_dev *hdev)
-
- hci_sock_dev_event(hdev, HCI_DEV_DOWN);
-
-+ aosp_do_close(hdev);
- msft_do_close(hdev);
-
- if (hdev->flush)
---
-2.43.0
-
+++ /dev/null
-From 8bf980068612e7431ce14077b115729a05ebd523 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 7 Sep 2021 15:42:40 +0530
-Subject: Bluetooth: Allow querying of supported offload codecs over SCO socket
-
-From: Kiran K <kiran.k@intel.com>
-
-[ Upstream commit 248733e87d503e75624a2e95e241f51334fdd320 ]
-
-Add BT_CODEC option for getsockopt systemcall to get the details
-of offload codecs supported over SCO socket
-
-Signed-off-by: Kiran K <kiran.k@intel.com>
-Reviewed-by: Chethan T N <chethan.tumkur.narayan@intel.com>
-Reviewed-by: Srivatsa Ravishankar <ravishankar.srivatsa@intel.com>
-Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
-Stable-dep-of: 51eda36d33e4 ("Bluetooth: SCO: Fix not validating setsockopt user input")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- include/net/bluetooth/bluetooth.h | 20 ++++++
- include/net/bluetooth/hci.h | 4 ++
- include/net/bluetooth/hci_core.h | 1 +
- net/bluetooth/sco.c | 101 ++++++++++++++++++++++++++++++
- 4 files changed, 126 insertions(+)
-
-diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
-index 355835639ae58..8700635f08a69 100644
---- a/include/net/bluetooth/bluetooth.h
-+++ b/include/net/bluetooth/bluetooth.h
-@@ -153,6 +153,26 @@ struct bt_voice {
-
- #define BT_SCM_PKT_STATUS 0x03
-
-+#define BT_CODEC 19
-+
-+struct bt_codec_caps {
-+ __u8 len;
-+ __u8 data[];
-+} __packed;
-+
-+struct bt_codec {
-+ __u8 id;
-+ __u16 cid;
-+ __u16 vid;
-+ __u8 data_path;
-+ __u8 num_caps;
-+} __packed;
-+
-+struct bt_codecs {
-+ __u8 num_codecs;
-+ struct bt_codec codecs[];
-+} __packed;
-+
- __printf(1, 2)
- void bt_info(const char *fmt, ...);
- __printf(1, 2)
-diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
-index 17ed339b54c73..fcb2852df3268 100644
---- a/include/net/bluetooth/hci.h
-+++ b/include/net/bluetooth/hci.h
-@@ -330,6 +330,7 @@ enum {
- HCI_CMD_PENDING,
- HCI_FORCE_NO_MITM,
- HCI_QUALITY_REPORT,
-+ HCI_OFFLOAD_CODECS_ENABLED,
-
- __HCI_NUM_FLAGS,
- };
-@@ -2584,6 +2585,9 @@ static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb)
- #define hci_iso_data_len(h) ((h) & 0x3fff)
- #define hci_iso_data_flags(h) ((h) >> 14)
-
-+/* codec transport types */
-+#define HCI_TRANSPORT_SCO_ESCO 0x01
-+
- /* le24 support */
- static inline void hci_cpu_to_le24(__u32 val, __u8 dst[3])
- {
-diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
-index 12d78527b0935..cb4d42a7a9f1f 100644
---- a/include/net/bluetooth/hci_core.h
-+++ b/include/net/bluetooth/hci_core.h
-@@ -599,6 +599,7 @@ struct hci_dev {
- void (*cmd_timeout)(struct hci_dev *hdev);
- bool (*prevent_wake)(struct hci_dev *hdev);
- int (*set_quality_report)(struct hci_dev *hdev, bool enable);
-+ int (*get_data_path_id)(struct hci_dev *hdev, __u8 *data_path);
- };
-
- #define HCI_PHY_HANDLE(handle) (handle & 0xff)
-diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
-index 8244d3ae185bf..5e518a6d5e13d 100644
---- a/net/bluetooth/sco.c
-+++ b/net/bluetooth/sco.c
-@@ -967,6 +967,12 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname,
- struct bt_voice voice;
- u32 phys;
- int pkt_status;
-+ int buf_len;
-+ struct codec_list *c;
-+ u8 num_codecs, i, __user *ptr;
-+ struct hci_dev *hdev;
-+ struct hci_codec_caps *caps;
-+ struct bt_codec codec;
-
- BT_DBG("sk %p", sk);
-
-@@ -1031,6 +1037,101 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname,
- err = -EFAULT;
- break;
-
-+ case BT_CODEC:
-+ num_codecs = 0;
-+ buf_len = 0;
-+
-+ hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src, BDADDR_BREDR);
-+ if (!hdev) {
-+ err = -EBADFD;
-+ break;
-+ }
-+
-+ if (!hci_dev_test_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED)) {
-+ hci_dev_put(hdev);
-+ err = -EOPNOTSUPP;
-+ break;
-+ }
-+
-+ if (!hdev->get_data_path_id) {
-+ hci_dev_put(hdev);
-+ err = -EOPNOTSUPP;
-+ break;
-+ }
-+
-+ /* find total buffer size required to copy codec + caps */
-+ hci_dev_lock(hdev);
-+ list_for_each_entry(c, &hdev->local_codecs, list) {
-+ if (c->transport != HCI_TRANSPORT_SCO_ESCO)
-+ continue;
-+ num_codecs++;
-+ for (i = 0, caps = c->caps; i < c->num_caps; i++) {
-+ buf_len += 1 + caps->len;
-+ caps = (void *)&caps->data[caps->len];
-+ }
-+ buf_len += sizeof(struct bt_codec);
-+ }
-+ hci_dev_unlock(hdev);
-+
-+ buf_len += sizeof(struct bt_codecs);
-+ if (buf_len > len) {
-+ hci_dev_put(hdev);
-+ err = -ENOBUFS;
-+ break;
-+ }
-+ ptr = optval;
-+
-+ if (put_user(num_codecs, ptr)) {
-+ hci_dev_put(hdev);
-+ err = -EFAULT;
-+ break;
-+ }
-+ ptr += sizeof(num_codecs);
-+
-+ /* Iterate all the codecs supported over SCO and populate
-+ * codec data
-+ */
-+ hci_dev_lock(hdev);
-+ list_for_each_entry(c, &hdev->local_codecs, list) {
-+ if (c->transport != HCI_TRANSPORT_SCO_ESCO)
-+ continue;
-+
-+ codec.id = c->id;
-+ codec.cid = c->cid;
-+ codec.vid = c->vid;
-+ err = hdev->get_data_path_id(hdev, &codec.data_path);
-+ if (err < 0)
-+ break;
-+ codec.num_caps = c->num_caps;
-+ if (copy_to_user(ptr, &codec, sizeof(codec))) {
-+ err = -EFAULT;
-+ break;
-+ }
-+ ptr += sizeof(codec);
-+
-+ /* find codec capabilities data length */
-+ len = 0;
-+ for (i = 0, caps = c->caps; i < c->num_caps; i++) {
-+ len += 1 + caps->len;
-+ caps = (void *)&caps->data[caps->len];
-+ }
-+
-+ /* copy codec capabilities data */
-+ if (len && copy_to_user(ptr, c->caps, len)) {
-+ err = -EFAULT;
-+ break;
-+ }
-+ ptr += len;
-+ }
-+
-+ if (!err && put_user(buf_len, optlen))
-+ err = -EFAULT;
-+
-+ hci_dev_unlock(hdev);
-+ hci_dev_put(hdev);
-+
-+ break;
-+
- default:
- err = -ENOPROTOOPT;
- break;
---
-2.43.0
-
+++ /dev/null
-From 7e59316473bc029ca3bfcea291cd36332f76dd57 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 7 Sep 2021 15:42:42 +0530
-Subject: Bluetooth: Allow setting of codec for HFP offload use case
-
-From: Kiran K <kiran.k@intel.com>
-
-[ Upstream commit f6873401a60865702069fb2e3f67671fff9c082c ]
-
-This patch allows user space to set the codec that needs to
-be used for HFP offload use case. The codec details are cached and
-the controller is configured before opening the SCO connection.
-
-Signed-off-by: Kiran K <kiran.k@intel.com>
-Reviewed-by: Chethan T N <chethan.tumkur.narayan@intel.com>
-Reviewed-by: Srivatsa Ravishankar <ravishankar.srivatsa@intel.com>
-Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
-Stable-dep-of: 51eda36d33e4 ("Bluetooth: SCO: Fix not validating setsockopt user input")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- include/net/bluetooth/bluetooth.h | 2 ++
- net/bluetooth/sco.c | 60 +++++++++++++++++++++++++++++++
- 2 files changed, 62 insertions(+)
-
-diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
-index 8700635f08a69..4191edbb0641d 100644
---- a/include/net/bluetooth/bluetooth.h
-+++ b/include/net/bluetooth/bluetooth.h
-@@ -173,6 +173,8 @@ struct bt_codecs {
- struct bt_codec codecs[];
- } __packed;
-
-+#define BT_CODEC_CVSD 0x02
-+
- __printf(1, 2)
- void bt_info(const char *fmt, ...);
- __printf(1, 2)
-diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
-index 5e518a6d5e13d..cef26f1d8a583 100644
---- a/net/bluetooth/sco.c
-+++ b/net/bluetooth/sco.c
-@@ -69,6 +69,7 @@ struct sco_pinfo {
- __u32 flags;
- __u16 setting;
- __u8 cmsg_mask;
-+ struct bt_codec codec;
- struct sco_conn *conn;
- };
-
-@@ -434,6 +435,7 @@ static void __sco_sock_close(struct sock *sk)
- sock_set_flag(sk, SOCK_ZAPPED);
- break;
- }
-+
- }
-
- /* Must be called on unlocked socket. */
-@@ -494,6 +496,10 @@ static struct sock *sco_sock_alloc(struct net *net, struct socket *sock,
- sk->sk_state = BT_OPEN;
-
- sco_pi(sk)->setting = BT_VOICE_CVSD_16BIT;
-+ sco_pi(sk)->codec.id = BT_CODEC_CVSD;
-+ sco_pi(sk)->codec.cid = 0xffff;
-+ sco_pi(sk)->codec.vid = 0xffff;
-+ sco_pi(sk)->codec.data_path = 0x00;
-
- bt_sock_link(&sco_sk_list, sk);
- return sk;
-@@ -828,6 +834,9 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
- int len, err = 0;
- struct bt_voice voice;
- u32 opt;
-+ struct bt_codecs *codecs;
-+ struct hci_dev *hdev;
-+ __u8 buffer[255];
-
- BT_DBG("sk %p", sk);
-
-@@ -889,6 +898,57 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
- sco_pi(sk)->cmsg_mask &= SCO_CMSG_PKT_STATUS;
- break;
-
-+ case BT_CODEC:
-+ if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND &&
-+ sk->sk_state != BT_CONNECT2) {
-+ err = -EINVAL;
-+ break;
-+ }
-+
-+ hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src,
-+ BDADDR_BREDR);
-+ if (!hdev) {
-+ err = -EBADFD;
-+ break;
-+ }
-+
-+ if (!hci_dev_test_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED)) {
-+ hci_dev_put(hdev);
-+ err = -EOPNOTSUPP;
-+ break;
-+ }
-+
-+ if (!hdev->get_data_path_id) {
-+ hci_dev_put(hdev);
-+ err = -EOPNOTSUPP;
-+ break;
-+ }
-+
-+ if (optlen < sizeof(struct bt_codecs) ||
-+ optlen > sizeof(buffer)) {
-+ hci_dev_put(hdev);
-+ err = -EINVAL;
-+ break;
-+ }
-+
-+ if (copy_from_sockptr(buffer, optval, optlen)) {
-+ hci_dev_put(hdev);
-+ err = -EFAULT;
-+ break;
-+ }
-+
-+ codecs = (void *)buffer;
-+
-+ if (codecs->num_codecs > 1) {
-+ hci_dev_put(hdev);
-+ err = -EINVAL;
-+ break;
-+ }
-+
-+ sco_pi(sk)->codec = codecs->codecs[0];
-+ hci_dev_put(hdev);
-+ break;
-+
- default:
- err = -ENOPROTOOPT;
- break;
---
-2.43.0
-
+++ /dev/null
-From 2db9c07bee1bfa5bd156e52dfb5f31eeb313e545 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 7 Sep 2021 15:42:37 +0530
-Subject: Bluetooth: Enumerate local supported codec and cache details
-
-From: Kiran K <kiran.k@intel.com>
-
-[ Upstream commit 8961987f3f5fa2f2618e72304d013c8dd5e604a6 ]
-
-Move reading of supported local codecs into a separate init function,
-query codecs capabilities and cache the data
-
-Signed-off-by: Kiran K <kiran.k@intel.com>
-Signed-off-by: Chethan T N <chethan.tumkur.narayan@intel.com>
-Signed-off-by: Srivatsa Ravishankar <ravishankar.srivatsa@intel.com>
-Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
-Stable-dep-of: 51eda36d33e4 ("Bluetooth: SCO: Fix not validating setsockopt user input")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- include/net/bluetooth/hci.h | 41 ++++++++
- include/net/bluetooth/hci_core.h | 17 +++
- net/bluetooth/Makefile | 2 +-
- net/bluetooth/hci_codec.c | 172 +++++++++++++++++++++++++++++++
- net/bluetooth/hci_codec.h | 6 ++
- net/bluetooth/hci_core.c | 11 +-
- 6 files changed, 244 insertions(+), 5 deletions(-)
- create mode 100644 net/bluetooth/hci_codec.c
- create mode 100644 net/bluetooth/hci_codec.h
-
-diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
-index 0e36974da384c..17ed339b54c73 100644
---- a/include/net/bluetooth/hci.h
-+++ b/include/net/bluetooth/hci.h
-@@ -1306,6 +1306,28 @@ struct hci_rp_read_data_block_size {
- } __packed;
-
- #define HCI_OP_READ_LOCAL_CODECS 0x100b
-+struct hci_std_codecs {
-+ __u8 num;
-+ __u8 codec[];
-+} __packed;
-+
-+struct hci_vnd_codec {
-+ /* company id */
-+ __le16 cid;
-+ /* vendor codec id */
-+ __le16 vid;
-+} __packed;
-+
-+struct hci_vnd_codecs {
-+ __u8 num;
-+ struct hci_vnd_codec codec[];
-+} __packed;
-+
-+struct hci_rp_read_local_supported_codecs {
-+ __u8 status;
-+ struct hci_std_codecs std_codecs;
-+ struct hci_vnd_codecs vnd_codecs;
-+} __packed;
-
- #define HCI_OP_READ_LOCAL_PAIRING_OPTS 0x100c
- struct hci_rp_read_local_pairing_opts {
-@@ -1314,6 +1336,25 @@ struct hci_rp_read_local_pairing_opts {
- __u8 max_key_size;
- } __packed;
-
-+#define HCI_OP_READ_LOCAL_CODEC_CAPS 0x100e
-+struct hci_op_read_local_codec_caps {
-+ __u8 id;
-+ __le16 cid;
-+ __le16 vid;
-+ __u8 transport;
-+ __u8 direction;
-+} __packed;
-+
-+struct hci_codec_caps {
-+ __u8 len;
-+ __u8 data[];
-+} __packed;
-+
-+struct hci_rp_read_local_codec_caps {
-+ __u8 status;
-+ __u8 num_caps;
-+} __packed;
-+
- #define HCI_OP_READ_PAGE_SCAN_ACTIVITY 0x0c1b
- struct hci_rp_read_page_scan_activity {
- __u8 status;
-diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
-index c8f11dde54837..12d78527b0935 100644
---- a/include/net/bluetooth/hci_core.h
-+++ b/include/net/bluetooth/hci_core.h
-@@ -132,6 +132,17 @@ struct bdaddr_list {
- u8 bdaddr_type;
- };
-
-+struct codec_list {
-+ struct list_head list;
-+ u8 id;
-+ __u16 cid;
-+ __u16 vid;
-+ u8 transport;
-+ u8 num_caps;
-+ u32 len;
-+ struct hci_codec_caps caps[];
-+};
-+
- struct bdaddr_list_with_irk {
- struct list_head list;
- bdaddr_t bdaddr;
-@@ -517,6 +528,7 @@ struct hci_dev {
- struct list_head pend_le_conns;
- struct list_head pend_le_reports;
- struct list_head blocked_keys;
-+ struct list_head local_codecs;
-
- struct hci_dev_stats stat;
-
-@@ -1819,4 +1831,9 @@ void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr,
- #define SCO_AIRMODE_CVSD 0x0000
- #define SCO_AIRMODE_TRANSP 0x0003
-
-+#define LOCAL_CODEC_ACL_MASK BIT(0)
-+#define LOCAL_CODEC_SCO_MASK BIT(1)
-+
-+#define TRANSPORT_TYPE_MAX 0x04
-+
- #endif /* __HCI_CORE_H */
-diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
-index cc0995301f93f..f3e439d98b85a 100644
---- a/net/bluetooth/Makefile
-+++ b/net/bluetooth/Makefile
-@@ -14,7 +14,7 @@ bluetooth_6lowpan-y := 6lowpan.o
-
- bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
- hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o lib.o \
-- ecdh_helper.o hci_request.o mgmt_util.o mgmt_config.o
-+ ecdh_helper.o hci_request.o mgmt_util.o mgmt_config.o hci_codec.o
-
- bluetooth-$(CONFIG_BT_BREDR) += sco.o
- bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o
-diff --git a/net/bluetooth/hci_codec.c b/net/bluetooth/hci_codec.c
-new file mode 100644
-index 0000000000000..f86ca6ba5814f
---- /dev/null
-+++ b/net/bluetooth/hci_codec.c
-@@ -0,0 +1,172 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+/* Copyright (C) 2021 Intel Corporation */
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+#include "hci_codec.h"
-+
-+static int hci_codec_list_add(struct list_head *list,
-+ struct hci_op_read_local_codec_caps *sent,
-+ struct hci_rp_read_local_codec_caps *rp,
-+ void *caps,
-+ __u32 len)
-+{
-+ struct codec_list *entry;
-+
-+ entry = kzalloc(sizeof(*entry) + len, GFP_KERNEL);
-+ if (!entry)
-+ return -ENOMEM;
-+
-+ entry->id = sent->id;
-+ if (sent->id == 0xFF) {
-+ entry->cid = __le16_to_cpu(sent->cid);
-+ entry->vid = __le16_to_cpu(sent->vid);
-+ }
-+ entry->transport = sent->transport;
-+ entry->len = len;
-+ entry->num_caps = rp->num_caps;
-+ if (rp->num_caps)
-+ memcpy(entry->caps, caps, len);
-+ list_add(&entry->list, list);
-+
-+ return 0;
-+}
-+
-+void hci_codec_list_clear(struct list_head *codec_list)
-+{
-+ struct codec_list *c, *n;
-+
-+ list_for_each_entry_safe(c, n, codec_list, list) {
-+ list_del(&c->list);
-+ kfree(c);
-+ }
-+}
-+
-+static void hci_read_codec_capabilities(struct hci_dev *hdev, __u8 transport,
-+ struct hci_op_read_local_codec_caps
-+ *cmd)
-+{
-+ __u8 i;
-+
-+ for (i = 0; i < TRANSPORT_TYPE_MAX; i++) {
-+ if (transport & BIT(i)) {
-+ struct hci_rp_read_local_codec_caps *rp;
-+ struct hci_codec_caps *caps;
-+ struct sk_buff *skb;
-+ __u8 j;
-+ __u32 len;
-+
-+ cmd->transport = i;
-+ skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_CODEC_CAPS,
-+ sizeof(*cmd), cmd,
-+ HCI_CMD_TIMEOUT);
-+ if (IS_ERR(skb)) {
-+ bt_dev_err(hdev, "Failed to read codec capabilities (%ld)",
-+ PTR_ERR(skb));
-+ continue;
-+ }
-+
-+ if (skb->len < sizeof(*rp))
-+ goto error;
-+
-+ rp = (void *)skb->data;
-+
-+ if (rp->status)
-+ goto error;
-+
-+ if (!rp->num_caps) {
-+ len = 0;
-+ /* this codec doesn't have capabilities */
-+ goto skip_caps_parse;
-+ }
-+
-+ skb_pull(skb, sizeof(*rp));
-+
-+ for (j = 0, len = 0; j < rp->num_caps; j++) {
-+ caps = (void *)skb->data;
-+ if (skb->len < sizeof(*caps))
-+ goto error;
-+ if (skb->len < caps->len)
-+ goto error;
-+ len += sizeof(caps->len) + caps->len;
-+ skb_pull(skb, sizeof(caps->len) + caps->len);
-+ }
-+
-+skip_caps_parse:
-+ hci_dev_lock(hdev);
-+ hci_codec_list_add(&hdev->local_codecs, cmd, rp,
-+ (__u8 *)rp + sizeof(*rp), len);
-+ hci_dev_unlock(hdev);
-+error:
-+ kfree_skb(skb);
-+ }
-+ }
-+}
-+
-+void hci_read_supported_codecs(struct hci_dev *hdev)
-+{
-+ struct sk_buff *skb;
-+ struct hci_rp_read_local_supported_codecs *rp;
-+ struct hci_std_codecs *std_codecs;
-+ struct hci_vnd_codecs *vnd_codecs;
-+ struct hci_op_read_local_codec_caps caps;
-+ __u8 i;
-+
-+ skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_CODECS, 0, NULL,
-+ HCI_CMD_TIMEOUT);
-+
-+ if (IS_ERR(skb)) {
-+ bt_dev_err(hdev, "Failed to read local supported codecs (%ld)",
-+ PTR_ERR(skb));
-+ return;
-+ }
-+
-+ if (skb->len < sizeof(*rp))
-+ goto error;
-+
-+ rp = (void *)skb->data;
-+
-+ if (rp->status)
-+ goto error;
-+
-+ skb_pull(skb, sizeof(rp->status));
-+
-+ std_codecs = (void *)skb->data;
-+
-+ /* validate codecs length before accessing */
-+ if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num)
-+ + sizeof(std_codecs->num))
-+ goto error;
-+
-+ /* enumerate codec capabilities of standard codecs */
-+ memset(&caps, 0, sizeof(caps));
-+ for (i = 0; i < std_codecs->num; i++) {
-+ caps.id = std_codecs->codec[i];
-+ caps.direction = 0x00;
-+ hci_read_codec_capabilities(hdev, LOCAL_CODEC_ACL_MASK, &caps);
-+ }
-+
-+ skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num)
-+ + sizeof(std_codecs->num));
-+
-+ vnd_codecs = (void *)skb->data;
-+
-+ /* validate vendor codecs length before accessing */
-+ if (skb->len <
-+ flex_array_size(vnd_codecs, codec, vnd_codecs->num)
-+ + sizeof(vnd_codecs->num))
-+ goto error;
-+
-+ /* enumerate vendor codec capabilities */
-+ for (i = 0; i < vnd_codecs->num; i++) {
-+ caps.id = 0xFF;
-+ caps.cid = vnd_codecs->codec[i].cid;
-+ caps.vid = vnd_codecs->codec[i].vid;
-+ caps.direction = 0x00;
-+ hci_read_codec_capabilities(hdev, LOCAL_CODEC_ACL_MASK, &caps);
-+ }
-+
-+error:
-+ kfree_skb(skb);
-+}
-diff --git a/net/bluetooth/hci_codec.h b/net/bluetooth/hci_codec.h
-new file mode 100644
-index 0000000000000..efb0df634ac6b
---- /dev/null
-+++ b/net/bluetooth/hci_codec.h
-@@ -0,0 +1,6 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/* Copyright (C) 2014 Intel Corporation */
-+
-+void hci_read_supported_codecs(struct hci_dev *hdev);
-+void hci_codec_list_clear(struct list_head *codec_list);
-diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
-index f4fc5a81ae928..0944721a786ba 100644
---- a/net/bluetooth/hci_core.c
-+++ b/net/bluetooth/hci_core.c
-@@ -45,6 +45,7 @@
- #include "leds.h"
- #include "msft.h"
- #include "aosp.h"
-+#include "hci_codec.h"
-
- static void hci_rx_work(struct work_struct *work);
- static void hci_cmd_work(struct work_struct *work);
-@@ -832,10 +833,6 @@ static int hci_init4_req(struct hci_request *req, unsigned long opt)
- if (hdev->commands[22] & 0x04)
- hci_set_event_mask_page_2(req);
-
-- /* Read local codec list if the HCI command is supported */
-- if (hdev->commands[29] & 0x20)
-- hci_req_add(req, HCI_OP_READ_LOCAL_CODECS, 0, NULL);
--
- /* Read local pairing options if the HCI command is supported */
- if (hdev->commands[41] & 0x08)
- hci_req_add(req, HCI_OP_READ_LOCAL_PAIRING_OPTS, 0, NULL);
-@@ -931,6 +928,10 @@ static int __hci_init(struct hci_dev *hdev)
- if (err < 0)
- return err;
-
-+ /* Read local codec list if the HCI command is supported */
-+ if (hdev->commands[29] & 0x20)
-+ hci_read_supported_codecs(hdev);
-+
- /* This function is only called when the controller is actually in
- * configured state. When the controller is marked as unconfigured,
- * this initialization procedure is not run.
-@@ -1841,6 +1842,7 @@ int hci_dev_do_close(struct hci_dev *hdev)
- memset(hdev->eir, 0, sizeof(hdev->eir));
- memset(hdev->dev_class, 0, sizeof(hdev->dev_class));
- bacpy(&hdev->random_addr, BDADDR_ANY);
-+ hci_codec_list_clear(&hdev->local_codecs);
-
- hci_req_sync_unlock(hdev);
-
-@@ -3678,6 +3680,7 @@ struct hci_dev *hci_alloc_dev(void)
- INIT_LIST_HEAD(&hdev->adv_instances);
- INIT_LIST_HEAD(&hdev->blocked_keys);
-
-+ INIT_LIST_HEAD(&hdev->local_codecs);
- INIT_WORK(&hdev->rx_work, hci_rx_work);
- INIT_WORK(&hdev->cmd_work, hci_cmd_work);
- INIT_WORK(&hdev->tx_work, hci_tx_work);
---
-2.43.0
-
+++ /dev/null
-From 704cacb29acbc095280862f903c7c19487f5f6f0 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sun, 14 Mar 2021 14:49:38 +0100
-Subject: Bluetooth: Fix mgmt status for LL Privacy experimental feature
-
-From: Marcel Holtmann <marcel@holtmann.org>
-
-[ Upstream commit 353cac0e108f0484b101fd8cc6c2c0c5d9100ca6 ]
-
-The return error when trying to change the setting when a controller is
-powered up, shall be MGMT_STATUS_REJECTED. However instead now the error
-MGMT_STATUS_NOT_POWERED is used which is exactly the opposite.
-
-Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
-Stable-dep-of: 51eda36d33e4 ("Bluetooth: SCO: Fix not validating setsockopt user input")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- net/bluetooth/mgmt.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
-index bd8cfcfca7aef..fd8bdafb71a0e 100644
---- a/net/bluetooth/mgmt.c
-+++ b/net/bluetooth/mgmt.c
-@@ -3968,7 +3968,7 @@ static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
- if (hdev_is_powered(hdev))
- return mgmt_cmd_status(sk, hdev->id,
- MGMT_OP_SET_EXP_FEATURE,
-- MGMT_STATUS_NOT_POWERED);
-+ MGMT_STATUS_REJECTED);
-
- /* Parameters are limited to a single octet */
- if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
---
-2.43.0
-
+++ /dev/null
-From 2530dd42cf909251594d1aa00c51ae026bf5926d Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sun, 15 Aug 2021 20:17:15 +0800
-Subject: Bluetooth: refactor set_exp_feature with a feature table
-
-From: Joseph Hwang <josephsih@chromium.org>
-
-[ Upstream commit 93fb70bc112e922def6e50b37e20ccfce0c67c0a ]
-
-This patch refactors the set_exp_feature with a feature table
-consisting of UUIDs and the corresponding callback functions.
-In this way, a new experimental feature setting function can be
-simply added with its UUID and callback function.
-
-Signed-off-by: Joseph Hwang <josephsih@chromium.org>
-Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
-Stable-dep-of: 51eda36d33e4 ("Bluetooth: SCO: Fix not validating setsockopt user input")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- net/bluetooth/mgmt.c | 248 +++++++++++++++++++++++++------------------
- 1 file changed, 142 insertions(+), 106 deletions(-)
-
-diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
-index fd8bdafb71a0e..8acfd9db00d63 100644
---- a/net/bluetooth/mgmt.c
-+++ b/net/bluetooth/mgmt.c
-@@ -3784,7 +3784,7 @@ static const u8 rpa_resolution_uuid[16] = {
- static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
- void *data, u16 data_len)
- {
-- char buf[62]; /* Enough space for 3 features */
-+ char buf[62]; /* Enough space for 3 features */
- struct mgmt_rp_read_exp_features_info *rp = (void *)buf;
- u16 idx = 0;
- u32 flags;
-@@ -3870,150 +3870,186 @@ static int exp_debug_feature_changed(bool enabled, struct sock *skip)
- }
- #endif
-
--static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
-- void *data, u16 data_len)
-+#define EXP_FEAT(_uuid, _set_func) \
-+{ \
-+ .uuid = _uuid, \
-+ .set_func = _set_func, \
-+}
-+
-+/* The zero key uuid is special. Multiple exp features are set through it. */
-+static int set_zero_key_func(struct sock *sk, struct hci_dev *hdev,
-+ struct mgmt_cp_set_exp_feature *cp, u16 data_len)
- {
-- struct mgmt_cp_set_exp_feature *cp = data;
- struct mgmt_rp_set_exp_feature rp;
-
-- bt_dev_dbg(hdev, "sock %p", sk);
--
-- if (!memcmp(cp->uuid, ZERO_KEY, 16)) {
-- memset(rp.uuid, 0, 16);
-- rp.flags = cpu_to_le32(0);
-+ memset(rp.uuid, 0, 16);
-+ rp.flags = cpu_to_le32(0);
-
- #ifdef CONFIG_BT_FEATURE_DEBUG
-- if (!hdev) {
-- bool changed = bt_dbg_get();
-+ if (!hdev) {
-+ bool changed = bt_dbg_get();
-
-- bt_dbg_set(false);
-+ bt_dbg_set(false);
-
-- if (changed)
-- exp_debug_feature_changed(false, sk);
-- }
-+ if (changed)
-+ exp_debug_feature_changed(false, sk);
-+ }
- #endif
-
-- if (hdev && use_ll_privacy(hdev) && !hdev_is_powered(hdev)) {
-- bool changed = hci_dev_test_flag(hdev,
-- HCI_ENABLE_LL_PRIVACY);
-+ if (hdev && use_ll_privacy(hdev) && !hdev_is_powered(hdev)) {
-+ bool changed = hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY);
-
-- hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY);
-+ hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY);
-
-- if (changed)
-- exp_ll_privacy_feature_changed(false, hdev, sk);
-- }
-+ if (changed)
-+ exp_ll_privacy_feature_changed(false, hdev, sk);
-+ }
-
-- hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
-+ hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
-
-- return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
-- MGMT_OP_SET_EXP_FEATURE, 0,
-- &rp, sizeof(rp));
-- }
-+ return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
-+ MGMT_OP_SET_EXP_FEATURE, 0,
-+ &rp, sizeof(rp));
-+}
-
- #ifdef CONFIG_BT_FEATURE_DEBUG
-- if (!memcmp(cp->uuid, debug_uuid, 16)) {
-- bool val, changed;
-- int err;
-+static int set_debug_func(struct sock *sk, struct hci_dev *hdev,
-+ struct mgmt_cp_set_exp_feature *cp, u16 data_len)
-+{
-+ struct mgmt_rp_set_exp_feature rp;
-
-- /* Command requires to use the non-controller index */
-- if (hdev)
-- return mgmt_cmd_status(sk, hdev->id,
-- MGMT_OP_SET_EXP_FEATURE,
-- MGMT_STATUS_INVALID_INDEX);
-+ bool val, changed;
-+ int err;
-
-- /* Parameters are limited to a single octet */
-- if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
-- return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
-- MGMT_OP_SET_EXP_FEATURE,
-- MGMT_STATUS_INVALID_PARAMS);
-+ /* Command requires to use the non-controller index */
-+ if (hdev)
-+ return mgmt_cmd_status(sk, hdev->id,
-+ MGMT_OP_SET_EXP_FEATURE,
-+ MGMT_STATUS_INVALID_INDEX);
-
-- /* Only boolean on/off is supported */
-- if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
-- return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
-- MGMT_OP_SET_EXP_FEATURE,
-- MGMT_STATUS_INVALID_PARAMS);
-+ /* Parameters are limited to a single octet */
-+ if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
-+ return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
-+ MGMT_OP_SET_EXP_FEATURE,
-+ MGMT_STATUS_INVALID_PARAMS);
-
-- val = !!cp->param[0];
-- changed = val ? !bt_dbg_get() : bt_dbg_get();
-- bt_dbg_set(val);
-+ /* Only boolean on/off is supported */
-+ if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
-+ return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
-+ MGMT_OP_SET_EXP_FEATURE,
-+ MGMT_STATUS_INVALID_PARAMS);
-
-- memcpy(rp.uuid, debug_uuid, 16);
-- rp.flags = cpu_to_le32(val ? BIT(0) : 0);
-+ val = !!cp->param[0];
-+ changed = val ? !bt_dbg_get() : bt_dbg_get();
-+ bt_dbg_set(val);
-
-- hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
-+ memcpy(rp.uuid, debug_uuid, 16);
-+ rp.flags = cpu_to_le32(val ? BIT(0) : 0);
-
-- err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
-- MGMT_OP_SET_EXP_FEATURE, 0,
-- &rp, sizeof(rp));
-+ hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
-
-- if (changed)
-- exp_debug_feature_changed(val, sk);
-+ err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
-+ MGMT_OP_SET_EXP_FEATURE, 0,
-+ &rp, sizeof(rp));
-
-- return err;
-- }
-+ if (changed)
-+ exp_debug_feature_changed(val, sk);
-+
-+ return err;
-+}
- #endif
-
-- if (!memcmp(cp->uuid, rpa_resolution_uuid, 16)) {
-- bool val, changed;
-- int err;
-- u32 flags;
-+static int set_rpa_resolution_func(struct sock *sk, struct hci_dev *hdev,
-+ struct mgmt_cp_set_exp_feature *cp,
-+ u16 data_len)
-+{
-+ struct mgmt_rp_set_exp_feature rp;
-+ bool val, changed;
-+ int err;
-+ u32 flags;
-+
-+ /* Command requires to use the controller index */
-+ if (!hdev)
-+ return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
-+ MGMT_OP_SET_EXP_FEATURE,
-+ MGMT_STATUS_INVALID_INDEX);
-
-- /* Command requires to use the controller index */
-- if (!hdev)
-- return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
-- MGMT_OP_SET_EXP_FEATURE,
-- MGMT_STATUS_INVALID_INDEX);
-+ /* Changes can only be made when controller is powered down */
-+ if (hdev_is_powered(hdev))
-+ return mgmt_cmd_status(sk, hdev->id,
-+ MGMT_OP_SET_EXP_FEATURE,
-+ MGMT_STATUS_REJECTED);
-
-- /* Changes can only be made when controller is powered down */
-- if (hdev_is_powered(hdev))
-- return mgmt_cmd_status(sk, hdev->id,
-- MGMT_OP_SET_EXP_FEATURE,
-- MGMT_STATUS_REJECTED);
-+ /* Parameters are limited to a single octet */
-+ if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
-+ return mgmt_cmd_status(sk, hdev->id,
-+ MGMT_OP_SET_EXP_FEATURE,
-+ MGMT_STATUS_INVALID_PARAMS);
-
-- /* Parameters are limited to a single octet */
-- if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
-- return mgmt_cmd_status(sk, hdev->id,
-- MGMT_OP_SET_EXP_FEATURE,
-- MGMT_STATUS_INVALID_PARAMS);
-+ /* Only boolean on/off is supported */
-+ if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
-+ return mgmt_cmd_status(sk, hdev->id,
-+ MGMT_OP_SET_EXP_FEATURE,
-+ MGMT_STATUS_INVALID_PARAMS);
-
-- /* Only boolean on/off is supported */
-- if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
-- return mgmt_cmd_status(sk, hdev->id,
-- MGMT_OP_SET_EXP_FEATURE,
-- MGMT_STATUS_INVALID_PARAMS);
-+ val = !!cp->param[0];
-
-- val = !!cp->param[0];
-+ if (val) {
-+ changed = !hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY);
-+ hci_dev_set_flag(hdev, HCI_ENABLE_LL_PRIVACY);
-+ hci_dev_clear_flag(hdev, HCI_ADVERTISING);
-
-- if (val) {
-- changed = !hci_dev_test_flag(hdev,
-- HCI_ENABLE_LL_PRIVACY);
-- hci_dev_set_flag(hdev, HCI_ENABLE_LL_PRIVACY);
-- hci_dev_clear_flag(hdev, HCI_ADVERTISING);
-+ /* Enable LL privacy + supported settings changed */
-+ flags = BIT(0) | BIT(1);
-+ } else {
-+ changed = hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY);
-+ hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY);
-
-- /* Enable LL privacy + supported settings changed */
-- flags = BIT(0) | BIT(1);
-- } else {
-- changed = hci_dev_test_flag(hdev,
-- HCI_ENABLE_LL_PRIVACY);
-- hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY);
-+ /* Disable LL privacy + supported settings changed */
-+ flags = BIT(1);
-+ }
-
-- /* Disable LL privacy + supported settings changed */
-- flags = BIT(1);
-- }
-+ memcpy(rp.uuid, rpa_resolution_uuid, 16);
-+ rp.flags = cpu_to_le32(flags);
-
-- memcpy(rp.uuid, rpa_resolution_uuid, 16);
-- rp.flags = cpu_to_le32(flags);
-+ hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
-
-- hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
-+ err = mgmt_cmd_complete(sk, hdev->id,
-+ MGMT_OP_SET_EXP_FEATURE, 0,
-+ &rp, sizeof(rp));
-
-- err = mgmt_cmd_complete(sk, hdev->id,
-- MGMT_OP_SET_EXP_FEATURE, 0,
-- &rp, sizeof(rp));
-+ if (changed)
-+ exp_ll_privacy_feature_changed(val, hdev, sk);
-
-- if (changed)
-- exp_ll_privacy_feature_changed(val, hdev, sk);
-+ return err;
-+}
-
-- return err;
-+static const struct mgmt_exp_feature {
-+ const u8 *uuid;
-+ int (*set_func)(struct sock *sk, struct hci_dev *hdev,
-+ struct mgmt_cp_set_exp_feature *cp, u16 data_len);
-+} exp_features[] = {
-+ EXP_FEAT(ZERO_KEY, set_zero_key_func),
-+#ifdef CONFIG_BT_FEATURE_DEBUG
-+ EXP_FEAT(debug_uuid, set_debug_func),
-+#endif
-+ EXP_FEAT(rpa_resolution_uuid, set_rpa_resolution_func),
-+
-+ /* end with a null feature */
-+ EXP_FEAT(NULL, NULL)
-+};
-+
-+static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
-+ void *data, u16 data_len)
-+{
-+ struct mgmt_cp_set_exp_feature *cp = data;
-+ size_t i = 0;
-+
-+ bt_dev_dbg(hdev, "sock %p", sk);
-+
-+ for (i = 0; exp_features[i].uuid; i++) {
-+ if (!memcmp(cp->uuid, exp_features[i].uuid, 16))
-+ return exp_features[i].set_func(sk, hdev, cp, data_len);
- }
-
- return mgmt_cmd_status(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
---
-2.43.0
-
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
- include/net/bluetooth/bluetooth.h | 9 +++++++++
- net/bluetooth/sco.c | 23 ++++++++++-------------
- 2 files changed, 19 insertions(+), 13 deletions(-)
+ include/net/bluetooth/bluetooth.h | 9 +++++++++
+ net/bluetooth/sco.c | 19 ++++++++-----------
+ 2 files changed, 17 insertions(+), 11 deletions(-)
-diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
-index 4191edbb0641d..2761db375836b 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
-@@ -509,6 +509,15 @@ static inline struct sk_buff *bt_skb_sendmmsg(struct sock *sk,
+@@ -487,6 +487,15 @@ static inline struct sk_buff *bt_skb_sen
return skb;
}
int bt_to_errno(u16 code);
void hci_sock_set_flag(struct sock *sk, int nr);
-diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
-index cef26f1d8a583..6509c40e898e2 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
-@@ -831,7 +831,7 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
+@@ -825,7 +825,7 @@ static int sco_sock_setsockopt(struct so
sockptr_t optval, unsigned int optlen)
{
struct sock *sk = sock->sk;
+ int err = 0;
struct bt_voice voice;
u32 opt;
- struct bt_codecs *codecs;
-@@ -850,10 +850,9 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
+
+@@ -841,10 +841,9 @@ static int sco_sock_setsockopt(struct so
break;
}
if (opt)
set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
-@@ -870,11 +869,10 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
+@@ -861,11 +860,10 @@ static int sco_sock_setsockopt(struct so
voice.setting = sco_pi(sk)->setting;
/* Explicitly check for these values */
if (voice.setting != BT_VOICE_TRANSPARENT &&
-@@ -887,10 +885,9 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
+@@ -878,10 +876,9 @@ static int sco_sock_setsockopt(struct so
break;
case BT_PKT_STATUS:
if (opt)
sco_pi(sk)->cmsg_mask |= SCO_CMSG_PKT_STATUS;
-@@ -931,9 +928,9 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
- break;
- }
-
-- if (copy_from_sockptr(buffer, optval, optlen)) {
-+ err = bt_copy_from_sockptr(buffer, optlen, optval, optlen);
-+ if (err) {
- hci_dev_put(hdev);
-- err = -EFAULT;
- break;
- }
-
---
-2.43.0
-
+++ /dev/null
-From e3e2c7a31fbb58c63dfa1ac477ee297e979f7eab Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sun, 15 Aug 2021 20:17:16 +0800
-Subject: Bluetooth: Support the quality report events
-
-From: Joseph Hwang <josephsih@chromium.org>
-
-[ Upstream commit ae7d925b5c0432c058fd175a70f1de6eee7a3f89 ]
-
-This patch allows a user space process to enable/disable the quality
-report events dynamically through the set experimental feature mgmt
-interface.
-
-Since the quality report feature needs to invoke the callback function
-provided by the driver, i.e., hdev->set_quality_report, a valid
-controller index is required.
-
-Reviewed-by: Miao-chen Chou <mcchou@chromium.org>
-Signed-off-by: Joseph Hwang <josephsih@chromium.org>
-Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
-Stable-dep-of: 51eda36d33e4 ("Bluetooth: SCO: Fix not validating setsockopt user input")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- include/net/bluetooth/hci.h | 1 +
- include/net/bluetooth/hci_core.h | 2 +
- net/bluetooth/mgmt.c | 109 ++++++++++++++++++++++++++++++-
- 3 files changed, 111 insertions(+), 1 deletion(-)
-
-diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
-index ede7a153c69a5..0e36974da384c 100644
---- a/include/net/bluetooth/hci.h
-+++ b/include/net/bluetooth/hci.h
-@@ -329,6 +329,7 @@ enum {
- HCI_ENABLE_LL_PRIVACY,
- HCI_CMD_PENDING,
- HCI_FORCE_NO_MITM,
-+ HCI_QUALITY_REPORT,
-
- __HCI_NUM_FLAGS,
- };
-diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
-index daafca376cb7c..c8f11dde54837 100644
---- a/include/net/bluetooth/hci_core.h
-+++ b/include/net/bluetooth/hci_core.h
-@@ -586,6 +586,7 @@ struct hci_dev {
- int (*set_bdaddr)(struct hci_dev *hdev, const bdaddr_t *bdaddr);
- void (*cmd_timeout)(struct hci_dev *hdev);
- bool (*prevent_wake)(struct hci_dev *hdev);
-+ int (*set_quality_report)(struct hci_dev *hdev, bool enable);
- };
-
- #define HCI_PHY_HANDLE(handle) (handle & 0xff)
-@@ -739,6 +740,7 @@ extern struct mutex hci_cb_list_lock;
- hci_dev_clear_flag(hdev, HCI_LE_ADV); \
- hci_dev_clear_flag(hdev, HCI_LL_RPA_RESOLUTION);\
- hci_dev_clear_flag(hdev, HCI_PERIODIC_INQ); \
-+ hci_dev_clear_flag(hdev, HCI_QUALITY_REPORT); \
- } while (0)
-
- /* ----- HCI interface to upper protocols ----- */
-diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
-index 8acfd9db00d63..b19ad142b8ba5 100644
---- a/net/bluetooth/mgmt.c
-+++ b/net/bluetooth/mgmt.c
-@@ -3769,6 +3769,12 @@ static const u8 debug_uuid[16] = {
- };
- #endif
-
-+/* 330859bc-7506-492d-9370-9a6f0614037f */
-+static const u8 quality_report_uuid[16] = {
-+ 0x7f, 0x03, 0x14, 0x06, 0x6f, 0x9a, 0x70, 0x93,
-+ 0x2d, 0x49, 0x06, 0x75, 0xbc, 0x59, 0x08, 0x33,
-+};
-+
- /* 671b10b5-42c0-4696-9227-eb28d1b049d6 */
- static const u8 simult_central_periph_uuid[16] = {
- 0xd6, 0x49, 0xb0, 0xd1, 0x28, 0xeb, 0x27, 0x92,
-@@ -3784,7 +3790,7 @@ static const u8 rpa_resolution_uuid[16] = {
- static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
- void *data, u16 data_len)
- {
-- char buf[62]; /* Enough space for 3 features */
-+ char buf[82]; /* Enough space for 4 features: 2 + 20 * 4 */
- struct mgmt_rp_read_exp_features_info *rp = (void *)buf;
- u16 idx = 0;
- u32 flags;
-@@ -3828,6 +3834,24 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
- idx++;
- }
-
-+ if (hdev) {
-+ if (hdev->set_quality_report) {
-+ /* BIT(0): indicating if set_quality_report is
-+ * supported by controller.
-+ */
-+ flags = BIT(0);
-+
-+ /* BIT(1): indicating if the feature is enabled. */
-+ if (hci_dev_test_flag(hdev, HCI_QUALITY_REPORT))
-+ flags |= BIT(1);
-+ } else {
-+ flags = 0;
-+ }
-+ memcpy(rp->features[idx].uuid, quality_report_uuid, 16);
-+ rp->features[idx].flags = cpu_to_le32(flags);
-+ idx++;
-+ }
-+
- rp->feature_count = cpu_to_le16(idx);
-
- /* After reading the experimental features information, enable
-@@ -3870,6 +3894,19 @@ static int exp_debug_feature_changed(bool enabled, struct sock *skip)
- }
- #endif
-
-+static int exp_quality_report_feature_changed(bool enabled, struct sock *skip)
-+{
-+ struct mgmt_ev_exp_feature_changed ev;
-+
-+ memset(&ev, 0, sizeof(ev));
-+ memcpy(ev.uuid, quality_report_uuid, 16);
-+ ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
-+
-+ return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, NULL,
-+ &ev, sizeof(ev),
-+ HCI_MGMT_EXP_FEATURE_EVENTS, skip);
-+}
-+
- #define EXP_FEAT(_uuid, _set_func) \
- { \
- .uuid = _uuid, \
-@@ -4024,6 +4061,75 @@ static int set_rpa_resolution_func(struct sock *sk, struct hci_dev *hdev,
- return err;
- }
-
-+static int set_quality_report_func(struct sock *sk, struct hci_dev *hdev,
-+ struct mgmt_cp_set_exp_feature *cp,
-+ u16 data_len)
-+{
-+ struct mgmt_rp_set_exp_feature rp;
-+ bool val, changed;
-+ int err;
-+
-+ /* Command requires to use a valid controller index */
-+ if (!hdev)
-+ return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
-+ MGMT_OP_SET_EXP_FEATURE,
-+ MGMT_STATUS_INVALID_INDEX);
-+
-+ /* Parameters are limited to a single octet */
-+ if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
-+ return mgmt_cmd_status(sk, hdev->id,
-+ MGMT_OP_SET_EXP_FEATURE,
-+ MGMT_STATUS_INVALID_PARAMS);
-+
-+ /* Only boolean on/off is supported */
-+ if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
-+ return mgmt_cmd_status(sk, hdev->id,
-+ MGMT_OP_SET_EXP_FEATURE,
-+ MGMT_STATUS_INVALID_PARAMS);
-+
-+ hci_req_sync_lock(hdev);
-+
-+ val = !!cp->param[0];
-+ changed = (val != hci_dev_test_flag(hdev, HCI_QUALITY_REPORT));
-+
-+ if (!hdev->set_quality_report) {
-+ err = mgmt_cmd_status(sk, hdev->id,
-+ MGMT_OP_SET_EXP_FEATURE,
-+ MGMT_STATUS_NOT_SUPPORTED);
-+ goto unlock_quality_report;
-+ }
-+
-+ if (changed) {
-+ err = hdev->set_quality_report(hdev, val);
-+ if (err) {
-+ err = mgmt_cmd_status(sk, hdev->id,
-+ MGMT_OP_SET_EXP_FEATURE,
-+ MGMT_STATUS_FAILED);
-+ goto unlock_quality_report;
-+ }
-+ if (val)
-+ hci_dev_set_flag(hdev, HCI_QUALITY_REPORT);
-+ else
-+ hci_dev_clear_flag(hdev, HCI_QUALITY_REPORT);
-+ }
-+
-+ bt_dev_dbg(hdev, "quality report enable %d changed %d", val, changed);
-+
-+ memcpy(rp.uuid, quality_report_uuid, 16);
-+ rp.flags = cpu_to_le32(val ? BIT(0) : 0);
-+ hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
-+ err = mgmt_cmd_complete(sk, hdev->id,
-+ MGMT_OP_SET_EXP_FEATURE, 0,
-+ &rp, sizeof(rp));
-+
-+ if (changed)
-+ exp_quality_report_feature_changed(val, sk);
-+
-+unlock_quality_report:
-+ hci_req_sync_unlock(hdev);
-+ return err;
-+}
-+
- static const struct mgmt_exp_feature {
- const u8 *uuid;
- int (*set_func)(struct sock *sk, struct hci_dev *hdev,
-@@ -4034,6 +4140,7 @@ static const struct mgmt_exp_feature {
- EXP_FEAT(debug_uuid, set_debug_func),
- #endif
- EXP_FEAT(rpa_resolution_uuid, set_rpa_resolution_func),
-+ EXP_FEAT(quality_report_uuid, set_quality_report_func),
-
- /* end with a null feature */
- EXP_FEAT(NULL, NULL)
---
-2.43.0
-
ipv6-fib-hide-unused-pn-variable.patch
ipv4-route-avoid-unused-but-set-variable-warning.patch
ipv6-fix-race-condition-between-ipv6_get_ifaddr-and-.patch
-bluetooth-fix-mgmt-status-for-ll-privacy-experimenta.patch
-bluetooth-add-support-for-reading-aosp-vendor-capabi.patch
-bluetooth-refactor-set_exp_feature-with-a-feature-ta.patch
-bluetooth-support-the-quality-report-events.patch
-bluetooth-enumerate-local-supported-codec-and-cache-.patch
-bluetooth-allow-querying-of-supported-offload-codecs.patch
-bluetooth-allow-setting-of-codec-for-hfp-offload-use.patch
bluetooth-sco-fix-not-validating-setsockopt-user-inp.patch
netfilter-complete-validation-of-user-input.patch
net-mlx5-properly-link-new-fs-rules-into-the-tree.patch