diff mbox series

[v1,2/7] Bluetooth: Add handler of MGMT_OP_READ_ADV_MONITOR_FEATURES

Message ID 20200528165324.v1.2.I7f3372c74a6569cd3445b77a67a0b0fcfdd8a333@changeid (mailing list archive)
State Superseded
Delegated to: Marcel Holtmann
Headers show
Series [v1,1/7] Bluetooth: Add definitions for advertisement monitor features | expand

Commit Message

Miao-chen Chou May 28, 2020, 11:54 p.m. UTC
This adds the request handler of MGMT_OP_READ_ADV_MONITOR_FEATURES
command. Since the controller-based monitoring is not yet in place, this
report only the supported features but not the enabled features.

The following test was performed.
- Issuing btmgmt advmon-features.

Signed-off-by: Miao-chen Chou <mcchou@chromium.org>
---

 include/net/bluetooth/hci_core.h | 24 +++++++++++++++++
 net/bluetooth/hci_core.c         | 10 ++++++-
 net/bluetooth/mgmt.c             | 46 ++++++++++++++++++++++++++++++++
 net/bluetooth/msft.c             |  7 +++++
 net/bluetooth/msft.h             |  9 +++++++
 5 files changed, 95 insertions(+), 1 deletion(-)

Comments

Marcel Holtmann June 3, 2020, 5:59 p.m. UTC | #1
Hi Miao-chen,

