xref: /openbmc/linux/net/bluetooth/msft.c (revision a85a60e6)
1145373cbSMiao-chen Chou // SPDX-License-Identifier: GPL-2.0-only
2145373cbSMiao-chen Chou /*
3145373cbSMiao-chen Chou  * Copyright (C) 2020 Google Corporation
4145373cbSMiao-chen Chou  */
5145373cbSMiao-chen Chou 
6145373cbSMiao-chen Chou #include <net/bluetooth/bluetooth.h>
7145373cbSMiao-chen Chou #include <net/bluetooth/hci_core.h>
8a2a4dedfSArchie Pusaka #include <net/bluetooth/mgmt.h>
9145373cbSMiao-chen Chou 
10a2a4dedfSArchie Pusaka #include "hci_request.h"
11a2a4dedfSArchie Pusaka #include "mgmt_util.h"
12145373cbSMiao-chen Chou #include "msft.h"
13145373cbSMiao-chen Chou 
14a2a4dedfSArchie Pusaka #define MSFT_RSSI_THRESHOLD_VALUE_MIN		-127
15a2a4dedfSArchie Pusaka #define MSFT_RSSI_THRESHOLD_VALUE_MAX		20
16a2a4dedfSArchie Pusaka #define MSFT_RSSI_LOW_TIMEOUT_MAX		0x3C
17a2a4dedfSArchie Pusaka 
18145373cbSMiao-chen Chou #define MSFT_OP_READ_SUPPORTED_FEATURES		0x00
19145373cbSMiao-chen Chou struct msft_cp_read_supported_features {
20145373cbSMiao-chen Chou 	__u8   sub_opcode;
21145373cbSMiao-chen Chou } __packed;
22b08eadd2SGustavo A. R. Silva 
23145373cbSMiao-chen Chou struct msft_rp_read_supported_features {
24145373cbSMiao-chen Chou 	__u8   status;
25145373cbSMiao-chen Chou 	__u8   sub_opcode;
26145373cbSMiao-chen Chou 	__le64 features;
27145373cbSMiao-chen Chou 	__u8   evt_prefix_len;
28b08eadd2SGustavo A. R. Silva 	__u8   evt_prefix[];
29145373cbSMiao-chen Chou } __packed;
30145373cbSMiao-chen Chou 
31a2a4dedfSArchie Pusaka #define MSFT_OP_LE_MONITOR_ADVERTISEMENT	0x03
32a2a4dedfSArchie Pusaka #define MSFT_MONITOR_ADVERTISEMENT_TYPE_PATTERN	0x01
33a2a4dedfSArchie Pusaka struct msft_le_monitor_advertisement_pattern {
34a2a4dedfSArchie Pusaka 	__u8 length;
35a2a4dedfSArchie Pusaka 	__u8 data_type;
36a2a4dedfSArchie Pusaka 	__u8 start_byte;
3707d85dbeSQiheng Lin 	__u8 pattern[];
38a2a4dedfSArchie Pusaka };
39a2a4dedfSArchie Pusaka 
40a2a4dedfSArchie Pusaka struct msft_le_monitor_advertisement_pattern_data {
41a2a4dedfSArchie Pusaka 	__u8 count;
4207d85dbeSQiheng Lin 	__u8 data[];
43a2a4dedfSArchie Pusaka };
44a2a4dedfSArchie Pusaka 
45a2a4dedfSArchie Pusaka struct msft_cp_le_monitor_advertisement {
46a2a4dedfSArchie Pusaka 	__u8 sub_opcode;
47a2a4dedfSArchie Pusaka 	__s8 rssi_high;
48a2a4dedfSArchie Pusaka 	__s8 rssi_low;
49a2a4dedfSArchie Pusaka 	__u8 rssi_low_interval;
50a2a4dedfSArchie Pusaka 	__u8 rssi_sampling_period;
51a2a4dedfSArchie Pusaka 	__u8 cond_type;
5207d85dbeSQiheng Lin 	__u8 data[];
53a2a4dedfSArchie Pusaka } __packed;
54a2a4dedfSArchie Pusaka 
55a2a4dedfSArchie Pusaka struct msft_rp_le_monitor_advertisement {
56a2a4dedfSArchie Pusaka 	__u8 status;
57a2a4dedfSArchie Pusaka 	__u8 sub_opcode;
58a2a4dedfSArchie Pusaka 	__u8 handle;
59a2a4dedfSArchie Pusaka } __packed;
60a2a4dedfSArchie Pusaka 
6166bd095aSArchie Pusaka #define MSFT_OP_LE_CANCEL_MONITOR_ADVERTISEMENT	0x04
6266bd095aSArchie Pusaka struct msft_cp_le_cancel_monitor_advertisement {
6366bd095aSArchie Pusaka 	__u8 sub_opcode;
6466bd095aSArchie Pusaka 	__u8 handle;
6566bd095aSArchie Pusaka } __packed;
6666bd095aSArchie Pusaka 
6766bd095aSArchie Pusaka struct msft_rp_le_cancel_monitor_advertisement {
6866bd095aSArchie Pusaka 	__u8 status;
6966bd095aSArchie Pusaka 	__u8 sub_opcode;
7066bd095aSArchie Pusaka } __packed;
7166bd095aSArchie Pusaka 
72394566bfSArchie Pusaka #define MSFT_OP_LE_SET_ADVERTISEMENT_FILTER_ENABLE	0x05
73394566bfSArchie Pusaka struct msft_cp_le_set_advertisement_filter_enable {
74394566bfSArchie Pusaka 	__u8 sub_opcode;
75394566bfSArchie Pusaka 	__u8 enable;
76394566bfSArchie Pusaka } __packed;
77394566bfSArchie Pusaka 
78394566bfSArchie Pusaka struct msft_rp_le_set_advertisement_filter_enable {
79394566bfSArchie Pusaka 	__u8 status;
80394566bfSArchie Pusaka 	__u8 sub_opcode;
81394566bfSArchie Pusaka } __packed;
82394566bfSArchie Pusaka 
833368aa35SManish Mandlik #define MSFT_EV_LE_MONITOR_DEVICE	0x02
843368aa35SManish Mandlik struct msft_ev_le_monitor_device {
853368aa35SManish Mandlik 	__u8     addr_type;
863368aa35SManish Mandlik 	bdaddr_t bdaddr;
873368aa35SManish Mandlik 	__u8     monitor_handle;
883368aa35SManish Mandlik 	__u8     monitor_state;
893368aa35SManish Mandlik } __packed;
903368aa35SManish Mandlik 
91a2a4dedfSArchie Pusaka struct msft_monitor_advertisement_handle_data {
92a2a4dedfSArchie Pusaka 	__u8  msft_handle;
93a2a4dedfSArchie Pusaka 	__u16 mgmt_handle;
949e14606dSHilda Wu 	__s8 rssi_high;
959e14606dSHilda Wu 	__s8 rssi_low;
969e14606dSHilda Wu 	__u8 rssi_low_interval;
979e14606dSHilda Wu 	__u8 rssi_sampling_period;
989e14606dSHilda Wu 	__u8 cond_type;
999e14606dSHilda Wu 	struct list_head list;
1009e14606dSHilda Wu };
1019e14606dSHilda Wu 
1029e14606dSHilda Wu enum monitor_addr_filter_state {
1039e14606dSHilda Wu 	AF_STATE_IDLE,
1049e14606dSHilda Wu 	AF_STATE_ADDING,
1059e14606dSHilda Wu 	AF_STATE_ADDED,
1069e14606dSHilda Wu 	AF_STATE_REMOVING,
1079e14606dSHilda Wu };
1089e14606dSHilda Wu 
1099e14606dSHilda Wu #define MSFT_MONITOR_ADVERTISEMENT_TYPE_ADDR	0x04
1109e14606dSHilda Wu struct msft_monitor_addr_filter_data {
1119e14606dSHilda Wu 	__u8     msft_handle;
1129e14606dSHilda Wu 	__u8     pattern_handle; /* address filters pertain to */
1139e14606dSHilda Wu 	__u16    mgmt_handle;
1149e14606dSHilda Wu 	int      state;
1159e14606dSHilda Wu 	__s8     rssi_high;
1169e14606dSHilda Wu 	__s8     rssi_low;
1179e14606dSHilda Wu 	__u8     rssi_low_interval;
1189e14606dSHilda Wu 	__u8     rssi_sampling_period;
1199e14606dSHilda Wu 	__u8     addr_type;
1209e14606dSHilda Wu 	bdaddr_t bdaddr;
121a2a4dedfSArchie Pusaka 	struct list_head list;
122a2a4dedfSArchie Pusaka };
123a2a4dedfSArchie Pusaka 
124145373cbSMiao-chen Chou struct msft_data {
125145373cbSMiao-chen Chou 	__u64 features;
126145373cbSMiao-chen Chou 	__u8  evt_prefix_len;
127145373cbSMiao-chen Chou 	__u8  *evt_prefix;
128a2a4dedfSArchie Pusaka 	struct list_head handle_map;
1299e14606dSHilda Wu 	struct list_head address_filters;
130182ee45dSLuiz Augusto von Dentz 	__u8 resuming;
131ce81843bSManish Mandlik 	__u8 suspending;
132394566bfSArchie Pusaka 	__u8 filter_enabled;
1339e14606dSHilda Wu 	/* To synchronize add/remove address filter and monitor device event.*/
1349e14606dSHilda Wu 	struct mutex filter_lock;
135145373cbSMiao-chen Chou };
136145373cbSMiao-chen Chou 
msft_monitor_supported(struct hci_dev * hdev)137a2a4dedfSArchie Pusaka bool msft_monitor_supported(struct hci_dev *hdev)
138a2a4dedfSArchie Pusaka {
139a2a4dedfSArchie Pusaka 	return !!(msft_get_features(hdev) & MSFT_FEATURE_MASK_LE_ADV_MONITOR);
140a2a4dedfSArchie Pusaka }
141a2a4dedfSArchie Pusaka 
read_supported_features(struct hci_dev * hdev,struct msft_data * msft)142145373cbSMiao-chen Chou static bool read_supported_features(struct hci_dev *hdev,
143145373cbSMiao-chen Chou 				    struct msft_data *msft)
144145373cbSMiao-chen Chou {
145145373cbSMiao-chen Chou 	struct msft_cp_read_supported_features cp;
146145373cbSMiao-chen Chou 	struct msft_rp_read_supported_features *rp;
147145373cbSMiao-chen Chou 	struct sk_buff *skb;
148145373cbSMiao-chen Chou 
149145373cbSMiao-chen Chou 	cp.sub_opcode = MSFT_OP_READ_SUPPORTED_FEATURES;
150145373cbSMiao-chen Chou 
151145373cbSMiao-chen Chou 	skb = __hci_cmd_sync(hdev, hdev->msft_opcode, sizeof(cp), &cp,
152145373cbSMiao-chen Chou 			     HCI_CMD_TIMEOUT);
15336626c26SDan Carpenter 	if (IS_ERR(skb)) {
154145373cbSMiao-chen Chou 		bt_dev_err(hdev, "Failed to read MSFT supported features (%ld)",
155145373cbSMiao-chen Chou 			   PTR_ERR(skb));
156145373cbSMiao-chen Chou 		return false;
157145373cbSMiao-chen Chou 	}
158145373cbSMiao-chen Chou 
159145373cbSMiao-chen Chou 	if (skb->len < sizeof(*rp)) {
160145373cbSMiao-chen Chou 		bt_dev_err(hdev, "MSFT supported features length mismatch");
161145373cbSMiao-chen Chou 		goto failed;
162145373cbSMiao-chen Chou 	}
163145373cbSMiao-chen Chou 
164145373cbSMiao-chen Chou 	rp = (struct msft_rp_read_supported_features *)skb->data;
165145373cbSMiao-chen Chou 
166145373cbSMiao-chen Chou 	if (rp->sub_opcode != MSFT_OP_READ_SUPPORTED_FEATURES)
167145373cbSMiao-chen Chou 		goto failed;
168145373cbSMiao-chen Chou 
169145373cbSMiao-chen Chou 	if (rp->evt_prefix_len > 0) {
170145373cbSMiao-chen Chou 		msft->evt_prefix = kmemdup(rp->evt_prefix, rp->evt_prefix_len,
171145373cbSMiao-chen Chou 					   GFP_KERNEL);
172145373cbSMiao-chen Chou 		if (!msft->evt_prefix)
173145373cbSMiao-chen Chou 			goto failed;
174145373cbSMiao-chen Chou 	}
175145373cbSMiao-chen Chou 
176145373cbSMiao-chen Chou 	msft->evt_prefix_len = rp->evt_prefix_len;
177145373cbSMiao-chen Chou 	msft->features = __le64_to_cpu(rp->features);
178145373cbSMiao-chen Chou 
179a61d6718SMarcel Holtmann 	if (msft->features & MSFT_FEATURE_MASK_CURVE_VALIDITY)
180a61d6718SMarcel Holtmann 		hdev->msft_curve_validity = true;
181a61d6718SMarcel Holtmann 
182145373cbSMiao-chen Chou 	kfree_skb(skb);
183145373cbSMiao-chen Chou 	return true;
184145373cbSMiao-chen Chou 
185145373cbSMiao-chen Chou failed:
186145373cbSMiao-chen Chou 	kfree_skb(skb);
187145373cbSMiao-chen Chou 	return false;
188145373cbSMiao-chen Chou }
189145373cbSMiao-chen Chou 
190182ee45dSLuiz Augusto von Dentz /* is_mgmt = true matches the handle exposed to userspace via mgmt.
191182ee45dSLuiz Augusto von Dentz  * is_mgmt = false matches the handle used by the msft controller.
192182ee45dSLuiz Augusto von Dentz  * This function requires the caller holds hdev->lock
193182ee45dSLuiz Augusto von Dentz  */
msft_find_handle_data(struct hci_dev * hdev,u16 handle,bool is_mgmt)194182ee45dSLuiz Augusto von Dentz static struct msft_monitor_advertisement_handle_data *msft_find_handle_data
195182ee45dSLuiz Augusto von Dentz 				(struct hci_dev *hdev, u16 handle, bool is_mgmt)
196ce81843bSManish Mandlik {
197182ee45dSLuiz Augusto von Dentz 	struct msft_monitor_advertisement_handle_data *entry;
198182ee45dSLuiz Augusto von Dentz 	struct msft_data *msft = hdev->msft_data;
199182ee45dSLuiz Augusto von Dentz 
200182ee45dSLuiz Augusto von Dentz 	list_for_each_entry(entry, &msft->handle_map, list) {
201182ee45dSLuiz Augusto von Dentz 		if (is_mgmt && entry->mgmt_handle == handle)
202182ee45dSLuiz Augusto von Dentz 			return entry;
203182ee45dSLuiz Augusto von Dentz 		if (!is_mgmt && entry->msft_handle == handle)
204182ee45dSLuiz Augusto von Dentz 			return entry;
205182ee45dSLuiz Augusto von Dentz 	}
206182ee45dSLuiz Augusto von Dentz 
207182ee45dSLuiz Augusto von Dentz 	return NULL;
208182ee45dSLuiz Augusto von Dentz }
209182ee45dSLuiz Augusto von Dentz 
2109e14606dSHilda Wu /* This function requires the caller holds msft->filter_lock */
msft_find_address_data(struct hci_dev * hdev,u8 addr_type,bdaddr_t * addr,u8 pattern_handle)2119e14606dSHilda Wu static struct msft_monitor_addr_filter_data *msft_find_address_data
2129e14606dSHilda Wu 			(struct hci_dev *hdev, u8 addr_type, bdaddr_t *addr,
2139e14606dSHilda Wu 			 u8 pattern_handle)
2149e14606dSHilda Wu {
2159e14606dSHilda Wu 	struct msft_monitor_addr_filter_data *entry;
2169e14606dSHilda Wu 	struct msft_data *msft = hdev->msft_data;
2179e14606dSHilda Wu 
2189e14606dSHilda Wu 	list_for_each_entry(entry, &msft->address_filters, list) {
2199e14606dSHilda Wu 		if (entry->pattern_handle == pattern_handle &&
2209e14606dSHilda Wu 		    addr_type == entry->addr_type &&
2219e14606dSHilda Wu 		    !bacmp(addr, &entry->bdaddr))
2229e14606dSHilda Wu 			return entry;
2239e14606dSHilda Wu 	}
2249e14606dSHilda Wu 
2259e14606dSHilda Wu 	return NULL;
2269e14606dSHilda Wu }
2279e14606dSHilda Wu 
2283368aa35SManish Mandlik /* This function requires the caller holds hdev->lock */
msft_monitor_device_del(struct hci_dev * hdev,__u16 mgmt_handle,bdaddr_t * bdaddr,__u8 addr_type,bool notify)2293368aa35SManish Mandlik static int msft_monitor_device_del(struct hci_dev *hdev, __u16 mgmt_handle,
2308d7f1677SManish Mandlik 				   bdaddr_t *bdaddr, __u8 addr_type,
2318d7f1677SManish Mandlik 				   bool notify)
2323368aa35SManish Mandlik {
2333368aa35SManish Mandlik 	struct monitored_device *dev, *tmp;
2343368aa35SManish Mandlik 	int count = 0;
2353368aa35SManish Mandlik 
2363368aa35SManish Mandlik 	list_for_each_entry_safe(dev, tmp, &hdev->monitored_devices, list) {
2373368aa35SManish Mandlik 		/* mgmt_handle == 0 indicates remove all devices, whereas,
2383368aa35SManish Mandlik 		 * bdaddr == NULL indicates remove all devices matching the
2393368aa35SManish Mandlik 		 * mgmt_handle.
2403368aa35SManish Mandlik 		 */
2413368aa35SManish Mandlik 		if ((!mgmt_handle || dev->handle == mgmt_handle) &&
2423368aa35SManish Mandlik 		    (!bdaddr || (!bacmp(bdaddr, &dev->bdaddr) &&
2433368aa35SManish Mandlik 				 addr_type == dev->addr_type))) {
2448d7f1677SManish Mandlik 			if (notify && dev->notified) {
2458d7f1677SManish Mandlik 				mgmt_adv_monitor_device_lost(hdev, dev->handle,
2468d7f1677SManish Mandlik 							     &dev->bdaddr,
2478d7f1677SManish Mandlik 							     dev->addr_type);
2488d7f1677SManish Mandlik 			}
2498d7f1677SManish Mandlik 
2503368aa35SManish Mandlik 			list_del(&dev->list);
2513368aa35SManish Mandlik 			kfree(dev);
2523368aa35SManish Mandlik 			count++;
2533368aa35SManish Mandlik 		}
2543368aa35SManish Mandlik 	}
2553368aa35SManish Mandlik 
2563368aa35SManish Mandlik 	return count;
2573368aa35SManish Mandlik }
2583368aa35SManish Mandlik 
msft_le_monitor_advertisement_cb(struct hci_dev * hdev,u16 opcode,struct adv_monitor * monitor,struct sk_buff * skb)259b747a836SManish Mandlik static int msft_le_monitor_advertisement_cb(struct hci_dev *hdev, u16 opcode,
260b747a836SManish Mandlik 					    struct adv_monitor *monitor,
261182ee45dSLuiz Augusto von Dentz 					    struct sk_buff *skb)
262182ee45dSLuiz Augusto von Dentz {
263182ee45dSLuiz Augusto von Dentz 	struct msft_rp_le_monitor_advertisement *rp;
264182ee45dSLuiz Augusto von Dentz 	struct msft_monitor_advertisement_handle_data *handle_data;
265182ee45dSLuiz Augusto von Dentz 	struct msft_data *msft = hdev->msft_data;
266b747a836SManish Mandlik 	int status = 0;
267182ee45dSLuiz Augusto von Dentz 
268182ee45dSLuiz Augusto von Dentz 	hci_dev_lock(hdev);
269182ee45dSLuiz Augusto von Dentz 
270182ee45dSLuiz Augusto von Dentz 	rp = (struct msft_rp_le_monitor_advertisement *)skb->data;
271182ee45dSLuiz Augusto von Dentz 	if (skb->len < sizeof(*rp)) {
272182ee45dSLuiz Augusto von Dentz 		status = HCI_ERROR_UNSPECIFIED;
273182ee45dSLuiz Augusto von Dentz 		goto unlock;
274182ee45dSLuiz Augusto von Dentz 	}
275182ee45dSLuiz Augusto von Dentz 
276b747a836SManish Mandlik 	status = rp->status;
277b747a836SManish Mandlik 	if (status)
278b747a836SManish Mandlik 		goto unlock;
279b747a836SManish Mandlik 
280182ee45dSLuiz Augusto von Dentz 	handle_data = kmalloc(sizeof(*handle_data), GFP_KERNEL);
281182ee45dSLuiz Augusto von Dentz 	if (!handle_data) {
282182ee45dSLuiz Augusto von Dentz 		status = HCI_ERROR_UNSPECIFIED;
283182ee45dSLuiz Augusto von Dentz 		goto unlock;
284182ee45dSLuiz Augusto von Dentz 	}
285182ee45dSLuiz Augusto von Dentz 
286182ee45dSLuiz Augusto von Dentz 	handle_data->mgmt_handle = monitor->handle;
287182ee45dSLuiz Augusto von Dentz 	handle_data->msft_handle = rp->handle;
2889e14606dSHilda Wu 	handle_data->cond_type   = MSFT_MONITOR_ADVERTISEMENT_TYPE_PATTERN;
289182ee45dSLuiz Augusto von Dentz 	INIT_LIST_HEAD(&handle_data->list);
290182ee45dSLuiz Augusto von Dentz 	list_add(&handle_data->list, &msft->handle_map);
291182ee45dSLuiz Augusto von Dentz 
292182ee45dSLuiz Augusto von Dentz 	monitor->state = ADV_MONITOR_STATE_OFFLOADED;
293182ee45dSLuiz Augusto von Dentz 
294182ee45dSLuiz Augusto von Dentz unlock:
295b747a836SManish Mandlik 	if (status)
296182ee45dSLuiz Augusto von Dentz 		hci_free_adv_monitor(hdev, monitor);
297182ee45dSLuiz Augusto von Dentz 
298182ee45dSLuiz Augusto von Dentz 	hci_dev_unlock(hdev);
299182ee45dSLuiz Augusto von Dentz 
300b747a836SManish Mandlik 	return status;
301182ee45dSLuiz Augusto von Dentz }
302182ee45dSLuiz Augusto von Dentz 
3039e14606dSHilda Wu /* This function requires the caller holds hci_req_sync_lock */
msft_remove_addr_filters_sync(struct hci_dev * hdev,u8 handle)3049e14606dSHilda Wu static void msft_remove_addr_filters_sync(struct hci_dev *hdev, u8 handle)
3059e14606dSHilda Wu {
3069e14606dSHilda Wu 	struct msft_monitor_addr_filter_data *address_filter, *n;
3079e14606dSHilda Wu 	struct msft_cp_le_cancel_monitor_advertisement cp;
3089e14606dSHilda Wu 	struct msft_data *msft = hdev->msft_data;
3099e14606dSHilda Wu 	struct list_head head;
3109e14606dSHilda Wu 	struct sk_buff *skb;
3119e14606dSHilda Wu 
3129e14606dSHilda Wu 	INIT_LIST_HEAD(&head);
3139e14606dSHilda Wu 
3149e14606dSHilda Wu 	/* Cancel all corresponding address monitors */
3159e14606dSHilda Wu 	mutex_lock(&msft->filter_lock);
3169e14606dSHilda Wu 
3179e14606dSHilda Wu 	list_for_each_entry_safe(address_filter, n, &msft->address_filters,
3189e14606dSHilda Wu 				 list) {
3199e14606dSHilda Wu 		if (address_filter->pattern_handle != handle)
3209e14606dSHilda Wu 			continue;
3219e14606dSHilda Wu 
3229e14606dSHilda Wu 		list_del(&address_filter->list);
3239e14606dSHilda Wu 
3249e14606dSHilda Wu 		/* Keep the address filter and let
3259e14606dSHilda Wu 		 * msft_add_address_filter_sync() remove and free the address
3269e14606dSHilda Wu 		 * filter.
3279e14606dSHilda Wu 		 */
3289e14606dSHilda Wu 		if (address_filter->state == AF_STATE_ADDING) {
3299e14606dSHilda Wu 			address_filter->state = AF_STATE_REMOVING;
3309e14606dSHilda Wu 			continue;
3319e14606dSHilda Wu 		}
3329e14606dSHilda Wu 
3339e14606dSHilda Wu 		/* Keep the address filter and let
3349e14606dSHilda Wu 		 * msft_cancel_address_filter_sync() remove and free the address
3359e14606dSHilda Wu 		 * filter
3369e14606dSHilda Wu 		 */
3379e14606dSHilda Wu 		if (address_filter->state == AF_STATE_REMOVING)
3389e14606dSHilda Wu 			continue;
3399e14606dSHilda Wu 
3409e14606dSHilda Wu 		list_add_tail(&address_filter->list, &head);
3419e14606dSHilda Wu 	}
3429e14606dSHilda Wu 
3439e14606dSHilda Wu 	mutex_unlock(&msft->filter_lock);
3449e14606dSHilda Wu 
3459e14606dSHilda Wu 	list_for_each_entry_safe(address_filter, n, &head, list) {
3469e14606dSHilda Wu 		list_del(&address_filter->list);
3479e14606dSHilda Wu 
3489e14606dSHilda Wu 		cp.sub_opcode = MSFT_OP_LE_CANCEL_MONITOR_ADVERTISEMENT;
3499e14606dSHilda Wu 		cp.handle = address_filter->msft_handle;
3509e14606dSHilda Wu 
3519e14606dSHilda Wu 		skb = __hci_cmd_sync(hdev, hdev->msft_opcode, sizeof(cp), &cp,
3529e14606dSHilda Wu 				     HCI_CMD_TIMEOUT);
35336626c26SDan Carpenter 		if (IS_ERR(skb)) {
3549e14606dSHilda Wu 			kfree(address_filter);
3559e14606dSHilda Wu 			continue;
3569e14606dSHilda Wu 		}
3579e14606dSHilda Wu 
3589e14606dSHilda Wu 		kfree_skb(skb);
3599e14606dSHilda Wu 
3609e14606dSHilda Wu 		bt_dev_dbg(hdev, "MSFT: Canceled device %pMR address filter",
3619e14606dSHilda Wu 			   &address_filter->bdaddr);
3629e14606dSHilda Wu 
3639e14606dSHilda Wu 		kfree(address_filter);
3649e14606dSHilda Wu 	}
3659e14606dSHilda Wu }
3669e14606dSHilda Wu 
msft_le_cancel_monitor_advertisement_cb(struct hci_dev * hdev,u16 opcode,struct adv_monitor * monitor,struct sk_buff * skb)3677cf5c297SManish Mandlik static int msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev,
3687cf5c297SManish Mandlik 						   u16 opcode,
3697cf5c297SManish Mandlik 						   struct adv_monitor *monitor,
370182ee45dSLuiz Augusto von Dentz 						   struct sk_buff *skb)
371182ee45dSLuiz Augusto von Dentz {
372182ee45dSLuiz Augusto von Dentz 	struct msft_rp_le_cancel_monitor_advertisement *rp;
373182ee45dSLuiz Augusto von Dentz 	struct msft_monitor_advertisement_handle_data *handle_data;
374ce81843bSManish Mandlik 	struct msft_data *msft = hdev->msft_data;
3757cf5c297SManish Mandlik 	int status = 0;
3769e14606dSHilda Wu 	u8 msft_handle;
377182ee45dSLuiz Augusto von Dentz 
378182ee45dSLuiz Augusto von Dentz 	rp = (struct msft_rp_le_cancel_monitor_advertisement *)skb->data;
379182ee45dSLuiz Augusto von Dentz 	if (skb->len < sizeof(*rp)) {
380182ee45dSLuiz Augusto von Dentz 		status = HCI_ERROR_UNSPECIFIED;
381182ee45dSLuiz Augusto von Dentz 		goto done;
382182ee45dSLuiz Augusto von Dentz 	}
383182ee45dSLuiz Augusto von Dentz 
3847cf5c297SManish Mandlik 	status = rp->status;
3857cf5c297SManish Mandlik 	if (status)
3867cf5c297SManish Mandlik 		goto done;
3877cf5c297SManish Mandlik 
388182ee45dSLuiz Augusto von Dentz 	hci_dev_lock(hdev);
389182ee45dSLuiz Augusto von Dentz 
3907cf5c297SManish Mandlik 	handle_data = msft_find_handle_data(hdev, monitor->handle, true);
391182ee45dSLuiz Augusto von Dentz 
392182ee45dSLuiz Augusto von Dentz 	if (handle_data) {
3937cf5c297SManish Mandlik 		if (monitor->state == ADV_MONITOR_STATE_OFFLOADED)
394182ee45dSLuiz Augusto von Dentz 			monitor->state = ADV_MONITOR_STATE_REGISTERED;
395182ee45dSLuiz Augusto von Dentz 
396182ee45dSLuiz Augusto von Dentz 		/* Do not free the monitor if it is being removed due to
397182ee45dSLuiz Augusto von Dentz 		 * suspend. It will be re-monitored on resume.
398182ee45dSLuiz Augusto von Dentz 		 */
3997cf5c297SManish Mandlik 		if (!msft->suspending) {
400182ee45dSLuiz Augusto von Dentz 			hci_free_adv_monitor(hdev, monitor);
401182ee45dSLuiz Augusto von Dentz 
4023368aa35SManish Mandlik 			/* Clear any monitored devices by this Adv Monitor */
40337b63c68SManish Mandlik 			msft_monitor_device_del(hdev, handle_data->mgmt_handle,
40437b63c68SManish Mandlik 						NULL, 0, false);
40537b63c68SManish Mandlik 		}
4063368aa35SManish Mandlik 
4079e14606dSHilda Wu 		msft_handle = handle_data->msft_handle;
4089e14606dSHilda Wu 
409182ee45dSLuiz Augusto von Dentz 		list_del(&handle_data->list);
410182ee45dSLuiz Augusto von Dentz 		kfree(handle_data);
411182ee45dSLuiz Augusto von Dentz 
412182ee45dSLuiz Augusto von Dentz 		hci_dev_unlock(hdev);
413182ee45dSLuiz Augusto von Dentz 
4149e14606dSHilda Wu 		msft_remove_addr_filters_sync(hdev, msft_handle);
4159e14606dSHilda Wu 	} else {
4169e14606dSHilda Wu 		hci_dev_unlock(hdev);
4179e14606dSHilda Wu 	}
4189e14606dSHilda Wu 
419182ee45dSLuiz Augusto von Dentz done:
4207cf5c297SManish Mandlik 	return status;
421182ee45dSLuiz Augusto von Dentz }
422182ee45dSLuiz Augusto von Dentz 
4237cf5c297SManish Mandlik /* This function requires the caller holds hci_req_sync_lock */
msft_remove_monitor_sync(struct hci_dev * hdev,struct adv_monitor * monitor)424182ee45dSLuiz Augusto von Dentz static int msft_remove_monitor_sync(struct hci_dev *hdev,
425182ee45dSLuiz Augusto von Dentz 				    struct adv_monitor *monitor)
426182ee45dSLuiz Augusto von Dentz {
427182ee45dSLuiz Augusto von Dentz 	struct msft_cp_le_cancel_monitor_advertisement cp;
428182ee45dSLuiz Augusto von Dentz 	struct msft_monitor_advertisement_handle_data *handle_data;
429182ee45dSLuiz Augusto von Dentz 	struct sk_buff *skb;
430182ee45dSLuiz Augusto von Dentz 
431182ee45dSLuiz Augusto von Dentz 	handle_data = msft_find_handle_data(hdev, monitor->handle, true);
432182ee45dSLuiz Augusto von Dentz 
433182ee45dSLuiz Augusto von Dentz 	/* If no matched handle, just remove without telling controller */
434182ee45dSLuiz Augusto von Dentz 	if (!handle_data)
435182ee45dSLuiz Augusto von Dentz 		return -ENOENT;
436182ee45dSLuiz Augusto von Dentz 
437182ee45dSLuiz Augusto von Dentz 	cp.sub_opcode = MSFT_OP_LE_CANCEL_MONITOR_ADVERTISEMENT;
438182ee45dSLuiz Augusto von Dentz 	cp.handle = handle_data->msft_handle;
439182ee45dSLuiz Augusto von Dentz 
440182ee45dSLuiz Augusto von Dentz 	skb = __hci_cmd_sync(hdev, hdev->msft_opcode, sizeof(cp), &cp,
441182ee45dSLuiz Augusto von Dentz 			     HCI_CMD_TIMEOUT);
44236626c26SDan Carpenter 	if (IS_ERR(skb))
443182ee45dSLuiz Augusto von Dentz 		return PTR_ERR(skb);
444182ee45dSLuiz Augusto von Dentz 
4457cf5c297SManish Mandlik 	return msft_le_cancel_monitor_advertisement_cb(hdev, hdev->msft_opcode,
4467cf5c297SManish Mandlik 						       monitor, skb);
447182ee45dSLuiz Augusto von Dentz }
448182ee45dSLuiz Augusto von Dentz 
449182ee45dSLuiz Augusto von Dentz /* This function requires the caller holds hci_req_sync_lock */
msft_suspend_sync(struct hci_dev * hdev)450182ee45dSLuiz Augusto von Dentz int msft_suspend_sync(struct hci_dev *hdev)
451182ee45dSLuiz Augusto von Dentz {
452182ee45dSLuiz Augusto von Dentz 	struct msft_data *msft = hdev->msft_data;
453182ee45dSLuiz Augusto von Dentz 	struct adv_monitor *monitor;
454182ee45dSLuiz Augusto von Dentz 	int handle = 0;
455182ee45dSLuiz Augusto von Dentz 
456182ee45dSLuiz Augusto von Dentz 	if (!msft || !msft_monitor_supported(hdev))
457182ee45dSLuiz Augusto von Dentz 		return 0;
458182ee45dSLuiz Augusto von Dentz 
459182ee45dSLuiz Augusto von Dentz 	msft->suspending = true;
460ce81843bSManish Mandlik 
461ce81843bSManish Mandlik 	while (1) {
462ce81843bSManish Mandlik 		monitor = idr_get_next(&hdev->adv_monitors_idr, &handle);
463182ee45dSLuiz Augusto von Dentz 		if (!monitor)
464182ee45dSLuiz Augusto von Dentz 			break;
465ce81843bSManish Mandlik 
466182ee45dSLuiz Augusto von Dentz 		msft_remove_monitor_sync(hdev, monitor);
467ce81843bSManish Mandlik 
468ce81843bSManish Mandlik 		handle++;
469ce81843bSManish Mandlik 	}
470182ee45dSLuiz Augusto von Dentz 
471182ee45dSLuiz Augusto von Dentz 	/* All monitors have been removed */
472182ee45dSLuiz Augusto von Dentz 	msft->suspending = false;
473182ee45dSLuiz Augusto von Dentz 
474182ee45dSLuiz Augusto von Dentz 	return 0;
475ce81843bSManish Mandlik }
476ce81843bSManish Mandlik 
msft_monitor_rssi_valid(struct adv_monitor * monitor)477182ee45dSLuiz Augusto von Dentz static bool msft_monitor_rssi_valid(struct adv_monitor *monitor)
478182ee45dSLuiz Augusto von Dentz {
479182ee45dSLuiz Augusto von Dentz 	struct adv_rssi_thresholds *r = &monitor->rssi;
480182ee45dSLuiz Augusto von Dentz 
481182ee45dSLuiz Augusto von Dentz 	if (r->high_threshold < MSFT_RSSI_THRESHOLD_VALUE_MIN ||
482182ee45dSLuiz Augusto von Dentz 	    r->high_threshold > MSFT_RSSI_THRESHOLD_VALUE_MAX ||
483182ee45dSLuiz Augusto von Dentz 	    r->low_threshold < MSFT_RSSI_THRESHOLD_VALUE_MIN ||
484182ee45dSLuiz Augusto von Dentz 	    r->low_threshold > MSFT_RSSI_THRESHOLD_VALUE_MAX)
485182ee45dSLuiz Augusto von Dentz 		return false;
486182ee45dSLuiz Augusto von Dentz 
487182ee45dSLuiz Augusto von Dentz 	/* High_threshold_timeout is not supported,
488182ee45dSLuiz Augusto von Dentz 	 * once high_threshold is reached, events are immediately reported.
489182ee45dSLuiz Augusto von Dentz 	 */
490182ee45dSLuiz Augusto von Dentz 	if (r->high_threshold_timeout != 0)
491182ee45dSLuiz Augusto von Dentz 		return false;
492182ee45dSLuiz Augusto von Dentz 
493182ee45dSLuiz Augusto von Dentz 	if (r->low_threshold_timeout > MSFT_RSSI_LOW_TIMEOUT_MAX)
494182ee45dSLuiz Augusto von Dentz 		return false;
495182ee45dSLuiz Augusto von Dentz 
496182ee45dSLuiz Augusto von Dentz 	/* Sampling period from 0x00 to 0xFF are all allowed */
497182ee45dSLuiz Augusto von Dentz 	return true;
498182ee45dSLuiz Augusto von Dentz }
499182ee45dSLuiz Augusto von Dentz 
msft_monitor_pattern_valid(struct adv_monitor * monitor)500182ee45dSLuiz Augusto von Dentz static bool msft_monitor_pattern_valid(struct adv_monitor *monitor)
501182ee45dSLuiz Augusto von Dentz {
502182ee45dSLuiz Augusto von Dentz 	return msft_monitor_rssi_valid(monitor);
503182ee45dSLuiz Augusto von Dentz 	/* No additional check needed for pattern-based monitor */
504182ee45dSLuiz Augusto von Dentz }
505182ee45dSLuiz Augusto von Dentz 
msft_add_monitor_sync(struct hci_dev * hdev,struct adv_monitor * monitor)506182ee45dSLuiz Augusto von Dentz static int msft_add_monitor_sync(struct hci_dev *hdev,
507182ee45dSLuiz Augusto von Dentz 				 struct adv_monitor *monitor)
508182ee45dSLuiz Augusto von Dentz {
509182ee45dSLuiz Augusto von Dentz 	struct msft_cp_le_monitor_advertisement *cp;
510182ee45dSLuiz Augusto von Dentz 	struct msft_le_monitor_advertisement_pattern_data *pattern_data;
5119e14606dSHilda Wu 	struct msft_monitor_advertisement_handle_data *handle_data;
512182ee45dSLuiz Augusto von Dentz 	struct msft_le_monitor_advertisement_pattern *pattern;
513182ee45dSLuiz Augusto von Dentz 	struct adv_pattern *entry;
514182ee45dSLuiz Augusto von Dentz 	size_t total_size = sizeof(*cp) + sizeof(*pattern_data);
515182ee45dSLuiz Augusto von Dentz 	ptrdiff_t offset = 0;
516182ee45dSLuiz Augusto von Dentz 	u8 pattern_count = 0;
517182ee45dSLuiz Augusto von Dentz 	struct sk_buff *skb;
5189e14606dSHilda Wu 	int err;
519182ee45dSLuiz Augusto von Dentz 
520182ee45dSLuiz Augusto von Dentz 	if (!msft_monitor_pattern_valid(monitor))
521182ee45dSLuiz Augusto von Dentz 		return -EINVAL;
522182ee45dSLuiz Augusto von Dentz 
523182ee45dSLuiz Augusto von Dentz 	list_for_each_entry(entry, &monitor->patterns, list) {
524182ee45dSLuiz Augusto von Dentz 		pattern_count++;
525182ee45dSLuiz Augusto von Dentz 		total_size += sizeof(*pattern) + entry->length;
526182ee45dSLuiz Augusto von Dentz 	}
527182ee45dSLuiz Augusto von Dentz 
528182ee45dSLuiz Augusto von Dentz 	cp = kmalloc(total_size, GFP_KERNEL);
529182ee45dSLuiz Augusto von Dentz 	if (!cp)
530182ee45dSLuiz Augusto von Dentz 		return -ENOMEM;
531182ee45dSLuiz Augusto von Dentz 
532182ee45dSLuiz Augusto von Dentz 	cp->sub_opcode = MSFT_OP_LE_MONITOR_ADVERTISEMENT;
533182ee45dSLuiz Augusto von Dentz 	cp->rssi_high = monitor->rssi.high_threshold;
534182ee45dSLuiz Augusto von Dentz 	cp->rssi_low = monitor->rssi.low_threshold;
535182ee45dSLuiz Augusto von Dentz 	cp->rssi_low_interval = (u8)monitor->rssi.low_threshold_timeout;
536182ee45dSLuiz Augusto von Dentz 	cp->rssi_sampling_period = monitor->rssi.sampling_period;
537182ee45dSLuiz Augusto von Dentz 
538182ee45dSLuiz Augusto von Dentz 	cp->cond_type = MSFT_MONITOR_ADVERTISEMENT_TYPE_PATTERN;
539182ee45dSLuiz Augusto von Dentz 
540182ee45dSLuiz Augusto von Dentz 	pattern_data = (void *)cp->data;
541182ee45dSLuiz Augusto von Dentz 	pattern_data->count = pattern_count;
542182ee45dSLuiz Augusto von Dentz 
543182ee45dSLuiz Augusto von Dentz 	list_for_each_entry(entry, &monitor->patterns, list) {
544182ee45dSLuiz Augusto von Dentz 		pattern = (void *)(pattern_data->data + offset);
545182ee45dSLuiz Augusto von Dentz 		/* the length also includes data_type and offset */
546182ee45dSLuiz Augusto von Dentz 		pattern->length = entry->length + 2;
547182ee45dSLuiz Augusto von Dentz 		pattern->data_type = entry->ad_type;
548182ee45dSLuiz Augusto von Dentz 		pattern->start_byte = entry->offset;
549182ee45dSLuiz Augusto von Dentz 		memcpy(pattern->pattern, entry->value, entry->length);
550182ee45dSLuiz Augusto von Dentz 		offset += sizeof(*pattern) + entry->length;
551182ee45dSLuiz Augusto von Dentz 	}
552182ee45dSLuiz Augusto von Dentz 
553182ee45dSLuiz Augusto von Dentz 	skb = __hci_cmd_sync(hdev, hdev->msft_opcode, total_size, cp,
554182ee45dSLuiz Augusto von Dentz 			     HCI_CMD_TIMEOUT);
555182ee45dSLuiz Augusto von Dentz 
55636626c26SDan Carpenter 	if (IS_ERR(skb)) {
5579e14606dSHilda Wu 		err = PTR_ERR(skb);
5589e14606dSHilda Wu 		goto out_free;
559ce78e557SSoenke Huster 	}
560182ee45dSLuiz Augusto von Dentz 
5619e14606dSHilda Wu 	err = msft_le_monitor_advertisement_cb(hdev, hdev->msft_opcode,
562b747a836SManish Mandlik 					       monitor, skb);
5639e14606dSHilda Wu 	if (err)
5649e14606dSHilda Wu 		goto out_free;
5659e14606dSHilda Wu 
5669e14606dSHilda Wu 	handle_data = msft_find_handle_data(hdev, monitor->handle, true);
5679e14606dSHilda Wu 	if (!handle_data) {
5689e14606dSHilda Wu 		err = -ENODATA;
5699e14606dSHilda Wu 		goto out_free;
5709e14606dSHilda Wu 	}
5719e14606dSHilda Wu 
5729e14606dSHilda Wu 	handle_data->rssi_high	= cp->rssi_high;
5739e14606dSHilda Wu 	handle_data->rssi_low	= cp->rssi_low;
5749e14606dSHilda Wu 	handle_data->rssi_low_interval	  = cp->rssi_low_interval;
5759e14606dSHilda Wu 	handle_data->rssi_sampling_period = cp->rssi_sampling_period;
5769e14606dSHilda Wu 
5779e14606dSHilda Wu out_free:
5789e14606dSHilda Wu 	kfree(cp);
5799e14606dSHilda Wu 	return err;
580b747a836SManish Mandlik }
581182ee45dSLuiz Augusto von Dentz 
582b747a836SManish Mandlik /* This function requires the caller holds hci_req_sync_lock */
reregister_monitor(struct hci_dev * hdev)583b747a836SManish Mandlik static void reregister_monitor(struct hci_dev *hdev)
584b747a836SManish Mandlik {
585b747a836SManish Mandlik 	struct adv_monitor *monitor;
586b747a836SManish Mandlik 	struct msft_data *msft = hdev->msft_data;
587b747a836SManish Mandlik 	int handle = 0;
588182ee45dSLuiz Augusto von Dentz 
589b747a836SManish Mandlik 	if (!msft)
590b747a836SManish Mandlik 		return;
591b747a836SManish Mandlik 
592b747a836SManish Mandlik 	msft->resuming = true;
593b747a836SManish Mandlik 
594b747a836SManish Mandlik 	while (1) {
595b747a836SManish Mandlik 		monitor = idr_get_next(&hdev->adv_monitors_idr, &handle);
596b747a836SManish Mandlik 		if (!monitor)
597b747a836SManish Mandlik 			break;
598b747a836SManish Mandlik 
599b747a836SManish Mandlik 		msft_add_monitor_sync(hdev, monitor);
600b747a836SManish Mandlik 
601b747a836SManish Mandlik 		handle++;
602b747a836SManish Mandlik 	}
603b747a836SManish Mandlik 
604b747a836SManish Mandlik 	/* All monitors have been reregistered */
605b747a836SManish Mandlik 	msft->resuming = false;
606182ee45dSLuiz Augusto von Dentz }
607182ee45dSLuiz Augusto von Dentz 
608182ee45dSLuiz Augusto von Dentz /* This function requires the caller holds hci_req_sync_lock */
msft_resume_sync(struct hci_dev * hdev)609182ee45dSLuiz Augusto von Dentz int msft_resume_sync(struct hci_dev *hdev)
610ce81843bSManish Mandlik {
611ce81843bSManish Mandlik 	struct msft_data *msft = hdev->msft_data;
612ce81843bSManish Mandlik 
613182ee45dSLuiz Augusto von Dentz 	if (!msft || !msft_monitor_supported(hdev))
614182ee45dSLuiz Augusto von Dentz 		return 0;
615ce81843bSManish Mandlik 
61637b63c68SManish Mandlik 	hci_dev_lock(hdev);
61737b63c68SManish Mandlik 
61837b63c68SManish Mandlik 	/* Clear already tracked devices on resume. Once the monitors are
61937b63c68SManish Mandlik 	 * reregistered, devices in range will be found again after resume.
62037b63c68SManish Mandlik 	 */
62137b63c68SManish Mandlik 	hdev->advmon_pend_notify = false;
62237b63c68SManish Mandlik 	msft_monitor_device_del(hdev, 0, NULL, 0, true);
62337b63c68SManish Mandlik 
62437b63c68SManish Mandlik 	hci_dev_unlock(hdev);
62537b63c68SManish Mandlik 
626b747a836SManish Mandlik 	reregister_monitor(hdev);
627ce81843bSManish Mandlik 
628182ee45dSLuiz Augusto von Dentz 	return 0;
629ce81843bSManish Mandlik }
630ce81843bSManish Mandlik 
631b747a836SManish Mandlik /* This function requires the caller holds hci_req_sync_lock */
msft_do_open(struct hci_dev * hdev)632145373cbSMiao-chen Chou void msft_do_open(struct hci_dev *hdev)
633145373cbSMiao-chen Chou {
6345031ffccSMiao-chen Chou 	struct msft_data *msft = hdev->msft_data;
635145373cbSMiao-chen Chou 
636145373cbSMiao-chen Chou 	if (hdev->msft_opcode == HCI_OP_NOP)
637145373cbSMiao-chen Chou 		return;
638145373cbSMiao-chen Chou 
6395031ffccSMiao-chen Chou 	if (!msft) {
6405031ffccSMiao-chen Chou 		bt_dev_err(hdev, "MSFT extension not registered");
6415031ffccSMiao-chen Chou 		return;
6425031ffccSMiao-chen Chou 	}
6435031ffccSMiao-chen Chou 
644145373cbSMiao-chen Chou 	bt_dev_dbg(hdev, "Initialize MSFT extension");
645145373cbSMiao-chen Chou 
6465031ffccSMiao-chen Chou 	/* Reset existing MSFT data before re-reading */
6475031ffccSMiao-chen Chou 	kfree(msft->evt_prefix);
6485031ffccSMiao-chen Chou 	msft->evt_prefix = NULL;
6495031ffccSMiao-chen Chou 	msft->evt_prefix_len = 0;
6505031ffccSMiao-chen Chou 	msft->features = 0;
651145373cbSMiao-chen Chou 
652145373cbSMiao-chen Chou 	if (!read_supported_features(hdev, msft)) {
6535031ffccSMiao-chen Chou 		hdev->msft_data = NULL;
654145373cbSMiao-chen Chou 		kfree(msft);
655145373cbSMiao-chen Chou 		return;
656145373cbSMiao-chen Chou 	}
657145373cbSMiao-chen Chou 
6584a37682cSArchie Pusaka 	if (msft_monitor_supported(hdev)) {
659182ee45dSLuiz Augusto von Dentz 		msft->resuming = true;
660394566bfSArchie Pusaka 		msft_set_filter_enable(hdev, true);
6615031ffccSMiao-chen Chou 		/* Monitors get removed on power off, so we need to explicitly
6625031ffccSMiao-chen Chou 		 * tell the controller to re-monitor.
6635031ffccSMiao-chen Chou 		 */
664b747a836SManish Mandlik 		reregister_monitor(hdev);
6654a37682cSArchie Pusaka 	}
666145373cbSMiao-chen Chou }
667145373cbSMiao-chen Chou 
msft_do_close(struct hci_dev * hdev)668145373cbSMiao-chen Chou void msft_do_close(struct hci_dev *hdev)
669145373cbSMiao-chen Chou {
670145373cbSMiao-chen Chou 	struct msft_data *msft = hdev->msft_data;
671a2a4dedfSArchie Pusaka 	struct msft_monitor_advertisement_handle_data *handle_data, *tmp;
6729e14606dSHilda Wu 	struct msft_monitor_addr_filter_data *address_filter, *n;
6734a37682cSArchie Pusaka 	struct adv_monitor *monitor;
674145373cbSMiao-chen Chou 
675145373cbSMiao-chen Chou 	if (!msft)
676145373cbSMiao-chen Chou 		return;
677145373cbSMiao-chen Chou 
678145373cbSMiao-chen Chou 	bt_dev_dbg(hdev, "Cleanup of MSFT extension");
679145373cbSMiao-chen Chou 
6805031ffccSMiao-chen Chou 	/* The controller will silently remove all monitors on power off.
6815031ffccSMiao-chen Chou 	 * Therefore, remove handle_data mapping and reset monitor state.
6825031ffccSMiao-chen Chou 	 */
683a2a4dedfSArchie Pusaka 	list_for_each_entry_safe(handle_data, tmp, &msft->handle_map, list) {
6844a37682cSArchie Pusaka 		monitor = idr_find(&hdev->adv_monitors_idr,
6854a37682cSArchie Pusaka 				   handle_data->mgmt_handle);
6864a37682cSArchie Pusaka 
6874a37682cSArchie Pusaka 		if (monitor && monitor->state == ADV_MONITOR_STATE_OFFLOADED)
6884a37682cSArchie Pusaka 			monitor->state = ADV_MONITOR_STATE_REGISTERED;
6894a37682cSArchie Pusaka 
690a2a4dedfSArchie Pusaka 		list_del(&handle_data->list);
691a2a4dedfSArchie Pusaka 		kfree(handle_data);
692a2a4dedfSArchie Pusaka 	}
6933368aa35SManish Mandlik 
6949e14606dSHilda Wu 	mutex_lock(&msft->filter_lock);
6959e14606dSHilda Wu 	list_for_each_entry_safe(address_filter, n, &msft->address_filters,
6969e14606dSHilda Wu 				 list) {
6979e14606dSHilda Wu 		list_del(&address_filter->list);
6989e14606dSHilda Wu 		kfree(address_filter);
6999e14606dSHilda Wu 	}
7009e14606dSHilda Wu 	mutex_unlock(&msft->filter_lock);
7019e14606dSHilda Wu 
7023368aa35SManish Mandlik 	hci_dev_lock(hdev);
7033368aa35SManish Mandlik 
7048d7f1677SManish Mandlik 	/* Clear any devices that are being monitored and notify device lost */
7058d7f1677SManish Mandlik 	hdev->advmon_pend_notify = false;
7068d7f1677SManish Mandlik 	msft_monitor_device_del(hdev, 0, NULL, 0, true);
7073368aa35SManish Mandlik 
7083368aa35SManish Mandlik 	hci_dev_unlock(hdev);
7095031ffccSMiao-chen Chou }
7105031ffccSMiao-chen Chou 
msft_cancel_address_filter_sync(struct hci_dev * hdev,void * data)7119e14606dSHilda Wu static int msft_cancel_address_filter_sync(struct hci_dev *hdev, void *data)
7129e14606dSHilda Wu {
7139e14606dSHilda Wu 	struct msft_monitor_addr_filter_data *address_filter = data;
7149e14606dSHilda Wu 	struct msft_cp_le_cancel_monitor_advertisement cp;
7159e14606dSHilda Wu 	struct msft_data *msft = hdev->msft_data;
7169e14606dSHilda Wu 	struct sk_buff *skb;
7179e14606dSHilda Wu 	int err = 0;
7189e14606dSHilda Wu 
7199e14606dSHilda Wu 	if (!msft) {
7209e14606dSHilda Wu 		bt_dev_err(hdev, "MSFT: msft data is freed");
7219e14606dSHilda Wu 		return -EINVAL;
7229e14606dSHilda Wu 	}
7239e14606dSHilda Wu 
7249e14606dSHilda Wu 	/* The address filter has been removed by hci dev close */
7259e14606dSHilda Wu 	if (!test_bit(HCI_UP, &hdev->flags))
7269e14606dSHilda Wu 		return 0;
7279e14606dSHilda Wu 
7289e14606dSHilda Wu 	mutex_lock(&msft->filter_lock);
7299e14606dSHilda Wu 	list_del(&address_filter->list);
7309e14606dSHilda Wu 	mutex_unlock(&msft->filter_lock);
7319e14606dSHilda Wu 
7329e14606dSHilda Wu 	cp.sub_opcode = MSFT_OP_LE_CANCEL_MONITOR_ADVERTISEMENT;
7339e14606dSHilda Wu 	cp.handle = address_filter->msft_handle;
7349e14606dSHilda Wu 
7359e14606dSHilda Wu 	skb = __hci_cmd_sync(hdev, hdev->msft_opcode, sizeof(cp), &cp,
7369e14606dSHilda Wu 			     HCI_CMD_TIMEOUT);
73736626c26SDan Carpenter 	if (IS_ERR(skb)) {
7389e14606dSHilda Wu 		bt_dev_err(hdev, "MSFT: Failed to cancel address (%pMR) filter",
7399e14606dSHilda Wu 			   &address_filter->bdaddr);
74036626c26SDan Carpenter 		err = PTR_ERR(skb);
7419e14606dSHilda Wu 		goto done;
7429e14606dSHilda Wu 	}
7439e14606dSHilda Wu 	kfree_skb(skb);
7449e14606dSHilda Wu 
7459e14606dSHilda Wu 	bt_dev_dbg(hdev, "MSFT: Canceled device %pMR address filter",
7469e14606dSHilda Wu 		   &address_filter->bdaddr);
7479e14606dSHilda Wu 
7489e14606dSHilda Wu done:
7499e14606dSHilda Wu 	kfree(address_filter);
7509e14606dSHilda Wu 
7519e14606dSHilda Wu 	return err;
7529e14606dSHilda Wu }
7539e14606dSHilda Wu 
msft_register(struct hci_dev * hdev)7545031ffccSMiao-chen Chou void msft_register(struct hci_dev *hdev)
7555031ffccSMiao-chen Chou {
7565031ffccSMiao-chen Chou 	struct msft_data *msft = NULL;
7575031ffccSMiao-chen Chou 
7585031ffccSMiao-chen Chou 	bt_dev_dbg(hdev, "Register MSFT extension");
7595031ffccSMiao-chen Chou 
7605031ffccSMiao-chen Chou 	msft = kzalloc(sizeof(*msft), GFP_KERNEL);
7615031ffccSMiao-chen Chou 	if (!msft) {
7625031ffccSMiao-chen Chou 		bt_dev_err(hdev, "Failed to register MSFT extension");
7635031ffccSMiao-chen Chou 		return;
7645031ffccSMiao-chen Chou 	}
7655031ffccSMiao-chen Chou 
7665031ffccSMiao-chen Chou 	INIT_LIST_HEAD(&msft->handle_map);
7679e14606dSHilda Wu 	INIT_LIST_HEAD(&msft->address_filters);
7685031ffccSMiao-chen Chou 	hdev->msft_data = msft;
7699e14606dSHilda Wu 	mutex_init(&msft->filter_lock);
7705031ffccSMiao-chen Chou }
7715031ffccSMiao-chen Chou 
msft_release(struct hci_dev * hdev)772a85a60e6SSungwoo Kim void msft_release(struct hci_dev *hdev)
7735031ffccSMiao-chen Chou {
7745031ffccSMiao-chen Chou 	struct msft_data *msft = hdev->msft_data;
7755031ffccSMiao-chen Chou 
7765031ffccSMiao-chen Chou 	if (!msft)
7775031ffccSMiao-chen Chou 		return;
7785031ffccSMiao-chen Chou 
7795031ffccSMiao-chen Chou 	bt_dev_dbg(hdev, "Unregister MSFT extension");
7805031ffccSMiao-chen Chou 
7815031ffccSMiao-chen Chou 	hdev->msft_data = NULL;
782a2a4dedfSArchie Pusaka 
783145373cbSMiao-chen Chou 	kfree(msft->evt_prefix);
7849e14606dSHilda Wu 	mutex_destroy(&msft->filter_lock);
785145373cbSMiao-chen Chou 	kfree(msft);
786145373cbSMiao-chen Chou }
787145373cbSMiao-chen Chou 
7883368aa35SManish Mandlik /* This function requires the caller holds hdev->lock */
msft_device_found(struct hci_dev * hdev,bdaddr_t * bdaddr,__u8 addr_type,__u16 mgmt_handle)7893368aa35SManish Mandlik static void msft_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr,
7903368aa35SManish Mandlik 			      __u8 addr_type, __u16 mgmt_handle)
7913368aa35SManish Mandlik {
7923368aa35SManish Mandlik 	struct monitored_device *dev;
7933368aa35SManish Mandlik 
7943368aa35SManish Mandlik 	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
7953368aa35SManish Mandlik 	if (!dev) {
7963368aa35SManish Mandlik 		bt_dev_err(hdev, "MSFT vendor event %u: no memory",
7973368aa35SManish Mandlik 			   MSFT_EV_LE_MONITOR_DEVICE);
7983368aa35SManish Mandlik 		return;
7993368aa35SManish Mandlik 	}
8003368aa35SManish Mandlik 
8013368aa35SManish Mandlik 	bacpy(&dev->bdaddr, bdaddr);
8023368aa35SManish Mandlik 	dev->addr_type = addr_type;
8033368aa35SManish Mandlik 	dev->handle = mgmt_handle;
8043368aa35SManish Mandlik 	dev->notified = false;
8053368aa35SManish Mandlik 
8063368aa35SManish Mandlik 	INIT_LIST_HEAD(&dev->list);
8073368aa35SManish Mandlik 	list_add(&dev->list, &hdev->monitored_devices);
8088d7f1677SManish Mandlik 	hdev->advmon_pend_notify = true;
8093368aa35SManish Mandlik }
8103368aa35SManish Mandlik 
8113368aa35SManish Mandlik /* This function requires the caller holds hdev->lock */
msft_device_lost(struct hci_dev * hdev,bdaddr_t * bdaddr,__u8 addr_type,__u16 mgmt_handle)8123368aa35SManish Mandlik static void msft_device_lost(struct hci_dev *hdev, bdaddr_t *bdaddr,
8133368aa35SManish Mandlik 			     __u8 addr_type, __u16 mgmt_handle)
8143368aa35SManish Mandlik {
8158d7f1677SManish Mandlik 	if (!msft_monitor_device_del(hdev, mgmt_handle, bdaddr, addr_type,
8168d7f1677SManish Mandlik 				     true)) {
8173368aa35SManish Mandlik 		bt_dev_err(hdev, "MSFT vendor event %u: dev %pMR not in list",
8183368aa35SManish Mandlik 			   MSFT_EV_LE_MONITOR_DEVICE, bdaddr);
8193368aa35SManish Mandlik 	}
8203368aa35SManish Mandlik }
8213368aa35SManish Mandlik 
msft_skb_pull(struct hci_dev * hdev,struct sk_buff * skb,u8 ev,size_t len)8223368aa35SManish Mandlik static void *msft_skb_pull(struct hci_dev *hdev, struct sk_buff *skb,
8233368aa35SManish Mandlik 			   u8 ev, size_t len)
8243368aa35SManish Mandlik {
8253368aa35SManish Mandlik 	void *data;
8263368aa35SManish Mandlik 
8273368aa35SManish Mandlik 	data = skb_pull_data(skb, len);
8283368aa35SManish Mandlik 	if (!data)
8293368aa35SManish Mandlik 		bt_dev_err(hdev, "Malformed MSFT vendor event: 0x%02x", ev);
8303368aa35SManish Mandlik 
8313368aa35SManish Mandlik 	return data;
8323368aa35SManish Mandlik }
8333368aa35SManish Mandlik 
msft_add_address_filter_sync(struct hci_dev * hdev,void * data)8349e14606dSHilda Wu static int msft_add_address_filter_sync(struct hci_dev *hdev, void *data)
8359e14606dSHilda Wu {
8369e14606dSHilda Wu 	struct msft_monitor_addr_filter_data *address_filter = data;
8379e14606dSHilda Wu 	struct msft_rp_le_monitor_advertisement *rp;
8389e14606dSHilda Wu 	struct msft_cp_le_monitor_advertisement *cp;
8399e14606dSHilda Wu 	struct msft_data *msft = hdev->msft_data;
8409e14606dSHilda Wu 	struct sk_buff *skb = NULL;
8419e14606dSHilda Wu 	bool remove = false;
8429e14606dSHilda Wu 	size_t size;
8439e14606dSHilda Wu 
8449e14606dSHilda Wu 	if (!msft) {
8459e14606dSHilda Wu 		bt_dev_err(hdev, "MSFT: msft data is freed");
8469e14606dSHilda Wu 		return -EINVAL;
8479e14606dSHilda Wu 	}
8489e14606dSHilda Wu 
8499e14606dSHilda Wu 	/* The address filter has been removed by hci dev close */
8509e14606dSHilda Wu 	if (!test_bit(HCI_UP, &hdev->flags))
8519e14606dSHilda Wu 		return -ENODEV;
8529e14606dSHilda Wu 
8539e14606dSHilda Wu 	/* We are safe to use the address filter from now on.
8549e14606dSHilda Wu 	 * msft_monitor_device_evt() wouldn't delete this filter because it's
8559e14606dSHilda Wu 	 * not been added by now.
8569e14606dSHilda Wu 	 * And all other functions that requiring hci_req_sync_lock wouldn't
8579e14606dSHilda Wu 	 * touch this filter before this func completes because it's protected
8589e14606dSHilda Wu 	 * by hci_req_sync_lock.
8599e14606dSHilda Wu 	 */
8609e14606dSHilda Wu 
8619e14606dSHilda Wu 	if (address_filter->state == AF_STATE_REMOVING) {
8629e14606dSHilda Wu 		mutex_lock(&msft->filter_lock);
8639e14606dSHilda Wu 		list_del(&address_filter->list);
8649e14606dSHilda Wu 		mutex_unlock(&msft->filter_lock);
8659e14606dSHilda Wu 		kfree(address_filter);
8669e14606dSHilda Wu 		return 0;
8679e14606dSHilda Wu 	}
8689e14606dSHilda Wu 
8699e14606dSHilda Wu 	size = sizeof(*cp) +
8709e14606dSHilda Wu 	       sizeof(address_filter->addr_type) +
8719e14606dSHilda Wu 	       sizeof(address_filter->bdaddr);
8729e14606dSHilda Wu 	cp = kzalloc(size, GFP_KERNEL);
8739e14606dSHilda Wu 	if (!cp) {
8749e14606dSHilda Wu 		bt_dev_err(hdev, "MSFT: Alloc cmd param err");
8759e14606dSHilda Wu 		remove = true;
8769e14606dSHilda Wu 		goto done;
8779e14606dSHilda Wu 	}
87898e9920cSLuiz Augusto von Dentz 
8799e14606dSHilda Wu 	cp->sub_opcode           = MSFT_OP_LE_MONITOR_ADVERTISEMENT;
8809e14606dSHilda Wu 	cp->rssi_high		 = address_filter->rssi_high;
8819e14606dSHilda Wu 	cp->rssi_low		 = address_filter->rssi_low;
8829e14606dSHilda Wu 	cp->rssi_low_interval    = address_filter->rssi_low_interval;
8839e14606dSHilda Wu 	cp->rssi_sampling_period = address_filter->rssi_sampling_period;
8849e14606dSHilda Wu 	cp->cond_type            = MSFT_MONITOR_ADVERTISEMENT_TYPE_ADDR;
8859e14606dSHilda Wu 	cp->data[0]              = address_filter->addr_type;
8869e14606dSHilda Wu 	memcpy(&cp->data[1], &address_filter->bdaddr,
8879e14606dSHilda Wu 	       sizeof(address_filter->bdaddr));
8889e14606dSHilda Wu 
8899e14606dSHilda Wu 	skb = __hci_cmd_sync(hdev, hdev->msft_opcode, size, cp,
8909e14606dSHilda Wu 			     HCI_CMD_TIMEOUT);
89198e9920cSLuiz Augusto von Dentz 	kfree(cp);
89298e9920cSLuiz Augusto von Dentz 
89336626c26SDan Carpenter 	if (IS_ERR(skb)) {
8949e14606dSHilda Wu 		bt_dev_err(hdev, "Failed to enable address %pMR filter",
8959e14606dSHilda Wu 			   &address_filter->bdaddr);
8969e14606dSHilda Wu 		skb = NULL;
8979e14606dSHilda Wu 		remove = true;
8989e14606dSHilda Wu 		goto done;
8999e14606dSHilda Wu 	}
9009e14606dSHilda Wu 
9019e14606dSHilda Wu 	rp = skb_pull_data(skb, sizeof(*rp));
9029e14606dSHilda Wu 	if (!rp || rp->sub_opcode != MSFT_OP_LE_MONITOR_ADVERTISEMENT ||
9039e14606dSHilda Wu 	    rp->status)
9049e14606dSHilda Wu 		remove = true;
9059e14606dSHilda Wu 
9069e14606dSHilda Wu done:
9079e14606dSHilda Wu 	mutex_lock(&msft->filter_lock);
9089e14606dSHilda Wu 
9099e14606dSHilda Wu 	if (remove) {
9109e14606dSHilda Wu 		bt_dev_warn(hdev, "MSFT: Remove address (%pMR) filter",
9119e14606dSHilda Wu 			    &address_filter->bdaddr);
9129e14606dSHilda Wu 		list_del(&address_filter->list);
9139e14606dSHilda Wu 		kfree(address_filter);
9149e14606dSHilda Wu 	} else {
9159e14606dSHilda Wu 		address_filter->state = AF_STATE_ADDED;
9169e14606dSHilda Wu 		address_filter->msft_handle = rp->handle;
9179e14606dSHilda Wu 		bt_dev_dbg(hdev, "MSFT: Address %pMR filter enabled",
9189e14606dSHilda Wu 			   &address_filter->bdaddr);
9199e14606dSHilda Wu 	}
9209e14606dSHilda Wu 	mutex_unlock(&msft->filter_lock);
9219e14606dSHilda Wu 
9229e14606dSHilda Wu 	kfree_skb(skb);
9239e14606dSHilda Wu 
9249e14606dSHilda Wu 	return 0;
9259e14606dSHilda Wu }
9269e14606dSHilda Wu 
9279e14606dSHilda Wu /* This function requires the caller holds msft->filter_lock */
msft_add_address_filter(struct hci_dev * hdev,u8 addr_type,bdaddr_t * bdaddr,struct msft_monitor_advertisement_handle_data * handle_data)9289e14606dSHilda Wu static struct msft_monitor_addr_filter_data *msft_add_address_filter
9299e14606dSHilda Wu 		(struct hci_dev *hdev, u8 addr_type, bdaddr_t *bdaddr,
9309e14606dSHilda Wu 		 struct msft_monitor_advertisement_handle_data *handle_data)
9319e14606dSHilda Wu {
9329e14606dSHilda Wu 	struct msft_monitor_addr_filter_data *address_filter = NULL;
9339e14606dSHilda Wu 	struct msft_data *msft = hdev->msft_data;
9349e14606dSHilda Wu 	int err;
9359e14606dSHilda Wu 
9369e14606dSHilda Wu 	address_filter = kzalloc(sizeof(*address_filter), GFP_KERNEL);
9379e14606dSHilda Wu 	if (!address_filter)
9389e14606dSHilda Wu 		return NULL;
9399e14606dSHilda Wu 
9409e14606dSHilda Wu 	address_filter->state             = AF_STATE_ADDING;
9419e14606dSHilda Wu 	address_filter->msft_handle       = 0xff;
9429e14606dSHilda Wu 	address_filter->pattern_handle    = handle_data->msft_handle;
9439e14606dSHilda Wu 	address_filter->mgmt_handle       = handle_data->mgmt_handle;
9449e14606dSHilda Wu 	address_filter->rssi_high         = handle_data->rssi_high;
9459e14606dSHilda Wu 	address_filter->rssi_low          = handle_data->rssi_low;
9469e14606dSHilda Wu 	address_filter->rssi_low_interval = handle_data->rssi_low_interval;
9479e14606dSHilda Wu 	address_filter->rssi_sampling_period = handle_data->rssi_sampling_period;
9489e14606dSHilda Wu 	address_filter->addr_type            = addr_type;
9499e14606dSHilda Wu 	bacpy(&address_filter->bdaddr, bdaddr);
9509e14606dSHilda Wu 
9519e14606dSHilda Wu 	/* With the above AF_STATE_ADDING, duplicated address filter can be
9529e14606dSHilda Wu 	 * avoided when receiving monitor device event (found/lost) frequently
9539e14606dSHilda Wu 	 * for the same device.
9549e14606dSHilda Wu 	 */
9559e14606dSHilda Wu 	list_add_tail(&address_filter->list, &msft->address_filters);
9569e14606dSHilda Wu 
9579e14606dSHilda Wu 	err = hci_cmd_sync_queue(hdev, msft_add_address_filter_sync,
9589e14606dSHilda Wu 				 address_filter, NULL);
9599e14606dSHilda Wu 	if (err < 0) {
9609e14606dSHilda Wu 		bt_dev_err(hdev, "MSFT: Add address %pMR filter err", bdaddr);
9619e14606dSHilda Wu 		list_del(&address_filter->list);
9629e14606dSHilda Wu 		kfree(address_filter);
9639e14606dSHilda Wu 		return NULL;
9649e14606dSHilda Wu 	}
9659e14606dSHilda Wu 
9669e14606dSHilda Wu 	bt_dev_dbg(hdev, "MSFT: Add device %pMR address filter",
9679e14606dSHilda Wu 		   &address_filter->bdaddr);
9689e14606dSHilda Wu 
9699e14606dSHilda Wu 	return address_filter;
9709e14606dSHilda Wu }
9719e14606dSHilda Wu 
9723368aa35SManish Mandlik /* This function requires the caller holds hdev->lock */
msft_monitor_device_evt(struct hci_dev * hdev,struct sk_buff * skb)9733368aa35SManish Mandlik static void msft_monitor_device_evt(struct hci_dev *hdev, struct sk_buff *skb)
9743368aa35SManish Mandlik {
9759e14606dSHilda Wu 	struct msft_monitor_addr_filter_data *n, *address_filter = NULL;
9763368aa35SManish Mandlik 	struct msft_ev_le_monitor_device *ev;
9773368aa35SManish Mandlik 	struct msft_monitor_advertisement_handle_data *handle_data;
9789e14606dSHilda Wu 	struct msft_data *msft = hdev->msft_data;
9799e14606dSHilda Wu 	u16 mgmt_handle = 0xffff;
9803368aa35SManish Mandlik 	u8 addr_type;
9813368aa35SManish Mandlik 
9823368aa35SManish Mandlik 	ev = msft_skb_pull(hdev, skb, MSFT_EV_LE_MONITOR_DEVICE, sizeof(*ev));
9833368aa35SManish Mandlik 	if (!ev)
9843368aa35SManish Mandlik 		return;
9853368aa35SManish Mandlik 
9863368aa35SManish Mandlik 	bt_dev_dbg(hdev,
9873368aa35SManish Mandlik 		   "MSFT vendor event 0x%02x: handle 0x%04x state %d addr %pMR",
9883368aa35SManish Mandlik 		   MSFT_EV_LE_MONITOR_DEVICE, ev->monitor_handle,
9893368aa35SManish Mandlik 		   ev->monitor_state, &ev->bdaddr);
9903368aa35SManish Mandlik 
9913368aa35SManish Mandlik 	handle_data = msft_find_handle_data(hdev, ev->monitor_handle, false);
9929e14606dSHilda Wu 
9939e14606dSHilda Wu 	if (!test_bit(HCI_QUIRK_USE_MSFT_EXT_ADDRESS_FILTER, &hdev->quirks)) {
9945201d23cSSoenke Huster 		if (!handle_data)
9955201d23cSSoenke Huster 			return;
9969e14606dSHilda Wu 		mgmt_handle = handle_data->mgmt_handle;
9979e14606dSHilda Wu 		goto report_state;
9989e14606dSHilda Wu 	}
9993368aa35SManish Mandlik 
10009e14606dSHilda Wu 	if (handle_data) {
10019e14606dSHilda Wu 		/* Don't report any device found/lost event from pattern
10029e14606dSHilda Wu 		 * monitors. Pattern monitor always has its address filters for
10039e14606dSHilda Wu 		 * tracking devices.
10049e14606dSHilda Wu 		 */
10059e14606dSHilda Wu 
10069e14606dSHilda Wu 		address_filter = msft_find_address_data(hdev, ev->addr_type,
10079e14606dSHilda Wu 							&ev->bdaddr,
10089e14606dSHilda Wu 							handle_data->msft_handle);
10099e14606dSHilda Wu 		if (address_filter)
10109e14606dSHilda Wu 			return;
10119e14606dSHilda Wu 
10129e14606dSHilda Wu 		if (ev->monitor_state && handle_data->cond_type ==
10139e14606dSHilda Wu 				MSFT_MONITOR_ADVERTISEMENT_TYPE_PATTERN)
10149e14606dSHilda Wu 			msft_add_address_filter(hdev, ev->addr_type,
10159e14606dSHilda Wu 						&ev->bdaddr, handle_data);
10169e14606dSHilda Wu 
10179e14606dSHilda Wu 		return;
10189e14606dSHilda Wu 	}
10199e14606dSHilda Wu 
10209e14606dSHilda Wu 	/* This device event is not from pattern monitor.
10219e14606dSHilda Wu 	 * Report it if there is a corresponding address_filter for it.
10229e14606dSHilda Wu 	 */
10239e14606dSHilda Wu 	list_for_each_entry(n, &msft->address_filters, list) {
10249e14606dSHilda Wu 		if (n->state == AF_STATE_ADDED &&
10259e14606dSHilda Wu 		    n->msft_handle == ev->monitor_handle) {
10269e14606dSHilda Wu 			mgmt_handle = n->mgmt_handle;
10279e14606dSHilda Wu 			address_filter = n;
10289e14606dSHilda Wu 			break;
10299e14606dSHilda Wu 		}
10309e14606dSHilda Wu 	}
10319e14606dSHilda Wu 
10329e14606dSHilda Wu 	if (!address_filter) {
10339e14606dSHilda Wu 		bt_dev_warn(hdev, "MSFT: Unexpected device event %pMR, %u, %u",
10349e14606dSHilda Wu 			    &ev->bdaddr, ev->monitor_handle, ev->monitor_state);
10359e14606dSHilda Wu 		return;
10369e14606dSHilda Wu 	}
10379e14606dSHilda Wu 
10389e14606dSHilda Wu report_state:
10393368aa35SManish Mandlik 	switch (ev->addr_type) {
10403368aa35SManish Mandlik 	case ADDR_LE_DEV_PUBLIC:
10413368aa35SManish Mandlik 		addr_type = BDADDR_LE_PUBLIC;
10423368aa35SManish Mandlik 		break;
10433368aa35SManish Mandlik 
10443368aa35SManish Mandlik 	case ADDR_LE_DEV_RANDOM:
10453368aa35SManish Mandlik 		addr_type = BDADDR_LE_RANDOM;
10463368aa35SManish Mandlik 		break;
10473368aa35SManish Mandlik 
10483368aa35SManish Mandlik 	default:
10493368aa35SManish Mandlik 		bt_dev_err(hdev,
10503368aa35SManish Mandlik 			   "MSFT vendor event 0x%02x: unknown addr type 0x%02x",
10513368aa35SManish Mandlik 			   MSFT_EV_LE_MONITOR_DEVICE, ev->addr_type);
10523368aa35SManish Mandlik 		return;
10533368aa35SManish Mandlik 	}
10543368aa35SManish Mandlik 
10559e14606dSHilda Wu 	if (ev->monitor_state) {
10569e14606dSHilda Wu 		msft_device_found(hdev, &ev->bdaddr, addr_type, mgmt_handle);
10579e14606dSHilda Wu 	} else {
10589e14606dSHilda Wu 		if (address_filter && address_filter->state == AF_STATE_ADDED) {
10599e14606dSHilda Wu 			address_filter->state = AF_STATE_REMOVING;
10609e14606dSHilda Wu 			hci_cmd_sync_queue(hdev,
10619e14606dSHilda Wu 					   msft_cancel_address_filter_sync,
10629e14606dSHilda Wu 					   address_filter,
10639e14606dSHilda Wu 					   NULL);
10649e14606dSHilda Wu 		}
10659e14606dSHilda Wu 		msft_device_lost(hdev, &ev->bdaddr, addr_type, mgmt_handle);
10669e14606dSHilda Wu 	}
10673368aa35SManish Mandlik }
10683368aa35SManish Mandlik 
msft_vendor_evt(struct hci_dev * hdev,void * data,struct sk_buff * skb)10693e54c589SLuiz Augusto von Dentz void msft_vendor_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb)
1070145373cbSMiao-chen Chou {
1071145373cbSMiao-chen Chou 	struct msft_data *msft = hdev->msft_data;
10723368aa35SManish Mandlik 	u8 *evt_prefix;
10733368aa35SManish Mandlik 	u8 *evt;
1074145373cbSMiao-chen Chou 
1075145373cbSMiao-chen Chou 	if (!msft)
1076145373cbSMiao-chen Chou 		return;
1077145373cbSMiao-chen Chou 
1078145373cbSMiao-chen Chou 	/* When the extension has defined an event prefix, check that it
1079145373cbSMiao-chen Chou 	 * matches, and otherwise just return.
1080145373cbSMiao-chen Chou 	 */
1081145373cbSMiao-chen Chou 	if (msft->evt_prefix_len > 0) {
10823368aa35SManish Mandlik 		evt_prefix = msft_skb_pull(hdev, skb, 0, msft->evt_prefix_len);
10833368aa35SManish Mandlik 		if (!evt_prefix)
1084145373cbSMiao-chen Chou 			return;
1085145373cbSMiao-chen Chou 
10863368aa35SManish Mandlik 		if (memcmp(evt_prefix, msft->evt_prefix, msft->evt_prefix_len))
1087145373cbSMiao-chen Chou 			return;
1088145373cbSMiao-chen Chou 	}
1089145373cbSMiao-chen Chou 
1090145373cbSMiao-chen Chou 	/* Every event starts at least with an event code and the rest of
1091145373cbSMiao-chen Chou 	 * the data is variable and depends on the event code.
1092145373cbSMiao-chen Chou 	 */
1093145373cbSMiao-chen Chou 	if (skb->len < 1)
1094145373cbSMiao-chen Chou 		return;
1095145373cbSMiao-chen Chou 
10963368aa35SManish Mandlik 	evt = msft_skb_pull(hdev, skb, 0, sizeof(*evt));
10973368aa35SManish Mandlik 	if (!evt)
10983368aa35SManish Mandlik 		return;
1099145373cbSMiao-chen Chou 
11003368aa35SManish Mandlik 	hci_dev_lock(hdev);
11013368aa35SManish Mandlik 
11023368aa35SManish Mandlik 	switch (*evt) {
11033368aa35SManish Mandlik 	case MSFT_EV_LE_MONITOR_DEVICE:
11049e14606dSHilda Wu 		mutex_lock(&msft->filter_lock);
11053368aa35SManish Mandlik 		msft_monitor_device_evt(hdev, skb);
11069e14606dSHilda Wu 		mutex_unlock(&msft->filter_lock);
11073368aa35SManish Mandlik 		break;
11083368aa35SManish Mandlik 
11093368aa35SManish Mandlik 	default:
11103368aa35SManish Mandlik 		bt_dev_dbg(hdev, "MSFT vendor event 0x%02x", *evt);
11113368aa35SManish Mandlik 		break;
11123368aa35SManish Mandlik 	}
11133368aa35SManish Mandlik 
11143368aa35SManish Mandlik 	hci_dev_unlock(hdev);
1115145373cbSMiao-chen Chou }
1116e5e1e7fdSMiao-chen Chou 
msft_get_features(struct hci_dev * hdev)1117e5e1e7fdSMiao-chen Chou __u64 msft_get_features(struct hci_dev *hdev)
1118e5e1e7fdSMiao-chen Chou {
1119e5e1e7fdSMiao-chen Chou 	struct msft_data *msft = hdev->msft_data;
1120e5e1e7fdSMiao-chen Chou 
1121e5e1e7fdSMiao-chen Chou 	return msft ? msft->features : 0;
1122e5e1e7fdSMiao-chen Chou }
1123a2a4dedfSArchie Pusaka 
msft_le_set_advertisement_filter_enable_cb(struct hci_dev * hdev,void * user_data,u8 status)1124394566bfSArchie Pusaka static void msft_le_set_advertisement_filter_enable_cb(struct hci_dev *hdev,
1125493ea699SBrian Gix 						       void *user_data,
1126493ea699SBrian Gix 						       u8 status)
1127394566bfSArchie Pusaka {
1128493ea699SBrian Gix 	struct msft_cp_le_set_advertisement_filter_enable *cp = user_data;
1129394566bfSArchie Pusaka 	struct msft_data *msft = hdev->msft_data;
1130394566bfSArchie Pusaka 
1131394566bfSArchie Pusaka 	/* Error 0x0C would be returned if the filter enabled status is
1132394566bfSArchie Pusaka 	 * already set to whatever we were trying to set.
1133394566bfSArchie Pusaka 	 * Although the default state should be disabled, some controller set
1134394566bfSArchie Pusaka 	 * the initial value to enabled. Because there is no way to know the
1135394566bfSArchie Pusaka 	 * actual initial value before sending this command, here we also treat
1136394566bfSArchie Pusaka 	 * error 0x0C as success.
1137394566bfSArchie Pusaka 	 */
1138394566bfSArchie Pusaka 	if (status != 0x00 && status != 0x0C)
1139394566bfSArchie Pusaka 		return;
1140394566bfSArchie Pusaka 
1141394566bfSArchie Pusaka 	hci_dev_lock(hdev);
1142394566bfSArchie Pusaka 
1143394566bfSArchie Pusaka 	msft->filter_enabled = cp->enable;
1144394566bfSArchie Pusaka 
1145394566bfSArchie Pusaka 	if (status == 0x0C)
1146394566bfSArchie Pusaka 		bt_dev_warn(hdev, "MSFT filter_enable is already %s",
1147394566bfSArchie Pusaka 			    cp->enable ? "on" : "off");
1148394566bfSArchie Pusaka 
1149394566bfSArchie Pusaka 	hci_dev_unlock(hdev);
1150394566bfSArchie Pusaka }
1151394566bfSArchie Pusaka 
1152b747a836SManish Mandlik /* This function requires the caller holds hci_req_sync_lock */
msft_add_monitor_pattern(struct hci_dev * hdev,struct adv_monitor * monitor)11534a37682cSArchie Pusaka int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor)
11544a37682cSArchie Pusaka {
11554a37682cSArchie Pusaka 	struct msft_data *msft = hdev->msft_data;
11564a37682cSArchie Pusaka 
11574a37682cSArchie Pusaka 	if (!msft)
11584a37682cSArchie Pusaka 		return -EOPNOTSUPP;
11594a37682cSArchie Pusaka 
1160182ee45dSLuiz Augusto von Dentz 	if (msft->resuming || msft->suspending)
11614a37682cSArchie Pusaka 		return -EBUSY;
11624a37682cSArchie Pusaka 
1163b747a836SManish Mandlik 	return msft_add_monitor_sync(hdev, monitor);
11644a37682cSArchie Pusaka }
11654a37682cSArchie Pusaka 
11667cf5c297SManish Mandlik /* This function requires the caller holds hci_req_sync_lock */
msft_remove_monitor(struct hci_dev * hdev,struct adv_monitor * monitor)11677cf5c297SManish Mandlik int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor)
1168ce81843bSManish Mandlik {
1169ce81843bSManish Mandlik 	struct msft_data *msft = hdev->msft_data;
1170ce81843bSManish Mandlik 
1171ce81843bSManish Mandlik 	if (!msft)
1172ce81843bSManish Mandlik 		return -EOPNOTSUPP;
1173ce81843bSManish Mandlik 
1174182ee45dSLuiz Augusto von Dentz 	if (msft->resuming || msft->suspending)
1175ce81843bSManish Mandlik 		return -EBUSY;
1176ce81843bSManish Mandlik 
11777cf5c297SManish Mandlik 	return msft_remove_monitor_sync(hdev, monitor);
1178ce81843bSManish Mandlik }
1179ce81843bSManish Mandlik 
msft_set_filter_enable(struct hci_dev * hdev,bool enable)1180394566bfSArchie Pusaka int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
1181394566bfSArchie Pusaka {
1182493ea699SBrian Gix 	struct msft_cp_le_set_advertisement_filter_enable cp;
1183394566bfSArchie Pusaka 	struct msft_data *msft = hdev->msft_data;
1184394566bfSArchie Pusaka 	int err;
1185394566bfSArchie Pusaka 
1186394566bfSArchie Pusaka 	if (!msft)
1187394566bfSArchie Pusaka 		return -EOPNOTSUPP;
1188394566bfSArchie Pusaka 
1189493ea699SBrian Gix 	cp.sub_opcode = MSFT_OP_LE_SET_ADVERTISEMENT_FILTER_ENABLE;
1190493ea699SBrian Gix 	cp.enable = enable;
1191493ea699SBrian Gix 	err = __hci_cmd_sync_status(hdev, hdev->msft_opcode, sizeof(cp), &cp,
1192493ea699SBrian Gix 				    HCI_CMD_TIMEOUT);
1193394566bfSArchie Pusaka 
1194493ea699SBrian Gix 	msft_le_set_advertisement_filter_enable_cb(hdev, &cp, err);
1195493ea699SBrian Gix 
1196493ea699SBrian Gix 	return 0;
1197394566bfSArchie Pusaka }
1198a61d6718SMarcel Holtmann 
msft_curve_validity(struct hci_dev * hdev)1199a61d6718SMarcel Holtmann bool msft_curve_validity(struct hci_dev *hdev)
1200a61d6718SMarcel Holtmann {
1201a61d6718SMarcel Holtmann 	return hdev->msft_curve_validity;
1202a61d6718SMarcel Holtmann }
1203