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, ¶ms->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, ¶ms->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, ¶ms->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, ¶ms->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, ¶ms->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(¶m_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 ¶m_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