> This adds the request handler of MGMT_OP_READ_ADV_MONITOR_FEATURES
> command. Since the controller-based monitoring is not yet in place, this
> report only the supported features but not the enabled features.
> 
> The following test was performed.
> - Issuing btmgmt advmon-features.
> 
> Signed-off-by: Miao-chen Chou <mcchou@chromium.org>
> ---
> 
> include/net/bluetooth/hci_core.h | 24 +++++++++++++++++
> net/bluetooth/hci_core.c         | 10 ++++++-
> net/bluetooth/mgmt.c             | 46 ++++++++++++++++++++++++++++++++
> net/bluetooth/msft.c             |  7 +++++
> net/bluetooth/msft.h             |  9 +++++++
> 5 files changed, 95 insertions(+), 1 deletion(-)
> 
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index cdd4f1db8670e..431fe0265dcfb 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -25,6 +25,7 @@
> #ifndef __HCI_CORE_H
> #define __HCI_CORE_H
> 
> +#include <linux/idr.h>
> #include <linux/leds.h>
> #include <linux/rculist.h>
> 
> @@ -220,6 +221,24 @@ struct adv_info {
> #define HCI_MAX_ADV_INSTANCES		5
> #define HCI_DEFAULT_ADV_DURATION	2
> 
> +struct adv_pattern {
> +	struct list_head list;
> +	__u8 ad_type;
> +	__u8 offset;
> +	__u8 length;
> +	__u8 value[HCI_MAX_AD_LENGTH];
> +};
> +
> +struct adv_monitor {
> +	struct list_head patterns;
> +	bool		active;
> +	__u16		handle;
> +};
> +
> +#define HCI_MIN_ADV_MONITOR_HANDLE		1
> +#define HCI_MAX_ADV_MONITOR_NUM_HANDLES	32
> +#define HCI_MAX_ADV_MONITOR_NUM_PATTERNS	16
> +
> #define HCI_MAX_SHORT_NAME_LENGTH	10
> 
> /* Min encryption key size to match with SMP */
> @@ -477,6 +496,9 @@ struct hci_dev {
> 	__u16			adv_instance_timeout;
> 	struct delayed_work	adv_instance_expire;
> 
> +	struct idr		adv_monitors_idr;
> +	unsigned int		adv_monitors_cnt;
> +
> 	__u8			irk[16];
> 	__u32			rpa_timeout;
> 	struct delayed_work	rpa_expired;
> @@ -1217,6 +1239,8 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
> int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance);
> void hci_adv_instances_set_rpa_expired(struct hci_dev *hdev, bool rpa_expired);
> 
> +void hci_adv_monitors_clear(struct hci_dev *hdev);
> +
> void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
> 
> void hci_init_sysfs(struct hci_dev *hdev);
> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
> index dbe2d79f233fb..23bfe4f1d1e9d 100644
> --- a/net/bluetooth/hci_core.c
> +++ b/net/bluetooth/hci_core.c
> @@ -26,7 +26,6 @@
> /* Bluetooth HCI core. */
> 
> #include <linux/export.h>
> -#include <linux/idr.h>
> #include <linux/rfkill.h>
> #include <linux/debugfs.h>
> #include <linux/crypto.h>
> @@ -2996,6 +2995,12 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
> 	return 0;
> }
> 
> +/* This function requires the caller holds hdev->lock */
> +void hci_adv_monitors_clear(struct hci_dev *hdev)
> +{
> +	idr_destroy(&hdev->adv_monitors_idr);
> +}
> +
> struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list,
> 					 bdaddr_t *bdaddr, u8 type)
> {
> @@ -3574,6 +3579,8 @@ int hci_register_dev(struct hci_dev *hdev)
> 
> 	queue_work(hdev->req_workqueue, &hdev->power_on);
> 
> +	idr_init(&hdev->adv_monitors_idr);
> +
> 	return id;
> 
> err_wqueue:
> @@ -3644,6 +3651,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
> 	hci_smp_irks_clear(hdev);
> 	hci_remote_oob_data_clear(hdev);
> 	hci_adv_instances_clear(hdev);
> +	hci_adv_monitors_clear(hdev);
> 	hci_bdaddr_list_clear(&hdev->le_white_list);
> 	hci_bdaddr_list_clear(&hdev->le_resolv_list);
> 	hci_conn_params_clear_all(hdev);
> diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
> index 9e8a3cccc6ca3..8d8275ee9718b 100644
> --- a/net/bluetooth/mgmt.c
> +++ b/net/bluetooth/mgmt.c
> @@ -36,6 +36,7 @@
> #include "hci_request.h"
> #include "smp.h"
> #include "mgmt_util.h"
> +#include "msft.h"
> 
> #define MGMT_VERSION	1
> #define MGMT_REVISION	17
> @@ -111,6 +112,7 @@ static const u16 mgmt_commands[] = {
> 	MGMT_OP_READ_SECURITY_INFO,
> 	MGMT_OP_READ_EXP_FEATURES_INFO,
> 	MGMT_OP_SET_EXP_FEATURE,
> +	MGMT_OP_READ_ADV_MONITOR_FEATURES,
> };
> 
> static const u16 mgmt_events[] = {
> @@ -3849,6 +3851,49 @@ static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
> 			       MGMT_STATUS_NOT_SUPPORTED);
> }
> 
> +static int read_adv_monitor_features(struct sock *sk, struct hci_dev *hdev,
> +				     void *data, u16 len)
> +{
> +	struct adv_monitor *monitor = NULL;
> +	struct mgmt_rp_read_adv_monitor_features *rp = NULL;
> +	int handle;
> +	size_t rp_size = 0;
> +	__u32 supported = 0;
> +	__u16 num_handles = 0;
> +	__u16 handles[HCI_MAX_ADV_MONITOR_NUM_HANDLES];
> +
> +	BT_DBG("request for %s", hdev->name);
> +
> +	hci_dev_lock(hdev);
> +
> +	if (msft_get_features(hdev) & MSFT_FEATURE_MASK_LE_ADV_MONITOR)
> +		supported |= MGMT_ADV_MONITOR_FEATURE_MASK_OR_PATTERNS;
> +
> +	idr_for_each_entry(&hdev->adv_monitors_idr, monitor, handle)
> +		handles[num_handles++] = monitor->handle;

I would put { } here to make it readable.

> +
> +	hci_dev_unlock(hdev);
> +
> +	rp_size = sizeof(*rp) + (num_handles * sizeof(u16));
> +	rp = kmalloc(rp_size, GFP_KERNEL);
> +	if (!rp)
> +		return -ENOMEM;
> +
> +	// Once controller-based monitoring is in place, the enabled_features
> +	// should reflect the use.

Please use /* */ comment style here.

> +	rp->supported_features = supported;
> +	rp->enabled_features = 0;
> +	rp->max_num_handles = HCI_MAX_ADV_MONITOR_NUM_HANDLES;
> +	rp->max_num_patterns = HCI_MAX_ADV_MONITOR_NUM_PATTERNS;

These are little-endian.

> +	rp->num_handles = num_handles;
> +	if (num_handles)
> +		memcpy(&rp->handles, &handles, (num_handles * sizeof(u16)));
> +
> +	return mgmt_cmd_complete(sk, hdev->id,
> +				 MGMT_OP_READ_ADV_MONITOR_FEATURES,
> +				 MGMT_STATUS_SUCCESS, rp, rp_size);
> +}
> +
> static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
> 				         u16 opcode, struct sk_buff *skb)
> {
> @@ -7297,6 +7342,7 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
> 	{ set_exp_feature,         MGMT_SET_EXP_FEATURE_SIZE,
> 						HCI_MGMT_VAR_LEN |
> 						HCI_MGMT_HDEV_OPTIONAL },
> +	{ read_adv_monitor_features, MGMT_READ_ADV_MONITOR_FEATURES_SIZE },
> };
> 
> void mgmt_index_added(struct hci_dev *hdev)
> diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
> index d6c4e6b5ae777..8579bfeb28364 100644
> --- a/net/bluetooth/msft.c
> +++ b/net/bluetooth/msft.c
> @@ -139,3 +139,10 @@ void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb)
> 
> 	bt_dev_dbg(hdev, "MSFT vendor event %u", event);
> }
> +
> +__u64 msft_get_features(struct hci_dev *hdev)
> +{
> +	struct msft_data *msft = hdev->msft_data;
> +
> +	return  msft ? msft->features : 0;
> +}
> diff --git a/net/bluetooth/msft.h b/net/bluetooth/msft.h
> index 5aa9130e1f8ab..e9c478e890b8b 100644
> --- a/net/bluetooth/msft.h
> +++ b/net/bluetooth/msft.h
> @@ -3,16 +3,25 @@
>  * Copyright (C) 2020 Google Corporation
>  */
> 
> +#define MSFT_FEATURE_MASK_BREDR_RSSI_MONITOR		BIT(0)
> +#define MSFT_FEATURE_MASK_LE_CONN_RSSI_MONITOR		BIT(1)
> +#define MSFT_FEATURE_MASK_LE_ADV_RSSI_MONITOR		BIT(2)
> +#define MSFT_FEATURE_MASK_LE_ADV_MONITOR		BIT(3)
> +#define MSFT_FEATURE_MASK_CURVE_VALIDITY		BIT(4)
> +#define MSFT_FEATURE_MASK_CONCURRENT_ADV_MONITOR	BIT(5)
> +
> #if IS_ENABLED(CONFIG_BT_MSFTEXT)
> 
> void msft_do_open(struct hci_dev *hdev);
> void msft_do_close(struct hci_dev *hdev);
> void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb);
> +__u64 msft_get_features(struct hci_dev *hdev);
> 
> #else
> 
> static inline void msft_do_open(struct hci_dev *hdev) {}
> static inline void msft_do_close(struct hci_dev *hdev) {}
> static inline void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb) {}
> +static inline __u64 msft_get_features(struct hci_dev *hdev) { return 0; }

