18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci   BlueZ - Bluetooth protocol stack for Linux
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci   Copyright (C) 2014 Intel Corporation
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci   This program is free software; you can redistribute it and/or modify
78c2ecf20Sopenharmony_ci   it under the terms of the GNU General Public License version 2 as
88c2ecf20Sopenharmony_ci   published by the Free Software Foundation;
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
118c2ecf20Sopenharmony_ci   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
128c2ecf20Sopenharmony_ci   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
138c2ecf20Sopenharmony_ci   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
148c2ecf20Sopenharmony_ci   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
158c2ecf20Sopenharmony_ci   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
168c2ecf20Sopenharmony_ci   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
178c2ecf20Sopenharmony_ci   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
208c2ecf20Sopenharmony_ci   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
218c2ecf20Sopenharmony_ci   SOFTWARE IS DISCLAIMED.
228c2ecf20Sopenharmony_ci*/
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include <net/bluetooth/bluetooth.h>
278c2ecf20Sopenharmony_ci#include <net/bluetooth/hci_core.h>
288c2ecf20Sopenharmony_ci#include <net/bluetooth/mgmt.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include "smp.h"
318c2ecf20Sopenharmony_ci#include "hci_request.h"
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define HCI_REQ_DONE	  0
348c2ecf20Sopenharmony_ci#define HCI_REQ_PEND	  1
358c2ecf20Sopenharmony_ci#define HCI_REQ_CANCELED  2
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_civoid hci_req_init(struct hci_request *req, struct hci_dev *hdev)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	skb_queue_head_init(&req->cmd_q);
408c2ecf20Sopenharmony_ci	req->hdev = hdev;
418c2ecf20Sopenharmony_ci	req->err = 0;
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_civoid hci_req_purge(struct hci_request *req)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	skb_queue_purge(&req->cmd_q);
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cibool hci_req_status_pend(struct hci_dev *hdev)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	return hdev->req_status == HCI_REQ_PEND;
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic int req_run(struct hci_request *req, hci_req_complete_t complete,
558c2ecf20Sopenharmony_ci		   hci_req_complete_skb_t complete_skb)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
588c2ecf20Sopenharmony_ci	struct sk_buff *skb;
598c2ecf20Sopenharmony_ci	unsigned long flags;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	BT_DBG("length %u", skb_queue_len(&req->cmd_q));
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	/* If an error occurred during request building, remove all HCI
648c2ecf20Sopenharmony_ci	 * commands queued on the HCI request queue.
658c2ecf20Sopenharmony_ci	 */
668c2ecf20Sopenharmony_ci	if (req->err) {
678c2ecf20Sopenharmony_ci		skb_queue_purge(&req->cmd_q);
688c2ecf20Sopenharmony_ci		return req->err;
698c2ecf20Sopenharmony_ci	}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	/* Do not allow empty requests */
728c2ecf20Sopenharmony_ci	if (skb_queue_empty(&req->cmd_q))
738c2ecf20Sopenharmony_ci		return -ENODATA;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	skb = skb_peek_tail(&req->cmd_q);
768c2ecf20Sopenharmony_ci	if (complete) {
778c2ecf20Sopenharmony_ci		bt_cb(skb)->hci.req_complete = complete;
788c2ecf20Sopenharmony_ci	} else if (complete_skb) {
798c2ecf20Sopenharmony_ci		bt_cb(skb)->hci.req_complete_skb = complete_skb;
808c2ecf20Sopenharmony_ci		bt_cb(skb)->hci.req_flags |= HCI_REQ_SKB;
818c2ecf20Sopenharmony_ci	}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hdev->cmd_q.lock, flags);
848c2ecf20Sopenharmony_ci	skb_queue_splice_tail(&req->cmd_q, &hdev->cmd_q);
858c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hdev->cmd_q.lock, flags);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	queue_work(hdev->workqueue, &hdev->cmd_work);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	return 0;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ciint hci_req_run(struct hci_request *req, hci_req_complete_t complete)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	return req_run(req, complete, NULL);
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ciint hci_req_run_skb(struct hci_request *req, hci_req_complete_skb_t complete)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	return req_run(req, NULL, complete);
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic void hci_req_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
1038c2ecf20Sopenharmony_ci				  struct sk_buff *skb)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	BT_DBG("%s result 0x%2.2x", hdev->name, result);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	if (hdev->req_status == HCI_REQ_PEND) {
1088c2ecf20Sopenharmony_ci		hdev->req_result = result;
1098c2ecf20Sopenharmony_ci		hdev->req_status = HCI_REQ_DONE;
1108c2ecf20Sopenharmony_ci		if (skb) {
1118c2ecf20Sopenharmony_ci			kfree_skb(hdev->req_skb);
1128c2ecf20Sopenharmony_ci			hdev->req_skb = skb_get(skb);
1138c2ecf20Sopenharmony_ci		}
1148c2ecf20Sopenharmony_ci		wake_up_interruptible(&hdev->req_wait_q);
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_civoid hci_req_sync_cancel(struct hci_dev *hdev, int err)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	BT_DBG("%s err 0x%2.2x", hdev->name, err);
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	if (hdev->req_status == HCI_REQ_PEND) {
1238c2ecf20Sopenharmony_ci		hdev->req_result = err;
1248c2ecf20Sopenharmony_ci		hdev->req_status = HCI_REQ_CANCELED;
1258c2ecf20Sopenharmony_ci		wake_up_interruptible(&hdev->req_wait_q);
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistruct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
1308c2ecf20Sopenharmony_ci				  const void *param, u8 event, u32 timeout)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	struct hci_request req;
1338c2ecf20Sopenharmony_ci	struct sk_buff *skb;
1348c2ecf20Sopenharmony_ci	int err = 0;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	BT_DBG("%s", hdev->name);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	hci_req_init(&req, hdev);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	hci_req_add_ev(&req, opcode, plen, param, event);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	hdev->req_status = HCI_REQ_PEND;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	err = hci_req_run_skb(&req, hci_req_sync_complete);
1458c2ecf20Sopenharmony_ci	if (err < 0)
1468c2ecf20Sopenharmony_ci		return ERR_PTR(err);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	err = wait_event_interruptible_timeout(hdev->req_wait_q,
1498c2ecf20Sopenharmony_ci			hdev->req_status != HCI_REQ_PEND, timeout);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	if (err == -ERESTARTSYS)
1528c2ecf20Sopenharmony_ci		return ERR_PTR(-EINTR);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	switch (hdev->req_status) {
1558c2ecf20Sopenharmony_ci	case HCI_REQ_DONE:
1568c2ecf20Sopenharmony_ci		err = -bt_to_errno(hdev->req_result);
1578c2ecf20Sopenharmony_ci		break;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	case HCI_REQ_CANCELED:
1608c2ecf20Sopenharmony_ci		err = -hdev->req_result;
1618c2ecf20Sopenharmony_ci		break;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	default:
1648c2ecf20Sopenharmony_ci		err = -ETIMEDOUT;
1658c2ecf20Sopenharmony_ci		break;
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	hdev->req_status = hdev->req_result = 0;
1698c2ecf20Sopenharmony_ci	skb = hdev->req_skb;
1708c2ecf20Sopenharmony_ci	hdev->req_skb = NULL;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	BT_DBG("%s end: err %d", hdev->name, err);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	if (err < 0) {
1758c2ecf20Sopenharmony_ci		kfree_skb(skb);
1768c2ecf20Sopenharmony_ci		return ERR_PTR(err);
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (!skb)
1808c2ecf20Sopenharmony_ci		return ERR_PTR(-ENODATA);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	return skb;
1838c2ecf20Sopenharmony_ci}
1848c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__hci_cmd_sync_ev);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cistruct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
1878c2ecf20Sopenharmony_ci			       const void *param, u32 timeout)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	return __hci_cmd_sync_ev(hdev, opcode, plen, param, 0, timeout);
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__hci_cmd_sync);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci/* Execute request and wait for completion. */
1948c2ecf20Sopenharmony_ciint __hci_req_sync(struct hci_dev *hdev, int (*func)(struct hci_request *req,
1958c2ecf20Sopenharmony_ci						     unsigned long opt),
1968c2ecf20Sopenharmony_ci		   unsigned long opt, u32 timeout, u8 *hci_status)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	struct hci_request req;
1998c2ecf20Sopenharmony_ci	int err = 0;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	BT_DBG("%s start", hdev->name);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	hci_req_init(&req, hdev);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	hdev->req_status = HCI_REQ_PEND;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	err = func(&req, opt);
2088c2ecf20Sopenharmony_ci	if (err) {
2098c2ecf20Sopenharmony_ci		if (hci_status)
2108c2ecf20Sopenharmony_ci			*hci_status = HCI_ERROR_UNSPECIFIED;
2118c2ecf20Sopenharmony_ci		return err;
2128c2ecf20Sopenharmony_ci	}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	err = hci_req_run_skb(&req, hci_req_sync_complete);
2158c2ecf20Sopenharmony_ci	if (err < 0) {
2168c2ecf20Sopenharmony_ci		hdev->req_status = 0;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci		/* ENODATA means the HCI request command queue is empty.
2198c2ecf20Sopenharmony_ci		 * This can happen when a request with conditionals doesn't
2208c2ecf20Sopenharmony_ci		 * trigger any commands to be sent. This is normal behavior
2218c2ecf20Sopenharmony_ci		 * and should not trigger an error return.
2228c2ecf20Sopenharmony_ci		 */
2238c2ecf20Sopenharmony_ci		if (err == -ENODATA) {
2248c2ecf20Sopenharmony_ci			if (hci_status)
2258c2ecf20Sopenharmony_ci				*hci_status = 0;
2268c2ecf20Sopenharmony_ci			return 0;
2278c2ecf20Sopenharmony_ci		}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci		if (hci_status)
2308c2ecf20Sopenharmony_ci			*hci_status = HCI_ERROR_UNSPECIFIED;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci		return err;
2338c2ecf20Sopenharmony_ci	}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	err = wait_event_interruptible_timeout(hdev->req_wait_q,
2368c2ecf20Sopenharmony_ci			hdev->req_status != HCI_REQ_PEND, timeout);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	if (err == -ERESTARTSYS)
2398c2ecf20Sopenharmony_ci		return -EINTR;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	switch (hdev->req_status) {
2428c2ecf20Sopenharmony_ci	case HCI_REQ_DONE:
2438c2ecf20Sopenharmony_ci		err = -bt_to_errno(hdev->req_result);
2448c2ecf20Sopenharmony_ci		if (hci_status)
2458c2ecf20Sopenharmony_ci			*hci_status = hdev->req_result;
2468c2ecf20Sopenharmony_ci		break;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	case HCI_REQ_CANCELED:
2498c2ecf20Sopenharmony_ci		err = -hdev->req_result;
2508c2ecf20Sopenharmony_ci		if (hci_status)
2518c2ecf20Sopenharmony_ci			*hci_status = HCI_ERROR_UNSPECIFIED;
2528c2ecf20Sopenharmony_ci		break;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	default:
2558c2ecf20Sopenharmony_ci		err = -ETIMEDOUT;
2568c2ecf20Sopenharmony_ci		if (hci_status)
2578c2ecf20Sopenharmony_ci			*hci_status = HCI_ERROR_UNSPECIFIED;
2588c2ecf20Sopenharmony_ci		break;
2598c2ecf20Sopenharmony_ci	}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	kfree_skb(hdev->req_skb);
2628c2ecf20Sopenharmony_ci	hdev->req_skb = NULL;
2638c2ecf20Sopenharmony_ci	hdev->req_status = hdev->req_result = 0;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	BT_DBG("%s end: err %d", hdev->name, err);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	return err;
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ciint hci_req_sync(struct hci_dev *hdev, int (*req)(struct hci_request *req,
2718c2ecf20Sopenharmony_ci						  unsigned long opt),
2728c2ecf20Sopenharmony_ci		 unsigned long opt, u32 timeout, u8 *hci_status)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	int ret;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	/* Serialize all requests */
2778c2ecf20Sopenharmony_ci	hci_req_sync_lock(hdev);
2788c2ecf20Sopenharmony_ci	/* check the state after obtaing the lock to protect the HCI_UP
2798c2ecf20Sopenharmony_ci	 * against any races from hci_dev_do_close when the controller
2808c2ecf20Sopenharmony_ci	 * gets removed.
2818c2ecf20Sopenharmony_ci	 */
2828c2ecf20Sopenharmony_ci	if (test_bit(HCI_UP, &hdev->flags))
2838c2ecf20Sopenharmony_ci		ret = __hci_req_sync(hdev, req, opt, timeout, hci_status);
2848c2ecf20Sopenharmony_ci	else
2858c2ecf20Sopenharmony_ci		ret = -ENETDOWN;
2868c2ecf20Sopenharmony_ci	hci_req_sync_unlock(hdev);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	return ret;
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistruct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode, u32 plen,
2928c2ecf20Sopenharmony_ci				const void *param)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	int len = HCI_COMMAND_HDR_SIZE + plen;
2958c2ecf20Sopenharmony_ci	struct hci_command_hdr *hdr;
2968c2ecf20Sopenharmony_ci	struct sk_buff *skb;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	skb = bt_skb_alloc(len, GFP_ATOMIC);
2998c2ecf20Sopenharmony_ci	if (!skb)
3008c2ecf20Sopenharmony_ci		return NULL;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	hdr = skb_put(skb, HCI_COMMAND_HDR_SIZE);
3038c2ecf20Sopenharmony_ci	hdr->opcode = cpu_to_le16(opcode);
3048c2ecf20Sopenharmony_ci	hdr->plen   = plen;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	if (plen)
3078c2ecf20Sopenharmony_ci		skb_put_data(skb, param, plen);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	BT_DBG("skb len %d", skb->len);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
3128c2ecf20Sopenharmony_ci	hci_skb_opcode(skb) = opcode;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	return skb;
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci/* Queue a command to an asynchronous HCI request */
3188c2ecf20Sopenharmony_civoid hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen,
3198c2ecf20Sopenharmony_ci		    const void *param, u8 event)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
3228c2ecf20Sopenharmony_ci	struct sk_buff *skb;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	BT_DBG("%s opcode 0x%4.4x plen %d", hdev->name, opcode, plen);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	/* If an error occurred during request building, there is no point in
3278c2ecf20Sopenharmony_ci	 * queueing the HCI command. We can simply return.
3288c2ecf20Sopenharmony_ci	 */
3298c2ecf20Sopenharmony_ci	if (req->err)
3308c2ecf20Sopenharmony_ci		return;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	skb = hci_prepare_cmd(hdev, opcode, plen, param);
3338c2ecf20Sopenharmony_ci	if (!skb) {
3348c2ecf20Sopenharmony_ci		bt_dev_err(hdev, "no memory for command (opcode 0x%4.4x)",
3358c2ecf20Sopenharmony_ci			   opcode);
3368c2ecf20Sopenharmony_ci		req->err = -ENOMEM;
3378c2ecf20Sopenharmony_ci		return;
3388c2ecf20Sopenharmony_ci	}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	if (skb_queue_empty(&req->cmd_q))
3418c2ecf20Sopenharmony_ci		bt_cb(skb)->hci.req_flags |= HCI_REQ_START;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	bt_cb(skb)->hci.req_event = event;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	skb_queue_tail(&req->cmd_q, skb);
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_civoid hci_req_add(struct hci_request *req, u16 opcode, u32 plen,
3498c2ecf20Sopenharmony_ci		 const void *param)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	hci_req_add_ev(req, opcode, plen, param, 0);
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_civoid __hci_req_write_fast_connectable(struct hci_request *req, bool enable)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
3578c2ecf20Sopenharmony_ci	struct hci_cp_write_page_scan_activity acp;
3588c2ecf20Sopenharmony_ci	u8 type;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
3618c2ecf20Sopenharmony_ci		return;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	if (hdev->hci_ver < BLUETOOTH_VER_1_2)
3648c2ecf20Sopenharmony_ci		return;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	if (enable) {
3678c2ecf20Sopenharmony_ci		type = PAGE_SCAN_TYPE_INTERLACED;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci		/* 160 msec page scan interval */
3708c2ecf20Sopenharmony_ci		acp.interval = cpu_to_le16(0x0100);
3718c2ecf20Sopenharmony_ci	} else {
3728c2ecf20Sopenharmony_ci		type = hdev->def_page_scan_type;
3738c2ecf20Sopenharmony_ci		acp.interval = cpu_to_le16(hdev->def_page_scan_int);
3748c2ecf20Sopenharmony_ci	}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	acp.window = cpu_to_le16(hdev->def_page_scan_window);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
3798c2ecf20Sopenharmony_ci	    __cpu_to_le16(hdev->page_scan_window) != acp.window)
3808c2ecf20Sopenharmony_ci		hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
3818c2ecf20Sopenharmony_ci			    sizeof(acp), &acp);
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	if (hdev->page_scan_type != type)
3848c2ecf20Sopenharmony_ci		hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_cistatic void start_interleave_scan(struct hci_dev *hdev)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	hdev->interleave_scan_state = INTERLEAVE_SCAN_NO_FILTER;
3908c2ecf20Sopenharmony_ci	queue_delayed_work(hdev->req_workqueue,
3918c2ecf20Sopenharmony_ci			   &hdev->interleave_scan, 0);
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_cistatic bool is_interleave_scanning(struct hci_dev *hdev)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	return hdev->interleave_scan_state != INTERLEAVE_SCAN_NONE;
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic void cancel_interleave_scan(struct hci_dev *hdev)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	bt_dev_dbg(hdev, "cancelling interleave scan");
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&hdev->interleave_scan);
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	hdev->interleave_scan_state = INTERLEAVE_SCAN_NONE;
4068c2ecf20Sopenharmony_ci}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci/* Return true if interleave_scan wasn't started until exiting this function,
4098c2ecf20Sopenharmony_ci * otherwise, return false
4108c2ecf20Sopenharmony_ci */
4118c2ecf20Sopenharmony_cistatic bool __hci_update_interleaved_scan(struct hci_dev *hdev)
4128c2ecf20Sopenharmony_ci{
4138c2ecf20Sopenharmony_ci	/* If there is at least one ADV monitors and one pending LE connection
4148c2ecf20Sopenharmony_ci	 * or one device to be scanned for, we should alternate between
4158c2ecf20Sopenharmony_ci	 * allowlist scan and one without any filters to save power.
4168c2ecf20Sopenharmony_ci	 */
4178c2ecf20Sopenharmony_ci	bool use_interleaving = hci_is_adv_monitoring(hdev) &&
4188c2ecf20Sopenharmony_ci				!(list_empty(&hdev->pend_le_conns) &&
4198c2ecf20Sopenharmony_ci				  list_empty(&hdev->pend_le_reports));
4208c2ecf20Sopenharmony_ci	bool is_interleaving = is_interleave_scanning(hdev);
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	if (use_interleaving && !is_interleaving) {
4238c2ecf20Sopenharmony_ci		start_interleave_scan(hdev);
4248c2ecf20Sopenharmony_ci		bt_dev_dbg(hdev, "starting interleave scan");
4258c2ecf20Sopenharmony_ci		return true;
4268c2ecf20Sopenharmony_ci	}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	if (!use_interleaving && is_interleaving)
4298c2ecf20Sopenharmony_ci		cancel_interleave_scan(hdev);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	return false;
4328c2ecf20Sopenharmony_ci}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci/* This function controls the background scanning based on hdev->pend_le_conns
4358c2ecf20Sopenharmony_ci * list. If there are pending LE connection we start the background scanning,
4368c2ecf20Sopenharmony_ci * otherwise we stop it.
4378c2ecf20Sopenharmony_ci *
4388c2ecf20Sopenharmony_ci * This function requires the caller holds hdev->lock.
4398c2ecf20Sopenharmony_ci */
4408c2ecf20Sopenharmony_cistatic void __hci_update_background_scan(struct hci_request *req)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	if (!test_bit(HCI_UP, &hdev->flags) ||
4458c2ecf20Sopenharmony_ci	    test_bit(HCI_INIT, &hdev->flags) ||
4468c2ecf20Sopenharmony_ci	    hci_dev_test_flag(hdev, HCI_SETUP) ||
4478c2ecf20Sopenharmony_ci	    hci_dev_test_flag(hdev, HCI_CONFIG) ||
4488c2ecf20Sopenharmony_ci	    hci_dev_test_flag(hdev, HCI_AUTO_OFF) ||
4498c2ecf20Sopenharmony_ci	    hci_dev_test_flag(hdev, HCI_UNREGISTER))
4508c2ecf20Sopenharmony_ci		return;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	/* No point in doing scanning if LE support hasn't been enabled */
4538c2ecf20Sopenharmony_ci	if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
4548c2ecf20Sopenharmony_ci		return;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	/* If discovery is active don't interfere with it */
4578c2ecf20Sopenharmony_ci	if (hdev->discovery.state != DISCOVERY_STOPPED)
4588c2ecf20Sopenharmony_ci		return;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	/* Reset RSSI and UUID filters when starting background scanning
4618c2ecf20Sopenharmony_ci	 * since these filters are meant for service discovery only.
4628c2ecf20Sopenharmony_ci	 *
4638c2ecf20Sopenharmony_ci	 * The Start Discovery and Start Service Discovery operations
4648c2ecf20Sopenharmony_ci	 * ensure to set proper values for RSSI threshold and UUID
4658c2ecf20Sopenharmony_ci	 * filter list. So it is safe to just reset them here.
4668c2ecf20Sopenharmony_ci	 */
4678c2ecf20Sopenharmony_ci	hci_discovery_filter_clear(hdev);
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	BT_DBG("%s ADV monitoring is %s", hdev->name,
4708c2ecf20Sopenharmony_ci	       hci_is_adv_monitoring(hdev) ? "on" : "off");
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	if (list_empty(&hdev->pend_le_conns) &&
4738c2ecf20Sopenharmony_ci	    list_empty(&hdev->pend_le_reports) &&
4748c2ecf20Sopenharmony_ci	    !hci_is_adv_monitoring(hdev)) {
4758c2ecf20Sopenharmony_ci		/* If there is no pending LE connections or devices
4768c2ecf20Sopenharmony_ci		 * to be scanned for or no ADV monitors, we should stop the
4778c2ecf20Sopenharmony_ci		 * background scanning.
4788c2ecf20Sopenharmony_ci		 */
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci		/* If controller is not scanning we are done. */
4818c2ecf20Sopenharmony_ci		if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
4828c2ecf20Sopenharmony_ci			return;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci		hci_req_add_le_scan_disable(req, false);
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci		BT_DBG("%s stopping background scanning", hdev->name);
4878c2ecf20Sopenharmony_ci	} else {
4888c2ecf20Sopenharmony_ci		/* If there is at least one pending LE connection, we should
4898c2ecf20Sopenharmony_ci		 * keep the background scan running.
4908c2ecf20Sopenharmony_ci		 */
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci		/* If controller is connecting, we should not start scanning
4938c2ecf20Sopenharmony_ci		 * since some controllers are not able to scan and connect at
4948c2ecf20Sopenharmony_ci		 * the same time.
4958c2ecf20Sopenharmony_ci		 */
4968c2ecf20Sopenharmony_ci		if (hci_lookup_le_connect(hdev))
4978c2ecf20Sopenharmony_ci			return;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci		/* If controller is currently scanning, we stop it to ensure we
5008c2ecf20Sopenharmony_ci		 * don't miss any advertising (due to duplicates filter).
5018c2ecf20Sopenharmony_ci		 */
5028c2ecf20Sopenharmony_ci		if (hci_dev_test_flag(hdev, HCI_LE_SCAN))
5038c2ecf20Sopenharmony_ci			hci_req_add_le_scan_disable(req, false);
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci		hci_req_add_le_passive_scan(req);
5068c2ecf20Sopenharmony_ci		bt_dev_dbg(hdev, "starting background scanning");
5078c2ecf20Sopenharmony_ci	}
5088c2ecf20Sopenharmony_ci}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_civoid __hci_req_update_name(struct hci_request *req)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
5138c2ecf20Sopenharmony_ci	struct hci_cp_write_local_name cp;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
5188c2ecf20Sopenharmony_ci}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci#define PNP_INFO_SVCLASS_ID		0x1200
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_cistatic u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	u8 *ptr = data, *uuids_start = NULL;
5258c2ecf20Sopenharmony_ci	struct bt_uuid *uuid;
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	if (len < 4)
5288c2ecf20Sopenharmony_ci		return ptr;
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	list_for_each_entry(uuid, &hdev->uuids, list) {
5318c2ecf20Sopenharmony_ci		u16 uuid16;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci		if (uuid->size != 16)
5348c2ecf20Sopenharmony_ci			continue;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci		uuid16 = get_unaligned_le16(&uuid->uuid[12]);
5378c2ecf20Sopenharmony_ci		if (uuid16 < 0x1100)
5388c2ecf20Sopenharmony_ci			continue;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci		if (uuid16 == PNP_INFO_SVCLASS_ID)
5418c2ecf20Sopenharmony_ci			continue;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci		if (!uuids_start) {
5448c2ecf20Sopenharmony_ci			uuids_start = ptr;
5458c2ecf20Sopenharmony_ci			uuids_start[0] = 1;
5468c2ecf20Sopenharmony_ci			uuids_start[1] = EIR_UUID16_ALL;
5478c2ecf20Sopenharmony_ci			ptr += 2;
5488c2ecf20Sopenharmony_ci		}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci		/* Stop if not enough space to put next UUID */
5518c2ecf20Sopenharmony_ci		if ((ptr - data) + sizeof(u16) > len) {
5528c2ecf20Sopenharmony_ci			uuids_start[1] = EIR_UUID16_SOME;
5538c2ecf20Sopenharmony_ci			break;
5548c2ecf20Sopenharmony_ci		}
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci		*ptr++ = (uuid16 & 0x00ff);
5578c2ecf20Sopenharmony_ci		*ptr++ = (uuid16 & 0xff00) >> 8;
5588c2ecf20Sopenharmony_ci		uuids_start[0] += sizeof(uuid16);
5598c2ecf20Sopenharmony_ci	}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	return ptr;
5628c2ecf20Sopenharmony_ci}
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_cistatic u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
5658c2ecf20Sopenharmony_ci{
5668c2ecf20Sopenharmony_ci	u8 *ptr = data, *uuids_start = NULL;
5678c2ecf20Sopenharmony_ci	struct bt_uuid *uuid;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	if (len < 6)
5708c2ecf20Sopenharmony_ci		return ptr;
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	list_for_each_entry(uuid, &hdev->uuids, list) {
5738c2ecf20Sopenharmony_ci		if (uuid->size != 32)
5748c2ecf20Sopenharmony_ci			continue;
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci		if (!uuids_start) {
5778c2ecf20Sopenharmony_ci			uuids_start = ptr;
5788c2ecf20Sopenharmony_ci			uuids_start[0] = 1;
5798c2ecf20Sopenharmony_ci			uuids_start[1] = EIR_UUID32_ALL;
5808c2ecf20Sopenharmony_ci			ptr += 2;
5818c2ecf20Sopenharmony_ci		}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci		/* Stop if not enough space to put next UUID */
5848c2ecf20Sopenharmony_ci		if ((ptr - data) + sizeof(u32) > len) {
5858c2ecf20Sopenharmony_ci			uuids_start[1] = EIR_UUID32_SOME;
5868c2ecf20Sopenharmony_ci			break;
5878c2ecf20Sopenharmony_ci		}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci		memcpy(ptr, &uuid->uuid[12], sizeof(u32));
5908c2ecf20Sopenharmony_ci		ptr += sizeof(u32);
5918c2ecf20Sopenharmony_ci		uuids_start[0] += sizeof(u32);
5928c2ecf20Sopenharmony_ci	}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	return ptr;
5958c2ecf20Sopenharmony_ci}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_cistatic u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
5988c2ecf20Sopenharmony_ci{
5998c2ecf20Sopenharmony_ci	u8 *ptr = data, *uuids_start = NULL;
6008c2ecf20Sopenharmony_ci	struct bt_uuid *uuid;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	if (len < 18)
6038c2ecf20Sopenharmony_ci		return ptr;
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	list_for_each_entry(uuid, &hdev->uuids, list) {
6068c2ecf20Sopenharmony_ci		if (uuid->size != 128)
6078c2ecf20Sopenharmony_ci			continue;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci		if (!uuids_start) {
6108c2ecf20Sopenharmony_ci			uuids_start = ptr;
6118c2ecf20Sopenharmony_ci			uuids_start[0] = 1;
6128c2ecf20Sopenharmony_ci			uuids_start[1] = EIR_UUID128_ALL;
6138c2ecf20Sopenharmony_ci			ptr += 2;
6148c2ecf20Sopenharmony_ci		}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci		/* Stop if not enough space to put next UUID */
6178c2ecf20Sopenharmony_ci		if ((ptr - data) + 16 > len) {
6188c2ecf20Sopenharmony_ci			uuids_start[1] = EIR_UUID128_SOME;
6198c2ecf20Sopenharmony_ci			break;
6208c2ecf20Sopenharmony_ci		}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci		memcpy(ptr, uuid->uuid, 16);
6238c2ecf20Sopenharmony_ci		ptr += 16;
6248c2ecf20Sopenharmony_ci		uuids_start[0] += 16;
6258c2ecf20Sopenharmony_ci	}
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	return ptr;
6288c2ecf20Sopenharmony_ci}
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_cistatic void create_eir(struct hci_dev *hdev, u8 *data)
6318c2ecf20Sopenharmony_ci{
6328c2ecf20Sopenharmony_ci	u8 *ptr = data;
6338c2ecf20Sopenharmony_ci	size_t name_len;
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	name_len = strlen(hdev->dev_name);
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	if (name_len > 0) {
6388c2ecf20Sopenharmony_ci		/* EIR Data type */
6398c2ecf20Sopenharmony_ci		if (name_len > 48) {
6408c2ecf20Sopenharmony_ci			name_len = 48;
6418c2ecf20Sopenharmony_ci			ptr[1] = EIR_NAME_SHORT;
6428c2ecf20Sopenharmony_ci		} else
6438c2ecf20Sopenharmony_ci			ptr[1] = EIR_NAME_COMPLETE;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci		/* EIR Data length */
6468c2ecf20Sopenharmony_ci		ptr[0] = name_len + 1;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci		memcpy(ptr + 2, hdev->dev_name, name_len);
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci		ptr += (name_len + 2);
6518c2ecf20Sopenharmony_ci	}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
6548c2ecf20Sopenharmony_ci		ptr[0] = 2;
6558c2ecf20Sopenharmony_ci		ptr[1] = EIR_TX_POWER;
6568c2ecf20Sopenharmony_ci		ptr[2] = (u8) hdev->inq_tx_power;
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci		ptr += 3;
6598c2ecf20Sopenharmony_ci	}
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	if (hdev->devid_source > 0) {
6628c2ecf20Sopenharmony_ci		ptr[0] = 9;
6638c2ecf20Sopenharmony_ci		ptr[1] = EIR_DEVICE_ID;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci		put_unaligned_le16(hdev->devid_source, ptr + 2);
6668c2ecf20Sopenharmony_ci		put_unaligned_le16(hdev->devid_vendor, ptr + 4);
6678c2ecf20Sopenharmony_ci		put_unaligned_le16(hdev->devid_product, ptr + 6);
6688c2ecf20Sopenharmony_ci		put_unaligned_le16(hdev->devid_version, ptr + 8);
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci		ptr += 10;
6718c2ecf20Sopenharmony_ci	}
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
6748c2ecf20Sopenharmony_ci	ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
6758c2ecf20Sopenharmony_ci	ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
6768c2ecf20Sopenharmony_ci}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_civoid __hci_req_update_eir(struct hci_request *req)
6798c2ecf20Sopenharmony_ci{
6808c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
6818c2ecf20Sopenharmony_ci	struct hci_cp_write_eir cp;
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	if (!hdev_is_powered(hdev))
6848c2ecf20Sopenharmony_ci		return;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	if (!lmp_ext_inq_capable(hdev))
6878c2ecf20Sopenharmony_ci		return;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
6908c2ecf20Sopenharmony_ci		return;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
6938c2ecf20Sopenharmony_ci		return;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	memset(&cp, 0, sizeof(cp));
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	create_eir(hdev, cp.data);
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
7008c2ecf20Sopenharmony_ci		return;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	memcpy(hdev->eir, cp.data, sizeof(cp.data));
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
7058c2ecf20Sopenharmony_ci}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_civoid hci_req_add_le_scan_disable(struct hci_request *req, bool rpa_le_conn)
7088c2ecf20Sopenharmony_ci{
7098c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	if (hdev->scanning_paused) {
7128c2ecf20Sopenharmony_ci		bt_dev_dbg(hdev, "Scanning is paused for suspend");
7138c2ecf20Sopenharmony_ci		return;
7148c2ecf20Sopenharmony_ci	}
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci	if (use_ext_scan(hdev)) {
7178c2ecf20Sopenharmony_ci		struct hci_cp_le_set_ext_scan_enable cp;
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci		memset(&cp, 0, sizeof(cp));
7208c2ecf20Sopenharmony_ci		cp.enable = LE_SCAN_DISABLE;
7218c2ecf20Sopenharmony_ci		hci_req_add(req, HCI_OP_LE_SET_EXT_SCAN_ENABLE, sizeof(cp),
7228c2ecf20Sopenharmony_ci			    &cp);
7238c2ecf20Sopenharmony_ci	} else {
7248c2ecf20Sopenharmony_ci		struct hci_cp_le_set_scan_enable cp;
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci		memset(&cp, 0, sizeof(cp));
7278c2ecf20Sopenharmony_ci		cp.enable = LE_SCAN_DISABLE;
7288c2ecf20Sopenharmony_ci		hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
7298c2ecf20Sopenharmony_ci	}
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	/* Disable address resolution */
7328c2ecf20Sopenharmony_ci	if (use_ll_privacy(hdev) &&
7338c2ecf20Sopenharmony_ci	    hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY) &&
7348c2ecf20Sopenharmony_ci	    hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION) && !rpa_le_conn) {
7358c2ecf20Sopenharmony_ci		__u8 enable = 0x00;
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci		hci_req_add(req, HCI_OP_LE_SET_ADDR_RESOLV_ENABLE, 1, &enable);
7388c2ecf20Sopenharmony_ci	}
7398c2ecf20Sopenharmony_ci}
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_cistatic void del_from_accept_list(struct hci_request *req, bdaddr_t *bdaddr,
7428c2ecf20Sopenharmony_ci				 u8 bdaddr_type)
7438c2ecf20Sopenharmony_ci{
7448c2ecf20Sopenharmony_ci	struct hci_cp_le_del_from_accept_list cp;
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	cp.bdaddr_type = bdaddr_type;
7478c2ecf20Sopenharmony_ci	bacpy(&cp.bdaddr, bdaddr);
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	bt_dev_dbg(req->hdev, "Remove %pMR (0x%x) from accept list", &cp.bdaddr,
7508c2ecf20Sopenharmony_ci		   cp.bdaddr_type);
7518c2ecf20Sopenharmony_ci	hci_req_add(req, HCI_OP_LE_DEL_FROM_ACCEPT_LIST, sizeof(cp), &cp);
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	if (use_ll_privacy(req->hdev) &&
7548c2ecf20Sopenharmony_ci	    hci_dev_test_flag(req->hdev, HCI_ENABLE_LL_PRIVACY)) {
7558c2ecf20Sopenharmony_ci		struct smp_irk *irk;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci		irk = hci_find_irk_by_addr(req->hdev, bdaddr, bdaddr_type);
7588c2ecf20Sopenharmony_ci		if (irk) {
7598c2ecf20Sopenharmony_ci			struct hci_cp_le_del_from_resolv_list cp;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci			cp.bdaddr_type = bdaddr_type;
7628c2ecf20Sopenharmony_ci			bacpy(&cp.bdaddr, bdaddr);
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci			hci_req_add(req, HCI_OP_LE_DEL_FROM_RESOLV_LIST,
7658c2ecf20Sopenharmony_ci				    sizeof(cp), &cp);
7668c2ecf20Sopenharmony_ci		}
7678c2ecf20Sopenharmony_ci	}
7688c2ecf20Sopenharmony_ci}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci/* Adds connection to accept list if needed. On error, returns -1. */
7718c2ecf20Sopenharmony_cistatic int add_to_accept_list(struct hci_request *req,
7728c2ecf20Sopenharmony_ci			      struct hci_conn_params *params, u8 *num_entries,
7738c2ecf20Sopenharmony_ci			      bool allow_rpa)
7748c2ecf20Sopenharmony_ci{
7758c2ecf20Sopenharmony_ci	struct hci_cp_le_add_to_accept_list cp;
7768c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	/* Already in accept list */
7798c2ecf20Sopenharmony_ci	if (hci_bdaddr_list_lookup(&hdev->le_accept_list, &params->addr,
7808c2ecf20Sopenharmony_ci				   params->addr_type))
7818c2ecf20Sopenharmony_ci		return 0;
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	/* Select filter policy to accept all advertising */
7848c2ecf20Sopenharmony_ci	if (*num_entries >= hdev->le_accept_list_size)
7858c2ecf20Sopenharmony_ci		return -1;
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	/* Accept list can not be used with RPAs */
7888c2ecf20Sopenharmony_ci	if (!allow_rpa &&
7898c2ecf20Sopenharmony_ci	    !hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY) &&
7908c2ecf20Sopenharmony_ci	    hci_find_irk_by_addr(hdev, &params->addr, params->addr_type)) {
7918c2ecf20Sopenharmony_ci		return -1;
7928c2ecf20Sopenharmony_ci	}
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	/* During suspend, only wakeable devices can be in accept list */
7958c2ecf20Sopenharmony_ci	if (hdev->suspended && !hci_conn_test_flag(HCI_CONN_FLAG_REMOTE_WAKEUP,
7968c2ecf20Sopenharmony_ci						   params->current_flags))
7978c2ecf20Sopenharmony_ci		return 0;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	*num_entries += 1;
8008c2ecf20Sopenharmony_ci	cp.bdaddr_type = params->addr_type;
8018c2ecf20Sopenharmony_ci	bacpy(&cp.bdaddr, &params->addr);
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	bt_dev_dbg(hdev, "Add %pMR (0x%x) to accept list", &cp.bdaddr,
8048c2ecf20Sopenharmony_ci		   cp.bdaddr_type);
8058c2ecf20Sopenharmony_ci	hci_req_add(req, HCI_OP_LE_ADD_TO_ACCEPT_LIST, sizeof(cp), &cp);
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	if (use_ll_privacy(hdev) &&
8088c2ecf20Sopenharmony_ci	    hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY)) {
8098c2ecf20Sopenharmony_ci		struct smp_irk *irk;
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci		irk = hci_find_irk_by_addr(hdev, &params->addr,
8128c2ecf20Sopenharmony_ci					   params->addr_type);
8138c2ecf20Sopenharmony_ci		if (irk) {
8148c2ecf20Sopenharmony_ci			struct hci_cp_le_add_to_resolv_list cp;
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci			cp.bdaddr_type = params->addr_type;
8178c2ecf20Sopenharmony_ci			bacpy(&cp.bdaddr, &params->addr);
8188c2ecf20Sopenharmony_ci			memcpy(cp.peer_irk, irk->val, 16);
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci			if (hci_dev_test_flag(hdev, HCI_PRIVACY))
8218c2ecf20Sopenharmony_ci				memcpy(cp.local_irk, hdev->irk, 16);
8228c2ecf20Sopenharmony_ci			else
8238c2ecf20Sopenharmony_ci				memset(cp.local_irk, 0, 16);
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci			hci_req_add(req, HCI_OP_LE_ADD_TO_RESOLV_LIST,
8268c2ecf20Sopenharmony_ci				    sizeof(cp), &cp);
8278c2ecf20Sopenharmony_ci		}
8288c2ecf20Sopenharmony_ci	}
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	return 0;
8318c2ecf20Sopenharmony_ci}
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_cistatic u8 update_accept_list(struct hci_request *req)
8348c2ecf20Sopenharmony_ci{
8358c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
8368c2ecf20Sopenharmony_ci	struct hci_conn_params *params;
8378c2ecf20Sopenharmony_ci	struct bdaddr_list *b;
8388c2ecf20Sopenharmony_ci	u8 num_entries = 0;
8398c2ecf20Sopenharmony_ci	bool pend_conn, pend_report;
8408c2ecf20Sopenharmony_ci	/* We allow usage of accept list even with RPAs in suspend. In the worst
8418c2ecf20Sopenharmony_ci	 * case, we won't be able to wake from devices that use the privacy1.2
8428c2ecf20Sopenharmony_ci	 * features. Additionally, once we support privacy1.2 and IRK
8438c2ecf20Sopenharmony_ci	 * offloading, we can update this to also check for those conditions.
8448c2ecf20Sopenharmony_ci	 */
8458c2ecf20Sopenharmony_ci	bool allow_rpa = hdev->suspended;
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	if (use_ll_privacy(hdev) &&
8488c2ecf20Sopenharmony_ci	    hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
8498c2ecf20Sopenharmony_ci		allow_rpa = true;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	/* Go through the current accept list programmed into the
8528c2ecf20Sopenharmony_ci	 * controller one by one and check if that address is still
8538c2ecf20Sopenharmony_ci	 * in the list of pending connections or list of devices to
8548c2ecf20Sopenharmony_ci	 * report. If not present in either list, then queue the
8558c2ecf20Sopenharmony_ci	 * command to remove it from the controller.
8568c2ecf20Sopenharmony_ci	 */
8578c2ecf20Sopenharmony_ci	list_for_each_entry(b, &hdev->le_accept_list, list) {
8588c2ecf20Sopenharmony_ci		pend_conn = hci_pend_le_action_lookup(&hdev->pend_le_conns,
8598c2ecf20Sopenharmony_ci						      &b->bdaddr,
8608c2ecf20Sopenharmony_ci						      b->bdaddr_type);
8618c2ecf20Sopenharmony_ci		pend_report = hci_pend_le_action_lookup(&hdev->pend_le_reports,
8628c2ecf20Sopenharmony_ci							&b->bdaddr,
8638c2ecf20Sopenharmony_ci							b->bdaddr_type);
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci		/* If the device is not likely to connect or report,
8668c2ecf20Sopenharmony_ci		 * remove it from the accept list.
8678c2ecf20Sopenharmony_ci		 */
8688c2ecf20Sopenharmony_ci		if (!pend_conn && !pend_report) {
8698c2ecf20Sopenharmony_ci			del_from_accept_list(req, &b->bdaddr, b->bdaddr_type);
8708c2ecf20Sopenharmony_ci			continue;
8718c2ecf20Sopenharmony_ci		}
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci		/* Accept list can not be used with RPAs */
8748c2ecf20Sopenharmony_ci		if (!allow_rpa &&
8758c2ecf20Sopenharmony_ci		    !hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY) &&
8768c2ecf20Sopenharmony_ci		    hci_find_irk_by_addr(hdev, &b->bdaddr, b->bdaddr_type)) {
8778c2ecf20Sopenharmony_ci			return 0x00;
8788c2ecf20Sopenharmony_ci		}
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci		num_entries++;
8818c2ecf20Sopenharmony_ci	}
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	/* Since all no longer valid accept list entries have been
8848c2ecf20Sopenharmony_ci	 * removed, walk through the list of pending connections
8858c2ecf20Sopenharmony_ci	 * and ensure that any new device gets programmed into
8868c2ecf20Sopenharmony_ci	 * the controller.
8878c2ecf20Sopenharmony_ci	 *
8888c2ecf20Sopenharmony_ci	 * If the list of the devices is larger than the list of
8898c2ecf20Sopenharmony_ci	 * available accept list entries in the controller, then
8908c2ecf20Sopenharmony_ci	 * just abort and return filer policy value to not use the
8918c2ecf20Sopenharmony_ci	 * accept list.
8928c2ecf20Sopenharmony_ci	 */
8938c2ecf20Sopenharmony_ci	list_for_each_entry(params, &hdev->pend_le_conns, action) {
8948c2ecf20Sopenharmony_ci		if (add_to_accept_list(req, params, &num_entries, allow_rpa))
8958c2ecf20Sopenharmony_ci			return 0x00;
8968c2ecf20Sopenharmony_ci	}
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	/* After adding all new pending connections, walk through
8998c2ecf20Sopenharmony_ci	 * the list of pending reports and also add these to the
9008c2ecf20Sopenharmony_ci	 * accept list if there is still space. Abort if space runs out.
9018c2ecf20Sopenharmony_ci	 */
9028c2ecf20Sopenharmony_ci	list_for_each_entry(params, &hdev->pend_le_reports, action) {
9038c2ecf20Sopenharmony_ci		if (add_to_accept_list(req, params, &num_entries, allow_rpa))
9048c2ecf20Sopenharmony_ci			return 0x00;
9058c2ecf20Sopenharmony_ci	}
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	/* Use the allowlist unless the following conditions are all true:
9088c2ecf20Sopenharmony_ci	 * - We are not currently suspending
9098c2ecf20Sopenharmony_ci	 * - There are 1 or more ADV monitors registered
9108c2ecf20Sopenharmony_ci	 * - Interleaved scanning is not currently using the allowlist
9118c2ecf20Sopenharmony_ci	 *
9128c2ecf20Sopenharmony_ci	 * Once the controller offloading of advertisement monitor is in place,
9138c2ecf20Sopenharmony_ci	 * the above condition should include the support of MSFT extension
9148c2ecf20Sopenharmony_ci	 * support.
9158c2ecf20Sopenharmony_ci	 */
9168c2ecf20Sopenharmony_ci	if (!idr_is_empty(&hdev->adv_monitors_idr) && !hdev->suspended &&
9178c2ecf20Sopenharmony_ci	    hdev->interleave_scan_state != INTERLEAVE_SCAN_ALLOWLIST)
9188c2ecf20Sopenharmony_ci		return 0x00;
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	/* Select filter policy to use accept list */
9218c2ecf20Sopenharmony_ci	return 0x01;
9228c2ecf20Sopenharmony_ci}
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_cistatic bool scan_use_rpa(struct hci_dev *hdev)
9258c2ecf20Sopenharmony_ci{
9268c2ecf20Sopenharmony_ci	return hci_dev_test_flag(hdev, HCI_PRIVACY);
9278c2ecf20Sopenharmony_ci}
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_cistatic void hci_req_start_scan(struct hci_request *req, u8 type, u16 interval,
9308c2ecf20Sopenharmony_ci			       u16 window, u8 own_addr_type, u8 filter_policy,
9318c2ecf20Sopenharmony_ci			       bool addr_resolv)
9328c2ecf20Sopenharmony_ci{
9338c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	if (hdev->scanning_paused) {
9368c2ecf20Sopenharmony_ci		bt_dev_dbg(hdev, "Scanning is paused for suspend");
9378c2ecf20Sopenharmony_ci		return;
9388c2ecf20Sopenharmony_ci	}
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	if (use_ll_privacy(hdev) &&
9418c2ecf20Sopenharmony_ci	    hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY) &&
9428c2ecf20Sopenharmony_ci	    addr_resolv) {
9438c2ecf20Sopenharmony_ci		u8 enable = 0x01;
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci		hci_req_add(req, HCI_OP_LE_SET_ADDR_RESOLV_ENABLE, 1, &enable);
9468c2ecf20Sopenharmony_ci	}
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	/* Use ext scanning if set ext scan param and ext scan enable is
9498c2ecf20Sopenharmony_ci	 * supported
9508c2ecf20Sopenharmony_ci	 */
9518c2ecf20Sopenharmony_ci	if (use_ext_scan(hdev)) {
9528c2ecf20Sopenharmony_ci		struct hci_cp_le_set_ext_scan_params *ext_param_cp;
9538c2ecf20Sopenharmony_ci		struct hci_cp_le_set_ext_scan_enable ext_enable_cp;
9548c2ecf20Sopenharmony_ci		struct hci_cp_le_scan_phy_params *phy_params;
9558c2ecf20Sopenharmony_ci		u8 data[sizeof(*ext_param_cp) + sizeof(*phy_params) * 2];
9568c2ecf20Sopenharmony_ci		u32 plen;
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci		ext_param_cp = (void *)data;
9598c2ecf20Sopenharmony_ci		phy_params = (void *)ext_param_cp->data;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci		memset(ext_param_cp, 0, sizeof(*ext_param_cp));
9628c2ecf20Sopenharmony_ci		ext_param_cp->own_addr_type = own_addr_type;
9638c2ecf20Sopenharmony_ci		ext_param_cp->filter_policy = filter_policy;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci		plen = sizeof(*ext_param_cp);
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci		if (scan_1m(hdev) || scan_2m(hdev)) {
9688c2ecf20Sopenharmony_ci			ext_param_cp->scanning_phys |= LE_SCAN_PHY_1M;
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci			memset(phy_params, 0, sizeof(*phy_params));
9718c2ecf20Sopenharmony_ci			phy_params->type = type;
9728c2ecf20Sopenharmony_ci			phy_params->interval = cpu_to_le16(interval);
9738c2ecf20Sopenharmony_ci			phy_params->window = cpu_to_le16(window);
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci			plen += sizeof(*phy_params);
9768c2ecf20Sopenharmony_ci			phy_params++;
9778c2ecf20Sopenharmony_ci		}
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci		if (scan_coded(hdev)) {
9808c2ecf20Sopenharmony_ci			ext_param_cp->scanning_phys |= LE_SCAN_PHY_CODED;
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci			memset(phy_params, 0, sizeof(*phy_params));
9838c2ecf20Sopenharmony_ci			phy_params->type = type;
9848c2ecf20Sopenharmony_ci			phy_params->interval = cpu_to_le16(interval);
9858c2ecf20Sopenharmony_ci			phy_params->window = cpu_to_le16(window);
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci			plen += sizeof(*phy_params);
9888c2ecf20Sopenharmony_ci			phy_params++;
9898c2ecf20Sopenharmony_ci		}
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci		hci_req_add(req, HCI_OP_LE_SET_EXT_SCAN_PARAMS,
9928c2ecf20Sopenharmony_ci			    plen, ext_param_cp);
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci		memset(&ext_enable_cp, 0, sizeof(ext_enable_cp));
9958c2ecf20Sopenharmony_ci		ext_enable_cp.enable = LE_SCAN_ENABLE;
9968c2ecf20Sopenharmony_ci		ext_enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci		hci_req_add(req, HCI_OP_LE_SET_EXT_SCAN_ENABLE,
9998c2ecf20Sopenharmony_ci			    sizeof(ext_enable_cp), &ext_enable_cp);
10008c2ecf20Sopenharmony_ci	} else {
10018c2ecf20Sopenharmony_ci		struct hci_cp_le_set_scan_param param_cp;
10028c2ecf20Sopenharmony_ci		struct hci_cp_le_set_scan_enable enable_cp;
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci		memset(&param_cp, 0, sizeof(param_cp));
10058c2ecf20Sopenharmony_ci		param_cp.type = type;
10068c2ecf20Sopenharmony_ci		param_cp.interval = cpu_to_le16(interval);
10078c2ecf20Sopenharmony_ci		param_cp.window = cpu_to_le16(window);
10088c2ecf20Sopenharmony_ci		param_cp.own_address_type = own_addr_type;
10098c2ecf20Sopenharmony_ci		param_cp.filter_policy = filter_policy;
10108c2ecf20Sopenharmony_ci		hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
10118c2ecf20Sopenharmony_ci			    &param_cp);
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci		memset(&enable_cp, 0, sizeof(enable_cp));
10148c2ecf20Sopenharmony_ci		enable_cp.enable = LE_SCAN_ENABLE;
10158c2ecf20Sopenharmony_ci		enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
10168c2ecf20Sopenharmony_ci		hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
10178c2ecf20Sopenharmony_ci			    &enable_cp);
10188c2ecf20Sopenharmony_ci	}
10198c2ecf20Sopenharmony_ci}
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci/* Returns true if an le connection is in the scanning state */
10228c2ecf20Sopenharmony_cistatic inline bool hci_is_le_conn_scanning(struct hci_dev *hdev)
10238c2ecf20Sopenharmony_ci{
10248c2ecf20Sopenharmony_ci	struct hci_conn_hash *h = &hdev->conn_hash;
10258c2ecf20Sopenharmony_ci	struct hci_conn  *c;
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	rcu_read_lock();
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(c, &h->list, list) {
10308c2ecf20Sopenharmony_ci		if (c->type == LE_LINK && c->state == BT_CONNECT &&
10318c2ecf20Sopenharmony_ci		    test_bit(HCI_CONN_SCANNING, &c->flags)) {
10328c2ecf20Sopenharmony_ci			rcu_read_unlock();
10338c2ecf20Sopenharmony_ci			return true;
10348c2ecf20Sopenharmony_ci		}
10358c2ecf20Sopenharmony_ci	}
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci	rcu_read_unlock();
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	return false;
10408c2ecf20Sopenharmony_ci}
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci/* Ensure to call hci_req_add_le_scan_disable() first to disable the
10438c2ecf20Sopenharmony_ci * controller based address resolution to be able to reconfigure
10448c2ecf20Sopenharmony_ci * resolving list.
10458c2ecf20Sopenharmony_ci */
10468c2ecf20Sopenharmony_civoid hci_req_add_le_passive_scan(struct hci_request *req)
10478c2ecf20Sopenharmony_ci{
10488c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
10498c2ecf20Sopenharmony_ci	u8 own_addr_type;
10508c2ecf20Sopenharmony_ci	u8 filter_policy;
10518c2ecf20Sopenharmony_ci	u16 window, interval;
10528c2ecf20Sopenharmony_ci	/* Background scanning should run with address resolution */
10538c2ecf20Sopenharmony_ci	bool addr_resolv = true;
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	if (hdev->scanning_paused) {
10568c2ecf20Sopenharmony_ci		bt_dev_dbg(hdev, "Scanning is paused for suspend");
10578c2ecf20Sopenharmony_ci		return;
10588c2ecf20Sopenharmony_ci	}
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci	/* Set require_privacy to false since no SCAN_REQ are send
10618c2ecf20Sopenharmony_ci	 * during passive scanning. Not using an non-resolvable address
10628c2ecf20Sopenharmony_ci	 * here is important so that peer devices using direct
10638c2ecf20Sopenharmony_ci	 * advertising with our address will be correctly reported
10648c2ecf20Sopenharmony_ci	 * by the controller.
10658c2ecf20Sopenharmony_ci	 */
10668c2ecf20Sopenharmony_ci	if (hci_update_random_address(req, false, scan_use_rpa(hdev),
10678c2ecf20Sopenharmony_ci				      &own_addr_type))
10688c2ecf20Sopenharmony_ci		return;
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	if (__hci_update_interleaved_scan(hdev))
10718c2ecf20Sopenharmony_ci		return;
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	bt_dev_dbg(hdev, "interleave state %d", hdev->interleave_scan_state);
10748c2ecf20Sopenharmony_ci	/* Adding or removing entries from the accept list must
10758c2ecf20Sopenharmony_ci	 * happen before enabling scanning. The controller does
10768c2ecf20Sopenharmony_ci	 * not allow accept list modification while scanning.
10778c2ecf20Sopenharmony_ci	 */
10788c2ecf20Sopenharmony_ci	filter_policy = update_accept_list(req);
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	/* When the controller is using random resolvable addresses and
10818c2ecf20Sopenharmony_ci	 * with that having LE privacy enabled, then controllers with
10828c2ecf20Sopenharmony_ci	 * Extended Scanner Filter Policies support can now enable support
10838c2ecf20Sopenharmony_ci	 * for handling directed advertising.
10848c2ecf20Sopenharmony_ci	 *
10858c2ecf20Sopenharmony_ci	 * So instead of using filter polices 0x00 (no accept list)
10868c2ecf20Sopenharmony_ci	 * and 0x01 (accept list enabled) use the new filter policies
10878c2ecf20Sopenharmony_ci	 * 0x02 (no accept list) and 0x03 (accept list enabled).
10888c2ecf20Sopenharmony_ci	 */
10898c2ecf20Sopenharmony_ci	if (hci_dev_test_flag(hdev, HCI_PRIVACY) &&
10908c2ecf20Sopenharmony_ci	    (hdev->le_features[0] & HCI_LE_EXT_SCAN_POLICY))
10918c2ecf20Sopenharmony_ci		filter_policy |= 0x02;
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	if (hdev->suspended) {
10948c2ecf20Sopenharmony_ci		window = hdev->le_scan_window_suspend;
10958c2ecf20Sopenharmony_ci		interval = hdev->le_scan_int_suspend;
10968c2ecf20Sopenharmony_ci	} else if (hci_is_le_conn_scanning(hdev)) {
10978c2ecf20Sopenharmony_ci		window = hdev->le_scan_window_connect;
10988c2ecf20Sopenharmony_ci		interval = hdev->le_scan_int_connect;
10998c2ecf20Sopenharmony_ci	} else if (hci_is_adv_monitoring(hdev)) {
11008c2ecf20Sopenharmony_ci		window = hdev->le_scan_window_adv_monitor;
11018c2ecf20Sopenharmony_ci		interval = hdev->le_scan_int_adv_monitor;
11028c2ecf20Sopenharmony_ci	} else {
11038c2ecf20Sopenharmony_ci		window = hdev->le_scan_window;
11048c2ecf20Sopenharmony_ci		interval = hdev->le_scan_interval;
11058c2ecf20Sopenharmony_ci	}
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	bt_dev_dbg(hdev, "LE passive scan with accept list = %d",
11088c2ecf20Sopenharmony_ci		   filter_policy);
11098c2ecf20Sopenharmony_ci	hci_req_start_scan(req, LE_SCAN_PASSIVE, interval, window,
11108c2ecf20Sopenharmony_ci			   own_addr_type, filter_policy, addr_resolv);
11118c2ecf20Sopenharmony_ci}
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_cistatic u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance)
11148c2ecf20Sopenharmony_ci{
11158c2ecf20Sopenharmony_ci	struct adv_info *adv_instance;
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	/* Instance 0x00 always set local name */
11188c2ecf20Sopenharmony_ci	if (instance == 0x00)
11198c2ecf20Sopenharmony_ci		return 1;
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	adv_instance = hci_find_adv_instance(hdev, instance);
11228c2ecf20Sopenharmony_ci	if (!adv_instance)
11238c2ecf20Sopenharmony_ci		return 0;
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	if (adv_instance->flags & MGMT_ADV_FLAG_APPEARANCE ||
11268c2ecf20Sopenharmony_ci	    adv_instance->flags & MGMT_ADV_FLAG_LOCAL_NAME)
11278c2ecf20Sopenharmony_ci		return 1;
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	return adv_instance->scan_rsp_len;
11308c2ecf20Sopenharmony_ci}
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_cistatic void hci_req_clear_event_filter(struct hci_request *req)
11338c2ecf20Sopenharmony_ci{
11348c2ecf20Sopenharmony_ci	struct hci_cp_set_event_filter f;
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci	memset(&f, 0, sizeof(f));
11378c2ecf20Sopenharmony_ci	f.flt_type = HCI_FLT_CLEAR_ALL;
11388c2ecf20Sopenharmony_ci	hci_req_add(req, HCI_OP_SET_EVENT_FLT, 1, &f);
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci	/* Update page scan state (since we may have modified it when setting
11418c2ecf20Sopenharmony_ci	 * the event filter).
11428c2ecf20Sopenharmony_ci	 */
11438c2ecf20Sopenharmony_ci	__hci_req_update_scan(req);
11448c2ecf20Sopenharmony_ci}
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_cistatic void hci_req_set_event_filter(struct hci_request *req)
11478c2ecf20Sopenharmony_ci{
11488c2ecf20Sopenharmony_ci	struct bdaddr_list_with_flags *b;
11498c2ecf20Sopenharmony_ci	struct hci_cp_set_event_filter f;
11508c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
11518c2ecf20Sopenharmony_ci	u8 scan = SCAN_DISABLED;
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci	/* Always clear event filter when starting */
11548c2ecf20Sopenharmony_ci	hci_req_clear_event_filter(req);
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci	list_for_each_entry(b, &hdev->accept_list, list) {
11578c2ecf20Sopenharmony_ci		if (!hci_conn_test_flag(HCI_CONN_FLAG_REMOTE_WAKEUP,
11588c2ecf20Sopenharmony_ci					b->current_flags))
11598c2ecf20Sopenharmony_ci			continue;
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci		memset(&f, 0, sizeof(f));
11628c2ecf20Sopenharmony_ci		bacpy(&f.addr_conn_flt.bdaddr, &b->bdaddr);
11638c2ecf20Sopenharmony_ci		f.flt_type = HCI_FLT_CONN_SETUP;
11648c2ecf20Sopenharmony_ci		f.cond_type = HCI_CONN_SETUP_ALLOW_BDADDR;
11658c2ecf20Sopenharmony_ci		f.addr_conn_flt.auto_accept = HCI_CONN_SETUP_AUTO_ON;
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci		bt_dev_dbg(hdev, "Adding event filters for %pMR", &b->bdaddr);
11688c2ecf20Sopenharmony_ci		hci_req_add(req, HCI_OP_SET_EVENT_FLT, sizeof(f), &f);
11698c2ecf20Sopenharmony_ci		scan = SCAN_PAGE;
11708c2ecf20Sopenharmony_ci	}
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci	hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
11738c2ecf20Sopenharmony_ci}
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_cistatic void hci_req_config_le_suspend_scan(struct hci_request *req)
11768c2ecf20Sopenharmony_ci{
11778c2ecf20Sopenharmony_ci	/* Before changing params disable scan if enabled */
11788c2ecf20Sopenharmony_ci	if (hci_dev_test_flag(req->hdev, HCI_LE_SCAN))
11798c2ecf20Sopenharmony_ci		hci_req_add_le_scan_disable(req, false);
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	/* Configure params and enable scanning */
11828c2ecf20Sopenharmony_ci	hci_req_add_le_passive_scan(req);
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	/* Block suspend notifier on response */
11858c2ecf20Sopenharmony_ci	set_bit(SUSPEND_SCAN_ENABLE, req->hdev->suspend_tasks);
11868c2ecf20Sopenharmony_ci}
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_cistatic void cancel_adv_timeout(struct hci_dev *hdev)
11898c2ecf20Sopenharmony_ci{
11908c2ecf20Sopenharmony_ci	if (hdev->adv_instance_timeout) {
11918c2ecf20Sopenharmony_ci		hdev->adv_instance_timeout = 0;
11928c2ecf20Sopenharmony_ci		cancel_delayed_work(&hdev->adv_instance_expire);
11938c2ecf20Sopenharmony_ci	}
11948c2ecf20Sopenharmony_ci}
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci/* This function requires the caller holds hdev->lock */
11978c2ecf20Sopenharmony_cistatic void hci_suspend_adv_instances(struct hci_request *req)
11988c2ecf20Sopenharmony_ci{
11998c2ecf20Sopenharmony_ci	bt_dev_dbg(req->hdev, "Suspending advertising instances");
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci	/* Call to disable any advertisements active on the controller.
12028c2ecf20Sopenharmony_ci	 * This will succeed even if no advertisements are configured.
12038c2ecf20Sopenharmony_ci	 */
12048c2ecf20Sopenharmony_ci	__hci_req_disable_advertising(req);
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	/* If we are using software rotation, pause the loop */
12078c2ecf20Sopenharmony_ci	if (!ext_adv_capable(req->hdev))
12088c2ecf20Sopenharmony_ci		cancel_adv_timeout(req->hdev);
12098c2ecf20Sopenharmony_ci}
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci/* This function requires the caller holds hdev->lock */
12128c2ecf20Sopenharmony_cistatic void hci_resume_adv_instances(struct hci_request *req)
12138c2ecf20Sopenharmony_ci{
12148c2ecf20Sopenharmony_ci	struct adv_info *adv;
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	bt_dev_dbg(req->hdev, "Resuming advertising instances");
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	if (ext_adv_capable(req->hdev)) {
12198c2ecf20Sopenharmony_ci		/* Call for each tracked instance to be re-enabled */
12208c2ecf20Sopenharmony_ci		list_for_each_entry(adv, &req->hdev->adv_instances, list) {
12218c2ecf20Sopenharmony_ci			__hci_req_enable_ext_advertising(req,
12228c2ecf20Sopenharmony_ci							 adv->instance);
12238c2ecf20Sopenharmony_ci		}
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	} else {
12268c2ecf20Sopenharmony_ci		/* Schedule for most recent instance to be restarted and begin
12278c2ecf20Sopenharmony_ci		 * the software rotation loop
12288c2ecf20Sopenharmony_ci		 */
12298c2ecf20Sopenharmony_ci		__hci_req_schedule_adv_instance(req,
12308c2ecf20Sopenharmony_ci						req->hdev->cur_adv_instance,
12318c2ecf20Sopenharmony_ci						true);
12328c2ecf20Sopenharmony_ci	}
12338c2ecf20Sopenharmony_ci}
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_cistatic void suspend_req_complete(struct hci_dev *hdev, u8 status, u16 opcode)
12368c2ecf20Sopenharmony_ci{
12378c2ecf20Sopenharmony_ci	bt_dev_dbg(hdev, "Request complete opcode=0x%x, status=0x%x", opcode,
12388c2ecf20Sopenharmony_ci		   status);
12398c2ecf20Sopenharmony_ci	if (test_and_clear_bit(SUSPEND_SCAN_ENABLE, hdev->suspend_tasks) ||
12408c2ecf20Sopenharmony_ci	    test_and_clear_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks)) {
12418c2ecf20Sopenharmony_ci		wake_up(&hdev->suspend_wait_q);
12428c2ecf20Sopenharmony_ci	}
12438c2ecf20Sopenharmony_ci}
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci/* Call with hci_dev_lock */
12468c2ecf20Sopenharmony_civoid hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next)
12478c2ecf20Sopenharmony_ci{
12488c2ecf20Sopenharmony_ci	int old_state;
12498c2ecf20Sopenharmony_ci	struct hci_conn *conn;
12508c2ecf20Sopenharmony_ci	struct hci_request req;
12518c2ecf20Sopenharmony_ci	u8 page_scan;
12528c2ecf20Sopenharmony_ci	int disconnect_counter;
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	if (next == hdev->suspend_state) {
12558c2ecf20Sopenharmony_ci		bt_dev_dbg(hdev, "Same state before and after: %d", next);
12568c2ecf20Sopenharmony_ci		goto done;
12578c2ecf20Sopenharmony_ci	}
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	hdev->suspend_state = next;
12608c2ecf20Sopenharmony_ci	hci_req_init(&req, hdev);
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci	if (next == BT_SUSPEND_DISCONNECT) {
12638c2ecf20Sopenharmony_ci		/* Mark device as suspended */
12648c2ecf20Sopenharmony_ci		hdev->suspended = true;
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci		/* Pause discovery if not already stopped */
12678c2ecf20Sopenharmony_ci		old_state = hdev->discovery.state;
12688c2ecf20Sopenharmony_ci		if (old_state != DISCOVERY_STOPPED) {
12698c2ecf20Sopenharmony_ci			set_bit(SUSPEND_PAUSE_DISCOVERY, hdev->suspend_tasks);
12708c2ecf20Sopenharmony_ci			hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
12718c2ecf20Sopenharmony_ci			queue_work(hdev->req_workqueue, &hdev->discov_update);
12728c2ecf20Sopenharmony_ci		}
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci		hdev->discovery_paused = true;
12758c2ecf20Sopenharmony_ci		hdev->discovery_old_state = old_state;
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci		/* Stop directed advertising */
12788c2ecf20Sopenharmony_ci		old_state = hci_dev_test_flag(hdev, HCI_ADVERTISING);
12798c2ecf20Sopenharmony_ci		if (old_state) {
12808c2ecf20Sopenharmony_ci			set_bit(SUSPEND_PAUSE_ADVERTISING, hdev->suspend_tasks);
12818c2ecf20Sopenharmony_ci			cancel_delayed_work(&hdev->discov_off);
12828c2ecf20Sopenharmony_ci			queue_delayed_work(hdev->req_workqueue,
12838c2ecf20Sopenharmony_ci					   &hdev->discov_off, 0);
12848c2ecf20Sopenharmony_ci		}
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci		/* Pause other advertisements */
12878c2ecf20Sopenharmony_ci		if (hdev->adv_instance_cnt)
12888c2ecf20Sopenharmony_ci			hci_suspend_adv_instances(&req);
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci		hdev->advertising_paused = true;
12918c2ecf20Sopenharmony_ci		hdev->advertising_old_state = old_state;
12928c2ecf20Sopenharmony_ci		/* Disable page scan */
12938c2ecf20Sopenharmony_ci		page_scan = SCAN_DISABLED;
12948c2ecf20Sopenharmony_ci		hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &page_scan);
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci		/* Disable LE passive scan if enabled */
12978c2ecf20Sopenharmony_ci		if (hci_dev_test_flag(hdev, HCI_LE_SCAN))
12988c2ecf20Sopenharmony_ci			hci_req_add_le_scan_disable(&req, false);
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci		/* Mark task needing completion */
13018c2ecf20Sopenharmony_ci		set_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks);
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci		/* Prevent disconnects from causing scanning to be re-enabled */
13048c2ecf20Sopenharmony_ci		hdev->scanning_paused = true;
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci		/* Run commands before disconnecting */
13078c2ecf20Sopenharmony_ci		hci_req_run(&req, suspend_req_complete);
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci		disconnect_counter = 0;
13108c2ecf20Sopenharmony_ci		/* Soft disconnect everything (power off) */
13118c2ecf20Sopenharmony_ci		list_for_each_entry(conn, &hdev->conn_hash.list, list) {
13128c2ecf20Sopenharmony_ci			hci_disconnect(conn, HCI_ERROR_REMOTE_POWER_OFF);
13138c2ecf20Sopenharmony_ci			disconnect_counter++;
13148c2ecf20Sopenharmony_ci		}
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci		if (disconnect_counter > 0) {
13178c2ecf20Sopenharmony_ci			bt_dev_dbg(hdev,
13188c2ecf20Sopenharmony_ci				   "Had %d disconnects. Will wait on them",
13198c2ecf20Sopenharmony_ci				   disconnect_counter);
13208c2ecf20Sopenharmony_ci			set_bit(SUSPEND_DISCONNECTING, hdev->suspend_tasks);
13218c2ecf20Sopenharmony_ci		}
13228c2ecf20Sopenharmony_ci	} else if (next == BT_SUSPEND_CONFIGURE_WAKE) {
13238c2ecf20Sopenharmony_ci		/* Unpause to take care of updating scanning params */
13248c2ecf20Sopenharmony_ci		hdev->scanning_paused = false;
13258c2ecf20Sopenharmony_ci		/* Enable event filter for paired devices */
13268c2ecf20Sopenharmony_ci		hci_req_set_event_filter(&req);
13278c2ecf20Sopenharmony_ci		/* Enable passive scan at lower duty cycle */
13288c2ecf20Sopenharmony_ci		hci_req_config_le_suspend_scan(&req);
13298c2ecf20Sopenharmony_ci		/* Pause scan changes again. */
13308c2ecf20Sopenharmony_ci		hdev->scanning_paused = true;
13318c2ecf20Sopenharmony_ci		hci_req_run(&req, suspend_req_complete);
13328c2ecf20Sopenharmony_ci	} else {
13338c2ecf20Sopenharmony_ci		hdev->suspended = false;
13348c2ecf20Sopenharmony_ci		hdev->scanning_paused = false;
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci		hci_req_clear_event_filter(&req);
13378c2ecf20Sopenharmony_ci		/* Reset passive/background scanning to normal */
13388c2ecf20Sopenharmony_ci		hci_req_config_le_suspend_scan(&req);
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci		/* Unpause directed advertising */
13418c2ecf20Sopenharmony_ci		hdev->advertising_paused = false;
13428c2ecf20Sopenharmony_ci		if (hdev->advertising_old_state) {
13438c2ecf20Sopenharmony_ci			set_bit(SUSPEND_UNPAUSE_ADVERTISING,
13448c2ecf20Sopenharmony_ci				hdev->suspend_tasks);
13458c2ecf20Sopenharmony_ci			hci_dev_set_flag(hdev, HCI_ADVERTISING);
13468c2ecf20Sopenharmony_ci			queue_work(hdev->req_workqueue,
13478c2ecf20Sopenharmony_ci				   &hdev->discoverable_update);
13488c2ecf20Sopenharmony_ci			hdev->advertising_old_state = 0;
13498c2ecf20Sopenharmony_ci		}
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci		/* Resume other advertisements */
13528c2ecf20Sopenharmony_ci		if (hdev->adv_instance_cnt)
13538c2ecf20Sopenharmony_ci			hci_resume_adv_instances(&req);
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci		/* Unpause discovery */
13568c2ecf20Sopenharmony_ci		hdev->discovery_paused = false;
13578c2ecf20Sopenharmony_ci		if (hdev->discovery_old_state != DISCOVERY_STOPPED &&
13588c2ecf20Sopenharmony_ci		    hdev->discovery_old_state != DISCOVERY_STOPPING) {
13598c2ecf20Sopenharmony_ci			set_bit(SUSPEND_UNPAUSE_DISCOVERY, hdev->suspend_tasks);
13608c2ecf20Sopenharmony_ci			hci_discovery_set_state(hdev, DISCOVERY_STARTING);
13618c2ecf20Sopenharmony_ci			queue_work(hdev->req_workqueue, &hdev->discov_update);
13628c2ecf20Sopenharmony_ci		}
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci		hci_req_run(&req, suspend_req_complete);
13658c2ecf20Sopenharmony_ci	}
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	hdev->suspend_state = next;
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_cidone:
13708c2ecf20Sopenharmony_ci	clear_bit(SUSPEND_PREPARE_NOTIFIER, hdev->suspend_tasks);
13718c2ecf20Sopenharmony_ci	wake_up(&hdev->suspend_wait_q);
13728c2ecf20Sopenharmony_ci}
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_cistatic u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev)
13758c2ecf20Sopenharmony_ci{
13768c2ecf20Sopenharmony_ci	u8 instance = hdev->cur_adv_instance;
13778c2ecf20Sopenharmony_ci	struct adv_info *adv_instance;
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci	/* Instance 0x00 always set local name */
13808c2ecf20Sopenharmony_ci	if (instance == 0x00)
13818c2ecf20Sopenharmony_ci		return 1;
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	adv_instance = hci_find_adv_instance(hdev, instance);
13848c2ecf20Sopenharmony_ci	if (!adv_instance)
13858c2ecf20Sopenharmony_ci		return 0;
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_ci	/* TODO: Take into account the "appearance" and "local-name" flags here.
13888c2ecf20Sopenharmony_ci	 * These are currently being ignored as they are not supported.
13898c2ecf20Sopenharmony_ci	 */
13908c2ecf20Sopenharmony_ci	return adv_instance->scan_rsp_len;
13918c2ecf20Sopenharmony_ci}
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_civoid __hci_req_disable_advertising(struct hci_request *req)
13948c2ecf20Sopenharmony_ci{
13958c2ecf20Sopenharmony_ci	if (ext_adv_capable(req->hdev)) {
13968c2ecf20Sopenharmony_ci		__hci_req_disable_ext_adv_instance(req, 0x00);
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	} else {
13998c2ecf20Sopenharmony_ci		u8 enable = 0x00;
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci		hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
14028c2ecf20Sopenharmony_ci	}
14038c2ecf20Sopenharmony_ci}
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_cistatic u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
14068c2ecf20Sopenharmony_ci{
14078c2ecf20Sopenharmony_ci	u32 flags;
14088c2ecf20Sopenharmony_ci	struct adv_info *adv_instance;
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	if (instance == 0x00) {
14118c2ecf20Sopenharmony_ci		/* Instance 0 always manages the "Tx Power" and "Flags"
14128c2ecf20Sopenharmony_ci		 * fields
14138c2ecf20Sopenharmony_ci		 */
14148c2ecf20Sopenharmony_ci		flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci		/* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting
14178c2ecf20Sopenharmony_ci		 * corresponds to the "connectable" instance flag.
14188c2ecf20Sopenharmony_ci		 */
14198c2ecf20Sopenharmony_ci		if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
14208c2ecf20Sopenharmony_ci			flags |= MGMT_ADV_FLAG_CONNECTABLE;
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_ci		if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
14238c2ecf20Sopenharmony_ci			flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
14248c2ecf20Sopenharmony_ci		else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
14258c2ecf20Sopenharmony_ci			flags |= MGMT_ADV_FLAG_DISCOV;
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci		return flags;
14288c2ecf20Sopenharmony_ci	}
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	adv_instance = hci_find_adv_instance(hdev, instance);
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci	/* Return 0 when we got an invalid instance identifier. */
14338c2ecf20Sopenharmony_ci	if (!adv_instance)
14348c2ecf20Sopenharmony_ci		return 0;
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	return adv_instance->flags;
14378c2ecf20Sopenharmony_ci}
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_cistatic bool adv_use_rpa(struct hci_dev *hdev, uint32_t flags)
14408c2ecf20Sopenharmony_ci{
14418c2ecf20Sopenharmony_ci	/* If privacy is not enabled don't use RPA */
14428c2ecf20Sopenharmony_ci	if (!hci_dev_test_flag(hdev, HCI_PRIVACY))
14438c2ecf20Sopenharmony_ci		return false;
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_ci	/* If basic privacy mode is enabled use RPA */
14468c2ecf20Sopenharmony_ci	if (!hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
14478c2ecf20Sopenharmony_ci		return true;
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci	/* If limited privacy mode is enabled don't use RPA if we're
14508c2ecf20Sopenharmony_ci	 * both discoverable and bondable.
14518c2ecf20Sopenharmony_ci	 */
14528c2ecf20Sopenharmony_ci	if ((flags & MGMT_ADV_FLAG_DISCOV) &&
14538c2ecf20Sopenharmony_ci	    hci_dev_test_flag(hdev, HCI_BONDABLE))
14548c2ecf20Sopenharmony_ci		return false;
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci	/* We're neither bondable nor discoverable in the limited
14578c2ecf20Sopenharmony_ci	 * privacy mode, therefore use RPA.
14588c2ecf20Sopenharmony_ci	 */
14598c2ecf20Sopenharmony_ci	return true;
14608c2ecf20Sopenharmony_ci}
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_cistatic bool is_advertising_allowed(struct hci_dev *hdev, bool connectable)
14638c2ecf20Sopenharmony_ci{
14648c2ecf20Sopenharmony_ci	/* If there is no connection we are OK to advertise. */
14658c2ecf20Sopenharmony_ci	if (hci_conn_num(hdev, LE_LINK) == 0)
14668c2ecf20Sopenharmony_ci		return true;
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci	/* Check le_states if there is any connection in slave role. */
14698c2ecf20Sopenharmony_ci	if (hdev->conn_hash.le_num_slave > 0) {
14708c2ecf20Sopenharmony_ci		/* Slave connection state and non connectable mode bit 20. */
14718c2ecf20Sopenharmony_ci		if (!connectable && !(hdev->le_states[2] & 0x10))
14728c2ecf20Sopenharmony_ci			return false;
14738c2ecf20Sopenharmony_ci
14748c2ecf20Sopenharmony_ci		/* Slave connection state and connectable mode bit 38
14758c2ecf20Sopenharmony_ci		 * and scannable bit 21.
14768c2ecf20Sopenharmony_ci		 */
14778c2ecf20Sopenharmony_ci		if (connectable && (!(hdev->le_states[4] & 0x40) ||
14788c2ecf20Sopenharmony_ci				    !(hdev->le_states[2] & 0x20)))
14798c2ecf20Sopenharmony_ci			return false;
14808c2ecf20Sopenharmony_ci	}
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci	/* Check le_states if there is any connection in master role. */
14838c2ecf20Sopenharmony_ci	if (hci_conn_num(hdev, LE_LINK) != hdev->conn_hash.le_num_slave) {
14848c2ecf20Sopenharmony_ci		/* Master connection state and non connectable mode bit 18. */
14858c2ecf20Sopenharmony_ci		if (!connectable && !(hdev->le_states[2] & 0x02))
14868c2ecf20Sopenharmony_ci			return false;
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci		/* Master connection state and connectable mode bit 35 and
14898c2ecf20Sopenharmony_ci		 * scannable 19.
14908c2ecf20Sopenharmony_ci		 */
14918c2ecf20Sopenharmony_ci		if (connectable && (!(hdev->le_states[4] & 0x08) ||
14928c2ecf20Sopenharmony_ci				    !(hdev->le_states[2] & 0x08)))
14938c2ecf20Sopenharmony_ci			return false;
14948c2ecf20Sopenharmony_ci	}
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	return true;
14978c2ecf20Sopenharmony_ci}
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_civoid __hci_req_enable_advertising(struct hci_request *req)
15008c2ecf20Sopenharmony_ci{
15018c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
15028c2ecf20Sopenharmony_ci	struct hci_cp_le_set_adv_param cp;
15038c2ecf20Sopenharmony_ci	u8 own_addr_type, enable = 0x01;
15048c2ecf20Sopenharmony_ci	bool connectable;
15058c2ecf20Sopenharmony_ci	u16 adv_min_interval, adv_max_interval;
15068c2ecf20Sopenharmony_ci	u32 flags;
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	flags = get_adv_instance_flags(hdev, hdev->cur_adv_instance);
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci	/* If the "connectable" instance flag was not set, then choose between
15118c2ecf20Sopenharmony_ci	 * ADV_IND and ADV_NONCONN_IND based on the global connectable setting.
15128c2ecf20Sopenharmony_ci	 */
15138c2ecf20Sopenharmony_ci	connectable = (flags & MGMT_ADV_FLAG_CONNECTABLE) ||
15148c2ecf20Sopenharmony_ci		      mgmt_get_connectable(hdev);
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci	if (!is_advertising_allowed(hdev, connectable))
15178c2ecf20Sopenharmony_ci		return;
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci	if (hci_dev_test_flag(hdev, HCI_LE_ADV))
15208c2ecf20Sopenharmony_ci		__hci_req_disable_advertising(req);
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci	/* Clear the HCI_LE_ADV bit temporarily so that the
15238c2ecf20Sopenharmony_ci	 * hci_update_random_address knows that it's safe to go ahead
15248c2ecf20Sopenharmony_ci	 * and write a new random address. The flag will be set back on
15258c2ecf20Sopenharmony_ci	 * as soon as the SET_ADV_ENABLE HCI command completes.
15268c2ecf20Sopenharmony_ci	 */
15278c2ecf20Sopenharmony_ci	hci_dev_clear_flag(hdev, HCI_LE_ADV);
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_ci	/* Set require_privacy to true only when non-connectable
15308c2ecf20Sopenharmony_ci	 * advertising is used. In that case it is fine to use a
15318c2ecf20Sopenharmony_ci	 * non-resolvable private address.
15328c2ecf20Sopenharmony_ci	 */
15338c2ecf20Sopenharmony_ci	if (hci_update_random_address(req, !connectable,
15348c2ecf20Sopenharmony_ci				      adv_use_rpa(hdev, flags),
15358c2ecf20Sopenharmony_ci				      &own_addr_type) < 0)
15368c2ecf20Sopenharmony_ci		return;
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci	memset(&cp, 0, sizeof(cp));
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci	if (connectable) {
15418c2ecf20Sopenharmony_ci		cp.type = LE_ADV_IND;
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci		adv_min_interval = hdev->le_adv_min_interval;
15448c2ecf20Sopenharmony_ci		adv_max_interval = hdev->le_adv_max_interval;
15458c2ecf20Sopenharmony_ci	} else {
15468c2ecf20Sopenharmony_ci		if (get_cur_adv_instance_scan_rsp_len(hdev))
15478c2ecf20Sopenharmony_ci			cp.type = LE_ADV_SCAN_IND;
15488c2ecf20Sopenharmony_ci		else
15498c2ecf20Sopenharmony_ci			cp.type = LE_ADV_NONCONN_IND;
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci		if (!hci_dev_test_flag(hdev, HCI_DISCOVERABLE) ||
15528c2ecf20Sopenharmony_ci		    hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE)) {
15538c2ecf20Sopenharmony_ci			adv_min_interval = DISCOV_LE_FAST_ADV_INT_MIN;
15548c2ecf20Sopenharmony_ci			adv_max_interval = DISCOV_LE_FAST_ADV_INT_MAX;
15558c2ecf20Sopenharmony_ci		} else {
15568c2ecf20Sopenharmony_ci			adv_min_interval = hdev->le_adv_min_interval;
15578c2ecf20Sopenharmony_ci			adv_max_interval = hdev->le_adv_max_interval;
15588c2ecf20Sopenharmony_ci		}
15598c2ecf20Sopenharmony_ci	}
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci	cp.min_interval = cpu_to_le16(adv_min_interval);
15628c2ecf20Sopenharmony_ci	cp.max_interval = cpu_to_le16(adv_max_interval);
15638c2ecf20Sopenharmony_ci	cp.own_address_type = own_addr_type;
15648c2ecf20Sopenharmony_ci	cp.channel_map = hdev->le_adv_channel_map;
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci	hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
15678c2ecf20Sopenharmony_ci
15688c2ecf20Sopenharmony_ci	hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
15698c2ecf20Sopenharmony_ci}
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ciu8 append_local_name(struct hci_dev *hdev, u8 *ptr, u8 ad_len)
15728c2ecf20Sopenharmony_ci{
15738c2ecf20Sopenharmony_ci	size_t short_len;
15748c2ecf20Sopenharmony_ci	size_t complete_len;
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_ci	/* no space left for name (+ NULL + type + len) */
15778c2ecf20Sopenharmony_ci	if ((HCI_MAX_AD_LENGTH - ad_len) < HCI_MAX_SHORT_NAME_LENGTH + 3)
15788c2ecf20Sopenharmony_ci		return ad_len;
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci	/* use complete name if present and fits */
15818c2ecf20Sopenharmony_ci	complete_len = strlen(hdev->dev_name);
15828c2ecf20Sopenharmony_ci	if (complete_len && complete_len <= HCI_MAX_SHORT_NAME_LENGTH)
15838c2ecf20Sopenharmony_ci		return eir_append_data(ptr, ad_len, EIR_NAME_COMPLETE,
15848c2ecf20Sopenharmony_ci				       hdev->dev_name, complete_len + 1);
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci	/* use short name if present */
15878c2ecf20Sopenharmony_ci	short_len = strlen(hdev->short_name);
15888c2ecf20Sopenharmony_ci	if (short_len)
15898c2ecf20Sopenharmony_ci		return eir_append_data(ptr, ad_len, EIR_NAME_SHORT,
15908c2ecf20Sopenharmony_ci				       hdev->short_name, short_len + 1);
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_ci	/* use shortened full name if present, we already know that name
15938c2ecf20Sopenharmony_ci	 * is longer then HCI_MAX_SHORT_NAME_LENGTH
15948c2ecf20Sopenharmony_ci	 */
15958c2ecf20Sopenharmony_ci	if (complete_len) {
15968c2ecf20Sopenharmony_ci		u8 name[HCI_MAX_SHORT_NAME_LENGTH + 1];
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci		memcpy(name, hdev->dev_name, HCI_MAX_SHORT_NAME_LENGTH);
15998c2ecf20Sopenharmony_ci		name[HCI_MAX_SHORT_NAME_LENGTH] = '\0';
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci		return eir_append_data(ptr, ad_len, EIR_NAME_SHORT, name,
16028c2ecf20Sopenharmony_ci				       sizeof(name));
16038c2ecf20Sopenharmony_ci	}
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci	return ad_len;
16068c2ecf20Sopenharmony_ci}
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_cistatic u8 append_appearance(struct hci_dev *hdev, u8 *ptr, u8 ad_len)
16098c2ecf20Sopenharmony_ci{
16108c2ecf20Sopenharmony_ci	return eir_append_le16(ptr, ad_len, EIR_APPEARANCE, hdev->appearance);
16118c2ecf20Sopenharmony_ci}
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_cistatic u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
16148c2ecf20Sopenharmony_ci{
16158c2ecf20Sopenharmony_ci	u8 scan_rsp_len = 0;
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci	if (hdev->appearance) {
16188c2ecf20Sopenharmony_ci		scan_rsp_len = append_appearance(hdev, ptr, scan_rsp_len);
16198c2ecf20Sopenharmony_ci	}
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci	return append_local_name(hdev, ptr, scan_rsp_len);
16228c2ecf20Sopenharmony_ci}
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_cistatic u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 instance,
16258c2ecf20Sopenharmony_ci					u8 *ptr)
16268c2ecf20Sopenharmony_ci{
16278c2ecf20Sopenharmony_ci	struct adv_info *adv_instance;
16288c2ecf20Sopenharmony_ci	u32 instance_flags;
16298c2ecf20Sopenharmony_ci	u8 scan_rsp_len = 0;
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_ci	adv_instance = hci_find_adv_instance(hdev, instance);
16328c2ecf20Sopenharmony_ci	if (!adv_instance)
16338c2ecf20Sopenharmony_ci		return 0;
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci	instance_flags = adv_instance->flags;
16368c2ecf20Sopenharmony_ci
16378c2ecf20Sopenharmony_ci	if ((instance_flags & MGMT_ADV_FLAG_APPEARANCE) && hdev->appearance) {
16388c2ecf20Sopenharmony_ci		scan_rsp_len = append_appearance(hdev, ptr, scan_rsp_len);
16398c2ecf20Sopenharmony_ci	}
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci	memcpy(&ptr[scan_rsp_len], adv_instance->scan_rsp_data,
16428c2ecf20Sopenharmony_ci	       adv_instance->scan_rsp_len);
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci	scan_rsp_len += adv_instance->scan_rsp_len;
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_ci	if (instance_flags & MGMT_ADV_FLAG_LOCAL_NAME)
16478c2ecf20Sopenharmony_ci		scan_rsp_len = append_local_name(hdev, ptr, scan_rsp_len);
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci	return scan_rsp_len;
16508c2ecf20Sopenharmony_ci}
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_civoid __hci_req_update_scan_rsp_data(struct hci_request *req, u8 instance)
16538c2ecf20Sopenharmony_ci{
16548c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
16558c2ecf20Sopenharmony_ci	u8 len;
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_ci	if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
16588c2ecf20Sopenharmony_ci		return;
16598c2ecf20Sopenharmony_ci
16608c2ecf20Sopenharmony_ci	if (ext_adv_capable(hdev)) {
16618c2ecf20Sopenharmony_ci		struct {
16628c2ecf20Sopenharmony_ci			struct hci_cp_le_set_ext_scan_rsp_data cp;
16638c2ecf20Sopenharmony_ci			u8 data[HCI_MAX_EXT_AD_LENGTH];
16648c2ecf20Sopenharmony_ci		} pdu;
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci		memset(&pdu, 0, sizeof(pdu));
16678c2ecf20Sopenharmony_ci
16688c2ecf20Sopenharmony_ci		if (instance)
16698c2ecf20Sopenharmony_ci			len = create_instance_scan_rsp_data(hdev, instance,
16708c2ecf20Sopenharmony_ci							    pdu.data);
16718c2ecf20Sopenharmony_ci		else
16728c2ecf20Sopenharmony_ci			len = create_default_scan_rsp_data(hdev, pdu.data);
16738c2ecf20Sopenharmony_ci
16748c2ecf20Sopenharmony_ci		if (hdev->scan_rsp_data_len == len &&
16758c2ecf20Sopenharmony_ci		    !memcmp(pdu.data, hdev->scan_rsp_data, len))
16768c2ecf20Sopenharmony_ci			return;
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci		memcpy(hdev->scan_rsp_data, pdu.data, len);
16798c2ecf20Sopenharmony_ci		hdev->scan_rsp_data_len = len;
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci		pdu.cp.handle = instance;
16828c2ecf20Sopenharmony_ci		pdu.cp.length = len;
16838c2ecf20Sopenharmony_ci		pdu.cp.operation = LE_SET_ADV_DATA_OP_COMPLETE;
16848c2ecf20Sopenharmony_ci		pdu.cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG;
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci		hci_req_add(req, HCI_OP_LE_SET_EXT_SCAN_RSP_DATA,
16878c2ecf20Sopenharmony_ci			    sizeof(pdu.cp) + len, &pdu.cp);
16888c2ecf20Sopenharmony_ci	} else {
16898c2ecf20Sopenharmony_ci		struct hci_cp_le_set_scan_rsp_data cp;
16908c2ecf20Sopenharmony_ci
16918c2ecf20Sopenharmony_ci		memset(&cp, 0, sizeof(cp));
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci		if (instance)
16948c2ecf20Sopenharmony_ci			len = create_instance_scan_rsp_data(hdev, instance,
16958c2ecf20Sopenharmony_ci							    cp.data);
16968c2ecf20Sopenharmony_ci		else
16978c2ecf20Sopenharmony_ci			len = create_default_scan_rsp_data(hdev, cp.data);
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_ci		if (hdev->scan_rsp_data_len == len &&
17008c2ecf20Sopenharmony_ci		    !memcmp(cp.data, hdev->scan_rsp_data, len))
17018c2ecf20Sopenharmony_ci			return;
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci		memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
17048c2ecf20Sopenharmony_ci		hdev->scan_rsp_data_len = len;
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ci		cp.length = len;
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci		hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
17098c2ecf20Sopenharmony_ci	}
17108c2ecf20Sopenharmony_ci}
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_cistatic u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
17138c2ecf20Sopenharmony_ci{
17148c2ecf20Sopenharmony_ci	struct adv_info *adv_instance = NULL;
17158c2ecf20Sopenharmony_ci	u8 ad_len = 0, flags = 0;
17168c2ecf20Sopenharmony_ci	u32 instance_flags;
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci	/* Return 0 when the current instance identifier is invalid. */
17198c2ecf20Sopenharmony_ci	if (instance) {
17208c2ecf20Sopenharmony_ci		adv_instance = hci_find_adv_instance(hdev, instance);
17218c2ecf20Sopenharmony_ci		if (!adv_instance)
17228c2ecf20Sopenharmony_ci			return 0;
17238c2ecf20Sopenharmony_ci	}
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_ci	instance_flags = get_adv_instance_flags(hdev, instance);
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_ci	/* If instance already has the flags set skip adding it once
17288c2ecf20Sopenharmony_ci	 * again.
17298c2ecf20Sopenharmony_ci	 */
17308c2ecf20Sopenharmony_ci	if (adv_instance && eir_get_data(adv_instance->adv_data,
17318c2ecf20Sopenharmony_ci					 adv_instance->adv_data_len, EIR_FLAGS,
17328c2ecf20Sopenharmony_ci					 NULL))
17338c2ecf20Sopenharmony_ci		goto skip_flags;
17348c2ecf20Sopenharmony_ci
17358c2ecf20Sopenharmony_ci	/* The Add Advertising command allows userspace to set both the general
17368c2ecf20Sopenharmony_ci	 * and limited discoverable flags.
17378c2ecf20Sopenharmony_ci	 */
17388c2ecf20Sopenharmony_ci	if (instance_flags & MGMT_ADV_FLAG_DISCOV)
17398c2ecf20Sopenharmony_ci		flags |= LE_AD_GENERAL;
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_ci	if (instance_flags & MGMT_ADV_FLAG_LIMITED_DISCOV)
17428c2ecf20Sopenharmony_ci		flags |= LE_AD_LIMITED;
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_ci	if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
17458c2ecf20Sopenharmony_ci		flags |= LE_AD_NO_BREDR;
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci	if (flags || (instance_flags & MGMT_ADV_FLAG_MANAGED_FLAGS)) {
17488c2ecf20Sopenharmony_ci		/* If a discovery flag wasn't provided, simply use the global
17498c2ecf20Sopenharmony_ci		 * settings.
17508c2ecf20Sopenharmony_ci		 */
17518c2ecf20Sopenharmony_ci		if (!flags)
17528c2ecf20Sopenharmony_ci			flags |= mgmt_get_adv_discov_flags(hdev);
17538c2ecf20Sopenharmony_ci
17548c2ecf20Sopenharmony_ci		/* If flags would still be empty, then there is no need to
17558c2ecf20Sopenharmony_ci		 * include the "Flags" AD field".
17568c2ecf20Sopenharmony_ci		 */
17578c2ecf20Sopenharmony_ci		if (flags) {
17588c2ecf20Sopenharmony_ci			ptr[0] = 0x02;
17598c2ecf20Sopenharmony_ci			ptr[1] = EIR_FLAGS;
17608c2ecf20Sopenharmony_ci			ptr[2] = flags;
17618c2ecf20Sopenharmony_ci
17628c2ecf20Sopenharmony_ci			ad_len += 3;
17638c2ecf20Sopenharmony_ci			ptr += 3;
17648c2ecf20Sopenharmony_ci		}
17658c2ecf20Sopenharmony_ci	}
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_ciskip_flags:
17688c2ecf20Sopenharmony_ci	if (adv_instance) {
17698c2ecf20Sopenharmony_ci		memcpy(ptr, adv_instance->adv_data,
17708c2ecf20Sopenharmony_ci		       adv_instance->adv_data_len);
17718c2ecf20Sopenharmony_ci		ad_len += adv_instance->adv_data_len;
17728c2ecf20Sopenharmony_ci		ptr += adv_instance->adv_data_len;
17738c2ecf20Sopenharmony_ci	}
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_ci	if (instance_flags & MGMT_ADV_FLAG_TX_POWER) {
17768c2ecf20Sopenharmony_ci		s8 adv_tx_power;
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_ci		if (ext_adv_capable(hdev)) {
17798c2ecf20Sopenharmony_ci			if (adv_instance)
17808c2ecf20Sopenharmony_ci				adv_tx_power = adv_instance->tx_power;
17818c2ecf20Sopenharmony_ci			else
17828c2ecf20Sopenharmony_ci				adv_tx_power = hdev->adv_tx_power;
17838c2ecf20Sopenharmony_ci		} else {
17848c2ecf20Sopenharmony_ci			adv_tx_power = hdev->adv_tx_power;
17858c2ecf20Sopenharmony_ci		}
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci		/* Provide Tx Power only if we can provide a valid value for it */
17888c2ecf20Sopenharmony_ci		if (adv_tx_power != HCI_TX_POWER_INVALID) {
17898c2ecf20Sopenharmony_ci			ptr[0] = 0x02;
17908c2ecf20Sopenharmony_ci			ptr[1] = EIR_TX_POWER;
17918c2ecf20Sopenharmony_ci			ptr[2] = (u8)adv_tx_power;
17928c2ecf20Sopenharmony_ci
17938c2ecf20Sopenharmony_ci			ad_len += 3;
17948c2ecf20Sopenharmony_ci			ptr += 3;
17958c2ecf20Sopenharmony_ci		}
17968c2ecf20Sopenharmony_ci	}
17978c2ecf20Sopenharmony_ci
17988c2ecf20Sopenharmony_ci	return ad_len;
17998c2ecf20Sopenharmony_ci}
18008c2ecf20Sopenharmony_ci
18018c2ecf20Sopenharmony_civoid __hci_req_update_adv_data(struct hci_request *req, u8 instance)
18028c2ecf20Sopenharmony_ci{
18038c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
18048c2ecf20Sopenharmony_ci	u8 len;
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci	if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
18078c2ecf20Sopenharmony_ci		return;
18088c2ecf20Sopenharmony_ci
18098c2ecf20Sopenharmony_ci	if (ext_adv_capable(hdev)) {
18108c2ecf20Sopenharmony_ci		struct {
18118c2ecf20Sopenharmony_ci			struct hci_cp_le_set_ext_adv_data cp;
18128c2ecf20Sopenharmony_ci			u8 data[HCI_MAX_EXT_AD_LENGTH];
18138c2ecf20Sopenharmony_ci		} pdu;
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ci		memset(&pdu, 0, sizeof(pdu));
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_ci		len = create_instance_adv_data(hdev, instance, pdu.data);
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci		/* There's nothing to do if the data hasn't changed */
18208c2ecf20Sopenharmony_ci		if (hdev->adv_data_len == len &&
18218c2ecf20Sopenharmony_ci		    memcmp(pdu.data, hdev->adv_data, len) == 0)
18228c2ecf20Sopenharmony_ci			return;
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_ci		memcpy(hdev->adv_data, pdu.data, len);
18258c2ecf20Sopenharmony_ci		hdev->adv_data_len = len;
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_ci		pdu.cp.length = len;
18288c2ecf20Sopenharmony_ci		pdu.cp.handle = instance;
18298c2ecf20Sopenharmony_ci		pdu.cp.operation = LE_SET_ADV_DATA_OP_COMPLETE;
18308c2ecf20Sopenharmony_ci		pdu.cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG;
18318c2ecf20Sopenharmony_ci
18328c2ecf20Sopenharmony_ci		hci_req_add(req, HCI_OP_LE_SET_EXT_ADV_DATA,
18338c2ecf20Sopenharmony_ci			    sizeof(pdu.cp) + len, &pdu.cp);
18348c2ecf20Sopenharmony_ci	} else {
18358c2ecf20Sopenharmony_ci		struct hci_cp_le_set_adv_data cp;
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci		memset(&cp, 0, sizeof(cp));
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci		len = create_instance_adv_data(hdev, instance, cp.data);
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ci		/* There's nothing to do if the data hasn't changed */
18428c2ecf20Sopenharmony_ci		if (hdev->adv_data_len == len &&
18438c2ecf20Sopenharmony_ci		    memcmp(cp.data, hdev->adv_data, len) == 0)
18448c2ecf20Sopenharmony_ci			return;
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci		memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
18478c2ecf20Sopenharmony_ci		hdev->adv_data_len = len;
18488c2ecf20Sopenharmony_ci
18498c2ecf20Sopenharmony_ci		cp.length = len;
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_ci		hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
18528c2ecf20Sopenharmony_ci	}
18538c2ecf20Sopenharmony_ci}
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ciint hci_req_update_adv_data(struct hci_dev *hdev, u8 instance)
18568c2ecf20Sopenharmony_ci{
18578c2ecf20Sopenharmony_ci	struct hci_request req;
18588c2ecf20Sopenharmony_ci
18598c2ecf20Sopenharmony_ci	hci_req_init(&req, hdev);
18608c2ecf20Sopenharmony_ci	__hci_req_update_adv_data(&req, instance);
18618c2ecf20Sopenharmony_ci
18628c2ecf20Sopenharmony_ci	return hci_req_run(&req, NULL);
18638c2ecf20Sopenharmony_ci}
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_cistatic void enable_addr_resolution_complete(struct hci_dev *hdev, u8 status,
18668c2ecf20Sopenharmony_ci					    u16 opcode)
18678c2ecf20Sopenharmony_ci{
18688c2ecf20Sopenharmony_ci	BT_DBG("%s status %u", hdev->name, status);
18698c2ecf20Sopenharmony_ci}
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_civoid hci_req_disable_address_resolution(struct hci_dev *hdev)
18728c2ecf20Sopenharmony_ci{
18738c2ecf20Sopenharmony_ci	struct hci_request req;
18748c2ecf20Sopenharmony_ci	__u8 enable = 0x00;
18758c2ecf20Sopenharmony_ci
18768c2ecf20Sopenharmony_ci	if (!use_ll_privacy(hdev) &&
18778c2ecf20Sopenharmony_ci	    !hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION))
18788c2ecf20Sopenharmony_ci		return;
18798c2ecf20Sopenharmony_ci
18808c2ecf20Sopenharmony_ci	hci_req_init(&req, hdev);
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_ci	hci_req_add(&req, HCI_OP_LE_SET_ADDR_RESOLV_ENABLE, 1, &enable);
18838c2ecf20Sopenharmony_ci
18848c2ecf20Sopenharmony_ci	hci_req_run(&req, enable_addr_resolution_complete);
18858c2ecf20Sopenharmony_ci}
18868c2ecf20Sopenharmony_ci
18878c2ecf20Sopenharmony_cistatic void adv_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
18888c2ecf20Sopenharmony_ci{
18898c2ecf20Sopenharmony_ci	BT_DBG("%s status %u", hdev->name, status);
18908c2ecf20Sopenharmony_ci}
18918c2ecf20Sopenharmony_ci
18928c2ecf20Sopenharmony_civoid hci_req_reenable_advertising(struct hci_dev *hdev)
18938c2ecf20Sopenharmony_ci{
18948c2ecf20Sopenharmony_ci	struct hci_request req;
18958c2ecf20Sopenharmony_ci
18968c2ecf20Sopenharmony_ci	if (!hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
18978c2ecf20Sopenharmony_ci	    list_empty(&hdev->adv_instances))
18988c2ecf20Sopenharmony_ci		return;
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci	hci_req_init(&req, hdev);
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_ci	if (hdev->cur_adv_instance) {
19038c2ecf20Sopenharmony_ci		__hci_req_schedule_adv_instance(&req, hdev->cur_adv_instance,
19048c2ecf20Sopenharmony_ci						true);
19058c2ecf20Sopenharmony_ci	} else {
19068c2ecf20Sopenharmony_ci		if (ext_adv_capable(hdev)) {
19078c2ecf20Sopenharmony_ci			__hci_req_start_ext_adv(&req, 0x00);
19088c2ecf20Sopenharmony_ci		} else {
19098c2ecf20Sopenharmony_ci			__hci_req_update_adv_data(&req, 0x00);
19108c2ecf20Sopenharmony_ci			__hci_req_update_scan_rsp_data(&req, 0x00);
19118c2ecf20Sopenharmony_ci			__hci_req_enable_advertising(&req);
19128c2ecf20Sopenharmony_ci		}
19138c2ecf20Sopenharmony_ci	}
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_ci	hci_req_run(&req, adv_enable_complete);
19168c2ecf20Sopenharmony_ci}
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_cistatic void adv_timeout_expire(struct work_struct *work)
19198c2ecf20Sopenharmony_ci{
19208c2ecf20Sopenharmony_ci	struct hci_dev *hdev = container_of(work, struct hci_dev,
19218c2ecf20Sopenharmony_ci					    adv_instance_expire.work);
19228c2ecf20Sopenharmony_ci
19238c2ecf20Sopenharmony_ci	struct hci_request req;
19248c2ecf20Sopenharmony_ci	u8 instance;
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_ci	BT_DBG("%s", hdev->name);
19278c2ecf20Sopenharmony_ci
19288c2ecf20Sopenharmony_ci	hci_dev_lock(hdev);
19298c2ecf20Sopenharmony_ci
19308c2ecf20Sopenharmony_ci	hdev->adv_instance_timeout = 0;
19318c2ecf20Sopenharmony_ci
19328c2ecf20Sopenharmony_ci	instance = hdev->cur_adv_instance;
19338c2ecf20Sopenharmony_ci	if (instance == 0x00)
19348c2ecf20Sopenharmony_ci		goto unlock;
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_ci	hci_req_init(&req, hdev);
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_ci	hci_req_clear_adv_instance(hdev, NULL, &req, instance, false);
19398c2ecf20Sopenharmony_ci
19408c2ecf20Sopenharmony_ci	if (list_empty(&hdev->adv_instances))
19418c2ecf20Sopenharmony_ci		__hci_req_disable_advertising(&req);
19428c2ecf20Sopenharmony_ci
19438c2ecf20Sopenharmony_ci	hci_req_run(&req, NULL);
19448c2ecf20Sopenharmony_ci
19458c2ecf20Sopenharmony_ciunlock:
19468c2ecf20Sopenharmony_ci	hci_dev_unlock(hdev);
19478c2ecf20Sopenharmony_ci}
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_cistatic int hci_req_add_le_interleaved_scan(struct hci_request *req,
19508c2ecf20Sopenharmony_ci					   unsigned long opt)
19518c2ecf20Sopenharmony_ci{
19528c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
19538c2ecf20Sopenharmony_ci	int ret = 0;
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_ci	hci_dev_lock(hdev);
19568c2ecf20Sopenharmony_ci
19578c2ecf20Sopenharmony_ci	if (hci_dev_test_flag(hdev, HCI_LE_SCAN))
19588c2ecf20Sopenharmony_ci		hci_req_add_le_scan_disable(req, false);
19598c2ecf20Sopenharmony_ci	hci_req_add_le_passive_scan(req);
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_ci	switch (hdev->interleave_scan_state) {
19628c2ecf20Sopenharmony_ci	case INTERLEAVE_SCAN_ALLOWLIST:
19638c2ecf20Sopenharmony_ci		bt_dev_dbg(hdev, "next state: allowlist");
19648c2ecf20Sopenharmony_ci		hdev->interleave_scan_state = INTERLEAVE_SCAN_NO_FILTER;
19658c2ecf20Sopenharmony_ci		break;
19668c2ecf20Sopenharmony_ci	case INTERLEAVE_SCAN_NO_FILTER:
19678c2ecf20Sopenharmony_ci		bt_dev_dbg(hdev, "next state: no filter");
19688c2ecf20Sopenharmony_ci		hdev->interleave_scan_state = INTERLEAVE_SCAN_ALLOWLIST;
19698c2ecf20Sopenharmony_ci		break;
19708c2ecf20Sopenharmony_ci	case INTERLEAVE_SCAN_NONE:
19718c2ecf20Sopenharmony_ci		BT_ERR("unexpected error");
19728c2ecf20Sopenharmony_ci		ret = -1;
19738c2ecf20Sopenharmony_ci	}
19748c2ecf20Sopenharmony_ci
19758c2ecf20Sopenharmony_ci	hci_dev_unlock(hdev);
19768c2ecf20Sopenharmony_ci
19778c2ecf20Sopenharmony_ci	return ret;
19788c2ecf20Sopenharmony_ci}
19798c2ecf20Sopenharmony_ci
19808c2ecf20Sopenharmony_cistatic void interleave_scan_work(struct work_struct *work)
19818c2ecf20Sopenharmony_ci{
19828c2ecf20Sopenharmony_ci	struct hci_dev *hdev = container_of(work, struct hci_dev,
19838c2ecf20Sopenharmony_ci					    interleave_scan.work);
19848c2ecf20Sopenharmony_ci	u8 status;
19858c2ecf20Sopenharmony_ci	unsigned long timeout;
19868c2ecf20Sopenharmony_ci
19878c2ecf20Sopenharmony_ci	if (hdev->interleave_scan_state == INTERLEAVE_SCAN_ALLOWLIST) {
19888c2ecf20Sopenharmony_ci		timeout = msecs_to_jiffies(hdev->advmon_allowlist_duration);
19898c2ecf20Sopenharmony_ci	} else if (hdev->interleave_scan_state == INTERLEAVE_SCAN_NO_FILTER) {
19908c2ecf20Sopenharmony_ci		timeout = msecs_to_jiffies(hdev->advmon_no_filter_duration);
19918c2ecf20Sopenharmony_ci	} else {
19928c2ecf20Sopenharmony_ci		bt_dev_err(hdev, "unexpected error");
19938c2ecf20Sopenharmony_ci		return;
19948c2ecf20Sopenharmony_ci	}
19958c2ecf20Sopenharmony_ci
19968c2ecf20Sopenharmony_ci	hci_req_sync(hdev, hci_req_add_le_interleaved_scan, 0,
19978c2ecf20Sopenharmony_ci		     HCI_CMD_TIMEOUT, &status);
19988c2ecf20Sopenharmony_ci
19998c2ecf20Sopenharmony_ci	/* Don't continue interleaving if it was canceled */
20008c2ecf20Sopenharmony_ci	if (is_interleave_scanning(hdev))
20018c2ecf20Sopenharmony_ci		queue_delayed_work(hdev->req_workqueue,
20028c2ecf20Sopenharmony_ci				   &hdev->interleave_scan, timeout);
20038c2ecf20Sopenharmony_ci}
20048c2ecf20Sopenharmony_ci
20058c2ecf20Sopenharmony_ciint hci_get_random_address(struct hci_dev *hdev, bool require_privacy,
20068c2ecf20Sopenharmony_ci			   bool use_rpa, struct adv_info *adv_instance,
20078c2ecf20Sopenharmony_ci			   u8 *own_addr_type, bdaddr_t *rand_addr)
20088c2ecf20Sopenharmony_ci{
20098c2ecf20Sopenharmony_ci	int err;
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ci	bacpy(rand_addr, BDADDR_ANY);
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_ci	/* If privacy is enabled use a resolvable private address. If
20148c2ecf20Sopenharmony_ci	 * current RPA has expired then generate a new one.
20158c2ecf20Sopenharmony_ci	 */
20168c2ecf20Sopenharmony_ci	if (use_rpa) {
20178c2ecf20Sopenharmony_ci		int to;
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ci		/* If Controller supports LL Privacy use own address type is
20208c2ecf20Sopenharmony_ci		 * 0x03
20218c2ecf20Sopenharmony_ci		 */
20228c2ecf20Sopenharmony_ci		if (use_ll_privacy(hdev))
20238c2ecf20Sopenharmony_ci			*own_addr_type = ADDR_LE_DEV_RANDOM_RESOLVED;
20248c2ecf20Sopenharmony_ci		else
20258c2ecf20Sopenharmony_ci			*own_addr_type = ADDR_LE_DEV_RANDOM;
20268c2ecf20Sopenharmony_ci
20278c2ecf20Sopenharmony_ci		if (adv_instance) {
20288c2ecf20Sopenharmony_ci			if (!adv_instance->rpa_expired &&
20298c2ecf20Sopenharmony_ci			    !bacmp(&adv_instance->random_addr, &hdev->rpa))
20308c2ecf20Sopenharmony_ci				return 0;
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_ci			adv_instance->rpa_expired = false;
20338c2ecf20Sopenharmony_ci		} else {
20348c2ecf20Sopenharmony_ci			if (!hci_dev_test_and_clear_flag(hdev, HCI_RPA_EXPIRED) &&
20358c2ecf20Sopenharmony_ci			    !bacmp(&hdev->random_addr, &hdev->rpa))
20368c2ecf20Sopenharmony_ci				return 0;
20378c2ecf20Sopenharmony_ci		}
20388c2ecf20Sopenharmony_ci
20398c2ecf20Sopenharmony_ci		err = smp_generate_rpa(hdev, hdev->irk, &hdev->rpa);
20408c2ecf20Sopenharmony_ci		if (err < 0) {
20418c2ecf20Sopenharmony_ci			bt_dev_err(hdev, "failed to generate new RPA");
20428c2ecf20Sopenharmony_ci			return err;
20438c2ecf20Sopenharmony_ci		}
20448c2ecf20Sopenharmony_ci
20458c2ecf20Sopenharmony_ci		bacpy(rand_addr, &hdev->rpa);
20468c2ecf20Sopenharmony_ci
20478c2ecf20Sopenharmony_ci		to = msecs_to_jiffies(hdev->rpa_timeout * 1000);
20488c2ecf20Sopenharmony_ci		if (adv_instance)
20498c2ecf20Sopenharmony_ci			queue_delayed_work(hdev->workqueue,
20508c2ecf20Sopenharmony_ci					   &adv_instance->rpa_expired_cb, to);
20518c2ecf20Sopenharmony_ci		else
20528c2ecf20Sopenharmony_ci			queue_delayed_work(hdev->workqueue,
20538c2ecf20Sopenharmony_ci					   &hdev->rpa_expired, to);
20548c2ecf20Sopenharmony_ci
20558c2ecf20Sopenharmony_ci		return 0;
20568c2ecf20Sopenharmony_ci	}
20578c2ecf20Sopenharmony_ci
20588c2ecf20Sopenharmony_ci	/* In case of required privacy without resolvable private address,
20598c2ecf20Sopenharmony_ci	 * use an non-resolvable private address. This is useful for
20608c2ecf20Sopenharmony_ci	 * non-connectable advertising.
20618c2ecf20Sopenharmony_ci	 */
20628c2ecf20Sopenharmony_ci	if (require_privacy) {
20638c2ecf20Sopenharmony_ci		bdaddr_t nrpa;
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_ci		while (true) {
20668c2ecf20Sopenharmony_ci			/* The non-resolvable private address is generated
20678c2ecf20Sopenharmony_ci			 * from random six bytes with the two most significant
20688c2ecf20Sopenharmony_ci			 * bits cleared.
20698c2ecf20Sopenharmony_ci			 */
20708c2ecf20Sopenharmony_ci			get_random_bytes(&nrpa, 6);
20718c2ecf20Sopenharmony_ci			nrpa.b[5] &= 0x3f;
20728c2ecf20Sopenharmony_ci
20738c2ecf20Sopenharmony_ci			/* The non-resolvable private address shall not be
20748c2ecf20Sopenharmony_ci			 * equal to the public address.
20758c2ecf20Sopenharmony_ci			 */
20768c2ecf20Sopenharmony_ci			if (bacmp(&hdev->bdaddr, &nrpa))
20778c2ecf20Sopenharmony_ci				break;
20788c2ecf20Sopenharmony_ci		}
20798c2ecf20Sopenharmony_ci
20808c2ecf20Sopenharmony_ci		*own_addr_type = ADDR_LE_DEV_RANDOM;
20818c2ecf20Sopenharmony_ci		bacpy(rand_addr, &nrpa);
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_ci		return 0;
20848c2ecf20Sopenharmony_ci	}
20858c2ecf20Sopenharmony_ci
20868c2ecf20Sopenharmony_ci	/* No privacy so use a public address. */
20878c2ecf20Sopenharmony_ci	*own_addr_type = ADDR_LE_DEV_PUBLIC;
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_ci	return 0;
20908c2ecf20Sopenharmony_ci}
20918c2ecf20Sopenharmony_ci
20928c2ecf20Sopenharmony_civoid __hci_req_clear_ext_adv_sets(struct hci_request *req)
20938c2ecf20Sopenharmony_ci{
20948c2ecf20Sopenharmony_ci	hci_req_add(req, HCI_OP_LE_CLEAR_ADV_SETS, 0, NULL);
20958c2ecf20Sopenharmony_ci}
20968c2ecf20Sopenharmony_ci
20978c2ecf20Sopenharmony_ciint __hci_req_setup_ext_adv_instance(struct hci_request *req, u8 instance)
20988c2ecf20Sopenharmony_ci{
20998c2ecf20Sopenharmony_ci	struct hci_cp_le_set_ext_adv_params cp;
21008c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
21018c2ecf20Sopenharmony_ci	bool connectable;
21028c2ecf20Sopenharmony_ci	u32 flags;
21038c2ecf20Sopenharmony_ci	bdaddr_t random_addr;
21048c2ecf20Sopenharmony_ci	u8 own_addr_type;
21058c2ecf20Sopenharmony_ci	int err;
21068c2ecf20Sopenharmony_ci	struct adv_info *adv_instance;
21078c2ecf20Sopenharmony_ci	bool secondary_adv;
21088c2ecf20Sopenharmony_ci
21098c2ecf20Sopenharmony_ci	if (instance > 0) {
21108c2ecf20Sopenharmony_ci		adv_instance = hci_find_adv_instance(hdev, instance);
21118c2ecf20Sopenharmony_ci		if (!adv_instance)
21128c2ecf20Sopenharmony_ci			return -EINVAL;
21138c2ecf20Sopenharmony_ci	} else {
21148c2ecf20Sopenharmony_ci		adv_instance = NULL;
21158c2ecf20Sopenharmony_ci	}
21168c2ecf20Sopenharmony_ci
21178c2ecf20Sopenharmony_ci	flags = get_adv_instance_flags(hdev, instance);
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_ci	/* If the "connectable" instance flag was not set, then choose between
21208c2ecf20Sopenharmony_ci	 * ADV_IND and ADV_NONCONN_IND based on the global connectable setting.
21218c2ecf20Sopenharmony_ci	 */
21228c2ecf20Sopenharmony_ci	connectable = (flags & MGMT_ADV_FLAG_CONNECTABLE) ||
21238c2ecf20Sopenharmony_ci		      mgmt_get_connectable(hdev);
21248c2ecf20Sopenharmony_ci
21258c2ecf20Sopenharmony_ci	if (!is_advertising_allowed(hdev, connectable))
21268c2ecf20Sopenharmony_ci		return -EPERM;
21278c2ecf20Sopenharmony_ci
21288c2ecf20Sopenharmony_ci	/* Set require_privacy to true only when non-connectable
21298c2ecf20Sopenharmony_ci	 * advertising is used. In that case it is fine to use a
21308c2ecf20Sopenharmony_ci	 * non-resolvable private address.
21318c2ecf20Sopenharmony_ci	 */
21328c2ecf20Sopenharmony_ci	err = hci_get_random_address(hdev, !connectable,
21338c2ecf20Sopenharmony_ci				     adv_use_rpa(hdev, flags), adv_instance,
21348c2ecf20Sopenharmony_ci				     &own_addr_type, &random_addr);
21358c2ecf20Sopenharmony_ci	if (err < 0)
21368c2ecf20Sopenharmony_ci		return err;
21378c2ecf20Sopenharmony_ci
21388c2ecf20Sopenharmony_ci	memset(&cp, 0, sizeof(cp));
21398c2ecf20Sopenharmony_ci
21408c2ecf20Sopenharmony_ci	/* In ext adv set param interval is 3 octets */
21418c2ecf20Sopenharmony_ci	hci_cpu_to_le24(hdev->le_adv_min_interval, cp.min_interval);
21428c2ecf20Sopenharmony_ci	hci_cpu_to_le24(hdev->le_adv_max_interval, cp.max_interval);
21438c2ecf20Sopenharmony_ci
21448c2ecf20Sopenharmony_ci	secondary_adv = (flags & MGMT_ADV_FLAG_SEC_MASK);
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_ci	if (connectable) {
21478c2ecf20Sopenharmony_ci		if (secondary_adv)
21488c2ecf20Sopenharmony_ci			cp.evt_properties = cpu_to_le16(LE_EXT_ADV_CONN_IND);
21498c2ecf20Sopenharmony_ci		else
21508c2ecf20Sopenharmony_ci			cp.evt_properties = cpu_to_le16(LE_LEGACY_ADV_IND);
21518c2ecf20Sopenharmony_ci	} else if (get_adv_instance_scan_rsp_len(hdev, instance)) {
21528c2ecf20Sopenharmony_ci		if (secondary_adv)
21538c2ecf20Sopenharmony_ci			cp.evt_properties = cpu_to_le16(LE_EXT_ADV_SCAN_IND);
21548c2ecf20Sopenharmony_ci		else
21558c2ecf20Sopenharmony_ci			cp.evt_properties = cpu_to_le16(LE_LEGACY_ADV_SCAN_IND);
21568c2ecf20Sopenharmony_ci	} else {
21578c2ecf20Sopenharmony_ci		if (secondary_adv)
21588c2ecf20Sopenharmony_ci			cp.evt_properties = cpu_to_le16(LE_EXT_ADV_NON_CONN_IND);
21598c2ecf20Sopenharmony_ci		else
21608c2ecf20Sopenharmony_ci			cp.evt_properties = cpu_to_le16(LE_LEGACY_NONCONN_IND);
21618c2ecf20Sopenharmony_ci	}
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_ci	cp.own_addr_type = own_addr_type;
21648c2ecf20Sopenharmony_ci	cp.channel_map = hdev->le_adv_channel_map;
21658c2ecf20Sopenharmony_ci	cp.tx_power = 127;
21668c2ecf20Sopenharmony_ci	cp.handle = instance;
21678c2ecf20Sopenharmony_ci
21688c2ecf20Sopenharmony_ci	if (flags & MGMT_ADV_FLAG_SEC_2M) {
21698c2ecf20Sopenharmony_ci		cp.primary_phy = HCI_ADV_PHY_1M;
21708c2ecf20Sopenharmony_ci		cp.secondary_phy = HCI_ADV_PHY_2M;
21718c2ecf20Sopenharmony_ci	} else if (flags & MGMT_ADV_FLAG_SEC_CODED) {
21728c2ecf20Sopenharmony_ci		cp.primary_phy = HCI_ADV_PHY_CODED;
21738c2ecf20Sopenharmony_ci		cp.secondary_phy = HCI_ADV_PHY_CODED;
21748c2ecf20Sopenharmony_ci	} else {
21758c2ecf20Sopenharmony_ci		/* In all other cases use 1M */
21768c2ecf20Sopenharmony_ci		cp.primary_phy = HCI_ADV_PHY_1M;
21778c2ecf20Sopenharmony_ci		cp.secondary_phy = HCI_ADV_PHY_1M;
21788c2ecf20Sopenharmony_ci	}
21798c2ecf20Sopenharmony_ci
21808c2ecf20Sopenharmony_ci	hci_req_add(req, HCI_OP_LE_SET_EXT_ADV_PARAMS, sizeof(cp), &cp);
21818c2ecf20Sopenharmony_ci
21828c2ecf20Sopenharmony_ci	if (own_addr_type == ADDR_LE_DEV_RANDOM &&
21838c2ecf20Sopenharmony_ci	    bacmp(&random_addr, BDADDR_ANY)) {
21848c2ecf20Sopenharmony_ci		struct hci_cp_le_set_adv_set_rand_addr cp;
21858c2ecf20Sopenharmony_ci
21868c2ecf20Sopenharmony_ci		/* Check if random address need to be updated */
21878c2ecf20Sopenharmony_ci		if (adv_instance) {
21888c2ecf20Sopenharmony_ci			if (!bacmp(&random_addr, &adv_instance->random_addr))
21898c2ecf20Sopenharmony_ci				return 0;
21908c2ecf20Sopenharmony_ci		} else {
21918c2ecf20Sopenharmony_ci			if (!bacmp(&random_addr, &hdev->random_addr))
21928c2ecf20Sopenharmony_ci				return 0;
21938c2ecf20Sopenharmony_ci		}
21948c2ecf20Sopenharmony_ci
21958c2ecf20Sopenharmony_ci		memset(&cp, 0, sizeof(cp));
21968c2ecf20Sopenharmony_ci
21978c2ecf20Sopenharmony_ci		cp.handle = instance;
21988c2ecf20Sopenharmony_ci		bacpy(&cp.bdaddr, &random_addr);
21998c2ecf20Sopenharmony_ci
22008c2ecf20Sopenharmony_ci		hci_req_add(req,
22018c2ecf20Sopenharmony_ci			    HCI_OP_LE_SET_ADV_SET_RAND_ADDR,
22028c2ecf20Sopenharmony_ci			    sizeof(cp), &cp);
22038c2ecf20Sopenharmony_ci	}
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_ci	return 0;
22068c2ecf20Sopenharmony_ci}
22078c2ecf20Sopenharmony_ci
22088c2ecf20Sopenharmony_ciint __hci_req_enable_ext_advertising(struct hci_request *req, u8 instance)
22098c2ecf20Sopenharmony_ci{
22108c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
22118c2ecf20Sopenharmony_ci	struct hci_cp_le_set_ext_adv_enable *cp;
22128c2ecf20Sopenharmony_ci	struct hci_cp_ext_adv_set *adv_set;
22138c2ecf20Sopenharmony_ci	u8 data[sizeof(*cp) + sizeof(*adv_set) * 1];
22148c2ecf20Sopenharmony_ci	struct adv_info *adv_instance;
22158c2ecf20Sopenharmony_ci
22168c2ecf20Sopenharmony_ci	if (instance > 0) {
22178c2ecf20Sopenharmony_ci		adv_instance = hci_find_adv_instance(hdev, instance);
22188c2ecf20Sopenharmony_ci		if (!adv_instance)
22198c2ecf20Sopenharmony_ci			return -EINVAL;
22208c2ecf20Sopenharmony_ci	} else {
22218c2ecf20Sopenharmony_ci		adv_instance = NULL;
22228c2ecf20Sopenharmony_ci	}
22238c2ecf20Sopenharmony_ci
22248c2ecf20Sopenharmony_ci	cp = (void *) data;
22258c2ecf20Sopenharmony_ci	adv_set = (void *) cp->data;
22268c2ecf20Sopenharmony_ci
22278c2ecf20Sopenharmony_ci	memset(cp, 0, sizeof(*cp));
22288c2ecf20Sopenharmony_ci
22298c2ecf20Sopenharmony_ci	cp->enable = 0x01;
22308c2ecf20Sopenharmony_ci	cp->num_of_sets = 0x01;
22318c2ecf20Sopenharmony_ci
22328c2ecf20Sopenharmony_ci	memset(adv_set, 0, sizeof(*adv_set));
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_ci	adv_set->handle = instance;
22358c2ecf20Sopenharmony_ci
22368c2ecf20Sopenharmony_ci	/* Set duration per instance since controller is responsible for
22378c2ecf20Sopenharmony_ci	 * scheduling it.
22388c2ecf20Sopenharmony_ci	 */
22398c2ecf20Sopenharmony_ci	if (adv_instance && adv_instance->timeout) {
22408c2ecf20Sopenharmony_ci		u16 duration = adv_instance->timeout * MSEC_PER_SEC;
22418c2ecf20Sopenharmony_ci
22428c2ecf20Sopenharmony_ci		/* Time = N * 10 ms */
22438c2ecf20Sopenharmony_ci		adv_set->duration = cpu_to_le16(duration / 10);
22448c2ecf20Sopenharmony_ci	}
22458c2ecf20Sopenharmony_ci
22468c2ecf20Sopenharmony_ci	hci_req_add(req, HCI_OP_LE_SET_EXT_ADV_ENABLE,
22478c2ecf20Sopenharmony_ci		    sizeof(*cp) + sizeof(*adv_set) * cp->num_of_sets,
22488c2ecf20Sopenharmony_ci		    data);
22498c2ecf20Sopenharmony_ci
22508c2ecf20Sopenharmony_ci	return 0;
22518c2ecf20Sopenharmony_ci}
22528c2ecf20Sopenharmony_ci
22538c2ecf20Sopenharmony_ciint __hci_req_disable_ext_adv_instance(struct hci_request *req, u8 instance)
22548c2ecf20Sopenharmony_ci{
22558c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
22568c2ecf20Sopenharmony_ci	struct hci_cp_le_set_ext_adv_enable *cp;
22578c2ecf20Sopenharmony_ci	struct hci_cp_ext_adv_set *adv_set;
22588c2ecf20Sopenharmony_ci	u8 data[sizeof(*cp) + sizeof(*adv_set) * 1];
22598c2ecf20Sopenharmony_ci	u8 req_size;
22608c2ecf20Sopenharmony_ci
22618c2ecf20Sopenharmony_ci	/* If request specifies an instance that doesn't exist, fail */
22628c2ecf20Sopenharmony_ci	if (instance > 0 && !hci_find_adv_instance(hdev, instance))
22638c2ecf20Sopenharmony_ci		return -EINVAL;
22648c2ecf20Sopenharmony_ci
22658c2ecf20Sopenharmony_ci	memset(data, 0, sizeof(data));
22668c2ecf20Sopenharmony_ci
22678c2ecf20Sopenharmony_ci	cp = (void *)data;
22688c2ecf20Sopenharmony_ci	adv_set = (void *)cp->data;
22698c2ecf20Sopenharmony_ci
22708c2ecf20Sopenharmony_ci	/* Instance 0x00 indicates all advertising instances will be disabled */
22718c2ecf20Sopenharmony_ci	cp->num_of_sets = !!instance;
22728c2ecf20Sopenharmony_ci	cp->enable = 0x00;
22738c2ecf20Sopenharmony_ci
22748c2ecf20Sopenharmony_ci	adv_set->handle = instance;
22758c2ecf20Sopenharmony_ci
22768c2ecf20Sopenharmony_ci	req_size = sizeof(*cp) + sizeof(*adv_set) * cp->num_of_sets;
22778c2ecf20Sopenharmony_ci	hci_req_add(req, HCI_OP_LE_SET_EXT_ADV_ENABLE, req_size, data);
22788c2ecf20Sopenharmony_ci
22798c2ecf20Sopenharmony_ci	return 0;
22808c2ecf20Sopenharmony_ci}
22818c2ecf20Sopenharmony_ci
22828c2ecf20Sopenharmony_ciint __hci_req_remove_ext_adv_instance(struct hci_request *req, u8 instance)
22838c2ecf20Sopenharmony_ci{
22848c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
22858c2ecf20Sopenharmony_ci
22868c2ecf20Sopenharmony_ci	/* If request specifies an instance that doesn't exist, fail */
22878c2ecf20Sopenharmony_ci	if (instance > 0 && !hci_find_adv_instance(hdev, instance))
22888c2ecf20Sopenharmony_ci		return -EINVAL;
22898c2ecf20Sopenharmony_ci
22908c2ecf20Sopenharmony_ci	hci_req_add(req, HCI_OP_LE_REMOVE_ADV_SET, sizeof(instance), &instance);
22918c2ecf20Sopenharmony_ci
22928c2ecf20Sopenharmony_ci	return 0;
22938c2ecf20Sopenharmony_ci}
22948c2ecf20Sopenharmony_ci
22958c2ecf20Sopenharmony_ciint __hci_req_start_ext_adv(struct hci_request *req, u8 instance)
22968c2ecf20Sopenharmony_ci{
22978c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
22988c2ecf20Sopenharmony_ci	struct adv_info *adv_instance = hci_find_adv_instance(hdev, instance);
22998c2ecf20Sopenharmony_ci	int err;
23008c2ecf20Sopenharmony_ci
23018c2ecf20Sopenharmony_ci	/* If instance isn't pending, the chip knows about it, and it's safe to
23028c2ecf20Sopenharmony_ci	 * disable
23038c2ecf20Sopenharmony_ci	 */
23048c2ecf20Sopenharmony_ci	if (adv_instance && !adv_instance->pending)
23058c2ecf20Sopenharmony_ci		__hci_req_disable_ext_adv_instance(req, instance);
23068c2ecf20Sopenharmony_ci
23078c2ecf20Sopenharmony_ci	err = __hci_req_setup_ext_adv_instance(req, instance);
23088c2ecf20Sopenharmony_ci	if (err < 0)
23098c2ecf20Sopenharmony_ci		return err;
23108c2ecf20Sopenharmony_ci
23118c2ecf20Sopenharmony_ci	__hci_req_update_scan_rsp_data(req, instance);
23128c2ecf20Sopenharmony_ci	__hci_req_enable_ext_advertising(req, instance);
23138c2ecf20Sopenharmony_ci
23148c2ecf20Sopenharmony_ci	return 0;
23158c2ecf20Sopenharmony_ci}
23168c2ecf20Sopenharmony_ci
23178c2ecf20Sopenharmony_ciint __hci_req_schedule_adv_instance(struct hci_request *req, u8 instance,
23188c2ecf20Sopenharmony_ci				    bool force)
23198c2ecf20Sopenharmony_ci{
23208c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
23218c2ecf20Sopenharmony_ci	struct adv_info *adv_instance = NULL;
23228c2ecf20Sopenharmony_ci	u16 timeout;
23238c2ecf20Sopenharmony_ci
23248c2ecf20Sopenharmony_ci	if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
23258c2ecf20Sopenharmony_ci	    list_empty(&hdev->adv_instances))
23268c2ecf20Sopenharmony_ci		return -EPERM;
23278c2ecf20Sopenharmony_ci
23288c2ecf20Sopenharmony_ci	if (hdev->adv_instance_timeout)
23298c2ecf20Sopenharmony_ci		return -EBUSY;
23308c2ecf20Sopenharmony_ci
23318c2ecf20Sopenharmony_ci	adv_instance = hci_find_adv_instance(hdev, instance);
23328c2ecf20Sopenharmony_ci	if (!adv_instance)
23338c2ecf20Sopenharmony_ci		return -ENOENT;
23348c2ecf20Sopenharmony_ci
23358c2ecf20Sopenharmony_ci	/* A zero timeout means unlimited advertising. As long as there is
23368c2ecf20Sopenharmony_ci	 * only one instance, duration should be ignored. We still set a timeout
23378c2ecf20Sopenharmony_ci	 * in case further instances are being added later on.
23388c2ecf20Sopenharmony_ci	 *
23398c2ecf20Sopenharmony_ci	 * If the remaining lifetime of the instance is more than the duration
23408c2ecf20Sopenharmony_ci	 * then the timeout corresponds to the duration, otherwise it will be
23418c2ecf20Sopenharmony_ci	 * reduced to the remaining instance lifetime.
23428c2ecf20Sopenharmony_ci	 */
23438c2ecf20Sopenharmony_ci	if (adv_instance->timeout == 0 ||
23448c2ecf20Sopenharmony_ci	    adv_instance->duration <= adv_instance->remaining_time)
23458c2ecf20Sopenharmony_ci		timeout = adv_instance->duration;
23468c2ecf20Sopenharmony_ci	else
23478c2ecf20Sopenharmony_ci		timeout = adv_instance->remaining_time;
23488c2ecf20Sopenharmony_ci
23498c2ecf20Sopenharmony_ci	/* The remaining time is being reduced unless the instance is being
23508c2ecf20Sopenharmony_ci	 * advertised without time limit.
23518c2ecf20Sopenharmony_ci	 */
23528c2ecf20Sopenharmony_ci	if (adv_instance->timeout)
23538c2ecf20Sopenharmony_ci		adv_instance->remaining_time =
23548c2ecf20Sopenharmony_ci				adv_instance->remaining_time - timeout;
23558c2ecf20Sopenharmony_ci
23568c2ecf20Sopenharmony_ci	/* Only use work for scheduling instances with legacy advertising */
23578c2ecf20Sopenharmony_ci	if (!ext_adv_capable(hdev)) {
23588c2ecf20Sopenharmony_ci		hdev->adv_instance_timeout = timeout;
23598c2ecf20Sopenharmony_ci		queue_delayed_work(hdev->req_workqueue,
23608c2ecf20Sopenharmony_ci			   &hdev->adv_instance_expire,
23618c2ecf20Sopenharmony_ci			   msecs_to_jiffies(timeout * 1000));
23628c2ecf20Sopenharmony_ci	}
23638c2ecf20Sopenharmony_ci
23648c2ecf20Sopenharmony_ci	/* If we're just re-scheduling the same instance again then do not
23658c2ecf20Sopenharmony_ci	 * execute any HCI commands. This happens when a single instance is
23668c2ecf20Sopenharmony_ci	 * being advertised.
23678c2ecf20Sopenharmony_ci	 */
23688c2ecf20Sopenharmony_ci	if (!force && hdev->cur_adv_instance == instance &&
23698c2ecf20Sopenharmony_ci	    hci_dev_test_flag(hdev, HCI_LE_ADV))
23708c2ecf20Sopenharmony_ci		return 0;
23718c2ecf20Sopenharmony_ci
23728c2ecf20Sopenharmony_ci	hdev->cur_adv_instance = instance;
23738c2ecf20Sopenharmony_ci	if (ext_adv_capable(hdev)) {
23748c2ecf20Sopenharmony_ci		__hci_req_start_ext_adv(req, instance);
23758c2ecf20Sopenharmony_ci	} else {
23768c2ecf20Sopenharmony_ci		__hci_req_update_adv_data(req, instance);
23778c2ecf20Sopenharmony_ci		__hci_req_update_scan_rsp_data(req, instance);
23788c2ecf20Sopenharmony_ci		__hci_req_enable_advertising(req);
23798c2ecf20Sopenharmony_ci	}
23808c2ecf20Sopenharmony_ci
23818c2ecf20Sopenharmony_ci	return 0;
23828c2ecf20Sopenharmony_ci}
23838c2ecf20Sopenharmony_ci
23848c2ecf20Sopenharmony_ci/* For a single instance:
23858c2ecf20Sopenharmony_ci * - force == true: The instance will be removed even when its remaining
23868c2ecf20Sopenharmony_ci *   lifetime is not zero.
23878c2ecf20Sopenharmony_ci * - force == false: the instance will be deactivated but kept stored unless
23888c2ecf20Sopenharmony_ci *   the remaining lifetime is zero.
23898c2ecf20Sopenharmony_ci *
23908c2ecf20Sopenharmony_ci * For instance == 0x00:
23918c2ecf20Sopenharmony_ci * - force == true: All instances will be removed regardless of their timeout
23928c2ecf20Sopenharmony_ci *   setting.
23938c2ecf20Sopenharmony_ci * - force == false: Only instances that have a timeout will be removed.
23948c2ecf20Sopenharmony_ci */
23958c2ecf20Sopenharmony_civoid hci_req_clear_adv_instance(struct hci_dev *hdev, struct sock *sk,
23968c2ecf20Sopenharmony_ci				struct hci_request *req, u8 instance,
23978c2ecf20Sopenharmony_ci				bool force)
23988c2ecf20Sopenharmony_ci{
23998c2ecf20Sopenharmony_ci	struct adv_info *adv_instance, *n, *next_instance = NULL;
24008c2ecf20Sopenharmony_ci	int err;
24018c2ecf20Sopenharmony_ci	u8 rem_inst;
24028c2ecf20Sopenharmony_ci
24038c2ecf20Sopenharmony_ci	/* Cancel any timeout concerning the removed instance(s). */
24048c2ecf20Sopenharmony_ci	if (!instance || hdev->cur_adv_instance == instance)
24058c2ecf20Sopenharmony_ci		cancel_adv_timeout(hdev);
24068c2ecf20Sopenharmony_ci
24078c2ecf20Sopenharmony_ci	/* Get the next instance to advertise BEFORE we remove
24088c2ecf20Sopenharmony_ci	 * the current one. This can be the same instance again
24098c2ecf20Sopenharmony_ci	 * if there is only one instance.
24108c2ecf20Sopenharmony_ci	 */
24118c2ecf20Sopenharmony_ci	if (instance && hdev->cur_adv_instance == instance)
24128c2ecf20Sopenharmony_ci		next_instance = hci_get_next_instance(hdev, instance);
24138c2ecf20Sopenharmony_ci
24148c2ecf20Sopenharmony_ci	if (instance == 0x00) {
24158c2ecf20Sopenharmony_ci		list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances,
24168c2ecf20Sopenharmony_ci					 list) {
24178c2ecf20Sopenharmony_ci			if (!(force || adv_instance->timeout))
24188c2ecf20Sopenharmony_ci				continue;
24198c2ecf20Sopenharmony_ci
24208c2ecf20Sopenharmony_ci			rem_inst = adv_instance->instance;
24218c2ecf20Sopenharmony_ci			err = hci_remove_adv_instance(hdev, rem_inst);
24228c2ecf20Sopenharmony_ci			if (!err)
24238c2ecf20Sopenharmony_ci				mgmt_advertising_removed(sk, hdev, rem_inst);
24248c2ecf20Sopenharmony_ci		}
24258c2ecf20Sopenharmony_ci	} else {
24268c2ecf20Sopenharmony_ci		adv_instance = hci_find_adv_instance(hdev, instance);
24278c2ecf20Sopenharmony_ci
24288c2ecf20Sopenharmony_ci		if (force || (adv_instance && adv_instance->timeout &&
24298c2ecf20Sopenharmony_ci			      !adv_instance->remaining_time)) {
24308c2ecf20Sopenharmony_ci			/* Don't advertise a removed instance. */
24318c2ecf20Sopenharmony_ci			if (next_instance &&
24328c2ecf20Sopenharmony_ci			    next_instance->instance == instance)
24338c2ecf20Sopenharmony_ci				next_instance = NULL;
24348c2ecf20Sopenharmony_ci
24358c2ecf20Sopenharmony_ci			err = hci_remove_adv_instance(hdev, instance);
24368c2ecf20Sopenharmony_ci			if (!err)
24378c2ecf20Sopenharmony_ci				mgmt_advertising_removed(sk, hdev, instance);
24388c2ecf20Sopenharmony_ci		}
24398c2ecf20Sopenharmony_ci	}
24408c2ecf20Sopenharmony_ci
24418c2ecf20Sopenharmony_ci	if (!req || !hdev_is_powered(hdev) ||
24428c2ecf20Sopenharmony_ci	    hci_dev_test_flag(hdev, HCI_ADVERTISING))
24438c2ecf20Sopenharmony_ci		return;
24448c2ecf20Sopenharmony_ci
24458c2ecf20Sopenharmony_ci	if (next_instance && !ext_adv_capable(hdev))
24468c2ecf20Sopenharmony_ci		__hci_req_schedule_adv_instance(req, next_instance->instance,
24478c2ecf20Sopenharmony_ci						false);
24488c2ecf20Sopenharmony_ci}
24498c2ecf20Sopenharmony_ci
24508c2ecf20Sopenharmony_cistatic void set_random_addr(struct hci_request *req, bdaddr_t *rpa)
24518c2ecf20Sopenharmony_ci{
24528c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
24538c2ecf20Sopenharmony_ci
24548c2ecf20Sopenharmony_ci	/* If we're advertising or initiating an LE connection we can't
24558c2ecf20Sopenharmony_ci	 * go ahead and change the random address at this time. This is
24568c2ecf20Sopenharmony_ci	 * because the eventual initiator address used for the
24578c2ecf20Sopenharmony_ci	 * subsequently created connection will be undefined (some
24588c2ecf20Sopenharmony_ci	 * controllers use the new address and others the one we had
24598c2ecf20Sopenharmony_ci	 * when the operation started).
24608c2ecf20Sopenharmony_ci	 *
24618c2ecf20Sopenharmony_ci	 * In this kind of scenario skip the update and let the random
24628c2ecf20Sopenharmony_ci	 * address be updated at the next cycle.
24638c2ecf20Sopenharmony_ci	 */
24648c2ecf20Sopenharmony_ci	if (hci_dev_test_flag(hdev, HCI_LE_ADV) ||
24658c2ecf20Sopenharmony_ci	    hci_lookup_le_connect(hdev)) {
24668c2ecf20Sopenharmony_ci		BT_DBG("Deferring random address update");
24678c2ecf20Sopenharmony_ci		hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
24688c2ecf20Sopenharmony_ci		return;
24698c2ecf20Sopenharmony_ci	}
24708c2ecf20Sopenharmony_ci
24718c2ecf20Sopenharmony_ci	hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6, rpa);
24728c2ecf20Sopenharmony_ci}
24738c2ecf20Sopenharmony_ci
24748c2ecf20Sopenharmony_ciint hci_update_random_address(struct hci_request *req, bool require_privacy,
24758c2ecf20Sopenharmony_ci			      bool use_rpa, u8 *own_addr_type)
24768c2ecf20Sopenharmony_ci{
24778c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
24788c2ecf20Sopenharmony_ci	int err;
24798c2ecf20Sopenharmony_ci
24808c2ecf20Sopenharmony_ci	/* If privacy is enabled use a resolvable private address. If
24818c2ecf20Sopenharmony_ci	 * current RPA has expired or there is something else than
24828c2ecf20Sopenharmony_ci	 * the current RPA in use, then generate a new one.
24838c2ecf20Sopenharmony_ci	 */
24848c2ecf20Sopenharmony_ci	if (use_rpa) {
24858c2ecf20Sopenharmony_ci		int to;
24868c2ecf20Sopenharmony_ci
24878c2ecf20Sopenharmony_ci		/* If Controller supports LL Privacy use own address type is
24888c2ecf20Sopenharmony_ci		 * 0x03
24898c2ecf20Sopenharmony_ci		 */
24908c2ecf20Sopenharmony_ci		if (use_ll_privacy(hdev))
24918c2ecf20Sopenharmony_ci			*own_addr_type = ADDR_LE_DEV_RANDOM_RESOLVED;
24928c2ecf20Sopenharmony_ci		else
24938c2ecf20Sopenharmony_ci			*own_addr_type = ADDR_LE_DEV_RANDOM;
24948c2ecf20Sopenharmony_ci
24958c2ecf20Sopenharmony_ci		if (!hci_dev_test_and_clear_flag(hdev, HCI_RPA_EXPIRED) &&
24968c2ecf20Sopenharmony_ci		    !bacmp(&hdev->random_addr, &hdev->rpa))
24978c2ecf20Sopenharmony_ci			return 0;
24988c2ecf20Sopenharmony_ci
24998c2ecf20Sopenharmony_ci		err = smp_generate_rpa(hdev, hdev->irk, &hdev->rpa);
25008c2ecf20Sopenharmony_ci		if (err < 0) {
25018c2ecf20Sopenharmony_ci			bt_dev_err(hdev, "failed to generate new RPA");
25028c2ecf20Sopenharmony_ci			return err;
25038c2ecf20Sopenharmony_ci		}
25048c2ecf20Sopenharmony_ci
25058c2ecf20Sopenharmony_ci		set_random_addr(req, &hdev->rpa);
25068c2ecf20Sopenharmony_ci
25078c2ecf20Sopenharmony_ci		to = msecs_to_jiffies(hdev->rpa_timeout * 1000);
25088c2ecf20Sopenharmony_ci		queue_delayed_work(hdev->workqueue, &hdev->rpa_expired, to);
25098c2ecf20Sopenharmony_ci
25108c2ecf20Sopenharmony_ci		return 0;
25118c2ecf20Sopenharmony_ci	}
25128c2ecf20Sopenharmony_ci
25138c2ecf20Sopenharmony_ci	/* In case of required privacy without resolvable private address,
25148c2ecf20Sopenharmony_ci	 * use an non-resolvable private address. This is useful for active
25158c2ecf20Sopenharmony_ci	 * scanning and non-connectable advertising.
25168c2ecf20Sopenharmony_ci	 */
25178c2ecf20Sopenharmony_ci	if (require_privacy) {
25188c2ecf20Sopenharmony_ci		bdaddr_t nrpa;
25198c2ecf20Sopenharmony_ci
25208c2ecf20Sopenharmony_ci		while (true) {
25218c2ecf20Sopenharmony_ci			/* The non-resolvable private address is generated
25228c2ecf20Sopenharmony_ci			 * from random six bytes with the two most significant
25238c2ecf20Sopenharmony_ci			 * bits cleared.
25248c2ecf20Sopenharmony_ci			 */
25258c2ecf20Sopenharmony_ci			get_random_bytes(&nrpa, 6);
25268c2ecf20Sopenharmony_ci			nrpa.b[5] &= 0x3f;
25278c2ecf20Sopenharmony_ci
25288c2ecf20Sopenharmony_ci			/* The non-resolvable private address shall not be
25298c2ecf20Sopenharmony_ci			 * equal to the public address.
25308c2ecf20Sopenharmony_ci			 */
25318c2ecf20Sopenharmony_ci			if (bacmp(&hdev->bdaddr, &nrpa))
25328c2ecf20Sopenharmony_ci				break;
25338c2ecf20Sopenharmony_ci		}
25348c2ecf20Sopenharmony_ci
25358c2ecf20Sopenharmony_ci		*own_addr_type = ADDR_LE_DEV_RANDOM;
25368c2ecf20Sopenharmony_ci		set_random_addr(req, &nrpa);
25378c2ecf20Sopenharmony_ci		return 0;
25388c2ecf20Sopenharmony_ci	}
25398c2ecf20Sopenharmony_ci
25408c2ecf20Sopenharmony_ci	/* If forcing static address is in use or there is no public
25418c2ecf20Sopenharmony_ci	 * address use the static address as random address (but skip
25428c2ecf20Sopenharmony_ci	 * the HCI command if the current random address is already the
25438c2ecf20Sopenharmony_ci	 * static one.
25448c2ecf20Sopenharmony_ci	 *
25458c2ecf20Sopenharmony_ci	 * In case BR/EDR has been disabled on a dual-mode controller
25468c2ecf20Sopenharmony_ci	 * and a static address has been configured, then use that
25478c2ecf20Sopenharmony_ci	 * address instead of the public BR/EDR address.
25488c2ecf20Sopenharmony_ci	 */
25498c2ecf20Sopenharmony_ci	if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
25508c2ecf20Sopenharmony_ci	    !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
25518c2ecf20Sopenharmony_ci	    (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
25528c2ecf20Sopenharmony_ci	     bacmp(&hdev->static_addr, BDADDR_ANY))) {
25538c2ecf20Sopenharmony_ci		*own_addr_type = ADDR_LE_DEV_RANDOM;
25548c2ecf20Sopenharmony_ci		if (bacmp(&hdev->static_addr, &hdev->random_addr))
25558c2ecf20Sopenharmony_ci			hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
25568c2ecf20Sopenharmony_ci				    &hdev->static_addr);
25578c2ecf20Sopenharmony_ci		return 0;
25588c2ecf20Sopenharmony_ci	}
25598c2ecf20Sopenharmony_ci
25608c2ecf20Sopenharmony_ci	/* Neither privacy nor static address is being used so use a
25618c2ecf20Sopenharmony_ci	 * public address.
25628c2ecf20Sopenharmony_ci	 */
25638c2ecf20Sopenharmony_ci	*own_addr_type = ADDR_LE_DEV_PUBLIC;
25648c2ecf20Sopenharmony_ci
25658c2ecf20Sopenharmony_ci	return 0;
25668c2ecf20Sopenharmony_ci}
25678c2ecf20Sopenharmony_ci
25688c2ecf20Sopenharmony_cistatic bool disconnected_accept_list_entries(struct hci_dev *hdev)
25698c2ecf20Sopenharmony_ci{
25708c2ecf20Sopenharmony_ci	struct bdaddr_list *b;
25718c2ecf20Sopenharmony_ci
25728c2ecf20Sopenharmony_ci	list_for_each_entry(b, &hdev->accept_list, list) {
25738c2ecf20Sopenharmony_ci		struct hci_conn *conn;
25748c2ecf20Sopenharmony_ci
25758c2ecf20Sopenharmony_ci		conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &b->bdaddr);
25768c2ecf20Sopenharmony_ci		if (!conn)
25778c2ecf20Sopenharmony_ci			return true;
25788c2ecf20Sopenharmony_ci
25798c2ecf20Sopenharmony_ci		if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
25808c2ecf20Sopenharmony_ci			return true;
25818c2ecf20Sopenharmony_ci	}
25828c2ecf20Sopenharmony_ci
25838c2ecf20Sopenharmony_ci	return false;
25848c2ecf20Sopenharmony_ci}
25858c2ecf20Sopenharmony_ci
25868c2ecf20Sopenharmony_civoid __hci_req_update_scan(struct hci_request *req)
25878c2ecf20Sopenharmony_ci{
25888c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
25898c2ecf20Sopenharmony_ci	u8 scan;
25908c2ecf20Sopenharmony_ci
25918c2ecf20Sopenharmony_ci	if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
25928c2ecf20Sopenharmony_ci		return;
25938c2ecf20Sopenharmony_ci
25948c2ecf20Sopenharmony_ci	if (!hdev_is_powered(hdev))
25958c2ecf20Sopenharmony_ci		return;
25968c2ecf20Sopenharmony_ci
25978c2ecf20Sopenharmony_ci	if (mgmt_powering_down(hdev))
25988c2ecf20Sopenharmony_ci		return;
25998c2ecf20Sopenharmony_ci
26008c2ecf20Sopenharmony_ci	if (hdev->scanning_paused)
26018c2ecf20Sopenharmony_ci		return;
26028c2ecf20Sopenharmony_ci
26038c2ecf20Sopenharmony_ci	if (hci_dev_test_flag(hdev, HCI_CONNECTABLE) ||
26048c2ecf20Sopenharmony_ci	    disconnected_accept_list_entries(hdev))
26058c2ecf20Sopenharmony_ci		scan = SCAN_PAGE;
26068c2ecf20Sopenharmony_ci	else
26078c2ecf20Sopenharmony_ci		scan = SCAN_DISABLED;
26088c2ecf20Sopenharmony_ci
26098c2ecf20Sopenharmony_ci	if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
26108c2ecf20Sopenharmony_ci		scan |= SCAN_INQUIRY;
26118c2ecf20Sopenharmony_ci
26128c2ecf20Sopenharmony_ci	if (test_bit(HCI_PSCAN, &hdev->flags) == !!(scan & SCAN_PAGE) &&
26138c2ecf20Sopenharmony_ci	    test_bit(HCI_ISCAN, &hdev->flags) == !!(scan & SCAN_INQUIRY))
26148c2ecf20Sopenharmony_ci		return;
26158c2ecf20Sopenharmony_ci
26168c2ecf20Sopenharmony_ci	hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
26178c2ecf20Sopenharmony_ci}
26188c2ecf20Sopenharmony_ci
26198c2ecf20Sopenharmony_cistatic int update_scan(struct hci_request *req, unsigned long opt)
26208c2ecf20Sopenharmony_ci{
26218c2ecf20Sopenharmony_ci	hci_dev_lock(req->hdev);
26228c2ecf20Sopenharmony_ci	__hci_req_update_scan(req);
26238c2ecf20Sopenharmony_ci	hci_dev_unlock(req->hdev);
26248c2ecf20Sopenharmony_ci	return 0;
26258c2ecf20Sopenharmony_ci}
26268c2ecf20Sopenharmony_ci
26278c2ecf20Sopenharmony_cistatic void scan_update_work(struct work_struct *work)
26288c2ecf20Sopenharmony_ci{
26298c2ecf20Sopenharmony_ci	struct hci_dev *hdev = container_of(work, struct hci_dev, scan_update);
26308c2ecf20Sopenharmony_ci
26318c2ecf20Sopenharmony_ci	hci_req_sync(hdev, update_scan, 0, HCI_CMD_TIMEOUT, NULL);
26328c2ecf20Sopenharmony_ci}
26338c2ecf20Sopenharmony_ci
26348c2ecf20Sopenharmony_cistatic int connectable_update(struct hci_request *req, unsigned long opt)
26358c2ecf20Sopenharmony_ci{
26368c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
26378c2ecf20Sopenharmony_ci
26388c2ecf20Sopenharmony_ci	hci_dev_lock(hdev);
26398c2ecf20Sopenharmony_ci
26408c2ecf20Sopenharmony_ci	__hci_req_update_scan(req);
26418c2ecf20Sopenharmony_ci
26428c2ecf20Sopenharmony_ci	/* If BR/EDR is not enabled and we disable advertising as a
26438c2ecf20Sopenharmony_ci	 * by-product of disabling connectable, we need to update the
26448c2ecf20Sopenharmony_ci	 * advertising flags.
26458c2ecf20Sopenharmony_ci	 */
26468c2ecf20Sopenharmony_ci	if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
26478c2ecf20Sopenharmony_ci		__hci_req_update_adv_data(req, hdev->cur_adv_instance);
26488c2ecf20Sopenharmony_ci
26498c2ecf20Sopenharmony_ci	/* Update the advertising parameters if necessary */
26508c2ecf20Sopenharmony_ci	if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
26518c2ecf20Sopenharmony_ci	    !list_empty(&hdev->adv_instances)) {
26528c2ecf20Sopenharmony_ci		if (ext_adv_capable(hdev))
26538c2ecf20Sopenharmony_ci			__hci_req_start_ext_adv(req, hdev->cur_adv_instance);
26548c2ecf20Sopenharmony_ci		else
26558c2ecf20Sopenharmony_ci			__hci_req_enable_advertising(req);
26568c2ecf20Sopenharmony_ci	}
26578c2ecf20Sopenharmony_ci
26588c2ecf20Sopenharmony_ci	__hci_update_background_scan(req);
26598c2ecf20Sopenharmony_ci
26608c2ecf20Sopenharmony_ci	hci_dev_unlock(hdev);
26618c2ecf20Sopenharmony_ci
26628c2ecf20Sopenharmony_ci	return 0;
26638c2ecf20Sopenharmony_ci}
26648c2ecf20Sopenharmony_ci
26658c2ecf20Sopenharmony_cistatic void connectable_update_work(struct work_struct *work)
26668c2ecf20Sopenharmony_ci{
26678c2ecf20Sopenharmony_ci	struct hci_dev *hdev = container_of(work, struct hci_dev,
26688c2ecf20Sopenharmony_ci					    connectable_update);
26698c2ecf20Sopenharmony_ci	u8 status;
26708c2ecf20Sopenharmony_ci
26718c2ecf20Sopenharmony_ci	hci_req_sync(hdev, connectable_update, 0, HCI_CMD_TIMEOUT, &status);
26728c2ecf20Sopenharmony_ci	mgmt_set_connectable_complete(hdev, status);
26738c2ecf20Sopenharmony_ci}
26748c2ecf20Sopenharmony_ci
26758c2ecf20Sopenharmony_cistatic u8 get_service_classes(struct hci_dev *hdev)
26768c2ecf20Sopenharmony_ci{
26778c2ecf20Sopenharmony_ci	struct bt_uuid *uuid;
26788c2ecf20Sopenharmony_ci	u8 val = 0;
26798c2ecf20Sopenharmony_ci
26808c2ecf20Sopenharmony_ci	list_for_each_entry(uuid, &hdev->uuids, list)
26818c2ecf20Sopenharmony_ci		val |= uuid->svc_hint;
26828c2ecf20Sopenharmony_ci
26838c2ecf20Sopenharmony_ci	return val;
26848c2ecf20Sopenharmony_ci}
26858c2ecf20Sopenharmony_ci
26868c2ecf20Sopenharmony_civoid __hci_req_update_class(struct hci_request *req)
26878c2ecf20Sopenharmony_ci{
26888c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
26898c2ecf20Sopenharmony_ci	u8 cod[3];
26908c2ecf20Sopenharmony_ci
26918c2ecf20Sopenharmony_ci	BT_DBG("%s", hdev->name);
26928c2ecf20Sopenharmony_ci
26938c2ecf20Sopenharmony_ci	if (!hdev_is_powered(hdev))
26948c2ecf20Sopenharmony_ci		return;
26958c2ecf20Sopenharmony_ci
26968c2ecf20Sopenharmony_ci	if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
26978c2ecf20Sopenharmony_ci		return;
26988c2ecf20Sopenharmony_ci
26998c2ecf20Sopenharmony_ci	if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
27008c2ecf20Sopenharmony_ci		return;
27018c2ecf20Sopenharmony_ci
27028c2ecf20Sopenharmony_ci	cod[0] = hdev->minor_class;
27038c2ecf20Sopenharmony_ci	cod[1] = hdev->major_class;
27048c2ecf20Sopenharmony_ci	cod[2] = get_service_classes(hdev);
27058c2ecf20Sopenharmony_ci
27068c2ecf20Sopenharmony_ci	if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
27078c2ecf20Sopenharmony_ci		cod[1] |= 0x20;
27088c2ecf20Sopenharmony_ci
27098c2ecf20Sopenharmony_ci	if (memcmp(cod, hdev->dev_class, 3) == 0)
27108c2ecf20Sopenharmony_ci		return;
27118c2ecf20Sopenharmony_ci
27128c2ecf20Sopenharmony_ci	hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
27138c2ecf20Sopenharmony_ci}
27148c2ecf20Sopenharmony_ci
27158c2ecf20Sopenharmony_cistatic void write_iac(struct hci_request *req)
27168c2ecf20Sopenharmony_ci{
27178c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
27188c2ecf20Sopenharmony_ci	struct hci_cp_write_current_iac_lap cp;
27198c2ecf20Sopenharmony_ci
27208c2ecf20Sopenharmony_ci	if (!hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
27218c2ecf20Sopenharmony_ci		return;
27228c2ecf20Sopenharmony_ci
27238c2ecf20Sopenharmony_ci	if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE)) {
27248c2ecf20Sopenharmony_ci		/* Limited discoverable mode */
27258c2ecf20Sopenharmony_ci		cp.num_iac = min_t(u8, hdev->num_iac, 2);
27268c2ecf20Sopenharmony_ci		cp.iac_lap[0] = 0x00;	/* LIAC */
27278c2ecf20Sopenharmony_ci		cp.iac_lap[1] = 0x8b;
27288c2ecf20Sopenharmony_ci		cp.iac_lap[2] = 0x9e;
27298c2ecf20Sopenharmony_ci		cp.iac_lap[3] = 0x33;	/* GIAC */
27308c2ecf20Sopenharmony_ci		cp.iac_lap[4] = 0x8b;
27318c2ecf20Sopenharmony_ci		cp.iac_lap[5] = 0x9e;
27328c2ecf20Sopenharmony_ci	} else {
27338c2ecf20Sopenharmony_ci		/* General discoverable mode */
27348c2ecf20Sopenharmony_ci		cp.num_iac = 1;
27358c2ecf20Sopenharmony_ci		cp.iac_lap[0] = 0x33;	/* GIAC */
27368c2ecf20Sopenharmony_ci		cp.iac_lap[1] = 0x8b;
27378c2ecf20Sopenharmony_ci		cp.iac_lap[2] = 0x9e;
27388c2ecf20Sopenharmony_ci	}
27398c2ecf20Sopenharmony_ci
27408c2ecf20Sopenharmony_ci	hci_req_add(req, HCI_OP_WRITE_CURRENT_IAC_LAP,
27418c2ecf20Sopenharmony_ci		    (cp.num_iac * 3) + 1, &cp);
27428c2ecf20Sopenharmony_ci}
27438c2ecf20Sopenharmony_ci
27448c2ecf20Sopenharmony_cistatic int discoverable_update(struct hci_request *req, unsigned long opt)
27458c2ecf20Sopenharmony_ci{
27468c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
27478c2ecf20Sopenharmony_ci
27488c2ecf20Sopenharmony_ci	hci_dev_lock(hdev);
27498c2ecf20Sopenharmony_ci
27508c2ecf20Sopenharmony_ci	if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
27518c2ecf20Sopenharmony_ci		write_iac(req);
27528c2ecf20Sopenharmony_ci		__hci_req_update_scan(req);
27538c2ecf20Sopenharmony_ci		__hci_req_update_class(req);
27548c2ecf20Sopenharmony_ci	}
27558c2ecf20Sopenharmony_ci
27568c2ecf20Sopenharmony_ci	/* Advertising instances don't use the global discoverable setting, so
27578c2ecf20Sopenharmony_ci	 * only update AD if advertising was enabled using Set Advertising.
27588c2ecf20Sopenharmony_ci	 */
27598c2ecf20Sopenharmony_ci	if (hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
27608c2ecf20Sopenharmony_ci		__hci_req_update_adv_data(req, 0x00);
27618c2ecf20Sopenharmony_ci
27628c2ecf20Sopenharmony_ci		/* Discoverable mode affects the local advertising
27638c2ecf20Sopenharmony_ci		 * address in limited privacy mode.
27648c2ecf20Sopenharmony_ci		 */
27658c2ecf20Sopenharmony_ci		if (hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY)) {
27668c2ecf20Sopenharmony_ci			if (ext_adv_capable(hdev))
27678c2ecf20Sopenharmony_ci				__hci_req_start_ext_adv(req, 0x00);
27688c2ecf20Sopenharmony_ci			else
27698c2ecf20Sopenharmony_ci				__hci_req_enable_advertising(req);
27708c2ecf20Sopenharmony_ci		}
27718c2ecf20Sopenharmony_ci	}
27728c2ecf20Sopenharmony_ci
27738c2ecf20Sopenharmony_ci	hci_dev_unlock(hdev);
27748c2ecf20Sopenharmony_ci
27758c2ecf20Sopenharmony_ci	return 0;
27768c2ecf20Sopenharmony_ci}
27778c2ecf20Sopenharmony_ci
27788c2ecf20Sopenharmony_cistatic void discoverable_update_work(struct work_struct *work)
27798c2ecf20Sopenharmony_ci{
27808c2ecf20Sopenharmony_ci	struct hci_dev *hdev = container_of(work, struct hci_dev,
27818c2ecf20Sopenharmony_ci					    discoverable_update);
27828c2ecf20Sopenharmony_ci	u8 status;
27838c2ecf20Sopenharmony_ci
27848c2ecf20Sopenharmony_ci	hci_req_sync(hdev, discoverable_update, 0, HCI_CMD_TIMEOUT, &status);
27858c2ecf20Sopenharmony_ci	mgmt_set_discoverable_complete(hdev, status);
27868c2ecf20Sopenharmony_ci}
27878c2ecf20Sopenharmony_ci
27888c2ecf20Sopenharmony_civoid __hci_abort_conn(struct hci_request *req, struct hci_conn *conn,
27898c2ecf20Sopenharmony_ci		      u8 reason)
27908c2ecf20Sopenharmony_ci{
27918c2ecf20Sopenharmony_ci	switch (conn->state) {
27928c2ecf20Sopenharmony_ci	case BT_CONNECTED:
27938c2ecf20Sopenharmony_ci	case BT_CONFIG:
27948c2ecf20Sopenharmony_ci		if (conn->type == AMP_LINK) {
27958c2ecf20Sopenharmony_ci			struct hci_cp_disconn_phy_link cp;
27968c2ecf20Sopenharmony_ci
27978c2ecf20Sopenharmony_ci			cp.phy_handle = HCI_PHY_HANDLE(conn->handle);
27988c2ecf20Sopenharmony_ci			cp.reason = reason;
27998c2ecf20Sopenharmony_ci			hci_req_add(req, HCI_OP_DISCONN_PHY_LINK, sizeof(cp),
28008c2ecf20Sopenharmony_ci				    &cp);
28018c2ecf20Sopenharmony_ci		} else {
28028c2ecf20Sopenharmony_ci			struct hci_cp_disconnect dc;
28038c2ecf20Sopenharmony_ci
28048c2ecf20Sopenharmony_ci			dc.handle = cpu_to_le16(conn->handle);
28058c2ecf20Sopenharmony_ci			dc.reason = reason;
28068c2ecf20Sopenharmony_ci			hci_req_add(req, HCI_OP_DISCONNECT, sizeof(dc), &dc);
28078c2ecf20Sopenharmony_ci		}
28088c2ecf20Sopenharmony_ci
28098c2ecf20Sopenharmony_ci		conn->state = BT_DISCONN;
28108c2ecf20Sopenharmony_ci
28118c2ecf20Sopenharmony_ci		break;
28128c2ecf20Sopenharmony_ci	case BT_CONNECT:
28138c2ecf20Sopenharmony_ci		if (conn->type == LE_LINK) {
28148c2ecf20Sopenharmony_ci			if (test_bit(HCI_CONN_SCANNING, &conn->flags))
28158c2ecf20Sopenharmony_ci				break;
28168c2ecf20Sopenharmony_ci			hci_req_add(req, HCI_OP_LE_CREATE_CONN_CANCEL,
28178c2ecf20Sopenharmony_ci				    0, NULL);
28188c2ecf20Sopenharmony_ci		} else if (conn->type == ACL_LINK) {
28198c2ecf20Sopenharmony_ci			if (req->hdev->hci_ver < BLUETOOTH_VER_1_2)
28208c2ecf20Sopenharmony_ci				break;
28218c2ecf20Sopenharmony_ci			hci_req_add(req, HCI_OP_CREATE_CONN_CANCEL,
28228c2ecf20Sopenharmony_ci				    6, &conn->dst);
28238c2ecf20Sopenharmony_ci		}
28248c2ecf20Sopenharmony_ci		break;
28258c2ecf20Sopenharmony_ci	case BT_CONNECT2:
28268c2ecf20Sopenharmony_ci		if (conn->type == ACL_LINK) {
28278c2ecf20Sopenharmony_ci			struct hci_cp_reject_conn_req rej;
28288c2ecf20Sopenharmony_ci
28298c2ecf20Sopenharmony_ci			bacpy(&rej.bdaddr, &conn->dst);
28308c2ecf20Sopenharmony_ci			rej.reason = reason;
28318c2ecf20Sopenharmony_ci
28328c2ecf20Sopenharmony_ci			hci_req_add(req, HCI_OP_REJECT_CONN_REQ,
28338c2ecf20Sopenharmony_ci				    sizeof(rej), &rej);
28348c2ecf20Sopenharmony_ci		} else if (conn->type == SCO_LINK || conn->type == ESCO_LINK) {
28358c2ecf20Sopenharmony_ci			struct hci_cp_reject_sync_conn_req rej;
28368c2ecf20Sopenharmony_ci
28378c2ecf20Sopenharmony_ci			bacpy(&rej.bdaddr, &conn->dst);
28388c2ecf20Sopenharmony_ci
28398c2ecf20Sopenharmony_ci			/* SCO rejection has its own limited set of
28408c2ecf20Sopenharmony_ci			 * allowed error values (0x0D-0x0F) which isn't
28418c2ecf20Sopenharmony_ci			 * compatible with most values passed to this
28428c2ecf20Sopenharmony_ci			 * function. To be safe hard-code one of the
28438c2ecf20Sopenharmony_ci			 * values that's suitable for SCO.
28448c2ecf20Sopenharmony_ci			 */
28458c2ecf20Sopenharmony_ci			rej.reason = HCI_ERROR_REJ_LIMITED_RESOURCES;
28468c2ecf20Sopenharmony_ci
28478c2ecf20Sopenharmony_ci			hci_req_add(req, HCI_OP_REJECT_SYNC_CONN_REQ,
28488c2ecf20Sopenharmony_ci				    sizeof(rej), &rej);
28498c2ecf20Sopenharmony_ci		}
28508c2ecf20Sopenharmony_ci		break;
28518c2ecf20Sopenharmony_ci	default:
28528c2ecf20Sopenharmony_ci		conn->state = BT_CLOSED;
28538c2ecf20Sopenharmony_ci		break;
28548c2ecf20Sopenharmony_ci	}
28558c2ecf20Sopenharmony_ci}
28568c2ecf20Sopenharmony_ci
28578c2ecf20Sopenharmony_cistatic void abort_conn_complete(struct hci_dev *hdev, u8 status, u16 opcode)
28588c2ecf20Sopenharmony_ci{
28598c2ecf20Sopenharmony_ci	if (status)
28608c2ecf20Sopenharmony_ci		BT_DBG("Failed to abort connection: status 0x%2.2x", status);
28618c2ecf20Sopenharmony_ci}
28628c2ecf20Sopenharmony_ci
28638c2ecf20Sopenharmony_ciint hci_abort_conn(struct hci_conn *conn, u8 reason)
28648c2ecf20Sopenharmony_ci{
28658c2ecf20Sopenharmony_ci	struct hci_request req;
28668c2ecf20Sopenharmony_ci	int err;
28678c2ecf20Sopenharmony_ci
28688c2ecf20Sopenharmony_ci	hci_req_init(&req, conn->hdev);
28698c2ecf20Sopenharmony_ci
28708c2ecf20Sopenharmony_ci	__hci_abort_conn(&req, conn, reason);
28718c2ecf20Sopenharmony_ci
28728c2ecf20Sopenharmony_ci	err = hci_req_run(&req, abort_conn_complete);
28738c2ecf20Sopenharmony_ci	if (err && err != -ENODATA) {
28748c2ecf20Sopenharmony_ci		bt_dev_err(conn->hdev, "failed to run HCI request: err %d", err);
28758c2ecf20Sopenharmony_ci		return err;
28768c2ecf20Sopenharmony_ci	}
28778c2ecf20Sopenharmony_ci
28788c2ecf20Sopenharmony_ci	return 0;
28798c2ecf20Sopenharmony_ci}
28808c2ecf20Sopenharmony_ci
28818c2ecf20Sopenharmony_cistatic int update_bg_scan(struct hci_request *req, unsigned long opt)
28828c2ecf20Sopenharmony_ci{
28838c2ecf20Sopenharmony_ci	hci_dev_lock(req->hdev);
28848c2ecf20Sopenharmony_ci	__hci_update_background_scan(req);
28858c2ecf20Sopenharmony_ci	hci_dev_unlock(req->hdev);
28868c2ecf20Sopenharmony_ci	return 0;
28878c2ecf20Sopenharmony_ci}
28888c2ecf20Sopenharmony_ci
28898c2ecf20Sopenharmony_cistatic void bg_scan_update(struct work_struct *work)
28908c2ecf20Sopenharmony_ci{
28918c2ecf20Sopenharmony_ci	struct hci_dev *hdev = container_of(work, struct hci_dev,
28928c2ecf20Sopenharmony_ci					    bg_scan_update);
28938c2ecf20Sopenharmony_ci	struct hci_conn *conn;
28948c2ecf20Sopenharmony_ci	u8 status;
28958c2ecf20Sopenharmony_ci	int err;
28968c2ecf20Sopenharmony_ci
28978c2ecf20Sopenharmony_ci	err = hci_req_sync(hdev, update_bg_scan, 0, HCI_CMD_TIMEOUT, &status);
28988c2ecf20Sopenharmony_ci	if (!err)
28998c2ecf20Sopenharmony_ci		return;
29008c2ecf20Sopenharmony_ci
29018c2ecf20Sopenharmony_ci	hci_dev_lock(hdev);
29028c2ecf20Sopenharmony_ci
29038c2ecf20Sopenharmony_ci	conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
29048c2ecf20Sopenharmony_ci	if (conn)
29058c2ecf20Sopenharmony_ci		hci_le_conn_failed(conn, status);
29068c2ecf20Sopenharmony_ci
29078c2ecf20Sopenharmony_ci	hci_dev_unlock(hdev);
29088c2ecf20Sopenharmony_ci}
29098c2ecf20Sopenharmony_ci
29108c2ecf20Sopenharmony_cistatic int le_scan_disable(struct hci_request *req, unsigned long opt)
29118c2ecf20Sopenharmony_ci{
29128c2ecf20Sopenharmony_ci	hci_req_add_le_scan_disable(req, false);
29138c2ecf20Sopenharmony_ci	return 0;
29148c2ecf20Sopenharmony_ci}
29158c2ecf20Sopenharmony_ci
29168c2ecf20Sopenharmony_cistatic int bredr_inquiry(struct hci_request *req, unsigned long opt)
29178c2ecf20Sopenharmony_ci{
29188c2ecf20Sopenharmony_ci	u8 length = opt;
29198c2ecf20Sopenharmony_ci	const u8 giac[3] = { 0x33, 0x8b, 0x9e };
29208c2ecf20Sopenharmony_ci	const u8 liac[3] = { 0x00, 0x8b, 0x9e };
29218c2ecf20Sopenharmony_ci	struct hci_cp_inquiry cp;
29228c2ecf20Sopenharmony_ci
29238c2ecf20Sopenharmony_ci	BT_DBG("%s", req->hdev->name);
29248c2ecf20Sopenharmony_ci
29258c2ecf20Sopenharmony_ci	hci_dev_lock(req->hdev);
29268c2ecf20Sopenharmony_ci	hci_inquiry_cache_flush(req->hdev);
29278c2ecf20Sopenharmony_ci	hci_dev_unlock(req->hdev);
29288c2ecf20Sopenharmony_ci
29298c2ecf20Sopenharmony_ci	memset(&cp, 0, sizeof(cp));
29308c2ecf20Sopenharmony_ci
29318c2ecf20Sopenharmony_ci	if (req->hdev->discovery.limited)
29328c2ecf20Sopenharmony_ci		memcpy(&cp.lap, liac, sizeof(cp.lap));
29338c2ecf20Sopenharmony_ci	else
29348c2ecf20Sopenharmony_ci		memcpy(&cp.lap, giac, sizeof(cp.lap));
29358c2ecf20Sopenharmony_ci
29368c2ecf20Sopenharmony_ci	cp.length = length;
29378c2ecf20Sopenharmony_ci
29388c2ecf20Sopenharmony_ci	hci_req_add(req, HCI_OP_INQUIRY, sizeof(cp), &cp);
29398c2ecf20Sopenharmony_ci
29408c2ecf20Sopenharmony_ci	return 0;
29418c2ecf20Sopenharmony_ci}
29428c2ecf20Sopenharmony_ci
29438c2ecf20Sopenharmony_cistatic void le_scan_disable_work(struct work_struct *work)
29448c2ecf20Sopenharmony_ci{
29458c2ecf20Sopenharmony_ci	struct hci_dev *hdev = container_of(work, struct hci_dev,
29468c2ecf20Sopenharmony_ci					    le_scan_disable.work);
29478c2ecf20Sopenharmony_ci	u8 status;
29488c2ecf20Sopenharmony_ci
29498c2ecf20Sopenharmony_ci	BT_DBG("%s", hdev->name);
29508c2ecf20Sopenharmony_ci
29518c2ecf20Sopenharmony_ci	if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
29528c2ecf20Sopenharmony_ci		return;
29538c2ecf20Sopenharmony_ci
29548c2ecf20Sopenharmony_ci	cancel_delayed_work(&hdev->le_scan_restart);
29558c2ecf20Sopenharmony_ci
29568c2ecf20Sopenharmony_ci	hci_req_sync(hdev, le_scan_disable, 0, HCI_CMD_TIMEOUT, &status);
29578c2ecf20Sopenharmony_ci	if (status) {
29588c2ecf20Sopenharmony_ci		bt_dev_err(hdev, "failed to disable LE scan: status 0x%02x",
29598c2ecf20Sopenharmony_ci			   status);
29608c2ecf20Sopenharmony_ci		return;
29618c2ecf20Sopenharmony_ci	}
29628c2ecf20Sopenharmony_ci
29638c2ecf20Sopenharmony_ci	hdev->discovery.scan_start = 0;
29648c2ecf20Sopenharmony_ci
29658c2ecf20Sopenharmony_ci	/* If we were running LE only scan, change discovery state. If
29668c2ecf20Sopenharmony_ci	 * we were running both LE and BR/EDR inquiry simultaneously,
29678c2ecf20Sopenharmony_ci	 * and BR/EDR inquiry is already finished, stop discovery,
29688c2ecf20Sopenharmony_ci	 * otherwise BR/EDR inquiry will stop discovery when finished.
29698c2ecf20Sopenharmony_ci	 * If we will resolve remote device name, do not change
29708c2ecf20Sopenharmony_ci	 * discovery state.
29718c2ecf20Sopenharmony_ci	 */
29728c2ecf20Sopenharmony_ci
29738c2ecf20Sopenharmony_ci	if (hdev->discovery.type == DISCOV_TYPE_LE)
29748c2ecf20Sopenharmony_ci		goto discov_stopped;
29758c2ecf20Sopenharmony_ci
29768c2ecf20Sopenharmony_ci	if (hdev->discovery.type != DISCOV_TYPE_INTERLEAVED)
29778c2ecf20Sopenharmony_ci		return;
29788c2ecf20Sopenharmony_ci
29798c2ecf20Sopenharmony_ci	if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks)) {
29808c2ecf20Sopenharmony_ci		if (!test_bit(HCI_INQUIRY, &hdev->flags) &&
29818c2ecf20Sopenharmony_ci		    hdev->discovery.state != DISCOVERY_RESOLVING)
29828c2ecf20Sopenharmony_ci			goto discov_stopped;
29838c2ecf20Sopenharmony_ci
29848c2ecf20Sopenharmony_ci		return;
29858c2ecf20Sopenharmony_ci	}
29868c2ecf20Sopenharmony_ci
29878c2ecf20Sopenharmony_ci	hci_req_sync(hdev, bredr_inquiry, DISCOV_INTERLEAVED_INQUIRY_LEN,
29888c2ecf20Sopenharmony_ci		     HCI_CMD_TIMEOUT, &status);
29898c2ecf20Sopenharmony_ci	if (status) {
29908c2ecf20Sopenharmony_ci		bt_dev_err(hdev, "inquiry failed: status 0x%02x", status);
29918c2ecf20Sopenharmony_ci		goto discov_stopped;
29928c2ecf20Sopenharmony_ci	}
29938c2ecf20Sopenharmony_ci
29948c2ecf20Sopenharmony_ci	return;
29958c2ecf20Sopenharmony_ci
29968c2ecf20Sopenharmony_cidiscov_stopped:
29978c2ecf20Sopenharmony_ci	hci_dev_lock(hdev);
29988c2ecf20Sopenharmony_ci	hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
29998c2ecf20Sopenharmony_ci	hci_dev_unlock(hdev);
30008c2ecf20Sopenharmony_ci}
30018c2ecf20Sopenharmony_ci
30028c2ecf20Sopenharmony_cistatic int le_scan_restart(struct hci_request *req, unsigned long opt)
30038c2ecf20Sopenharmony_ci{
30048c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
30058c2ecf20Sopenharmony_ci
30068c2ecf20Sopenharmony_ci	/* If controller is not scanning we are done. */
30078c2ecf20Sopenharmony_ci	if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
30088c2ecf20Sopenharmony_ci		return 0;
30098c2ecf20Sopenharmony_ci
30108c2ecf20Sopenharmony_ci	if (hdev->scanning_paused) {
30118c2ecf20Sopenharmony_ci		bt_dev_dbg(hdev, "Scanning is paused for suspend");
30128c2ecf20Sopenharmony_ci		return 0;
30138c2ecf20Sopenharmony_ci	}
30148c2ecf20Sopenharmony_ci
30158c2ecf20Sopenharmony_ci	hci_req_add_le_scan_disable(req, false);
30168c2ecf20Sopenharmony_ci
30178c2ecf20Sopenharmony_ci	if (use_ext_scan(hdev)) {
30188c2ecf20Sopenharmony_ci		struct hci_cp_le_set_ext_scan_enable ext_enable_cp;
30198c2ecf20Sopenharmony_ci
30208c2ecf20Sopenharmony_ci		memset(&ext_enable_cp, 0, sizeof(ext_enable_cp));
30218c2ecf20Sopenharmony_ci		ext_enable_cp.enable = LE_SCAN_ENABLE;
30228c2ecf20Sopenharmony_ci		ext_enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
30238c2ecf20Sopenharmony_ci
30248c2ecf20Sopenharmony_ci		hci_req_add(req, HCI_OP_LE_SET_EXT_SCAN_ENABLE,
30258c2ecf20Sopenharmony_ci			    sizeof(ext_enable_cp), &ext_enable_cp);
30268c2ecf20Sopenharmony_ci	} else {
30278c2ecf20Sopenharmony_ci		struct hci_cp_le_set_scan_enable cp;
30288c2ecf20Sopenharmony_ci
30298c2ecf20Sopenharmony_ci		memset(&cp, 0, sizeof(cp));
30308c2ecf20Sopenharmony_ci		cp.enable = LE_SCAN_ENABLE;
30318c2ecf20Sopenharmony_ci		cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
30328c2ecf20Sopenharmony_ci		hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
30338c2ecf20Sopenharmony_ci	}
30348c2ecf20Sopenharmony_ci
30358c2ecf20Sopenharmony_ci	return 0;
30368c2ecf20Sopenharmony_ci}
30378c2ecf20Sopenharmony_ci
30388c2ecf20Sopenharmony_cistatic void le_scan_restart_work(struct work_struct *work)
30398c2ecf20Sopenharmony_ci{
30408c2ecf20Sopenharmony_ci	struct hci_dev *hdev = container_of(work, struct hci_dev,
30418c2ecf20Sopenharmony_ci					    le_scan_restart.work);
30428c2ecf20Sopenharmony_ci	unsigned long timeout, duration, scan_start, now;
30438c2ecf20Sopenharmony_ci	u8 status;
30448c2ecf20Sopenharmony_ci
30458c2ecf20Sopenharmony_ci	BT_DBG("%s", hdev->name);
30468c2ecf20Sopenharmony_ci
30478c2ecf20Sopenharmony_ci	hci_req_sync(hdev, le_scan_restart, 0, HCI_CMD_TIMEOUT, &status);
30488c2ecf20Sopenharmony_ci	if (status) {
30498c2ecf20Sopenharmony_ci		bt_dev_err(hdev, "failed to restart LE scan: status %d",
30508c2ecf20Sopenharmony_ci			   status);
30518c2ecf20Sopenharmony_ci		return;
30528c2ecf20Sopenharmony_ci	}
30538c2ecf20Sopenharmony_ci
30548c2ecf20Sopenharmony_ci	hci_dev_lock(hdev);
30558c2ecf20Sopenharmony_ci
30568c2ecf20Sopenharmony_ci	if (!test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks) ||
30578c2ecf20Sopenharmony_ci	    !hdev->discovery.scan_start)
30588c2ecf20Sopenharmony_ci		goto unlock;
30598c2ecf20Sopenharmony_ci
30608c2ecf20Sopenharmony_ci	/* When the scan was started, hdev->le_scan_disable has been queued
30618c2ecf20Sopenharmony_ci	 * after duration from scan_start. During scan restart this job
30628c2ecf20Sopenharmony_ci	 * has been canceled, and we need to queue it again after proper
30638c2ecf20Sopenharmony_ci	 * timeout, to make sure that scan does not run indefinitely.
30648c2ecf20Sopenharmony_ci	 */
30658c2ecf20Sopenharmony_ci	duration = hdev->discovery.scan_duration;
30668c2ecf20Sopenharmony_ci	scan_start = hdev->discovery.scan_start;
30678c2ecf20Sopenharmony_ci	now = jiffies;
30688c2ecf20Sopenharmony_ci	if (now - scan_start <= duration) {
30698c2ecf20Sopenharmony_ci		int elapsed;
30708c2ecf20Sopenharmony_ci
30718c2ecf20Sopenharmony_ci		if (now >= scan_start)
30728c2ecf20Sopenharmony_ci			elapsed = now - scan_start;
30738c2ecf20Sopenharmony_ci		else
30748c2ecf20Sopenharmony_ci			elapsed = ULONG_MAX - scan_start + now;
30758c2ecf20Sopenharmony_ci
30768c2ecf20Sopenharmony_ci		timeout = duration - elapsed;
30778c2ecf20Sopenharmony_ci	} else {
30788c2ecf20Sopenharmony_ci		timeout = 0;
30798c2ecf20Sopenharmony_ci	}
30808c2ecf20Sopenharmony_ci
30818c2ecf20Sopenharmony_ci	queue_delayed_work(hdev->req_workqueue,
30828c2ecf20Sopenharmony_ci			   &hdev->le_scan_disable, timeout);
30838c2ecf20Sopenharmony_ci
30848c2ecf20Sopenharmony_ciunlock:
30858c2ecf20Sopenharmony_ci	hci_dev_unlock(hdev);
30868c2ecf20Sopenharmony_ci}
30878c2ecf20Sopenharmony_ci
30888c2ecf20Sopenharmony_cistatic int active_scan(struct hci_request *req, unsigned long opt)
30898c2ecf20Sopenharmony_ci{
30908c2ecf20Sopenharmony_ci	uint16_t interval = opt;
30918c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
30928c2ecf20Sopenharmony_ci	u8 own_addr_type;
30938c2ecf20Sopenharmony_ci	/* Accept list is not used for discovery */
30948c2ecf20Sopenharmony_ci	u8 filter_policy = 0x00;
30958c2ecf20Sopenharmony_ci	/* Discovery doesn't require controller address resolution */
30968c2ecf20Sopenharmony_ci	bool addr_resolv = false;
30978c2ecf20Sopenharmony_ci	int err;
30988c2ecf20Sopenharmony_ci
30998c2ecf20Sopenharmony_ci	BT_DBG("%s", hdev->name);
31008c2ecf20Sopenharmony_ci
31018c2ecf20Sopenharmony_ci	/* If controller is scanning, it means the background scanning is
31028c2ecf20Sopenharmony_ci	 * running. Thus, we should temporarily stop it in order to set the
31038c2ecf20Sopenharmony_ci	 * discovery scanning parameters.
31048c2ecf20Sopenharmony_ci	 */
31058c2ecf20Sopenharmony_ci	if (hci_dev_test_flag(hdev, HCI_LE_SCAN))
31068c2ecf20Sopenharmony_ci		hci_req_add_le_scan_disable(req, false);
31078c2ecf20Sopenharmony_ci
31088c2ecf20Sopenharmony_ci	/* All active scans will be done with either a resolvable private
31098c2ecf20Sopenharmony_ci	 * address (when privacy feature has been enabled) or non-resolvable
31108c2ecf20Sopenharmony_ci	 * private address.
31118c2ecf20Sopenharmony_ci	 */
31128c2ecf20Sopenharmony_ci	err = hci_update_random_address(req, true, scan_use_rpa(hdev),
31138c2ecf20Sopenharmony_ci					&own_addr_type);
31148c2ecf20Sopenharmony_ci	if (err < 0)
31158c2ecf20Sopenharmony_ci		own_addr_type = ADDR_LE_DEV_PUBLIC;
31168c2ecf20Sopenharmony_ci
31178c2ecf20Sopenharmony_ci	hci_req_start_scan(req, LE_SCAN_ACTIVE, interval,
31188c2ecf20Sopenharmony_ci			   hdev->le_scan_window_discovery, own_addr_type,
31198c2ecf20Sopenharmony_ci			   filter_policy, addr_resolv);
31208c2ecf20Sopenharmony_ci	return 0;
31218c2ecf20Sopenharmony_ci}
31228c2ecf20Sopenharmony_ci
31238c2ecf20Sopenharmony_cistatic int interleaved_discov(struct hci_request *req, unsigned long opt)
31248c2ecf20Sopenharmony_ci{
31258c2ecf20Sopenharmony_ci	int err;
31268c2ecf20Sopenharmony_ci
31278c2ecf20Sopenharmony_ci	BT_DBG("%s", req->hdev->name);
31288c2ecf20Sopenharmony_ci
31298c2ecf20Sopenharmony_ci	err = active_scan(req, opt);
31308c2ecf20Sopenharmony_ci	if (err)
31318c2ecf20Sopenharmony_ci		return err;
31328c2ecf20Sopenharmony_ci
31338c2ecf20Sopenharmony_ci	return bredr_inquiry(req, DISCOV_BREDR_INQUIRY_LEN);
31348c2ecf20Sopenharmony_ci}
31358c2ecf20Sopenharmony_ci
31368c2ecf20Sopenharmony_cistatic void start_discovery(struct hci_dev *hdev, u8 *status)
31378c2ecf20Sopenharmony_ci{
31388c2ecf20Sopenharmony_ci	unsigned long timeout;
31398c2ecf20Sopenharmony_ci
31408c2ecf20Sopenharmony_ci	BT_DBG("%s type %u", hdev->name, hdev->discovery.type);
31418c2ecf20Sopenharmony_ci
31428c2ecf20Sopenharmony_ci	switch (hdev->discovery.type) {
31438c2ecf20Sopenharmony_ci	case DISCOV_TYPE_BREDR:
31448c2ecf20Sopenharmony_ci		if (!hci_dev_test_flag(hdev, HCI_INQUIRY))
31458c2ecf20Sopenharmony_ci			hci_req_sync(hdev, bredr_inquiry,
31468c2ecf20Sopenharmony_ci				     DISCOV_BREDR_INQUIRY_LEN, HCI_CMD_TIMEOUT,
31478c2ecf20Sopenharmony_ci				     status);
31488c2ecf20Sopenharmony_ci		return;
31498c2ecf20Sopenharmony_ci	case DISCOV_TYPE_INTERLEAVED:
31508c2ecf20Sopenharmony_ci		/* When running simultaneous discovery, the LE scanning time
31518c2ecf20Sopenharmony_ci		 * should occupy the whole discovery time sine BR/EDR inquiry
31528c2ecf20Sopenharmony_ci		 * and LE scanning are scheduled by the controller.
31538c2ecf20Sopenharmony_ci		 *
31548c2ecf20Sopenharmony_ci		 * For interleaving discovery in comparison, BR/EDR inquiry
31558c2ecf20Sopenharmony_ci		 * and LE scanning are done sequentially with separate
31568c2ecf20Sopenharmony_ci		 * timeouts.
31578c2ecf20Sopenharmony_ci		 */
31588c2ecf20Sopenharmony_ci		if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY,
31598c2ecf20Sopenharmony_ci			     &hdev->quirks)) {
31608c2ecf20Sopenharmony_ci			timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
31618c2ecf20Sopenharmony_ci			/* During simultaneous discovery, we double LE scan
31628c2ecf20Sopenharmony_ci			 * interval. We must leave some time for the controller
31638c2ecf20Sopenharmony_ci			 * to do BR/EDR inquiry.
31648c2ecf20Sopenharmony_ci			 */
31658c2ecf20Sopenharmony_ci			hci_req_sync(hdev, interleaved_discov,
31668c2ecf20Sopenharmony_ci				     hdev->le_scan_int_discovery * 2, HCI_CMD_TIMEOUT,
31678c2ecf20Sopenharmony_ci				     status);
31688c2ecf20Sopenharmony_ci			break;
31698c2ecf20Sopenharmony_ci		}
31708c2ecf20Sopenharmony_ci
31718c2ecf20Sopenharmony_ci		timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout);
31728c2ecf20Sopenharmony_ci		hci_req_sync(hdev, active_scan, hdev->le_scan_int_discovery,
31738c2ecf20Sopenharmony_ci			     HCI_CMD_TIMEOUT, status);
31748c2ecf20Sopenharmony_ci		break;
31758c2ecf20Sopenharmony_ci	case DISCOV_TYPE_LE:
31768c2ecf20Sopenharmony_ci		timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
31778c2ecf20Sopenharmony_ci		hci_req_sync(hdev, active_scan, hdev->le_scan_int_discovery,
31788c2ecf20Sopenharmony_ci			     HCI_CMD_TIMEOUT, status);
31798c2ecf20Sopenharmony_ci		break;
31808c2ecf20Sopenharmony_ci	default:
31818c2ecf20Sopenharmony_ci		*status = HCI_ERROR_UNSPECIFIED;
31828c2ecf20Sopenharmony_ci		return;
31838c2ecf20Sopenharmony_ci	}
31848c2ecf20Sopenharmony_ci
31858c2ecf20Sopenharmony_ci	if (*status)
31868c2ecf20Sopenharmony_ci		return;
31878c2ecf20Sopenharmony_ci
31888c2ecf20Sopenharmony_ci	BT_DBG("%s timeout %u ms", hdev->name, jiffies_to_msecs(timeout));
31898c2ecf20Sopenharmony_ci
31908c2ecf20Sopenharmony_ci	/* When service discovery is used and the controller has a
31918c2ecf20Sopenharmony_ci	 * strict duplicate filter, it is important to remember the
31928c2ecf20Sopenharmony_ci	 * start and duration of the scan. This is required for
31938c2ecf20Sopenharmony_ci	 * restarting scanning during the discovery phase.
31948c2ecf20Sopenharmony_ci	 */
31958c2ecf20Sopenharmony_ci	if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks) &&
31968c2ecf20Sopenharmony_ci		     hdev->discovery.result_filtering) {
31978c2ecf20Sopenharmony_ci		hdev->discovery.scan_start = jiffies;
31988c2ecf20Sopenharmony_ci		hdev->discovery.scan_duration = timeout;
31998c2ecf20Sopenharmony_ci	}
32008c2ecf20Sopenharmony_ci
32018c2ecf20Sopenharmony_ci	queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_disable,
32028c2ecf20Sopenharmony_ci			   timeout);
32038c2ecf20Sopenharmony_ci}
32048c2ecf20Sopenharmony_ci
32058c2ecf20Sopenharmony_cibool hci_req_stop_discovery(struct hci_request *req)
32068c2ecf20Sopenharmony_ci{
32078c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
32088c2ecf20Sopenharmony_ci	struct discovery_state *d = &hdev->discovery;
32098c2ecf20Sopenharmony_ci	struct hci_cp_remote_name_req_cancel cp;
32108c2ecf20Sopenharmony_ci	struct inquiry_entry *e;
32118c2ecf20Sopenharmony_ci	bool ret = false;
32128c2ecf20Sopenharmony_ci
32138c2ecf20Sopenharmony_ci	BT_DBG("%s state %u", hdev->name, hdev->discovery.state);
32148c2ecf20Sopenharmony_ci
32158c2ecf20Sopenharmony_ci	if (d->state == DISCOVERY_FINDING || d->state == DISCOVERY_STOPPING) {
32168c2ecf20Sopenharmony_ci		if (test_bit(HCI_INQUIRY, &hdev->flags))
32178c2ecf20Sopenharmony_ci			hci_req_add(req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
32188c2ecf20Sopenharmony_ci
32198c2ecf20Sopenharmony_ci		if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
32208c2ecf20Sopenharmony_ci			cancel_delayed_work(&hdev->le_scan_disable);
32218c2ecf20Sopenharmony_ci			hci_req_add_le_scan_disable(req, false);
32228c2ecf20Sopenharmony_ci		}
32238c2ecf20Sopenharmony_ci
32248c2ecf20Sopenharmony_ci		ret = true;
32258c2ecf20Sopenharmony_ci	} else {
32268c2ecf20Sopenharmony_ci		/* Passive scanning */
32278c2ecf20Sopenharmony_ci		if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
32288c2ecf20Sopenharmony_ci			hci_req_add_le_scan_disable(req, false);
32298c2ecf20Sopenharmony_ci			ret = true;
32308c2ecf20Sopenharmony_ci		}
32318c2ecf20Sopenharmony_ci	}
32328c2ecf20Sopenharmony_ci
32338c2ecf20Sopenharmony_ci	/* No further actions needed for LE-only discovery */
32348c2ecf20Sopenharmony_ci	if (d->type == DISCOV_TYPE_LE)
32358c2ecf20Sopenharmony_ci		return ret;
32368c2ecf20Sopenharmony_ci
32378c2ecf20Sopenharmony_ci	if (d->state == DISCOVERY_RESOLVING || d->state == DISCOVERY_STOPPING) {
32388c2ecf20Sopenharmony_ci		e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
32398c2ecf20Sopenharmony_ci						     NAME_PENDING);
32408c2ecf20Sopenharmony_ci		if (!e)
32418c2ecf20Sopenharmony_ci			return ret;
32428c2ecf20Sopenharmony_ci
32438c2ecf20Sopenharmony_ci		bacpy(&cp.bdaddr, &e->data.bdaddr);
32448c2ecf20Sopenharmony_ci		hci_req_add(req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
32458c2ecf20Sopenharmony_ci			    &cp);
32468c2ecf20Sopenharmony_ci		ret = true;
32478c2ecf20Sopenharmony_ci	}
32488c2ecf20Sopenharmony_ci
32498c2ecf20Sopenharmony_ci	return ret;
32508c2ecf20Sopenharmony_ci}
32518c2ecf20Sopenharmony_ci
32528c2ecf20Sopenharmony_cistatic int stop_discovery(struct hci_request *req, unsigned long opt)
32538c2ecf20Sopenharmony_ci{
32548c2ecf20Sopenharmony_ci	hci_dev_lock(req->hdev);
32558c2ecf20Sopenharmony_ci	hci_req_stop_discovery(req);
32568c2ecf20Sopenharmony_ci	hci_dev_unlock(req->hdev);
32578c2ecf20Sopenharmony_ci
32588c2ecf20Sopenharmony_ci	return 0;
32598c2ecf20Sopenharmony_ci}
32608c2ecf20Sopenharmony_ci
32618c2ecf20Sopenharmony_cistatic void discov_update(struct work_struct *work)
32628c2ecf20Sopenharmony_ci{
32638c2ecf20Sopenharmony_ci	struct hci_dev *hdev = container_of(work, struct hci_dev,
32648c2ecf20Sopenharmony_ci					    discov_update);
32658c2ecf20Sopenharmony_ci	u8 status = 0;
32668c2ecf20Sopenharmony_ci
32678c2ecf20Sopenharmony_ci	switch (hdev->discovery.state) {
32688c2ecf20Sopenharmony_ci	case DISCOVERY_STARTING:
32698c2ecf20Sopenharmony_ci		start_discovery(hdev, &status);
32708c2ecf20Sopenharmony_ci		mgmt_start_discovery_complete(hdev, status);
32718c2ecf20Sopenharmony_ci		if (status)
32728c2ecf20Sopenharmony_ci			hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
32738c2ecf20Sopenharmony_ci		else
32748c2ecf20Sopenharmony_ci			hci_discovery_set_state(hdev, DISCOVERY_FINDING);
32758c2ecf20Sopenharmony_ci		break;
32768c2ecf20Sopenharmony_ci	case DISCOVERY_STOPPING:
32778c2ecf20Sopenharmony_ci		hci_req_sync(hdev, stop_discovery, 0, HCI_CMD_TIMEOUT, &status);
32788c2ecf20Sopenharmony_ci		mgmt_stop_discovery_complete(hdev, status);
32798c2ecf20Sopenharmony_ci		if (!status)
32808c2ecf20Sopenharmony_ci			hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
32818c2ecf20Sopenharmony_ci		break;
32828c2ecf20Sopenharmony_ci	case DISCOVERY_STOPPED:
32838c2ecf20Sopenharmony_ci	default:
32848c2ecf20Sopenharmony_ci		return;
32858c2ecf20Sopenharmony_ci	}
32868c2ecf20Sopenharmony_ci}
32878c2ecf20Sopenharmony_ci
32888c2ecf20Sopenharmony_cistatic void discov_off(struct work_struct *work)
32898c2ecf20Sopenharmony_ci{
32908c2ecf20Sopenharmony_ci	struct hci_dev *hdev = container_of(work, struct hci_dev,
32918c2ecf20Sopenharmony_ci					    discov_off.work);
32928c2ecf20Sopenharmony_ci
32938c2ecf20Sopenharmony_ci	BT_DBG("%s", hdev->name);
32948c2ecf20Sopenharmony_ci
32958c2ecf20Sopenharmony_ci	hci_dev_lock(hdev);
32968c2ecf20Sopenharmony_ci
32978c2ecf20Sopenharmony_ci	/* When discoverable timeout triggers, then just make sure
32988c2ecf20Sopenharmony_ci	 * the limited discoverable flag is cleared. Even in the case
32998c2ecf20Sopenharmony_ci	 * of a timeout triggered from general discoverable, it is
33008c2ecf20Sopenharmony_ci	 * safe to unconditionally clear the flag.
33018c2ecf20Sopenharmony_ci	 */
33028c2ecf20Sopenharmony_ci	hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
33038c2ecf20Sopenharmony_ci	hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
33048c2ecf20Sopenharmony_ci	hdev->discov_timeout = 0;
33058c2ecf20Sopenharmony_ci
33068c2ecf20Sopenharmony_ci	hci_dev_unlock(hdev);
33078c2ecf20Sopenharmony_ci
33088c2ecf20Sopenharmony_ci	hci_req_sync(hdev, discoverable_update, 0, HCI_CMD_TIMEOUT, NULL);
33098c2ecf20Sopenharmony_ci	mgmt_new_settings(hdev);
33108c2ecf20Sopenharmony_ci}
33118c2ecf20Sopenharmony_ci
33128c2ecf20Sopenharmony_cistatic int powered_update_hci(struct hci_request *req, unsigned long opt)
33138c2ecf20Sopenharmony_ci{
33148c2ecf20Sopenharmony_ci	struct hci_dev *hdev = req->hdev;
33158c2ecf20Sopenharmony_ci	u8 link_sec;
33168c2ecf20Sopenharmony_ci
33178c2ecf20Sopenharmony_ci	hci_dev_lock(hdev);
33188c2ecf20Sopenharmony_ci
33198c2ecf20Sopenharmony_ci	if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED) &&
33208c2ecf20Sopenharmony_ci	    !lmp_host_ssp_capable(hdev)) {
33218c2ecf20Sopenharmony_ci		u8 mode = 0x01;
33228c2ecf20Sopenharmony_ci
33238c2ecf20Sopenharmony_ci		hci_req_add(req, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode);
33248c2ecf20Sopenharmony_ci
33258c2ecf20Sopenharmony_ci		if (bredr_sc_enabled(hdev) && !lmp_host_sc_capable(hdev)) {
33268c2ecf20Sopenharmony_ci			u8 support = 0x01;
33278c2ecf20Sopenharmony_ci
33288c2ecf20Sopenharmony_ci			hci_req_add(req, HCI_OP_WRITE_SC_SUPPORT,
33298c2ecf20Sopenharmony_ci				    sizeof(support), &support);
33308c2ecf20Sopenharmony_ci		}
33318c2ecf20Sopenharmony_ci	}
33328c2ecf20Sopenharmony_ci
33338c2ecf20Sopenharmony_ci	if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
33348c2ecf20Sopenharmony_ci	    lmp_bredr_capable(hdev)) {
33358c2ecf20Sopenharmony_ci		struct hci_cp_write_le_host_supported cp;
33368c2ecf20Sopenharmony_ci
33378c2ecf20Sopenharmony_ci		cp.le = 0x01;
33388c2ecf20Sopenharmony_ci		cp.simul = 0x00;
33398c2ecf20Sopenharmony_ci
33408c2ecf20Sopenharmony_ci		/* Check first if we already have the right
33418c2ecf20Sopenharmony_ci		 * host state (host features set)
33428c2ecf20Sopenharmony_ci		 */
33438c2ecf20Sopenharmony_ci		if (cp.le != lmp_host_le_capable(hdev) ||
33448c2ecf20Sopenharmony_ci		    cp.simul != lmp_host_le_br_capable(hdev))
33458c2ecf20Sopenharmony_ci			hci_req_add(req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
33468c2ecf20Sopenharmony_ci				    sizeof(cp), &cp);
33478c2ecf20Sopenharmony_ci	}
33488c2ecf20Sopenharmony_ci
33498c2ecf20Sopenharmony_ci	if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
33508c2ecf20Sopenharmony_ci		/* Make sure the controller has a good default for
33518c2ecf20Sopenharmony_ci		 * advertising data. This also applies to the case
33528c2ecf20Sopenharmony_ci		 * where BR/EDR was toggled during the AUTO_OFF phase.
33538c2ecf20Sopenharmony_ci		 */
33548c2ecf20Sopenharmony_ci		if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
33558c2ecf20Sopenharmony_ci		    list_empty(&hdev->adv_instances)) {
33568c2ecf20Sopenharmony_ci			int err;
33578c2ecf20Sopenharmony_ci
33588c2ecf20Sopenharmony_ci			if (ext_adv_capable(hdev)) {
33598c2ecf20Sopenharmony_ci				err = __hci_req_setup_ext_adv_instance(req,
33608c2ecf20Sopenharmony_ci								       0x00);
33618c2ecf20Sopenharmony_ci				if (!err)
33628c2ecf20Sopenharmony_ci					__hci_req_update_scan_rsp_data(req,
33638c2ecf20Sopenharmony_ci								       0x00);
33648c2ecf20Sopenharmony_ci			} else {
33658c2ecf20Sopenharmony_ci				err = 0;
33668c2ecf20Sopenharmony_ci				__hci_req_update_adv_data(req, 0x00);
33678c2ecf20Sopenharmony_ci				__hci_req_update_scan_rsp_data(req, 0x00);
33688c2ecf20Sopenharmony_ci			}
33698c2ecf20Sopenharmony_ci
33708c2ecf20Sopenharmony_ci			if (hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
33718c2ecf20Sopenharmony_ci				if (!ext_adv_capable(hdev))
33728c2ecf20Sopenharmony_ci					__hci_req_enable_advertising(req);
33738c2ecf20Sopenharmony_ci				else if (!err)
33748c2ecf20Sopenharmony_ci					__hci_req_enable_ext_advertising(req,
33758c2ecf20Sopenharmony_ci									 0x00);
33768c2ecf20Sopenharmony_ci			}
33778c2ecf20Sopenharmony_ci		} else if (!list_empty(&hdev->adv_instances)) {
33788c2ecf20Sopenharmony_ci			struct adv_info *adv_instance;
33798c2ecf20Sopenharmony_ci
33808c2ecf20Sopenharmony_ci			adv_instance = list_first_entry(&hdev->adv_instances,
33818c2ecf20Sopenharmony_ci							struct adv_info, list);
33828c2ecf20Sopenharmony_ci			__hci_req_schedule_adv_instance(req,
33838c2ecf20Sopenharmony_ci							adv_instance->instance,
33848c2ecf20Sopenharmony_ci							true);
33858c2ecf20Sopenharmony_ci		}
33868c2ecf20Sopenharmony_ci	}
33878c2ecf20Sopenharmony_ci
33888c2ecf20Sopenharmony_ci	link_sec = hci_dev_test_flag(hdev, HCI_LINK_SECURITY);
33898c2ecf20Sopenharmony_ci	if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
33908c2ecf20Sopenharmony_ci		hci_req_add(req, HCI_OP_WRITE_AUTH_ENABLE,
33918c2ecf20Sopenharmony_ci			    sizeof(link_sec), &link_sec);
33928c2ecf20Sopenharmony_ci
33938c2ecf20Sopenharmony_ci	if (lmp_bredr_capable(hdev)) {
33948c2ecf20Sopenharmony_ci		if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
33958c2ecf20Sopenharmony_ci			__hci_req_write_fast_connectable(req, true);
33968c2ecf20Sopenharmony_ci		else
33978c2ecf20Sopenharmony_ci			__hci_req_write_fast_connectable(req, false);
33988c2ecf20Sopenharmony_ci		__hci_req_update_scan(req);
33998c2ecf20Sopenharmony_ci		__hci_req_update_class(req);
34008c2ecf20Sopenharmony_ci		__hci_req_update_name(req);
34018c2ecf20Sopenharmony_ci		__hci_req_update_eir(req);
34028c2ecf20Sopenharmony_ci	}
34038c2ecf20Sopenharmony_ci
34048c2ecf20Sopenharmony_ci	hci_dev_unlock(hdev);
34058c2ecf20Sopenharmony_ci	return 0;
34068c2ecf20Sopenharmony_ci}
34078c2ecf20Sopenharmony_ci
34088c2ecf20Sopenharmony_ciint __hci_req_hci_power_on(struct hci_dev *hdev)
34098c2ecf20Sopenharmony_ci{
34108c2ecf20Sopenharmony_ci	/* Register the available SMP channels (BR/EDR and LE) only when
34118c2ecf20Sopenharmony_ci	 * successfully powering on the controller. This late
34128c2ecf20Sopenharmony_ci	 * registration is required so that LE SMP can clearly decide if
34138c2ecf20Sopenharmony_ci	 * the public address or static address is used.
34148c2ecf20Sopenharmony_ci	 */
34158c2ecf20Sopenharmony_ci	smp_register(hdev);
34168c2ecf20Sopenharmony_ci
34178c2ecf20Sopenharmony_ci	return __hci_req_sync(hdev, powered_update_hci, 0, HCI_CMD_TIMEOUT,
34188c2ecf20Sopenharmony_ci			      NULL);
34198c2ecf20Sopenharmony_ci}
34208c2ecf20Sopenharmony_ci
34218c2ecf20Sopenharmony_civoid hci_request_setup(struct hci_dev *hdev)
34228c2ecf20Sopenharmony_ci{
34238c2ecf20Sopenharmony_ci	INIT_WORK(&hdev->discov_update, discov_update);
34248c2ecf20Sopenharmony_ci	INIT_WORK(&hdev->bg_scan_update, bg_scan_update);
34258c2ecf20Sopenharmony_ci	INIT_WORK(&hdev->scan_update, scan_update_work);
34268c2ecf20Sopenharmony_ci	INIT_WORK(&hdev->connectable_update, connectable_update_work);
34278c2ecf20Sopenharmony_ci	INIT_WORK(&hdev->discoverable_update, discoverable_update_work);
34288c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&hdev->discov_off, discov_off);
34298c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work);
34308c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&hdev->le_scan_restart, le_scan_restart_work);
34318c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&hdev->adv_instance_expire, adv_timeout_expire);
34328c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&hdev->interleave_scan, interleave_scan_work);
34338c2ecf20Sopenharmony_ci}
34348c2ecf20Sopenharmony_ci
34358c2ecf20Sopenharmony_civoid hci_request_cancel_all(struct hci_dev *hdev)
34368c2ecf20Sopenharmony_ci{
34378c2ecf20Sopenharmony_ci	hci_req_sync_cancel(hdev, ENODEV);
34388c2ecf20Sopenharmony_ci
34398c2ecf20Sopenharmony_ci	cancel_work_sync(&hdev->discov_update);
34408c2ecf20Sopenharmony_ci	cancel_work_sync(&hdev->bg_scan_update);
34418c2ecf20Sopenharmony_ci	cancel_work_sync(&hdev->scan_update);
34428c2ecf20Sopenharmony_ci	cancel_work_sync(&hdev->connectable_update);
34438c2ecf20Sopenharmony_ci	cancel_work_sync(&hdev->discoverable_update);
34448c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&hdev->discov_off);
34458c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&hdev->le_scan_disable);
34468c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&hdev->le_scan_restart);
34478c2ecf20Sopenharmony_ci
34488c2ecf20Sopenharmony_ci	if (hdev->adv_instance_timeout) {
34498c2ecf20Sopenharmony_ci		cancel_delayed_work_sync(&hdev->adv_instance_expire);
34508c2ecf20Sopenharmony_ci		hdev->adv_instance_timeout = 0;
34518c2ecf20Sopenharmony_ci	}
34528c2ecf20Sopenharmony_ci
34538c2ecf20Sopenharmony_ci	cancel_interleave_scan(hdev);
34548c2ecf20Sopenharmony_ci}
3455