From patchwork Tue Feb 25 00:00:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Abhishek Pandit-Subedi X-Patchwork-Id: 11402195 X-Patchwork-Delegate: marcel@holtmann.org Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7F2F4138D for ; Tue, 25 Feb 2020 00:01:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5549F22464 for ; Tue, 25 Feb 2020 00:01:17 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="F4gi54FJ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728606AbgBYAAw (ORCPT ); Mon, 24 Feb 2020 19:00:52 -0500 Received: from mail-pg1-f195.google.com ([209.85.215.195]:46465 "EHLO mail-pg1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728541AbgBYAAu (ORCPT ); Mon, 24 Feb 2020 19:00:50 -0500 Received: by mail-pg1-f195.google.com with SMTP id y30so5931194pga.13 for ; Mon, 24 Feb 2020 16:00:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=kaVCPPxHc40mrNYqH9lQEfFX5d6zeck8hgx/mYih64U=; b=F4gi54FJx9W9NsOhzfC3tDJp8NovGcNme3kdY86iOVd0jmRr5bUz6q8q2KFLCYAUXa fYMjwjUUjLGhSRlWgC8U2MuGfaVRzgmTuMIiI+q7hPNYs/ZsVMSbOWcZ1vzX7a4pFHCr TztLLVUtF96YYdh393AmwGBlUmY53EPTBC/kE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=kaVCPPxHc40mrNYqH9lQEfFX5d6zeck8hgx/mYih64U=; b=aDY94Y68X9IdZpvTrVFn0n6EwER8AXlpBlsp4msanIJChtqIxou8s7loU9Nl7h8m00 xYf8lb6pkzdhGglTWye40ZY/ijcADaNm++LFqA3VLrBmDgIYqtb/8NYc8I01Wuar0hHO 8VuFjQo5a98QcLr3H0saBn6j6KwgH1CUBceMYsCoa1hHm+zRlYCt+JU/D0hzUu5a8VL1 e/TeWVaZ8RS4B6a/lr88qeSiR6pPKWpAvJSqlAn/CiZGNUbUT23HScDjQpLwDTbyYNWs 9hgfFBW68qosI6I2H7rFkwxO9XKoJCRvTgTapC4HAHnCVOmH+CZWa4ny1Di/GHqw+a/9 hWwg== X-Gm-Message-State: APjAAAXIG/GIriNdvrcuqv/v5wWHn/NJ8pYZnClhyLoOQ9nK0WmeQJ0X SmWj8HovyOrlzGt+6//Lg+KrMg== X-Google-Smtp-Source: APXvYqzxgWUbf63leJRRwe95Viu2F5jUfEK3x9nWPu9XeJJ7mD+wcYOoFw+Mysx/CdLf8Mf8lWVBog== X-Received: by 2002:a63:d94d:: with SMTP id e13mr54065336pgj.240.1582588848141; Mon, 24 Feb 2020 16:00:48 -0800 (PST) Received: from apsdesk.mtv.corp.google.com ([2620:15c:202:1:e09a:8d06:a338:aafb]) by smtp.gmail.com with ESMTPSA id c188sm14477657pfb.151.2020.02.24.16.00.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 24 Feb 2020 16:00:47 -0800 (PST) From: Abhishek Pandit-Subedi To: marcel@holtmann.org, luiz.dentz@gmail.com, alainm@chromium.org Cc: linux-bluetooth@vger.kernel.org, chromeos-bluetooth-upstreaming@chromium.org, Abhishek Pandit-Subedi , "David S. Miller" , Johan Hedberg , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Jakub Kicinski Subject: [RFC PATCH v3 1/5] Bluetooth: Add mgmt op set_wake_capable Date: Mon, 24 Feb 2020 16:00:32 -0800 Message-Id: <20200224160019.RFC.v3.1.I797e2f4cb824299043e771f3ab9cef86ee09f4db@changeid> X-Mailer: git-send-email 2.25.0.265.gbab2e86ba0-goog In-Reply-To: <20200225000036.156250-1-abhishekpandit@chromium.org> References: <20200225000036.156250-1-abhishekpandit@chromium.org> MIME-Version: 1.0 Sender: linux-bluetooth-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org When the system is suspended, only some connected Bluetooth devices cause user input that should wake the system (mostly HID devices). Add a list to keep track of devices that can wake the system and add a management API to let userspace tell the kernel whether a device is wake capable or not. For LE devices, the wakeable property is added to the connection parameter and can only be modified after calling add_device. Signed-off-by: Abhishek Pandit-Subedi --- Changes in v3: None Changes in v2: None include/net/bluetooth/hci_core.h | 2 ++ include/net/bluetooth/mgmt.h | 7 +++++ net/bluetooth/hci_core.c | 1 + net/bluetooth/mgmt.c | 51 ++++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index dcc0dc6e2624..9d9ada5bc9d4 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -394,6 +394,7 @@ struct hci_dev { struct list_head mgmt_pending; struct list_head blacklist; struct list_head whitelist; + struct list_head wakeable; struct list_head uuids; struct list_head link_keys; struct list_head long_term_keys; @@ -575,6 +576,7 @@ struct hci_conn_params { struct hci_conn *conn; bool explicit_connect; + bool wakeable; }; extern struct list_head hci_dev_list; diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index a90666af05bd..283ba5320bdb 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -671,6 +671,13 @@ struct mgmt_cp_set_blocked_keys { } __packed; #define MGMT_OP_SET_BLOCKED_KEYS_SIZE 2 +#define MGMT_OP_SET_WAKE_CAPABLE 0x0047 +#define MGMT_SET_WAKE_CAPABLE_SIZE 8 +struct mgmt_cp_set_wake_capable { + struct mgmt_addr_info addr; + u8 wake_capable; +} __packed; + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index cbbc34a006d1..2fceaf76644a 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3299,6 +3299,7 @@ struct hci_dev *hci_alloc_dev(void) INIT_LIST_HEAD(&hdev->mgmt_pending); INIT_LIST_HEAD(&hdev->blacklist); INIT_LIST_HEAD(&hdev->whitelist); + INIT_LIST_HEAD(&hdev->wakeable); INIT_LIST_HEAD(&hdev->uuids); INIT_LIST_HEAD(&hdev->link_keys); INIT_LIST_HEAD(&hdev->long_term_keys); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3074363c68df..9a873097000b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -107,6 +107,7 @@ static const u16 mgmt_commands[] = { MGMT_OP_READ_EXT_INFO, MGMT_OP_SET_APPEARANCE, MGMT_OP_SET_BLOCKED_KEYS, + MGMT_OP_SET_WAKE_CAPABLE, }; static const u16 mgmt_events[] = { @@ -4663,6 +4664,48 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, return err; } +static int set_wake_capable(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) +{ + struct mgmt_cp_set_wake_capable *cp = data; + struct hci_conn_params *params; + int err; + u8 status = MGMT_STATUS_FAILED; + u8 addr_type = cp->addr.type == BDADDR_BREDR ? + cp->addr.type : + le_addr_type(cp->addr.type); + + BT_DBG("Set wake capable %pMR (type 0x%x) = 0x%x\n", &cp->addr.bdaddr, + addr_type, cp->wake_capable); + + if (cp->addr.type == BDADDR_BREDR) { + if (cp->wake_capable) + err = hci_bdaddr_list_add(&hdev->wakeable, + &cp->addr.bdaddr, addr_type); + else + err = hci_bdaddr_list_del(&hdev->wakeable, + &cp->addr.bdaddr, addr_type); + + if (!err || err == -EEXIST || err == -ENOENT) + status = MGMT_STATUS_SUCCESS; + + goto done; + } + + /* Add wakeable param to le connection parameters */ + params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type); + if (params) { + params->wakeable = cp->wake_capable; + status = MGMT_STATUS_SUCCESS; + } + +done: + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_WAKE_CAPABLE, status, + cp, sizeof(*cp)); + + return err; +} + static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode) { struct mgmt_pending_cmd *cmd; @@ -5791,6 +5834,13 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, err = hci_bdaddr_list_del(&hdev->whitelist, &cp->addr.bdaddr, cp->addr.type); + + /* Don't check result since it either succeeds or device + * wasn't there (not wakeable or invalid params as + * covered by deleting from whitelist). + */ + hci_bdaddr_list_del(&hdev->wakeable, &cp->addr.bdaddr, + cp->addr.type); if (err) { err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, @@ -6990,6 +7040,7 @@ static const struct hci_mgmt_handler mgmt_handlers[] = { { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE }, { set_blocked_keys, MGMT_OP_SET_BLOCKED_KEYS_SIZE, HCI_MGMT_VAR_LEN }, + { set_wake_capable, MGMT_SET_WAKE_CAPABLE_SIZE }, }; void mgmt_index_added(struct hci_dev *hdev) From patchwork Tue Feb 25 00:00:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Abhishek Pandit-Subedi X-Patchwork-Id: 11402199 X-Patchwork-Delegate: marcel@holtmann.org Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 95AA9138D for ; Tue, 25 Feb 2020 00:01:24 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 6C00D22464 for ; Tue, 25 Feb 2020 00:01:24 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="kRrwaphC" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728718AbgBYABX (ORCPT ); Mon, 24 Feb 2020 19:01:23 -0500 Received: from mail-pj1-f67.google.com ([209.85.216.67]:38141 "EHLO mail-pj1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728544AbgBYAAu (ORCPT ); Mon, 24 Feb 2020 19:00:50 -0500 Received: by mail-pj1-f67.google.com with SMTP id j17so472798pjz.3 for ; Mon, 24 Feb 2020 16:00:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Um7WHOq7oL5BVx9ef4KzYXbuCI2F7lnanA46u13kxmc=; b=kRrwaphC58E38cqB5LNH0sgRf1ij9PWALl3QAH2ukpR5WJs/3M5veVc9Nr6ri0lFsA 0BS0dswuppwNLRyw6hEBqx1tSuQMJWCY/3HGwMJ/RHGjC7e8w0SA4NdALO1eSzcTZJW5 VgK+aCryTDc3WEJU7Rw0l3PwPExF+qIGm2NBM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Um7WHOq7oL5BVx9ef4KzYXbuCI2F7lnanA46u13kxmc=; b=I6u+hMsmBu1R6hHtEDypTHxJNuHUSPReihDvqTT/933I8qOzx+LN/4Iz6md1I4Osfw 7pTDK3vTpZvvQP9HizsT/71PvurpjiWzvjafak+rfN/Qxf2UNLnkBKFF5WSi5IzUDfnO oP5ugduToH02qfciVyGSqt6zSCDHlmRmWg7aiFlvPPX7dLwoOoELbe6LSC0VAieuwa1Q kfDlOg/167QIC/bVBLYkKvztkbWHlVGg9LKSUP2taKt1y9mAG8E4mBoEGNVBm2d3tMBG imj2fCxVuln8cs0wC22TadBHgV93cuMdsZSyZjg1IEIlW1ldVq6mLGVIRH+gVw/jrg6b 6L+A== X-Gm-Message-State: APjAAAVvsVkJbmidKO6KCqaenZK0jclgD/0sGGGwni+gSOX7qjES0h+G YRQl/PdpCx9nvQfDfX6+TyfTiA== X-Google-Smtp-Source: APXvYqwtq0+XJEvBPN5FsKCYE1xi/p/7DfSAUUaxn0Z/X4xOZVCnAT1fSbzjFBPZgoeMsQFTtxRHEA== X-Received: by 2002:a17:90a:a409:: with SMTP id y9mr1803111pjp.119.1582588849314; Mon, 24 Feb 2020 16:00:49 -0800 (PST) Received: from apsdesk.mtv.corp.google.com ([2620:15c:202:1:e09a:8d06:a338:aafb]) by smtp.gmail.com with ESMTPSA id c188sm14477657pfb.151.2020.02.24.16.00.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 24 Feb 2020 16:00:48 -0800 (PST) From: Abhishek Pandit-Subedi To: marcel@holtmann.org, luiz.dentz@gmail.com, alainm@chromium.org Cc: linux-bluetooth@vger.kernel.org, chromeos-bluetooth-upstreaming@chromium.org, Abhishek Pandit-Subedi , "David S. Miller" , Johan Hedberg , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Jakub Kicinski Subject: [RFC PATCH v3 2/5] Bluetooth: Handle PM_SUSPEND_PREPARE and PM_POST_SUSPEND Date: Mon, 24 Feb 2020 16:00:33 -0800 Message-Id: <20200224160019.RFC.v3.2.I62f17edc39370044c75ad43a55a7382b4b8a5ceb@changeid> X-Mailer: git-send-email 2.25.0.265.gbab2e86ba0-goog In-Reply-To: <20200225000036.156250-1-abhishekpandit@chromium.org> References: <20200225000036.156250-1-abhishekpandit@chromium.org> MIME-Version: 1.0 Sender: linux-bluetooth-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org Register for PM_SUSPEND_PREPARE and PM_POST_SUSPEND to make sure the Bluetooth controller is prepared correctly for suspend/resume. Implement the registration, scheduling and task handling portions only in this patch. Signed-off-by: Abhishek Pandit-Subedi --- Changes in v3: None Changes in v2: * Moved pm notifier registration into its own patch and moved params out of separate suspend_state include/net/bluetooth/hci_core.h | 21 ++++++++++ net/bluetooth/hci_core.c | 70 ++++++++++++++++++++++++++++++++ net/bluetooth/hci_request.c | 19 +++++++++ net/bluetooth/hci_request.h | 2 + 4 files changed, 112 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9d9ada5bc9d4..bc9620e5b65b 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -88,6 +88,18 @@ struct discovery_state { unsigned long scan_duration; }; +#define SUSPEND_NOTIFIER_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ + +enum suspend_tasks { + SUSPEND_PREPARE_NOTIFIER, + __SUSPEND_NUM_TASKS +}; + +enum suspended_state { + BT_RUNNING = 0, + BT_SUSPENDED, +}; + struct hci_conn_hash { struct list_head list; unsigned int acl_num; @@ -389,6 +401,15 @@ struct hci_dev { void *smp_bredr_data; struct discovery_state discovery; + + struct notifier_block suspend_notifier; + struct work_struct suspend_prepare; + enum suspended_state suspend_state_next; + enum suspended_state suspend_state; + + wait_queue_head_t suspend_wait_q; + DECLARE_BITMAP(suspend_tasks, __SUSPEND_NUM_TASKS); + struct hci_conn_hash conn_hash; struct list_head mgmt_pending; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 2fceaf76644a..6ca0aa8d30dd 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include @@ -3241,6 +3243,65 @@ void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr, } } +static int hci_suspend_wait_event(struct hci_dev *hdev) +{ +#define WAKE_COND \ + (find_first_bit(hdev->suspend_tasks, __SUSPEND_NUM_TASKS) == \ + __SUSPEND_NUM_TASKS) + + int i; + int ret = wait_event_timeout(hdev->suspend_wait_q, + WAKE_COND, SUSPEND_NOTIFIER_TIMEOUT); + + if (ret == 0) { + BT_DBG("Timed out waiting for suspend"); + for (i = 0; i < __SUSPEND_NUM_TASKS; ++i) { + if (test_bit(i, hdev->suspend_tasks)) + BT_DBG("Bit %d is set", i); + clear_bit(i, hdev->suspend_tasks); + } + + ret = -ETIMEDOUT; + } else { + ret = 0; + } + + return ret; +} + +static void hci_prepare_suspend(struct work_struct *work) +{ + struct hci_dev *hdev = + container_of(work, struct hci_dev, suspend_prepare); + + hci_dev_lock(hdev); + hci_req_prepare_suspend(hdev, hdev->suspend_state_next); + hci_dev_unlock(hdev); +} + +static int hci_suspend_notifier(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct hci_dev *hdev = + container_of(nb, struct hci_dev, suspend_notifier); + int ret = 0; + + if (action == PM_SUSPEND_PREPARE) { + hdev->suspend_state_next = BT_SUSPENDED; + set_bit(SUSPEND_PREPARE_NOTIFIER, hdev->suspend_tasks); + queue_work(hdev->req_workqueue, &hdev->suspend_prepare); + + ret = hci_suspend_wait_event(hdev); + } else if (action == PM_POST_SUSPEND) { + hdev->suspend_state_next = BT_RUNNING; + set_bit(SUSPEND_PREPARE_NOTIFIER, hdev->suspend_tasks); + queue_work(hdev->req_workqueue, &hdev->suspend_prepare); + + ret = hci_suspend_wait_event(hdev); + } + + return ret ? notifier_from_errno(-EBUSY) : NOTIFY_STOP; +} /* Alloc HCI device */ struct hci_dev *hci_alloc_dev(void) { @@ -3319,6 +3380,7 @@ struct hci_dev *hci_alloc_dev(void) INIT_WORK(&hdev->tx_work, hci_tx_work); INIT_WORK(&hdev->power_on, hci_power_on); INIT_WORK(&hdev->error_reset, hci_error_reset); + INIT_WORK(&hdev->suspend_prepare, hci_prepare_suspend); INIT_DELAYED_WORK(&hdev->power_off, hci_power_off); @@ -3327,6 +3389,7 @@ struct hci_dev *hci_alloc_dev(void) skb_queue_head_init(&hdev->raw_q); init_waitqueue_head(&hdev->req_wait_q); + init_waitqueue_head(&hdev->suspend_wait_q); INIT_DELAYED_WORK(&hdev->cmd_timer, hci_cmd_timeout); @@ -3438,6 +3501,11 @@ int hci_register_dev(struct hci_dev *hdev) hci_sock_dev_event(hdev, HCI_DEV_REG); hci_dev_hold(hdev); + hdev->suspend_notifier.notifier_call = hci_suspend_notifier; + error = register_pm_notifier(&hdev->suspend_notifier); + if (error) + goto err_wqueue; + queue_work(hdev->req_workqueue, &hdev->power_on); return id; @@ -3471,6 +3539,8 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_dev_do_close(hdev); + unregister_pm_notifier(&hdev->suspend_notifier); + if (!test_bit(HCI_INIT, &hdev->flags) && !hci_dev_test_flag(hdev, HCI_SETUP) && !hci_dev_test_flag(hdev, HCI_CONFIG)) { diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index 2a1b64dbf76e..08908469c043 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -918,6 +918,25 @@ static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance) return adv_instance->scan_rsp_len; } +/* Call with hci_dev_lock */ +void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next) +{ + int old_state; + struct hci_conn *conn; + struct hci_request req; + + if (next == hdev->suspend_state) { + BT_DBG("Same state before and after: %d", next); + goto done; + } + + hdev->suspend_state = next; + +done: + clear_bit(SUSPEND_PREPARE_NOTIFIER, hdev->suspend_tasks); + wake_up(&hdev->suspend_wait_q); +} + static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev) { u8 instance = hdev->cur_adv_instance; diff --git a/net/bluetooth/hci_request.h b/net/bluetooth/hci_request.h index a7019fbeadd3..0e81614d235e 100644 --- a/net/bluetooth/hci_request.h +++ b/net/bluetooth/hci_request.h @@ -68,6 +68,8 @@ void __hci_req_update_eir(struct hci_request *req); void hci_req_add_le_scan_disable(struct hci_request *req); void hci_req_add_le_passive_scan(struct hci_request *req); +void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next); + void hci_req_reenable_advertising(struct hci_dev *hdev); void __hci_req_enable_advertising(struct hci_request *req); void __hci_req_disable_advertising(struct hci_request *req); From patchwork Tue Feb 25 00:00:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Abhishek Pandit-Subedi X-Patchwork-Id: 11402197 X-Patchwork-Delegate: marcel@holtmann.org Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8020314BC for ; Tue, 25 Feb 2020 00:01:19 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 4B0EF21D7E for ; Tue, 25 Feb 2020 00:01:19 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="dBAl+L53" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728581AbgBYAAw (ORCPT ); Mon, 24 Feb 2020 19:00:52 -0500 Received: from mail-pg1-f194.google.com ([209.85.215.194]:43591 "EHLO mail-pg1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728567AbgBYAAv (ORCPT ); Mon, 24 Feb 2020 19:00:51 -0500 Received: by mail-pg1-f194.google.com with SMTP id u12so5943460pgb.10 for ; Mon, 24 Feb 2020 16:00:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=eCXHKHSG5tUPSj/yQUn0bkQviD7fnjUbdLXbxBcttuo=; b=dBAl+L53PGN6bN4IcYwOx4NFEh5M4UIEVmBXUT9yEG+bVp5/kNlc3e2bhadpz5/IhR K26yQomUUpkY+eQp/bwMnp3ZqekXI48Mxjvt3NkxZqC23y2UKy1fOM9mEAaHvuDxEf11 9+kc+GQFC9Lw7sQRxBRWdobYz/5qwJCM3nhB0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=eCXHKHSG5tUPSj/yQUn0bkQviD7fnjUbdLXbxBcttuo=; b=syw135CpisabrgIGWMmljOn9R+dLRd4pveQHscC0vI1Iw8NKaNLq2enRnAGumXeSkT f+Jo7gdu9JIi7qo68SLkxgjl/E1NHNw+ShQEhd1rb8YWHngK7yT3ZWmfsdQqZznoFeoz LMpf1PezNjmUN5xptYwhm8AS//5yzc5RHaZ4mcRQYn1xXymra3/NvLCZJ2IkbJDsBRjr wjZ+RJsRcRT4Zc8qqN31dRzxkuCZ7xxtqO5l/OfQEITEhAgeNVYAyda25dtW5F2Tc6xB wIYMgff9vkLu9PYBPbR6ZOrBSi5pjjz6/JPmt3uTXjJrxbn65tI4Zw1y1cErwlVuaiCt 1odA== X-Gm-Message-State: APjAAAVOCCIxJGlLyHBTwZH2ie5R+YUGN9M6H4YnTZoEFwTLvMM5dJyY /nOKHvN4lc/ea+jS3de6kuYEXw== X-Google-Smtp-Source: APXvYqwOWjtbYtWknl4UkWTjpQEhekZVVkt8T8cNU9N7dgD8W9ctQnQV3fXsHsv11R0fWzIAKQ9FVQ== X-Received: by 2002:a63:3048:: with SMTP id w69mr26679991pgw.184.1582588850449; Mon, 24 Feb 2020 16:00:50 -0800 (PST) Received: from apsdesk.mtv.corp.google.com ([2620:15c:202:1:e09a:8d06:a338:aafb]) by smtp.gmail.com with ESMTPSA id c188sm14477657pfb.151.2020.02.24.16.00.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 24 Feb 2020 16:00:49 -0800 (PST) From: Abhishek Pandit-Subedi To: marcel@holtmann.org, luiz.dentz@gmail.com, alainm@chromium.org Cc: linux-bluetooth@vger.kernel.org, chromeos-bluetooth-upstreaming@chromium.org, Abhishek Pandit-Subedi , "David S. Miller" , Johan Hedberg , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Jakub Kicinski Subject: [RFC PATCH v3 3/5] Bluetooth: Handle BR/EDR devices during suspend Date: Mon, 24 Feb 2020 16:00:34 -0800 Message-Id: <20200224160019.RFC.v3.3.Icc7c35e1cabf10f8a383a009694987520f1d1b35@changeid> X-Mailer: git-send-email 2.25.0.265.gbab2e86ba0-goog In-Reply-To: <20200225000036.156250-1-abhishekpandit@chromium.org> References: <20200225000036.156250-1-abhishekpandit@chromium.org> MIME-Version: 1.0 Sender: linux-bluetooth-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org To handle BR/EDR devices, we first disable page scan and disconnect all connected devices. Once that is complete, we add event filters (for devices that can wake the system) and re-enable page scan. Signed-off-by: Abhishek Pandit-Subedi --- Changes in v3: * Refactored to only handle BR/EDR devices Changes in v2: * Refactored filters and whitelist settings to its own patch * Refactored update_white_list to have clearer edge cases * Add connected devices to whitelist (previously missing corner case) include/net/bluetooth/hci.h | 17 ++++-- include/net/bluetooth/hci_core.h | 9 ++- net/bluetooth/hci_core.c | 21 ++++++- net/bluetooth/hci_event.c | 24 ++++++++ net/bluetooth/hci_request.c | 101 +++++++++++++++++++++++++++++++ 5 files changed, 162 insertions(+), 10 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 6293bdd7d862..720d8e633f7e 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -932,10 +932,14 @@ struct hci_cp_sniff_subrate { #define HCI_OP_RESET 0x0c03 #define HCI_OP_SET_EVENT_FLT 0x0c05 -struct hci_cp_set_event_flt { - __u8 flt_type; - __u8 cond_type; - __u8 condition[0]; +#define HCI_SET_EVENT_FLT_SIZE 9 +struct hci_cp_set_event_filter { + __u8 flt_type; + __u8 cond_type; + struct { + bdaddr_t bdaddr; + __u8 auto_accept; + } __packed addr_conn_flt; } __packed; /* Filter types */ @@ -949,8 +953,9 @@ struct hci_cp_set_event_flt { #define HCI_CONN_SETUP_ALLOW_BDADDR 0x02 /* CONN_SETUP Conditions */ -#define HCI_CONN_SETUP_AUTO_OFF 0x01 -#define HCI_CONN_SETUP_AUTO_ON 0x02 +#define HCI_CONN_SETUP_AUTO_OFF 0x01 +#define HCI_CONN_SETUP_AUTO_ON 0x02 +#define HCI_CONN_SETUP_AUTO_ON_WITH_RS 0x03 #define HCI_OP_READ_STORED_LINK_KEY 0x0c0d struct hci_cp_read_stored_link_key { diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index bc9620e5b65b..2723a608183e 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -91,13 +91,18 @@ struct discovery_state { #define SUSPEND_NOTIFIER_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ enum suspend_tasks { + SUSPEND_SCAN_DISABLE, + SUSPEND_SCAN_ENABLE, + SUSPEND_DISCONNECTING, + SUSPEND_PREPARE_NOTIFIER, __SUSPEND_NUM_TASKS }; enum suspended_state { BT_RUNNING = 0, - BT_SUSPENDED, + BT_SUSPEND_DISCONNECT, + BT_SUSPEND_COMPLETE, }; struct hci_conn_hash { @@ -406,6 +411,8 @@ struct hci_dev { struct work_struct suspend_prepare; enum suspended_state suspend_state_next; enum suspended_state suspend_state; + bool scanning_paused; + bool suspended; wait_queue_head_t suspend_wait_q; DECLARE_BITMAP(suspend_tasks, __SUSPEND_NUM_TASKS); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 6ca0aa8d30dd..66b5dbbe8ea0 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3287,16 +3287,31 @@ static int hci_suspend_notifier(struct notifier_block *nb, unsigned long action, int ret = 0; if (action == PM_SUSPEND_PREPARE) { - hdev->suspend_state_next = BT_SUSPENDED; + /* Suspend consists of two actions: + * - First, disconnect everything and make the controller not + * connectable (disabling scanning) + * - Second, program event filter/whitelist and enable scan + */ + hdev->suspend_state_next = BT_SUSPEND_DISCONNECT; set_bit(SUSPEND_PREPARE_NOTIFIER, hdev->suspend_tasks); queue_work(hdev->req_workqueue, &hdev->suspend_prepare); - ret = hci_suspend_wait_event(hdev); + + /* If the disconnect portion failed, don't attempt to complete + * by configuring the whitelist. The suspend notifier will + * follow a cancelled suspend with a PM_POST_SUSPEND + * notification. + */ + if (!ret) { + hdev->suspend_state_next = BT_SUSPEND_COMPLETE; + set_bit(SUSPEND_PREPARE_NOTIFIER, hdev->suspend_tasks); + queue_work(hdev->req_workqueue, &hdev->suspend_prepare); + ret = hci_suspend_wait_event(hdev); + } } else if (action == PM_POST_SUSPEND) { hdev->suspend_state_next = BT_RUNNING; set_bit(SUSPEND_PREPARE_NOTIFIER, hdev->suspend_tasks); queue_work(hdev->req_workqueue, &hdev->suspend_prepare); - ret = hci_suspend_wait_event(hdev); } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 591e7477e925..e3c36230f705 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2474,6 +2474,7 @@ static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb) static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_conn_complete *ev = (void *) skb->data; + struct inquiry_entry *ie; struct hci_conn *conn; BT_DBG("%s", hdev->name); @@ -2482,6 +2483,21 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); if (!conn) { + /* Connection may not exist if auto-connected. Check the inquiry + * cache to see if we've already discovered this bdaddr before. + * If found and link is an ACL type, create a connection class + * automatically. + */ + ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr); + if (ie && ev->link_type == ACL_LINK) { + conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr, + HCI_ROLE_SLAVE); + if (!conn) { + bt_dev_err(hdev, "no memory for new conn"); + goto unlock; + } + } + if (ev->link_type != SCO_LINK) goto unlock; @@ -2743,6 +2759,14 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_disconn_cfm(conn, ev->reason); hci_conn_del(conn); + /* The suspend notifier is waiting for all devices to disconnect so + * clear the bit from pending tasks and inform the wait queue. + */ + if (list_empty(&hdev->conn_hash.list) && + test_and_clear_bit(SUSPEND_DISCONNECTING, hdev->suspend_tasks)) { + wake_up(&hdev->suspend_wait_q); + } + /* Re-enable advertising if necessary, since it might * have been disabled by the connection. From the * HCI_LE_Set_Advertise_Enable command description in diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index 08908469c043..4d67b1d08608 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -918,12 +918,62 @@ static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance) return adv_instance->scan_rsp_len; } +static void hci_req_clear_event_filter(struct hci_request *req) +{ + struct hci_cp_set_event_filter f; + + memset(&f, 0, sizeof(f)); + f.flt_type = HCI_FLT_CLEAR_ALL; + hci_req_add(req, HCI_OP_SET_EVENT_FLT, 1, &f); + + /* Update page scan state (since we may have modified it when setting + * the event filter). + */ + __hci_req_update_scan(req); +} + +static void hci_req_set_event_filter(struct hci_request *req) +{ + struct bdaddr_list *b; + struct hci_cp_set_event_filter f; + struct hci_dev *hdev = req->hdev; + u8 scan; + + /* Always clear event filter when starting */ + hci_req_clear_event_filter(req); + + list_for_each_entry(b, &hdev->wakeable, list) { + memset(&f, 0, sizeof(f)); + bacpy(&f.addr_conn_flt.bdaddr, &b->bdaddr); + f.flt_type = HCI_FLT_CONN_SETUP; + f.cond_type = HCI_CONN_SETUP_ALLOW_BDADDR; + f.addr_conn_flt.auto_accept = HCI_CONN_SETUP_AUTO_ON; + + BT_DBG("Adding event filters for %pMR", &b->bdaddr); + hci_req_add(req, HCI_OP_SET_EVENT_FLT, sizeof(f), &f); + } + + scan = !list_empty(&hdev->wakeable) ? SCAN_PAGE : SCAN_DISABLED; + hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); +} + +static void suspend_req_complete(struct hci_dev *hdev, u8 status, u16 opcode) +{ + BT_DBG("Request complete opcode=0x%x, status=0x%x", opcode, status); + if (test_and_clear_bit(SUSPEND_SCAN_ENABLE, hdev->suspend_tasks) || + test_and_clear_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks)) { + wake_up(&hdev->suspend_wait_q); + } +} + /* Call with hci_dev_lock */ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next) { int old_state; struct hci_conn *conn; struct hci_request req; + u8 page_scan; + int disconnect_counter; if (next == hdev->suspend_state) { BT_DBG("Same state before and after: %d", next); @@ -931,6 +981,54 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next) } hdev->suspend_state = next; + hci_req_init(&req, hdev); + + if (next == BT_SUSPEND_DISCONNECT) { + /* Mark device as suspended */ + hdev->suspended = true; + + /* Disable page scan */ + page_scan = SCAN_DISABLED; + hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &page_scan); + + /* Mark task needing completion */ + set_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks); + + /* Prevent disconnects from causing scanning to be re-enabled */ + hdev->scanning_paused = true; + + /* Run commands before disconnecting */ + hci_req_run(&req, suspend_req_complete); + + disconnect_counter = 0; + /* Soft disconnect everything (power off) */ + list_for_each_entry(conn, &hdev->conn_hash.list, list) { + hci_disconnect(conn, HCI_ERROR_REMOTE_POWER_OFF); + disconnect_counter++; + } + + if (disconnect_counter > 0) { + BT_DBG("Had %d disconnects. Will wait on them", + disconnect_counter); + set_bit(SUSPEND_DISCONNECTING, hdev->suspend_tasks); + } + } else if (next == BT_SUSPEND_COMPLETE) { + /* Unpause to take care of updating scanning params */ + hdev->scanning_paused = false; + /* Enable event filter for paired devices */ + hci_req_set_event_filter(&req); + /* Pause scan changes again. */ + hdev->scanning_paused = true; + hci_req_run(&req, suspend_req_complete); + } else { + hdev->suspended = false; + hdev->scanning_paused = false; + + hci_req_clear_event_filter(&req); + hci_req_run(&req, suspend_req_complete); + } + + hdev->suspend_state = next; done: clear_bit(SUSPEND_PREPARE_NOTIFIER, hdev->suspend_tasks); @@ -2034,6 +2132,9 @@ void __hci_req_update_scan(struct hci_request *req) if (mgmt_powering_down(hdev)) return; + if (hdev->scanning_paused) + return; + if (hci_dev_test_flag(hdev, HCI_CONNECTABLE) || disconnected_whitelist_entries(hdev)) scan = SCAN_PAGE; From patchwork Tue Feb 25 00:00:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Abhishek Pandit-Subedi X-Patchwork-Id: 11402193 X-Patchwork-Delegate: marcel@holtmann.org Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B6B7914BC for ; Tue, 25 Feb 2020 00:01:01 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 82E6421D7E for ; Tue, 25 Feb 2020 00:01:01 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="gV+jwYMR" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728640AbgBYAA4 (ORCPT ); Mon, 24 Feb 2020 19:00:56 -0500 Received: from mail-pl1-f194.google.com ([209.85.214.194]:39953 "EHLO mail-pl1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727976AbgBYAAz (ORCPT ); Mon, 24 Feb 2020 19:00:55 -0500 Received: by mail-pl1-f194.google.com with SMTP id y1so4713990plp.7 for ; Mon, 24 Feb 2020 16:00:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=myJLgG9BE+MUXNRRJ0hieOGmdciJV1l3cKauPWcptSU=; b=gV+jwYMRdCuUvb4VhBxge+ppcWXXFigYDestJDpLmuG9m7owNDMIGwbUwMqK5NEBwm sbzQGiWQSMx9JOk78lk248hTduBHePvmWoVII1OCvuonwVLd2901qQY3Nl1/zQ6VLFUE V51RTv25AN/DAx2UHYyNZpRyXUdMz5mZeHc6Q= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=myJLgG9BE+MUXNRRJ0hieOGmdciJV1l3cKauPWcptSU=; b=bWw77PFpN7tOCrff9HzG3L+0q2ZPw1gY/iBfBYbsTocApGnZIFAW4FD8ZNWjgWeyQ4 qnn3buj7yCmNzd4oisWK0QIMQpfxvU62LFRtPKg4iX3ezGn+kCcPDxeHbpXd5JGmLpwc pZP6sfC8R61EGFPX2ifNcA4oAOVopX065KOQdTOJ5nfs/83aDuaeM7jptXy4mvdyIftL oGTMaHqZBXRo24oghz6bQih3XHZ2YiO4F0pZL9lmJmC6ioTbH3HmloO3h4ThZajwDESQ x7wHQqSEHLyxSgS3Bh/tRLtqzZl7Fjv33r0KYlEkaY06pRgRHzQOL0w8p3sG+B5K41MT sbSQ== X-Gm-Message-State: APjAAAWtW7oEdi9Jn39whe5wNfHsSj1Y3HMY2aUp++ogq5av3GRI6yok ttNIYm4NyAY+X1LedOHzFif1OA== X-Google-Smtp-Source: APXvYqxRujKEdv5iqske1ySlD5V/kC3NklON/+EJd06CjFw9d0enrxl043JqWWeaAN0pQvLZLiO+Jw== X-Received: by 2002:a17:90a:2ec7:: with SMTP id h7mr1837219pjs.107.1582588853256; Mon, 24 Feb 2020 16:00:53 -0800 (PST) Received: from apsdesk.mtv.corp.google.com ([2620:15c:202:1:e09a:8d06:a338:aafb]) by smtp.gmail.com with ESMTPSA id c188sm14477657pfb.151.2020.02.24.16.00.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 24 Feb 2020 16:00:51 -0800 (PST) From: Abhishek Pandit-Subedi To: marcel@holtmann.org, luiz.dentz@gmail.com, alainm@chromium.org Cc: linux-bluetooth@vger.kernel.org, chromeos-bluetooth-upstreaming@chromium.org, Abhishek Pandit-Subedi , "David S. Miller" , Johan Hedberg , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Jakub Kicinski Subject: [RFC PATCH v3 4/5] Bluetooth: Handle LE devices during suspend Date: Mon, 24 Feb 2020 16:00:35 -0800 Message-Id: <20200224160019.RFC.v3.4.Ib0d1956aff8b9b0eff8efff085675f2156fe91c5@changeid> X-Mailer: git-send-email 2.25.0.265.gbab2e86ba0-goog In-Reply-To: <20200225000036.156250-1-abhishekpandit@chromium.org> References: <20200225000036.156250-1-abhishekpandit@chromium.org> MIME-Version: 1.0 Sender: linux-bluetooth-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org To handle LE devices, we must first disable passive scanning and disconnect all connected devices. Once that is complete, we update the whitelist and re-enable scanning Signed-off-by: Abhishek Pandit-Subedi --- Changes in v3: * Split LE changes into its own commit Changes in v2: None net/bluetooth/hci_request.c | 164 ++++++++++++++++++++++++------------ 1 file changed, 110 insertions(+), 54 deletions(-) diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index 4d67b1d08608..88fd95d70f89 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -34,6 +34,9 @@ #define HCI_REQ_PEND 1 #define HCI_REQ_CANCELED 2 +#define LE_SUSPEND_SCAN_WINDOW 0x0012 +#define LE_SUSPEND_SCAN_INTERVAL 0x0060 + void hci_req_init(struct hci_request *req, struct hci_dev *hdev) { skb_queue_head_init(&req->cmd_q); @@ -654,6 +657,11 @@ void hci_req_add_le_scan_disable(struct hci_request *req) { struct hci_dev *hdev = req->hdev; + if (hdev->scanning_paused) { + BT_DBG("Scanning is paused for suspend"); + return; + } + if (use_ext_scan(hdev)) { struct hci_cp_le_set_ext_scan_enable cp; @@ -670,15 +678,53 @@ void hci_req_add_le_scan_disable(struct hci_request *req) } } -static void add_to_white_list(struct hci_request *req, - struct hci_conn_params *params) +static void del_from_white_list(struct hci_request *req, bdaddr_t *bdaddr, + u8 bdaddr_type) +{ + struct hci_cp_le_del_from_white_list cp; + + cp.bdaddr_type = bdaddr_type; + bacpy(&cp.bdaddr, bdaddr); + + BT_DBG("Remove %pMR (0x%x) from whitelist", &cp.bdaddr, cp.bdaddr_type); + hci_req_add(req, HCI_OP_LE_DEL_FROM_WHITE_LIST, sizeof(cp), &cp); +} + +/* Adds connection to white list if needed. On error, returns -1. */ +static int add_to_white_list(struct hci_request *req, + struct hci_conn_params *params, u8 *num_entries, + bool allow_rpa) { struct hci_cp_le_add_to_white_list cp; + struct hci_dev *hdev = req->hdev; + + /* Already in white list */ + if (hci_bdaddr_list_lookup(&hdev->le_white_list, ¶ms->addr, + params->addr_type)) + return 0; + + /* Select filter policy to accept all advertising */ + if (*num_entries >= hdev->le_white_list_size) + return -1; + /* White list can not be used with RPAs */ + if (!allow_rpa && + hci_find_irk_by_addr(hdev, ¶ms->addr, params->addr_type)) { + return -1; + } + + /* During suspend, only wakeable devices can be in whitelist */ + if (hdev->suspended && !params->wakeable) + return 0; + + *num_entries += 1; cp.bdaddr_type = params->addr_type; bacpy(&cp.bdaddr, ¶ms->addr); + BT_DBG("Add %pMR (0x%x) to whitelist", &cp.bdaddr, cp.bdaddr_type); hci_req_add(req, HCI_OP_LE_ADD_TO_WHITE_LIST, sizeof(cp), &cp); + + return 0; } static u8 update_white_list(struct hci_request *req) @@ -686,7 +732,14 @@ static u8 update_white_list(struct hci_request *req) struct hci_dev *hdev = req->hdev; struct hci_conn_params *params; struct bdaddr_list *b; - uint8_t white_list_entries = 0; + u8 num_entries = 0; + bool pend_conn, pend_report; + /* We allow whitelisting even with RPAs in suspend. In the worst case, + * we won't be able to wake from devices that use the privacy1.2 + * features. Additionally, once we support privacy1.2 and IRK + * offloading, we can update this to also check for those conditions. + */ + bool allow_rpa = hdev->suspended; /* Go through the current white list programmed into the * controller one by one and check if that address is still @@ -695,29 +748,28 @@ static u8 update_white_list(struct hci_request *req) * command to remove it from the controller. */ list_for_each_entry(b, &hdev->le_white_list, list) { - /* If the device is neither in pend_le_conns nor - * pend_le_reports then remove it from the whitelist. + pend_conn = hci_pend_le_action_lookup(&hdev->pend_le_conns, + &b->bdaddr, + b->bdaddr_type); + pend_report = hci_pend_le_action_lookup(&hdev->pend_le_reports, + &b->bdaddr, + b->bdaddr_type); + + /* If the device is not likely to connect or report, + * remove it from the whitelist. */ - if (!hci_pend_le_action_lookup(&hdev->pend_le_conns, - &b->bdaddr, b->bdaddr_type) && - !hci_pend_le_action_lookup(&hdev->pend_le_reports, - &b->bdaddr, b->bdaddr_type)) { - struct hci_cp_le_del_from_white_list cp; - - cp.bdaddr_type = b->bdaddr_type; - bacpy(&cp.bdaddr, &b->bdaddr); - - hci_req_add(req, HCI_OP_LE_DEL_FROM_WHITE_LIST, - sizeof(cp), &cp); + if (!pend_conn && !pend_report) { + del_from_white_list(req, &b->bdaddr, b->bdaddr_type); continue; } - if (hci_find_irk_by_addr(hdev, &b->bdaddr, b->bdaddr_type)) { - /* White list can not be used with RPAs */ + /* White list can not be used with RPAs */ + if (!allow_rpa && + hci_find_irk_by_addr(hdev, &b->bdaddr, b->bdaddr_type)) { return 0x00; } - white_list_entries++; + num_entries++; } /* Since all no longer valid white list entries have been @@ -731,47 +783,17 @@ static u8 update_white_list(struct hci_request *req) * white list. */ list_for_each_entry(params, &hdev->pend_le_conns, action) { - if (hci_bdaddr_list_lookup(&hdev->le_white_list, - ¶ms->addr, params->addr_type)) - continue; - - if (white_list_entries >= hdev->le_white_list_size) { - /* Select filter policy to accept all advertising */ + if (add_to_white_list(req, params, &num_entries, allow_rpa)) return 0x00; - } - - if (hci_find_irk_by_addr(hdev, ¶ms->addr, - params->addr_type)) { - /* White list can not be used with RPAs */ - return 0x00; - } - - white_list_entries++; - add_to_white_list(req, params); } /* After adding all new pending connections, walk through * the list of pending reports and also add these to the - * white list if there is still space. + * white list if there is still space. Abort if space runs out. */ list_for_each_entry(params, &hdev->pend_le_reports, action) { - if (hci_bdaddr_list_lookup(&hdev->le_white_list, - ¶ms->addr, params->addr_type)) - continue; - - if (white_list_entries >= hdev->le_white_list_size) { - /* Select filter policy to accept all advertising */ + if (add_to_white_list(req, params, &num_entries, allow_rpa)) return 0x00; - } - - if (hci_find_irk_by_addr(hdev, ¶ms->addr, - params->addr_type)) { - /* White list can not be used with RPAs */ - return 0x00; - } - - white_list_entries++; - add_to_white_list(req, params); } /* Select filter policy to use white list */ @@ -866,6 +888,12 @@ void hci_req_add_le_passive_scan(struct hci_request *req) struct hci_dev *hdev = req->hdev; u8 own_addr_type; u8 filter_policy; + u8 window, interval; + + if (hdev->scanning_paused) { + BT_DBG("Scanning is paused for suspend"); + return; + } /* Set require_privacy to false since no SCAN_REQ are send * during passive scanning. Not using an non-resolvable address @@ -896,8 +924,17 @@ void hci_req_add_le_passive_scan(struct hci_request *req) (hdev->le_features[0] & HCI_LE_EXT_SCAN_POLICY)) filter_policy |= 0x02; - hci_req_start_scan(req, LE_SCAN_PASSIVE, hdev->le_scan_interval, - hdev->le_scan_window, own_addr_type, filter_policy); + if (hdev->suspended) { + window = LE_SUSPEND_SCAN_WINDOW; + interval = LE_SUSPEND_SCAN_INTERVAL; + } else { + window = hdev->le_scan_window; + interval = hdev->le_scan_interval; + } + + BT_DBG("LE passive scan with whitelist = %d", filter_policy); + hci_req_start_scan(req, LE_SCAN_PASSIVE, interval, window, + own_addr_type, filter_policy); } static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance) @@ -957,6 +994,18 @@ static void hci_req_set_event_filter(struct hci_request *req) hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); } +static void hci_req_config_le_suspend_scan(struct hci_request *req) +{ + /* Can't change params without disabling first */ + hci_req_add_le_scan_disable(req); + + /* Configure params and enable scanning */ + hci_req_add_le_passive_scan(req); + + /* Block suspend notifier on response */ + set_bit(SUSPEND_SCAN_ENABLE, req->hdev->suspend_tasks); +} + static void suspend_req_complete(struct hci_dev *hdev, u8 status, u16 opcode) { BT_DBG("Request complete opcode=0x%x, status=0x%x", opcode, status); @@ -991,6 +1040,9 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next) page_scan = SCAN_DISABLED; hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &page_scan); + /* Disable LE passive scan */ + hci_req_add_le_scan_disable(&req); + /* Mark task needing completion */ set_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks); @@ -1017,6 +1069,8 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next) hdev->scanning_paused = false; /* Enable event filter for paired devices */ hci_req_set_event_filter(&req); + /* Enable passive scan at lower duty cycle */ + hci_req_config_le_suspend_scan(&req); /* Pause scan changes again. */ hdev->scanning_paused = true; hci_req_run(&req, suspend_req_complete); @@ -1025,6 +1079,8 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next) hdev->scanning_paused = false; hci_req_clear_event_filter(&req); + /* Reset passive/background scanning to normal */ + hci_req_config_le_suspend_scan(&req); hci_req_run(&req, suspend_req_complete); } From patchwork Tue Feb 25 00:00:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Abhishek Pandit-Subedi X-Patchwork-Id: 11402191 X-Patchwork-Delegate: marcel@holtmann.org Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 92F61138D for ; Tue, 25 Feb 2020 00:00:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 6810F24672 for ; Tue, 25 Feb 2020 00:00:58 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="nrNCzO17" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728649AbgBYAA4 (ORCPT ); Mon, 24 Feb 2020 19:00:56 -0500 Received: from mail-pj1-f65.google.com ([209.85.216.65]:53290 "EHLO mail-pj1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728635AbgBYAAz (ORCPT ); Mon, 24 Feb 2020 19:00:55 -0500 Received: by mail-pj1-f65.google.com with SMTP id n96so456951pjc.3 for ; Mon, 24 Feb 2020 16:00:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=xHRY7WtQ/mTsM4blN4RvkEu7lSvJwYKGrcsPCUjqi1w=; b=nrNCzO17Ip6gwc/HJhU+z2ULsZYfZdYh52BwHIBofjhEaQsisKLQf+p4DpHb39Oz0A fslccTXzhPbffblSV+7qwYDEzFnRhDJ2UO8upFmFz8pebaVwFKlzX6/aNp/PQiCAIZuE LUNM5OwUt4WxcD1GG0/k1WkBhamtpYE+LX6OE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=xHRY7WtQ/mTsM4blN4RvkEu7lSvJwYKGrcsPCUjqi1w=; b=RUObLQPqot4ajJZeiJ5CsXvPX1qS+j2PXZUiRgtEULmYZHTSL5hcPG8ZGav76zLDik dVgt9pSdOwqLQ42WWsQjHUvvenFfSNjSnZ+zFwbxvzk+AaWo72oL3gCOm/QjCcaEeTl0 kVAFICMRURYIW0fylOVmYwNuQ96QODpqdR3el2c0FDGs/az1W8DqxJMVE0rojmN9Ot8W VMubjZmQVtldy3zd+btN6Lb7RKLEVVYXj7gd3AI/0tzGPDGk+TJgf/OKHy1Oxu5MNWVJ 70vtaNuCR9WeT4RhMUbEbHCSVKmLErG3QsAOMcbfrxQKVSHF53RdeOK0leGUUZ/5pZ8P R8FQ== X-Gm-Message-State: APjAAAUtZSPgbz2kWcykV9Ze0qqKqGUUdmfNKnzkQoVU3DddYVv/Utkb hoDNGlGA1AE1WLnA4YgB3ZZdhg== X-Google-Smtp-Source: APXvYqyEo8nafOO4GtiPLOCcQTE8wcq6OhIY5ASSpLxQpulK8z0O3H5wWbZb8HqXzVnKaUSlYPIemw== X-Received: by 2002:a17:90a:8a98:: with SMTP id x24mr1892450pjn.113.1582588854288; Mon, 24 Feb 2020 16:00:54 -0800 (PST) Received: from apsdesk.mtv.corp.google.com ([2620:15c:202:1:e09a:8d06:a338:aafb]) by smtp.gmail.com with ESMTPSA id c188sm14477657pfb.151.2020.02.24.16.00.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 24 Feb 2020 16:00:53 -0800 (PST) From: Abhishek Pandit-Subedi To: marcel@holtmann.org, luiz.dentz@gmail.com, alainm@chromium.org Cc: linux-bluetooth@vger.kernel.org, chromeos-bluetooth-upstreaming@chromium.org, Abhishek Pandit-Subedi , "David S. Miller" , Johan Hedberg , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Jakub Kicinski Subject: [RFC PATCH v3 5/5] Bluetooth: Pause discovery and advertising during suspend Date: Mon, 24 Feb 2020 16:00:36 -0800 Message-Id: <20200224160019.RFC.v3.5.Iccdad520469ca3524a7e5966c5f88e5bca756e13@changeid> X-Mailer: git-send-email 2.25.0.265.gbab2e86ba0-goog In-Reply-To: <20200225000036.156250-1-abhishekpandit@chromium.org> References: <20200225000036.156250-1-abhishekpandit@chromium.org> MIME-Version: 1.0 Sender: linux-bluetooth-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org To prevent spurious wake ups, we disable any discovery or advertising when we enter suspend and restore it when we exit suspend. While paused, we disable any management requests to modify discovery or advertising. Signed-off-by: Abhishek Pandit-Subedi --- Changes in v3: None Changes in v2: * Refactored pause discovery + advertising into its own patch include/net/bluetooth/hci_core.h | 11 ++++++++ net/bluetooth/hci_request.c | 43 ++++++++++++++++++++++++++++++++ net/bluetooth/mgmt.c | 41 ++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2723a608183e..41ea2d8c73d4 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -91,6 +91,12 @@ struct discovery_state { #define SUSPEND_NOTIFIER_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ enum suspend_tasks { + SUSPEND_PAUSE_DISCOVERY, + SUSPEND_UNPAUSE_DISCOVERY, + + SUSPEND_PAUSE_ADVERTISING, + SUSPEND_UNPAUSE_ADVERTISING, + SUSPEND_SCAN_DISABLE, SUSPEND_SCAN_ENABLE, SUSPEND_DISCONNECTING, @@ -407,6 +413,11 @@ struct hci_dev { struct discovery_state discovery; + int discovery_old_state; + bool discovery_paused; + int advertising_old_state; + bool advertising_paused; + struct notifier_block suspend_notifier; struct work_struct suspend_prepare; enum suspended_state suspend_state_next; diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index 88fd95d70f89..e25cfb6fd9aa 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -1036,6 +1036,28 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next) /* Mark device as suspended */ hdev->suspended = true; + /* Pause discovery if not already stopped */ + old_state = hdev->discovery.state; + if (old_state != DISCOVERY_STOPPED) { + set_bit(SUSPEND_PAUSE_DISCOVERY, hdev->suspend_tasks); + hci_discovery_set_state(hdev, DISCOVERY_STOPPING); + queue_work(hdev->req_workqueue, &hdev->discov_update); + } + + hdev->discovery_paused = true; + hdev->discovery_old_state = old_state; + + /* Stop advertising */ + old_state = hci_dev_test_flag(hdev, HCI_ADVERTISING); + if (old_state) { + set_bit(SUSPEND_PAUSE_ADVERTISING, hdev->suspend_tasks); + cancel_delayed_work(&hdev->discov_off); + queue_delayed_work(hdev->req_workqueue, + &hdev->discov_off, 0); + } + + hdev->advertising_paused = true; + hdev->advertising_old_state = old_state; /* Disable page scan */ page_scan = SCAN_DISABLED; hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &page_scan); @@ -1081,6 +1103,27 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next) hci_req_clear_event_filter(&req); /* Reset passive/background scanning to normal */ hci_req_config_le_suspend_scan(&req); + + /* Unpause advertising */ + hdev->advertising_paused = false; + if (hdev->advertising_old_state) { + set_bit(SUSPEND_UNPAUSE_ADVERTISING, + hdev->suspend_tasks); + hci_dev_set_flag(hdev, HCI_ADVERTISING); + queue_work(hdev->req_workqueue, + &hdev->discoverable_update); + hdev->advertising_old_state = 0; + } + + /* Unpause discovery */ + hdev->discovery_paused = false; + if (hdev->discovery_old_state != DISCOVERY_STOPPED && + hdev->discovery_old_state != DISCOVERY_STOPPING) { + set_bit(SUSPEND_UNPAUSE_DISCOVERY, hdev->suspend_tasks); + hci_discovery_set_state(hdev, DISCOVERY_STARTING); + queue_work(hdev->req_workqueue, &hdev->discov_update); + } + hci_req_run(&req, suspend_req_complete); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9a873097000b..b41c2e3cf3bb 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1383,6 +1383,12 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, goto failed; } + if (hdev->advertising_paused) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, + MGMT_STATUS_BUSY); + goto failed; + } + if (!hdev_is_powered(hdev)) { bool changed = false; @@ -3866,6 +3872,13 @@ void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status) } hci_dev_unlock(hdev); + + /* Handle suspend notifier */ + if (test_and_clear_bit(SUSPEND_UNPAUSE_DISCOVERY, + hdev->suspend_tasks)) { + BT_DBG("Unpaused discovery"); + wake_up(&hdev->suspend_wait_q); + } } static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type, @@ -3927,6 +3940,13 @@ static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev, goto failed; } + /* Can't start discovery when it is paused */ + if (hdev->discovery_paused) { + err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY, + &cp->type, sizeof(cp->type)); + goto failed; + } + /* Clear the discovery filter first to free any previously * allocated memory for the UUID list. */ @@ -4094,6 +4114,12 @@ void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status) } hci_dev_unlock(hdev); + + /* Handle suspend notifier */ + if (test_and_clear_bit(SUSPEND_PAUSE_DISCOVERY, hdev->suspend_tasks)) { + BT_DBG("Paused discovery"); + wake_up(&hdev->suspend_wait_q); + } } static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data, @@ -4325,6 +4351,17 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status, if (match.sk) sock_put(match.sk); + /* Handle suspend notifier */ + if (test_and_clear_bit(SUSPEND_PAUSE_ADVERTISING, + hdev->suspend_tasks)) { + BT_DBG("Paused advertising"); + wake_up(&hdev->suspend_wait_q); + } else if (test_and_clear_bit(SUSPEND_UNPAUSE_ADVERTISING, + hdev->suspend_tasks)) { + BT_DBG("Unpaused advertising"); + wake_up(&hdev->suspend_wait_q); + } + /* If "Set Advertising" was just disabled and instance advertising was * set up earlier, then re-enable multi-instance advertising. */ @@ -4376,6 +4413,10 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING, MGMT_STATUS_INVALID_PARAMS); + if (hdev->advertising_paused) + return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING, + MGMT_STATUS_BUSY); + hci_dev_lock(hdev); val = !!cp->val;