Regards

Marcel
Miao-chen Chou June 3, 2020, 11:05 p.m. UTC | #2
Hi Marcel,

Thanks for your review. V2 was uploaded to address these 3 comments.

Regards,
Miao

On Wed, Jun 3, 2020 at 10:59 AM Marcel Holtmann <marcel@holtmann.org> wrote:
>
> Hi Miao-chen,
>
> > This adds the request handler of MGMT_OP_READ_ADV_MONITOR_FEATURES
> > command. Since the controller-based monitoring is not yet in place, this
> > report only the supported features but not the enabled features.
> >
> > The following test was performed.
> > - Issuing btmgmt advmon-features.
> >
> > Signed-off-by: Miao-chen Chou <mcchou@chromium.org>
> > ---
> >
> > include/net/bluetooth/hci_core.h | 24 +++++++++++++++++
> > net/bluetooth/hci_core.c         | 10 ++++++-
> > net/bluetooth/mgmt.c             | 46 ++++++++++++++++++++++++++++++++
> > net/bluetooth/msft.c             |  7 +++++
> > net/bluetooth/msft.h             |  9 +++++++
> > 5 files changed, 95 insertions(+), 1 deletion(-)
> >
> > diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> > index cdd4f1db8670e..431fe0265dcfb 100644
> > --- a/include/net/bluetooth/hci_core.h
> > +++ b/include/net/bluetooth/hci_core.h
> > @@ -25,6 +25,7 @@
> > #ifndef __HCI_CORE_H
> > #define __HCI_CORE_H
> >
> > +#include <linux/idr.h>
> > #include <linux/leds.h>
> > #include <linux/rculist.h>
> >
> > @@ -220,6 +221,24 @@ struct adv_info {
> > #define HCI_MAX_ADV_INSTANCES         5
> > #define HCI_DEFAULT_ADV_DURATION      2
> >
> > +struct adv_pattern {
> > +     struct list_head list;
> > +     __u8 ad_type;
> > +     __u8 offset;
> > +     __u8 length;
> > +     __u8 value[HCI_MAX_AD_LENGTH];
> > +};
> > +
> > +struct adv_monitor {
> > +     struct list_head patterns;
> > +     bool            active;
> > +     __u16           handle;
> > +};
> > +
> > +#define HCI_MIN_ADV_MONITOR_HANDLE           1
> > +#define HCI_MAX_ADV_MONITOR_NUM_HANDLES      32
> > +#define HCI_MAX_ADV_MONITOR_NUM_PATTERNS     16
> > +
> > #define HCI_MAX_SHORT_NAME_LENGTH     10
> >
> > /* Min encryption key size to match with SMP */
> > @@ -477,6 +496,9 @@ struct hci_dev {
> >       __u16                   adv_instance_timeout;
> >       struct delayed_work     adv_instance_expire;
> >
> > +     struct idr              adv_monitors_idr;
> > +     unsigned int            adv_monitors_cnt;
> > +
> >       __u8                    irk[16];
> >       __u32                   rpa_timeout;
> >       struct delayed_work     rpa_expired;
> > @@ -1217,6 +1239,8 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
> > int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance);
> > void hci_adv_instances_set_rpa_expired(struct hci_dev *hdev, bool rpa_expired);
> >
> > +void hci_adv_monitors_clear(struct hci_dev *hdev);
> > +
> > void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
> >
> > void hci_init_sysfs(struct hci_dev *hdev);
> > diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
> > index dbe2d79f233fb..23bfe4f1d1e9d 100644
> > --- a/net/bluetooth/hci_core.c
> > +++ b/net/bluetooth/hci_core.c
> > @@ -26,7 +26,6 @@
> > /* Bluetooth HCI core. */
> >
> > #include <linux/export.h>
> > -#include <linux/idr.h>
> > #include <linux/rfkill.h>
> > #include <linux/debugfs.h>
> > #include <linux/crypto.h>
> > @@ -2996,6 +2995,12 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
> >       return 0;
> > }
> >
> > +/* This function requires the caller holds hdev->lock */
> > +void hci_adv_monitors_clear(struct hci_dev *hdev)
> > +{
> > +     idr_destroy(&hdev->adv_monitors_idr);
> > +}
> > +
> > struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list,
> >                                        bdaddr_t *bdaddr, u8 type)
> > {
> > @@ -3574,6 +3579,8 @@ int hci_register_dev(struct hci_dev *hdev)
> >
> >       queue_work(hdev->req_workqueue, &hdev->power_on);
> >
> > +     idr_init(&hdev->adv_monitors_idr);
> > +
> >       return id;
> >
> > err_wqueue:
> > @@ -3644,6 +3651,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
> >       hci_smp_irks_clear(hdev);
> >       hci_remote_oob_data_clear(hdev);
> >       hci_adv_instances_clear(hdev);
> > +     hci_adv_monitors_clear(hdev);
> >       hci_bdaddr_list_clear(&hdev->le_white_list);
> >       hci_bdaddr_list_clear(&hdev->le_resolv_list);
> >       hci_conn_params_clear_all(hdev);
> > diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
> > index 9e8a3cccc6ca3..8d8275ee9718b 100644
> > --- a/net/bluetooth/mgmt.c
> > +++ b/net/bluetooth/mgmt.c
> > @@ -36,6 +36,7 @@
> > #include "hci_request.h"
> > #include "smp.h"
> > #include "mgmt_util.h"
> > +#include "msft.h"
> >
> > #define MGMT_VERSION  1
> > #define MGMT_REVISION 17
> > @@ -111,6 +112,7 @@ static const u16 mgmt_commands[] = {
> >       MGMT_OP_READ_SECURITY_INFO,
> >       MGMT_OP_READ_EXP_FEATURES_INFO,
> >       MGMT_OP_SET_EXP_FEATURE,
> > +     MGMT_OP_READ_ADV_MONITOR_FEATURES,
> > };
> >
> > static const u16 mgmt_events[] = {
> > @@ -3849,6 +3851,49 @@ static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
> >                              MGMT_STATUS_NOT_SUPPORTED);
> > }
> >
> > +static int read_adv_monitor_features(struct sock *sk, struct hci_dev *hdev,
> > +                                  void *data, u16 len)
> > +{
> > +     struct adv_monitor *monitor = NULL;
> > +     struct mgmt_rp_read_adv_monitor_features *rp = NULL;
> > +     int handle;
> > +     size_t rp_size = 0;
> > +     __u32 supported = 0;
> > +     __u16 num_handles = 0;
> > +     __u16 handles[HCI_MAX_ADV_MONITOR_NUM_HANDLES];
> > +
> > +     BT_DBG("request for %s", hdev->name);
> > +
> > +     hci_dev_lock(hdev);
> > +
> > +     if (msft_get_features(hdev) & MSFT_FEATURE_MASK_LE_ADV_MONITOR)
> > +             supported |= MGMT_ADV_MONITOR_FEATURE_MASK_OR_PATTERNS;
> > +
> > +     idr_for_each_entry(&hdev->adv_monitors_idr, monitor, handle)
> > +             handles[num_handles++] = monitor->handle;
>
> I would put { } here to make it readable.
>
> > +
> > +     hci_dev_unlock(hdev);
> > +
> > +     rp_size = sizeof(*rp) + (num_handles * sizeof(u16));
> > +     rp = kmalloc(rp_size, GFP_KERNEL);
> > +     if (!rp)
> > +             return -ENOMEM;
> > +
> > +     // Once controller-based monitoring is in place, the enabled_features
> > +     // should reflect the use.
>
> Please use /* */ comment style here.
>
> > +     rp->supported_features = supported;
> > +     rp->enabled_features = 0;
> > +     rp->max_num_handles = HCI_MAX_ADV_MONITOR_NUM_HANDLES;
> > +     rp->max_num_patterns = HCI_MAX_ADV_MONITOR_NUM_PATTERNS;
>
> These are little-endian.
>
> > +     rp->num_handles = num_handles;
> > +     if (num_handles)
> > +             memcpy(&rp->handles, &handles, (num_handles * sizeof(u16)));
> > +
> > +     return mgmt_cmd_complete(sk, hdev->id,
> > +                              MGMT_OP_READ_ADV_MONITOR_FEATURES,
> > +                              MGMT_STATUS_SUCCESS, rp, rp_size);
> > +}
> > +
> > static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
> >                                        u16 opcode, struct sk_buff *skb)
> > {
> > @@ -7297,6 +7342,7 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
> >       { set_exp_feature,         MGMT_SET_EXP_FEATURE_SIZE,
> >                                               HCI_MGMT_VAR_LEN |
> >                                               HCI_MGMT_HDEV_OPTIONAL },
> > +     { read_adv_monitor_features, MGMT_READ_ADV_MONITOR_FEATURES_SIZE },
> > };
> >
> > void mgmt_index_added(struct hci_dev *hdev)
> > diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
> > index d6c4e6b5ae777..8579bfeb28364 100644
> > --- a/net/bluetooth/msft.c
> > +++ b/net/bluetooth/msft.c
> > @@ -139,3 +139,10 @@ void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb)
> >
> >       bt_dev_dbg(hdev, "MSFT vendor event %u", event);
> > }
> > +
> > +__u64 msft_get_features(struct hci_dev *hdev)
> > +{
> > +     struct msft_data *msft = hdev->msft_data;
> > +
> > +     return  msft ? msft->features : 0;
> > +}
> > diff --git a/net/bluetooth/msft.h b/net/bluetooth/msft.h
> > index 5aa9130e1f8ab..e9c478e890b8b 100644
> > --- a/net/bluetooth/msft.h
> > +++ b/net/bluetooth/msft.h
> > @@ -3,16 +3,25 @@
> >  * Copyright (C) 2020 Google Corporation
> >  */
> >
> > +#define MSFT_FEATURE_MASK_BREDR_RSSI_MONITOR         BIT(0)
> > +#define MSFT_FEATURE_MASK_LE_CONN_RSSI_MONITOR               BIT(1)
> > +#define MSFT_FEATURE_MASK_LE_ADV_RSSI_MONITOR                BIT(2)
> > +#define MSFT_FEATURE_MASK_LE_ADV_MONITOR             BIT(3)
> > +#define MSFT_FEATURE_MASK_CURVE_VALIDITY             BIT(4)
> > +#define MSFT_FEATURE_MASK_CONCURRENT_ADV_MONITOR     BIT(5)
> > +
> > #if IS_ENABLED(CONFIG_BT_MSFTEXT)
> >
> > void msft_do_open(struct hci_dev *hdev);
> > void msft_do_close(struct hci_dev *hdev);
> > void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb);
> > +__u64 msft_get_features(struct hci_dev *hdev);
> >
> > #else
> >
> > static inline void msft_do_open(struct hci_dev *hdev) {}
> > static inline void msft_do_close(struct hci_dev *hdev) {}
> > static inline void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb) {}
> > +static inline __u64 msft_get_features(struct hci_dev *hdev) { return 0; }
>
> Regards
>
> Marcel
>
diff mbox series

Patch

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index cdd4f1db8670e..431fe0265dcfb 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -25,6 +25,7 @@ 
 #ifndef __HCI_CORE_H
 #define __HCI_CORE_H
 
+#include <linux/idr.h>
 #include <linux/leds.h>
 #include <linux/rculist.h>
 
@@ -220,6 +221,24 @@  struct adv_info {
 #define HCI_MAX_ADV_INSTANCES		5
 #define HCI_DEFAULT_ADV_DURATION	2
 
+struct adv_pattern {
+	struct list_head list;
+	__u8 ad_type;
+	__u8 offset;
+	__u8 length;
+	__u8 value[HCI_MAX_AD_LENGTH];
+};
+
+struct adv_monitor {
+	struct list_head patterns;
+	bool		active;
+	__u16		handle;
+};
+
+#define HCI_MIN_ADV_MONITOR_HANDLE		1
+#define HCI_MAX_ADV_MONITOR_NUM_HANDLES	32
+#define HCI_MAX_ADV_MONITOR_NUM_PATTERNS	16
+
 #define HCI_MAX_SHORT_NAME_LENGTH	10
 
 /* Min encryption key size to match with SMP */
@@ -477,6 +496,9 @@  struct hci_dev {
 	__u16			adv_instance_timeout;
 	struct delayed_work	adv_instance_expire;
 
+	struct idr		adv_monitors_idr;
+	unsigned int		adv_monitors_cnt;
+
 	__u8			irk[16];
 	__u32			rpa_timeout;
 	struct delayed_work	rpa_expired;
@@ -1217,6 +1239,8 @@  int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
 int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance);
 void hci_adv_instances_set_rpa_expired(struct hci_dev *hdev, bool rpa_expired);
 
+void hci_adv_monitors_clear(struct hci_dev *hdev);
+
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
 
 void hci_init_sysfs(struct hci_dev *hdev);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index dbe2d79f233fb..23bfe4f1d1e9d 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -26,7 +26,6 @@ 
 /* Bluetooth HCI core. */
 
 #include <linux/export.h>
-#include <linux/idr.h>
 #include <linux/rfkill.h>
 #include <linux/debugfs.h>
 #include <linux/crypto.h>
@@ -2996,6 +2995,12 @@  int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
 	return 0;
 }
 
+/* This function requires the caller holds hdev->lock */
+void hci_adv_monitors_clear(struct hci_dev *hdev)
+{
+	idr_destroy(&hdev->adv_monitors_idr);
+}
+
 struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list,
 					 bdaddr_t *bdaddr, u8 type)
 {
@@ -3574,6 +3579,8 @@  int hci_register_dev(struct hci_dev *hdev)
 
 	queue_work(hdev->req_workqueue, &hdev->power_on);
 
+	idr_init(&hdev->adv_monitors_idr);
+
 	return id;
 
 err_wqueue:
@@ -3644,6 +3651,7 @@  void hci_unregister_dev(struct hci_dev *hdev)
 	hci_smp_irks_clear(hdev);
 	hci_remote_oob_data_clear(hdev);
 	hci_adv_instances_clear(hdev);
+	hci_adv_monitors_clear(hdev);
 	hci_bdaddr_list_clear(&hdev->le_white_list);
 	hci_bdaddr_list_clear(&hdev->le_resolv_list);
 	hci_conn_params_clear_all(hdev);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 9e8a3cccc6ca3..8d8275ee9718b 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -36,6 +36,7 @@ 
 #include "hci_request.h"
 #include "smp.h"
 #include "mgmt_util.h"
+#include "msft.h"
 
 #define MGMT_VERSION	1
 #define MGMT_REVISION	17
@@ -111,6 +112,7 @@  static const u16 mgmt_commands[] = {
 	MGMT_OP_READ_SECURITY_INFO,
 	MGMT_OP_READ_EXP_FEATURES_INFO,
 	MGMT_OP_SET_EXP_FEATURE,
+	MGMT_OP_READ_ADV_MONITOR_FEATURES,
 };
 
 static const u16 mgmt_events[] = {
@@ -3849,6 +3851,49 @@  static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
 			       MGMT_STATUS_NOT_SUPPORTED);
 }
 
+static int read_adv_monitor_features(struct sock *sk, struct hci_dev *hdev,
+				     void *data, u16 len)
+{
+	struct adv_monitor *monitor = NULL;
+	struct mgmt_rp_read_adv_monitor_features *rp = NULL;
+	int handle;
+	size_t rp_size = 0;
+	__u32 supported = 0;
+	__u16 num_handles = 0;
+	__u16 handles[HCI_MAX_ADV_MONITOR_NUM_HANDLES];
+
+	BT_DBG("request for %s", hdev->name);
+
+	hci_dev_lock(hdev);
+
+	if (msft_get_features(hdev) & MSFT_FEATURE_MASK_LE_ADV_MONITOR)
+		supported |= MGMT_ADV_MONITOR_FEATURE_MASK_OR_PATTERNS;
+
+	idr_for_each_entry(&hdev->adv_monitors_idr, monitor, handle)
+		handles[num_handles++] = monitor->handle;
+
+	hci_dev_unlock(hdev);
+
+	rp_size = sizeof(*rp) + (num_handles * sizeof(u16));
+	rp = kmalloc(rp_size, GFP_KERNEL);
+	if (!rp)
+		return -ENOMEM;
+
+	// Once controller-based monitoring is in place, the enabled_features
+	// should reflect the use.
+	rp->supported_features = supported;
+	rp->enabled_features = 0;
+	rp->max_num_handles = HCI_MAX_ADV_MONITOR_NUM_HANDLES;
+	rp->max_num_patterns = HCI_MAX_ADV_MONITOR_NUM_PATTERNS;
+	rp->num_handles = num_handles;
+	if (num_handles)
+		memcpy(&rp->handles, &handles, (num_handles * sizeof(u16)));
+
+	return mgmt_cmd_complete(sk, hdev->id,
+				 MGMT_OP_READ_ADV_MONITOR_FEATURES,
+				 MGMT_STATUS_SUCCESS, rp, rp_size);
+}
+
 static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
 				         u16 opcode, struct sk_buff *skb)
 {
@@ -7297,6 +7342,7 @@  static const struct hci_mgmt_handler mgmt_handlers[] = {
 	{ set_exp_feature,         MGMT_SET_EXP_FEATURE_SIZE,
 						HCI_MGMT_VAR_LEN |
 						HCI_MGMT_HDEV_OPTIONAL },
+	{ read_adv_monitor_features, MGMT_READ_ADV_MONITOR_FEATURES_SIZE },
 };
 
 void mgmt_index_added(struct hci_dev *hdev)
diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index d6c4e6b5ae777..8579bfeb28364 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -139,3 +139,10 @@  void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
 	bt_dev_dbg(hdev, "MSFT vendor event %u", event);
 }
+
+__u64 msft_get_features(struct hci_dev *hdev)
+{
+	struct msft_data *msft = hdev->msft_data;
+
+	return  msft ? msft->features : 0;
+}
diff --git a/net/bluetooth/msft.h b/net/bluetooth/msft.h
index 5aa9130e1f8ab..e9c478e890b8b 100644
--- a/net/bluetooth/msft.h
+++ b/net/bluetooth/msft.h
@@ -3,16 +3,25 @@ 
  * Copyright (C) 2020 Google Corporation
  */
 
+#define MSFT_FEATURE_MASK_BREDR_RSSI_MONITOR		BIT(0)
+#define MSFT_FEATURE_MASK_LE_CONN_RSSI_MONITOR		BIT(1)
+#define MSFT_FEATURE_MASK_LE_ADV_RSSI_MONITOR		BIT(2)
+#define MSFT_FEATURE_MASK_LE_ADV_MONITOR		BIT(3)
+#define MSFT_FEATURE_MASK_CURVE_VALIDITY		BIT(4)
+#define MSFT_FEATURE_MASK_CONCURRENT_ADV_MONITOR	BIT(5)
+
 #if IS_ENABLED(CONFIG_BT_MSFTEXT)
 
 void msft_do_open(struct hci_dev *hdev);
 void msft_do_close(struct hci_dev *hdev);
 void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb);
+__u64 msft_get_features(struct hci_dev *hdev);
 
 #else
 
 static inline void msft_do_open(struct hci_dev *hdev) {}
 static inline void msft_do_close(struct hci_dev *hdev) {}
 static inline void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb) {}
+static inline __u64 msft_get_features(struct hci_dev *hdev) { return 0; }
 
 #endif