From patchwork Thu Dec 3 10:29:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Archie Pusaka X-Patchwork-Id: 11948359 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-26.2 required=3.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 137F9C83014 for ; Thu, 3 Dec 2020 10:31:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BFDA021D1A for ; Thu, 3 Dec 2020 10:31:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388807AbgLCKbH (ORCPT ); Thu, 3 Dec 2020 05:31:07 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59104 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388801AbgLCKbG (ORCPT ); Thu, 3 Dec 2020 05:31:06 -0500 Received: from mail-pl1-x649.google.com (mail-pl1-x649.google.com [IPv6:2607:f8b0:4864:20::649]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C20E7C061A55 for ; Thu, 3 Dec 2020 02:29:50 -0800 (PST) Received: by mail-pl1-x649.google.com with SMTP id bd1so912122plb.22 for ; Thu, 03 Dec 2020 02:29:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=LgFUufeP/6GJIT+/FBOIVfpSa89RyGRkt3hInsL6vv8=; b=eq/xwaUjQ+yC41iYj9sWUZ1k+KkznoXg2gfXaN99+GUdDMSNHSwtAq3yhyapLGx7xT FYAkzvUmLS3uyff8mQCmRlNDddihzyYvy8UcD+FIfDjda09gubm7I6euR09pOtN+ZEEh gZ/KqZD25eu81rhmAyEw9NBJPbISqpU6qNxHVTK3N/DTnG1OssSzevwhT4KV3fjMVbIw nTrjEPoBoZurKWT+S7jxmdcifv62CkLSzWL2T2Z6JBqT6YKi8xJcE4UotJsquVLx1fBx pxGbe57TgtTR5XBgtsbsosbNmM50UXn9sG8WuA2rnBrc4M+YRxSiePVmlQK/FZlQR1e5 uL1w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=LgFUufeP/6GJIT+/FBOIVfpSa89RyGRkt3hInsL6vv8=; b=hCAErPn2XRIaVJQpzFrqctdIeboMAav23rsJ7EcpRUKoRdiPQXVGdmpdKV9zVUME2f 9h/phta2lpRttwDv+JzT/HbuCKpXBzdS2I36vtQdsrug2gJ3XPKt0ocgjm+MA29EkrBf FqCH+wDRVoK1LEyX51Kdf5f+U86KtAv5xXS+eBv1pNRzImzmjgAaVd3VeSq0o4iEcB7e RIi4k4n79TnPGJnaaMvpsusy5tr0e5GSSx62PtJCTJSkTDoiOZx3l/RfLR4D4htqRkEI EgDgg+goYrvqfkp/c/0d+d/C2cUNQ/FIy9J56xTi5sZoE3hiG6+GZ3XzywhzuxzbYNrK IKMw== X-Gm-Message-State: AOAM533dKikUTJi6ulrqdi2GNq4Kyti7SInDKhyHSNTsaPohWaz+zITL izNYdFRuPOJtdcqoCPU68FWDqkZhtkpLBqtliXFV77Uhomy3NCjtD8jPxO+pFW8nZgiAmonm3UQ ex/ClcF1+uyC8K1bdJGRjRs6j+M5+K1KEPEORS1KQWnxlSlU6qwix5rsXepMNHZzvewtGbPGSeK 9D X-Google-Smtp-Source: ABdhPJz1kh8OY2kfEa5qWxyAYd5fj4rgXnXnpj1E6hxkmaWSDTZKCbEpyoyG2efc/XOhnBO2b+XkFj0MmFtC Sender: "apusaka via sendgmr" X-Received: from apusaka-p920.tpe.corp.google.com ([2401:fa00:1:b:f693:9fff:fef4:2347]) (user=apusaka job=sendgmr) by 2002:a17:90b:4b07:: with SMTP id lx7mr2511105pjb.230.1606991390116; Thu, 03 Dec 2020 02:29:50 -0800 (PST) Date: Thu, 3 Dec 2020 18:29:31 +0800 In-Reply-To: <20201203102936.4049556-1-apusaka@google.com> Message-Id: <20201203182903.v1.1.I92d2e2a87419730d60136680cbe27636baf94b15@changeid> Mime-Version: 1.0 References: <20201203102936.4049556-1-apusaka@google.com> X-Mailer: git-send-email 2.29.2.454.gaff20da3a2-goog Subject: [PATCH v1 1/5] Bluetooth: advmon offload MSFT add rssi support From: Archie Pusaka To: linux-bluetooth , Marcel Holtmann Cc: CrosBT Upstreaming , Archie Pusaka , Miao-chen Chou , Yun-Hao Chung , "David S. Miller" , Jakub Kicinski , Johan Hedberg , linux-kernel@vger.kernel.org, netdev@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Archie Pusaka MSFT needs rssi parameter for monitoring advertisement packet, therefore we should supply them from mgmt. Signed-off-by: Archie Pusaka Reviewed-by: Miao-chen Chou Reviewed-by: Yun-Hao Chung --- include/net/bluetooth/hci_core.h | 9 +++++++++ include/net/bluetooth/mgmt.h | 9 +++++++++ net/bluetooth/mgmt.c | 8 ++++++++ 3 files changed, 26 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9873e1c8cd16..42d446417817 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -246,8 +246,17 @@ struct adv_pattern { __u8 value[HCI_MAX_AD_LENGTH]; }; +struct adv_rssi_thresholds { + __s8 low_threshold; + __s8 high_threshold; + __u16 low_threshold_timeout; + __u16 high_threshold_timeout; + __u8 sampling_period; +}; + struct adv_monitor { struct list_head patterns; + struct adv_rssi_thresholds rssi; bool active; __u16 handle; }; diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index d8367850e8cd..dc534837be0e 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -763,9 +763,18 @@ struct mgmt_adv_pattern { __u8 value[31]; } __packed; +struct mgmt_adv_rssi_thresholds { + __s8 high_threshold; + __le16 high_threshold_timeout; + __s8 low_threshold; + __le16 low_threshold_timeout; + __u8 sampling_period; +} __packed; + #define MGMT_OP_ADD_ADV_PATTERNS_MONITOR 0x0052 struct mgmt_cp_add_adv_patterns_monitor { __u8 pattern_count; + struct mgmt_adv_rssi_thresholds rssi; struct mgmt_adv_pattern patterns[]; } __packed; #define MGMT_ADD_ADV_PATTERNS_MONITOR_SIZE 1 diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3dfed4efa078..5f0f03dcd81d 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4237,6 +4237,14 @@ static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev, INIT_LIST_HEAD(&m->patterns); m->active = false; + m->rssi.low_threshold = cp->rssi.low_threshold; + m->rssi.low_threshold_timeout = + __le16_to_cpu(cp->rssi.low_threshold_timeout); + m->rssi.high_threshold = cp->rssi.high_threshold; + m->rssi.high_threshold_timeout = + __le16_to_cpu(cp->rssi.high_threshold_timeout); + m->rssi.sampling_period = cp->rssi.sampling_period; + for (i = 0; i < cp->pattern_count; i++) { if (++mp_cnt > HCI_MAX_ADV_MONITOR_NUM_PATTERNS) { err = mgmt_cmd_status(sk, hdev->id, From patchwork Thu Dec 3 10:29:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Archie Pusaka X-Patchwork-Id: 11948363 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-26.2 required=3.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2296CC8301A for ; Thu, 3 Dec 2020 10:31:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D1DA421D1A for ; Thu, 3 Dec 2020 10:31:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388852AbgLCKbN (ORCPT ); Thu, 3 Dec 2020 05:31:13 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59110 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388848AbgLCKbM (ORCPT ); Thu, 3 Dec 2020 05:31:12 -0500 Received: from mail-qv1-xf4a.google.com (mail-qv1-xf4a.google.com [IPv6:2607:f8b0:4864:20::f4a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D161DC08E85E for ; Thu, 3 Dec 2020 02:29:57 -0800 (PST) Received: by mail-qv1-xf4a.google.com with SMTP id t3so1252757qvp.13 for ; Thu, 03 Dec 2020 02:29:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=2MP1RjIGFF9D/gvOeRuyKdDPDniKC2v8Hvc4E66Ncv4=; b=XfUAAKss0UY0qd3zenKrgykQBXmePl5ZpSUONNcKrIvjbytcK667A5a8NgGd/UwJjB OAXWgHV6BZ2paYPseVEj3bIkJ9B0DrhmkzZboFt4VlBpF1piOJdX3uFtyTOGEmnVUWUi 7KQc1h6oHbeZXUh3uF7MZLoAKEyMTrd3UHvwVoiOisBY28Zc37wl+6gnKLvUmACYR2iL VHLjkdsVXOUud7YmsY8WOwCtvjWkPSdQ6ViHqgcuK57blLHgAXHTnpfNNDn6R+M1KlaF NhgNIT9GI4sRVHa4uPS6yvG7bYdy4PXJg2hJP/fWef38mi3n44Teeo4kUMZ6e6tl5dwt Royw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=2MP1RjIGFF9D/gvOeRuyKdDPDniKC2v8Hvc4E66Ncv4=; b=T7Z6xun8x7HlYu3BSzxE+xmss9+R1vTw80BwdUUtG0OnRx9bpiHdWcpQfJTi9KGefg 8soF+1QSeUBacRbkyry1IrfEKh9dJbhZxKgm+6RtrI+cJlWUG2dtME76d90Ng0+qDhjR zKxo6horn0xM+Gkg6/X4RB8VC7UdHQrhfnuCK3hM+MZ0+Zbu7FPeqxbuz08At9CvOltu IwTVv77db0OXNjGvsFfmR3Bi2pidYHsSyZEDM4ctUGywA77dLK868TI6PgWI1rCZtl6e PDTkZN3Wag0JdXJ/vZgcCyIpQKooSxtnu5sQCylQFpCcbXQNAyuJvbOeVhWtfuSyST+H gMag== X-Gm-Message-State: AOAM532pgKfMvNde5AdcVn2Wcybuhd+bSgf2NuHNBF1dMXcueqq9jR+K 3Xhk13gLJlWHty0UOtgO7EotoylVdpfogANOCGxqJhFrYIZQcfmw6+sgfMOnp9w/ay/9d6PRHW6 s9qX2h5JZhrm6zr+uWo1ktsG3p1U2PqL20YKE2QPiGHfnmCgpr4SdRWcZewVuPxJohRohwn6mNC F8 X-Google-Smtp-Source: ABdhPJx8hnLrP5Y4752iH/6Oc8r0mYAGDMRvTwYVP640yfa09JZ5mkva4W2cHYRhbv6Mw37t78URc0rAp9Ne Sender: "apusaka via sendgmr" X-Received: from apusaka-p920.tpe.corp.google.com ([2401:fa00:1:b:f693:9fff:fef4:2347]) (user=apusaka job=sendgmr) by 2002:ad4:4e47:: with SMTP id eb7mr2397518qvb.39.1606991396908; Thu, 03 Dec 2020 02:29:56 -0800 (PST) Date: Thu, 3 Dec 2020 18:29:32 +0800 In-Reply-To: <20201203102936.4049556-1-apusaka@google.com> Message-Id: <20201203182903.v1.2.I4969a334028027df34dab9740cd16bbce278633c@changeid> Mime-Version: 1.0 References: <20201203102936.4049556-1-apusaka@google.com> X-Mailer: git-send-email 2.29.2.454.gaff20da3a2-goog Subject: [PATCH v1 2/5] Bluetooth: advmon offload MSFT add monitor From: Archie Pusaka To: linux-bluetooth , Marcel Holtmann Cc: CrosBT Upstreaming , Archie Pusaka , Manish Mandlik , Miao-chen Chou , Yun-Hao Chung , "David S. Miller" , Jakub Kicinski , Johan Hedberg , linux-kernel@vger.kernel.org, netdev@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Archie Pusaka Enables advertising monitor offloading to the controller, if MSFT extension is supported. The kernel won't adjust the monitor parameters to match what the controller supports - that is the user space's responsibility. This patch only manages the addition of monitors. Monitor removal is going to be handled by another patch. Signed-off-by: Archie Pusaka Reviewed-by: Manish Mandlik Reviewed-by: Miao-chen Chou Reviewed-by: Yun-Hao Chung --- include/net/bluetooth/hci_core.h | 17 ++- net/bluetooth/hci_core.c | 54 +++++++-- net/bluetooth/mgmt.c | 150 +++++++++++++++-------- net/bluetooth/msft.c | 201 ++++++++++++++++++++++++++++++- net/bluetooth/msft.h | 12 ++ 5 files changed, 369 insertions(+), 65 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 42d446417817..275061a1b670 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -257,13 +257,20 @@ struct adv_rssi_thresholds { struct adv_monitor { struct list_head patterns; struct adv_rssi_thresholds rssi; - bool active; __u16 handle; + + enum { + ADV_MONITOR_STATE_NOT_REGISTERED, + ADV_MONITOR_STATE_REGISTERED, + ADV_MONITOR_STATE_OFFLOADED + } state; }; #define HCI_MIN_ADV_MONITOR_HANDLE 1 -#define HCI_MAX_ADV_MONITOR_NUM_HANDLES 32 +#define HCI_MAX_ADV_MONITOR_NUM_HANDLES 32 #define HCI_MAX_ADV_MONITOR_NUM_PATTERNS 16 +#define HCI_ADV_MONITOR_EXT_NONE 1 +#define HCI_ADV_MONITOR_EXT_MSFT 2 #define HCI_MAX_SHORT_NAME_LENGTH 10 @@ -1305,9 +1312,12 @@ void hci_adv_instances_set_rpa_expired(struct hci_dev *hdev, bool rpa_expired); void hci_adv_monitors_clear(struct hci_dev *hdev); void hci_free_adv_monitor(struct adv_monitor *monitor); -int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor); +int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status); +bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor, + int *err); int hci_remove_adv_monitor(struct hci_dev *hdev, u16 handle); bool hci_is_adv_monitoring(struct hci_dev *hdev); +int hci_get_adv_monitor_offload_ext(struct hci_dev *hdev); void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); @@ -1783,6 +1793,7 @@ void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev, u8 instance); int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip); +int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status); u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, u16 to_multiplier); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index c4aa2cbb9269..7f70812dde15 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3031,27 +3031,55 @@ void hci_free_adv_monitor(struct adv_monitor *monitor) kfree(monitor); } -/* This function requires the caller holds hdev->lock */ -int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor) +int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status) +{ + return mgmt_add_adv_patterns_monitor_complete(hdev, status); +} + +/* Assigns handle to a monitor, and if offloading is supported and power is on, + * also attempts to forward the request to the controller. + * Returns true if request is forwarded (result is pending), false otherwise. + * This function requires the caller holds hdev->lock. + */ +bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor, + int *err) { int min, max, handle; - if (!monitor) - return -EINVAL; + *err = 0; + + if (!monitor) { + *err = -EINVAL; + return false; + } min = HCI_MIN_ADV_MONITOR_HANDLE; max = HCI_MIN_ADV_MONITOR_HANDLE + HCI_MAX_ADV_MONITOR_NUM_HANDLES; handle = idr_alloc(&hdev->adv_monitors_idr, monitor, min, max, GFP_KERNEL); - if (handle < 0) - return handle; + if (handle < 0) { + *err = handle; + return false; + } - hdev->adv_monitors_cnt++; monitor->handle = handle; - hci_update_background_scan(hdev); + if (!hdev_is_powered(hdev)) + return false; - return 0; + switch (hci_get_adv_monitor_offload_ext(hdev)) { + case HCI_ADV_MONITOR_EXT_NONE: + hci_update_background_scan(hdev); + BT_DBG("%s add monitor status %d", hdev->name, *err); + /* Message was not forwarded to controller - not an error */ + return false; + case HCI_ADV_MONITOR_EXT_MSFT: + *err = msft_add_monitor_pattern(hdev, monitor); + BT_DBG("%s add monitor msft status %d", hdev->name, *err); + break; + } + + return (*err == 0); } static int free_adv_monitor(int id, void *ptr, void *data) @@ -3095,6 +3123,14 @@ bool hci_is_adv_monitoring(struct hci_dev *hdev) return !idr_is_empty(&hdev->adv_monitors_idr); } +int hci_get_adv_monitor_offload_ext(struct hci_dev *hdev) +{ + if (msft_monitor_supported(hdev)) + return HCI_ADV_MONITOR_EXT_MSFT; + + return HCI_ADV_MONITOR_EXT_NONE; +} + struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list, bdaddr_t *bdaddr, u8 type) { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 5f0f03dcd81d..d32761f64360 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4167,6 +4167,7 @@ static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev, int handle, err; size_t rp_size = 0; __u32 supported = 0; + __u32 enabled = 0; __u16 num_handles = 0; __u16 handles[HCI_MAX_ADV_MONITOR_NUM_HANDLES]; @@ -4174,12 +4175,11 @@ static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev, hci_dev_lock(hdev); - if (msft_get_features(hdev) & MSFT_FEATURE_MASK_LE_ADV_MONITOR) + if (msft_monitor_supported(hdev)) supported |= MGMT_ADV_MONITOR_FEATURE_MASK_OR_PATTERNS; - idr_for_each_entry(&hdev->adv_monitors_idr, monitor, handle) { + idr_for_each_entry(&hdev->adv_monitors_idr, monitor, handle) handles[num_handles++] = monitor->handle; - } hci_dev_unlock(hdev); @@ -4188,11 +4188,11 @@ static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev, if (!rp) return -ENOMEM; - /* Once controller-based monitoring is in place, the enabled_features - * should reflect the use. - */ + /* All supported features are currently enabled */ + enabled = supported; + rp->supported_features = cpu_to_le32(supported); - rp->enabled_features = 0; + rp->enabled_features = cpu_to_le32(enabled); rp->max_num_handles = cpu_to_le16(HCI_MAX_ADV_MONITOR_NUM_HANDLES); rp->max_num_patterns = HCI_MAX_ADV_MONITOR_NUM_PATTERNS; rp->num_handles = cpu_to_le16(num_handles); @@ -4208,6 +4208,42 @@ static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev, return err; } +int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status) +{ + struct mgmt_rp_add_adv_patterns_monitor rp; + struct mgmt_pending_cmd *cmd; + struct adv_monitor *monitor; + int err = 0; + + hci_dev_lock(hdev); + + cmd = pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev); + if (!cmd) + goto done; + + monitor = cmd->user_data; + rp.monitor_handle = cpu_to_le16(monitor->handle); + + if (!status) { + mgmt_adv_monitor_added(cmd->sk, hdev, monitor->handle); + hdev->adv_monitors_cnt++; + if (monitor->state == ADV_MONITOR_STATE_NOT_REGISTERED) + monitor->state = ADV_MONITOR_STATE_REGISTERED; + hci_update_background_scan(hdev); + } + + err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, + mgmt_status(status), &rp, sizeof(rp)); + mgmt_pending_remove(cmd); + +done: + hci_dev_unlock(hdev); + bt_dev_dbg(hdev, "add monitor %d complete, status %d", + rp.monitor_handle, status); + + return err; +} + static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { @@ -4215,27 +4251,35 @@ static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev, struct mgmt_rp_add_adv_patterns_monitor rp; struct adv_monitor *m = NULL; struct adv_pattern *p = NULL; - unsigned int mp_cnt = 0, prev_adv_monitors_cnt; + struct mgmt_pending_cmd *cmd; __u8 cp_ofst = 0, cp_len = 0; - int err, i; + int err, status, i; + bool pending; BT_DBG("request for %s", hdev->name); + hci_dev_lock(hdev); + + if (pending_find(MGMT_OP_SET_LE, hdev) || + pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) || + pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev)) { + status = MGMT_STATUS_BUSY; + goto unlock; + } + if (len <= sizeof(*cp) || cp->pattern_count == 0) { - err = mgmt_cmd_status(sk, hdev->id, - MGMT_OP_ADD_ADV_PATTERNS_MONITOR, - MGMT_STATUS_INVALID_PARAMS); - goto failed; + status = MGMT_STATUS_INVALID_PARAMS; + goto unlock; } m = kmalloc(sizeof(*m), GFP_KERNEL); if (!m) { - err = -ENOMEM; - goto failed; + status = MGMT_STATUS_NO_RESOURCES; + goto unlock; } INIT_LIST_HEAD(&m->patterns); - m->active = false; + m->state = ADV_MONITOR_STATE_NOT_REGISTERED; m->rssi.low_threshold = cp->rssi.low_threshold; m->rssi.low_threshold_timeout = @@ -4245,29 +4289,25 @@ static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev, __le16_to_cpu(cp->rssi.high_threshold_timeout); m->rssi.sampling_period = cp->rssi.sampling_period; - for (i = 0; i < cp->pattern_count; i++) { - if (++mp_cnt > HCI_MAX_ADV_MONITOR_NUM_PATTERNS) { - err = mgmt_cmd_status(sk, hdev->id, - MGMT_OP_ADD_ADV_PATTERNS_MONITOR, - MGMT_STATUS_INVALID_PARAMS); - goto failed; - } + if (cp->pattern_count > HCI_MAX_ADV_MONITOR_NUM_PATTERNS) { + status = MGMT_STATUS_INVALID_PARAMS; + goto unlock; + } + for (i = 0; i < cp->pattern_count; i++) { cp_ofst = cp->patterns[i].offset; cp_len = cp->patterns[i].length; if (cp_ofst >= HCI_MAX_AD_LENGTH || cp_len > HCI_MAX_AD_LENGTH || (cp_ofst + cp_len) > HCI_MAX_AD_LENGTH) { - err = mgmt_cmd_status(sk, hdev->id, - MGMT_OP_ADD_ADV_PATTERNS_MONITOR, - MGMT_STATUS_INVALID_PARAMS); - goto failed; + status = MGMT_STATUS_INVALID_PARAMS; + goto unlock; } p = kmalloc(sizeof(*p), GFP_KERNEL); if (!p) { - err = -ENOMEM; - goto failed; + status = MGMT_STATUS_NO_RESOURCES; + goto unlock; } p->ad_type = cp->patterns[i].ad_type; @@ -4279,43 +4319,49 @@ static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev, list_add(&p->list, &m->patterns); } - if (mp_cnt != cp->pattern_count) { - err = mgmt_cmd_status(sk, hdev->id, - MGMT_OP_ADD_ADV_PATTERNS_MONITOR, - MGMT_STATUS_INVALID_PARAMS); - goto failed; + cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADV_PATTERNS_MONITOR, + hdev, data, len); + if (!cmd) { + status = MGMT_STATUS_NO_RESOURCES; + goto unlock; } - hci_dev_lock(hdev); - - prev_adv_monitors_cnt = hdev->adv_monitors_cnt; - - err = hci_add_adv_monitor(hdev, m); + pending = hci_add_adv_monitor(hdev, m, &err); if (err) { - if (err == -ENOSPC) { - mgmt_cmd_status(sk, hdev->id, - MGMT_OP_ADD_ADV_PATTERNS_MONITOR, - MGMT_STATUS_NO_RESOURCES); - } + if (err == -ENOSPC || err == -ENOMEM) + status = MGMT_STATUS_NO_RESOURCES; + else if (err == -EINVAL) + status = MGMT_STATUS_INVALID_PARAMS; + else + status = MGMT_STATUS_FAILED; + + mgmt_pending_remove(cmd); goto unlock; } - if (hdev->adv_monitors_cnt > prev_adv_monitors_cnt) + if (!pending) { + mgmt_pending_remove(cmd); + rp.monitor_handle = cpu_to_le16(m->handle); mgmt_adv_monitor_added(sk, hdev, m->handle); + m->state = ADV_MONITOR_STATE_REGISTERED; + hdev->adv_monitors_cnt++; - hci_dev_unlock(hdev); + hci_dev_unlock(hdev); + return mgmt_cmd_complete(sk, hdev->id, + MGMT_OP_ADD_ADV_PATTERNS_MONITOR, + MGMT_STATUS_SUCCESS, &rp, sizeof(rp)); + } - rp.monitor_handle = cpu_to_le16(m->handle); + hci_dev_unlock(hdev); - return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADV_PATTERNS_MONITOR, - MGMT_STATUS_SUCCESS, &rp, sizeof(rp)); + cmd->user_data = m; + return 0; unlock: hci_dev_unlock(hdev); - -failed: hci_free_adv_monitor(m); - return err; + return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADV_PATTERNS_MONITOR, + status); } static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev, diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c index 4b39534a14a1..e4b8fe71b9c3 100644 --- a/net/bluetooth/msft.c +++ b/net/bluetooth/msft.c @@ -5,9 +5,16 @@ #include #include +#include +#include "hci_request.h" +#include "mgmt_util.h" #include "msft.h" +#define MSFT_RSSI_THRESHOLD_VALUE_MIN -127 +#define MSFT_RSSI_THRESHOLD_VALUE_MAX 20 +#define MSFT_RSSI_LOW_TIMEOUT_MAX 0x3C + #define MSFT_OP_READ_SUPPORTED_FEATURES 0x00 struct msft_cp_read_supported_features { __u8 sub_opcode; @@ -21,12 +28,55 @@ struct msft_rp_read_supported_features { __u8 evt_prefix[]; } __packed; +#define MSFT_OP_LE_MONITOR_ADVERTISEMENT 0x03 +#define MSFT_MONITOR_ADVERTISEMENT_TYPE_PATTERN 0x01 +struct msft_le_monitor_advertisement_pattern { + __u8 length; + __u8 data_type; + __u8 start_byte; + __u8 pattern[0]; +}; + +struct msft_le_monitor_advertisement_pattern_data { + __u8 count; + __u8 data[0]; +}; + +struct msft_cp_le_monitor_advertisement { + __u8 sub_opcode; + __s8 rssi_high; + __s8 rssi_low; + __u8 rssi_low_interval; + __u8 rssi_sampling_period; + __u8 cond_type; + __u8 data[0]; +} __packed; + +struct msft_rp_le_monitor_advertisement { + __u8 status; + __u8 sub_opcode; + __u8 handle; +} __packed; + +struct msft_monitor_advertisement_handle_data { + __u8 msft_handle; + __u16 mgmt_handle; + struct list_head list; +}; + struct msft_data { __u64 features; __u8 evt_prefix_len; __u8 *evt_prefix; + struct list_head handle_map; + __u16 pending_add_handle; }; +bool msft_monitor_supported(struct hci_dev *hdev) +{ + return !!(msft_get_features(hdev) & MSFT_FEATURE_MASK_LE_ADV_MONITOR); +} + static bool read_supported_features(struct hci_dev *hdev, struct msft_data *msft) { @@ -90,12 +140,14 @@ void msft_do_open(struct hci_dev *hdev) return; } + INIT_LIST_HEAD(&msft->handle_map); hdev->msft_data = msft; } void msft_do_close(struct hci_dev *hdev) { struct msft_data *msft = hdev->msft_data; + struct msft_monitor_advertisement_handle_data *handle_data, *tmp; if (!msft) return; @@ -104,6 +156,11 @@ void msft_do_close(struct hci_dev *hdev) hdev->msft_data = NULL; + list_for_each_entry_safe(handle_data, tmp, &msft->handle_map, list) { + list_del(&handle_data->list); + kfree(handle_data); + } + kfree(msft->evt_prefix); kfree(msft); } @@ -145,5 +202,147 @@ __u64 msft_get_features(struct hci_dev *hdev) { struct msft_data *msft = hdev->msft_data; - return msft ? msft->features : 0; + return msft ? msft->features : 0; +} + +static void msft_le_monitor_advertisement_cb(struct hci_dev *hdev, + u8 status, u16 opcode, + struct sk_buff *skb) +{ + struct msft_rp_le_monitor_advertisement *rp; + struct adv_monitor *monitor; + struct msft_monitor_advertisement_handle_data *handle_data; + struct msft_data *msft = hdev->msft_data; + + hci_dev_lock(hdev); + + monitor = idr_find(&hdev->adv_monitors_idr, msft->pending_add_handle); + if (!monitor) { + bt_dev_err(hdev, "msft add advmon: monitor %d is not found!", + msft->pending_add_handle); + status = HCI_ERROR_UNSPECIFIED; + goto unlock; + } + + if (status) + goto unlock; + + rp = (struct msft_rp_le_monitor_advertisement *)skb->data; + if (skb->len < sizeof(*rp)) { + status = HCI_ERROR_UNSPECIFIED; + goto unlock; + } + + handle_data = kmalloc(sizeof(*handle_data), GFP_KERNEL); + if (!handle_data) { + status = HCI_ERROR_UNSPECIFIED; + goto unlock; + } + + handle_data->mgmt_handle = monitor->handle; + handle_data->msft_handle = rp->handle; + INIT_LIST_HEAD(&handle_data->list); + list_add(&handle_data->list, &msft->handle_map); + + monitor->state = ADV_MONITOR_STATE_OFFLOADED; + +unlock: + if (status && monitor) { + idr_remove(&hdev->adv_monitors_idr, monitor->handle); + hci_free_adv_monitor(monitor); + } + + hci_dev_unlock(hdev); + + hci_add_adv_patterns_monitor_complete(hdev, status); +} + +static bool msft_monitor_rssi_valid(struct adv_monitor *monitor) +{ + struct adv_rssi_thresholds *r = &monitor->rssi; + + if (r->high_threshold < MSFT_RSSI_THRESHOLD_VALUE_MIN || + r->high_threshold > MSFT_RSSI_THRESHOLD_VALUE_MAX || + r->low_threshold < MSFT_RSSI_THRESHOLD_VALUE_MIN || + r->low_threshold > MSFT_RSSI_THRESHOLD_VALUE_MAX) + return false; + + /* High_threshold_timeout is not supported, + * once high_threshold is reached, events are immediately reported. + */ + if (r->high_threshold_timeout != 0) + return false; + + if (r->low_threshold_timeout > MSFT_RSSI_LOW_TIMEOUT_MAX) + return false; + + /* Sampling period from 0x00 to 0xFF are all allowed */ + return true; +} + +static bool msft_monitor_pattern_valid(struct adv_monitor *monitor) +{ + return msft_monitor_rssi_valid(monitor); + /* No additional check needed for pattern-based monitor */ +} + +/* This function requires the caller holds hdev->lock */ +int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor) +{ + struct msft_cp_le_monitor_advertisement *cp; + struct msft_le_monitor_advertisement_pattern_data *pattern_data; + struct msft_le_monitor_advertisement_pattern *pattern; + struct adv_pattern *entry; + struct hci_request req; + struct msft_data *msft = hdev->msft_data; + size_t total_size = sizeof(*cp) + sizeof(*pattern_data); + ptrdiff_t offset = 0; + u8 pattern_count = 0; + int err = 0; + + if (!msft) + return -EOPNOTSUPP; + + if (!msft_monitor_pattern_valid(monitor)) + return -EINVAL; + + list_for_each_entry(entry, &monitor->patterns, list) { + pattern_count++; + total_size += sizeof(*pattern) + entry->length; + } + + cp = kmalloc(total_size, GFP_KERNEL); + if (!cp) + return -ENOMEM; + + cp->sub_opcode = MSFT_OP_LE_MONITOR_ADVERTISEMENT; + cp->rssi_high = monitor->rssi.high_threshold; + cp->rssi_low = monitor->rssi.low_threshold; + cp->rssi_low_interval = (u8)monitor->rssi.low_threshold_timeout; + cp->rssi_sampling_period = monitor->rssi.sampling_period; + + cp->cond_type = MSFT_MONITOR_ADVERTISEMENT_TYPE_PATTERN; + + pattern_data = (void *)cp->data; + pattern_data->count = pattern_count; + + list_for_each_entry(entry, &monitor->patterns, list) { + pattern = (void *)(pattern_data->data + offset); + /* the length also includes data_type and offset */ + pattern->length = entry->length + 2; + pattern->data_type = entry->ad_type; + pattern->start_byte = entry->offset; + memcpy(pattern->pattern, entry->value, entry->length); + offset += sizeof(*pattern) + entry->length; + } + + hci_req_init(&req, hdev); + hci_req_add(&req, hdev->msft_opcode, total_size, cp); + err = hci_req_run_skb(&req, msft_le_monitor_advertisement_cb); + kfree(cp); + + if (!err) + msft->pending_add_handle = monitor->handle; + + return err; } diff --git a/net/bluetooth/msft.h b/net/bluetooth/msft.h index e9c478e890b8..0ac9b15322b1 100644 --- a/net/bluetooth/msft.h +++ b/net/bluetooth/msft.h @@ -12,16 +12,28 @@ #if IS_ENABLED(CONFIG_BT_MSFTEXT) +bool msft_monitor_supported(struct hci_dev *hdev); void msft_do_open(struct hci_dev *hdev); void msft_do_close(struct hci_dev *hdev); void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb); __u64 msft_get_features(struct hci_dev *hdev); +int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor); #else +static inline bool msft_monitor_supported(struct hci_dev *hdev) +{ + return false; +} + static inline void msft_do_open(struct hci_dev *hdev) {} static inline void msft_do_close(struct hci_dev *hdev) {} static inline void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb) {} static inline __u64 msft_get_features(struct hci_dev *hdev) { return 0; } +static inline int msft_add_monitor_pattern(struct hci_dev *hdev, + struct adv_monitor *monitor) +{ + return -EOPNOTSUPP; +} #endif From patchwork Thu Dec 3 10:29:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Archie Pusaka X-Patchwork-Id: 11948361 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-26.2 required=3.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E226FC83017 for ; Thu, 3 Dec 2020 10:31:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9DA0B21527 for ; Thu, 3 Dec 2020 10:31:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388669AbgLCKbN (ORCPT ); Thu, 3 Dec 2020 05:31:13 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59128 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388846AbgLCKbM (ORCPT ); Thu, 3 Dec 2020 05:31:12 -0500 Received: from mail-yb1-xb4a.google.com (mail-yb1-xb4a.google.com [IPv6:2607:f8b0:4864:20::b4a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 77033C08E861 for ; Thu, 3 Dec 2020 02:30:02 -0800 (PST) Received: by mail-yb1-xb4a.google.com with SMTP id a13so2089603ybj.3 for ; Thu, 03 Dec 2020 02:30:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=u7LA7TI+m014MHf1r0Np3Fnca+wIIXRyz0e4OSJVybk=; b=AiGnGEISBW9febMfT350l4B+LEsYU2Vyi85aZunXUCPDDqmpy++ZIaMeBaozY3vefp Yd6bISUo2tP37vay5KdrpTBhCZYbPCmzDUaqnIbKKBsb8IQTjU1ILiOnKWzeS2VOxkha gg+h+MEExNYHxsmdhXejQX8I3tiHLO6yAV5jJHVJsNAQvjut+hehTYUy7gpVyhJGtGCi lHi8797dsw4c7ExkNcWfaXMM2F23UjK/XNKgh0z0fftULr0r3g0wUMufJMmAk6gv+ZUo VLLSfgKgOruZPdUq4B0cNPRavehf+5Vd6W1xmPCQ/jqUl6OE/ZSvd6rBETAqQ73nn94H 9O8g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=u7LA7TI+m014MHf1r0Np3Fnca+wIIXRyz0e4OSJVybk=; b=UNpTps6onitUbjUKIdRvU5uL/OtfDaHKId6SX+bo8ljOLoB46Te06sJwKqxsr4QmQo 2haUGQTjCFzPYUx0cViTnFIP02aTUh9HoeaU+77lqcMduDh9+0PlItmbSZV0rP6UJopB z5OVq23Bg93LvwZ1C6yXAH4r9pw2z+z20aCxB6G6PoRdLiI9g8lEa+3N5ftfzSaL3ISd CvU5yJYPZEEcYyBDHksesTwf/Y+lXt+6+Puyp8mkCWAnohPp+SD4498zRpJ7e56uHgo4 ym5bVW/r1M67n50jFhGcoCgzUwjkqd68SuUbwdAJNxBtdKKtCj0RCj95tJjEjmME6QH9 WJ9A== X-Gm-Message-State: AOAM533grbMA/Ujnmwc9XlWntzPWgi6kKLhhrO+F35ZV9jOu3JO522pN HsgTiENbpe35VxpP+yTIGE5orSM9fX01Qe8BQbJ7oEMyd2qHJHZVp7JaO21cP3JfNkbdLL/8W2R d2VE2eHtjhoughHRL6dJVvIIpnpMEEDau4heo3IS6hkLdIoPDouFJBAscMBHRw/TdfbuAx2LihT aW X-Google-Smtp-Source: ABdhPJxeZHDgb1NLZtyJBmiArkVC0Zo0t3zCQ1zCXBGzL40EwWZRXoa6KOi3JZO1c11HK67x/1NsGn1lssIf Sender: "apusaka via sendgmr" X-Received: from apusaka-p920.tpe.corp.google.com ([2401:fa00:1:b:f693:9fff:fef4:2347]) (user=apusaka job=sendgmr) by 2002:a25:ab72:: with SMTP id u105mr3621729ybi.406.1606991401633; Thu, 03 Dec 2020 02:30:01 -0800 (PST) Date: Thu, 3 Dec 2020 18:29:33 +0800 In-Reply-To: <20201203102936.4049556-1-apusaka@google.com> Message-Id: <20201203182903.v1.3.I2bdb3d9953a91dc7865da6e57166260b3a75c146@changeid> Mime-Version: 1.0 References: <20201203102936.4049556-1-apusaka@google.com> X-Mailer: git-send-email 2.29.2.454.gaff20da3a2-goog Subject: [PATCH v1 3/5] Bluetooth: advmon offload MSFT remove monitor From: Archie Pusaka To: linux-bluetooth , Marcel Holtmann Cc: CrosBT Upstreaming , Archie Pusaka , Miao-chen Chou , Yun-Hao Chung , "David S. Miller" , Jakub Kicinski , Johan Hedberg , linux-kernel@vger.kernel.org, netdev@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Archie Pusaka Implements the monitor removal functionality for advertising monitor offloading to MSFT controllers. Supply handle = 0 to remove all monitors. Signed-off-by: Archie Pusaka Reviewed-by: Miao-chen Chou Reviewed-by: Yun-Hao Chung --- include/net/bluetooth/hci_core.h | 8 +- net/bluetooth/hci_core.c | 119 +++++++++++++++++++++++------ net/bluetooth/mgmt.c | 109 +++++++++++++++++++++----- net/bluetooth/msft.c | 127 ++++++++++++++++++++++++++++++- net/bluetooth/msft.h | 9 +++ 5 files changed, 322 insertions(+), 50 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 275061a1b670..0a211cd52fdb 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1311,11 +1311,13 @@ int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance); void hci_adv_instances_set_rpa_expired(struct hci_dev *hdev, bool rpa_expired); void hci_adv_monitors_clear(struct hci_dev *hdev); -void hci_free_adv_monitor(struct adv_monitor *monitor); +void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor); int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status); +int hci_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status); bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor, int *err); -int hci_remove_adv_monitor(struct hci_dev *hdev, u16 handle); +bool hci_remove_single_adv_monitor(struct hci_dev *hdev, u16 handle, int *err); +bool hci_remove_all_adv_monitor(struct hci_dev *hdev, int *err); bool hci_is_adv_monitoring(struct hci_dev *hdev); int hci_get_adv_monitor_offload_ext(struct hci_dev *hdev); @@ -1792,8 +1794,10 @@ void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance); void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev, u8 instance); +void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle); int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip); int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status); +int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status); u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, u16 to_multiplier); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 7f70812dde15..70bb2a11d9b1 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3012,12 +3012,15 @@ void hci_adv_monitors_clear(struct hci_dev *hdev) int handle; idr_for_each_entry(&hdev->adv_monitors_idr, monitor, handle) - hci_free_adv_monitor(monitor); + hci_free_adv_monitor(hdev, monitor); idr_destroy(&hdev->adv_monitors_idr); } -void hci_free_adv_monitor(struct adv_monitor *monitor) +/* Frees the monitor structure and do some bookkeepings. + * This function requires the caller holds hdev->lock. + */ +void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor) { struct adv_pattern *pattern; struct adv_pattern *tmp; @@ -3025,8 +3028,18 @@ void hci_free_adv_monitor(struct adv_monitor *monitor) if (!monitor) return; - list_for_each_entry_safe(pattern, tmp, &monitor->patterns, list) + list_for_each_entry_safe(pattern, tmp, &monitor->patterns, list) { + list_del(&pattern->list); kfree(pattern); + } + + if (monitor->handle) + idr_remove(&hdev->adv_monitors_idr, monitor->handle); + + if (monitor->state != ADV_MONITOR_STATE_NOT_REGISTERED) { + hdev->adv_monitors_cnt--; + mgmt_adv_monitor_removed(hdev, monitor->handle); + } kfree(monitor); } @@ -3036,6 +3049,11 @@ int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status) return mgmt_add_adv_patterns_monitor_complete(hdev, status); } +int hci_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status) +{ + return mgmt_remove_adv_monitor_complete(hdev, status); +} + /* Assigns handle to a monitor, and if offloading is supported and power is on, * also attempts to forward the request to the controller. * Returns true if request is forwarded (result is pending), false otherwise. @@ -3082,39 +3100,94 @@ bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor, return (*err == 0); } -static int free_adv_monitor(int id, void *ptr, void *data) +/* Attempts to tell the controller and free the monitor. If somehow the + * controller doesn't have a corresponding handle, remove anyway. + * Returns true if request is forwarded (result is pending), false otherwise. + * This function requires the caller holds hdev->lock. + */ +static bool hci_remove_adv_monitor(struct hci_dev *hdev, + struct adv_monitor *monitor, + u16 handle, int *err) { - struct hci_dev *hdev = data; - struct adv_monitor *monitor = ptr; + *err = 0; - idr_remove(&hdev->adv_monitors_idr, monitor->handle); - hci_free_adv_monitor(monitor); - hdev->adv_monitors_cnt--; + switch (hci_get_adv_monitor_offload_ext(hdev)) { + case HCI_ADV_MONITOR_EXT_NONE: /* also goes here when powered off */ + goto free_monitor; + case HCI_ADV_MONITOR_EXT_MSFT: + *err = msft_remove_monitor(hdev, monitor, handle); + break; + } - return 0; + /* In case no matching handle registered, just free the monitor */ + if (*err == -ENOENT) + goto free_monitor; + + return (*err == 0); + +free_monitor: + if (*err == -ENOENT) + bt_dev_warn(hdev, "Removing monitor with no matching handle %d", + monitor->handle); + hci_free_adv_monitor(hdev, monitor); + + *err = 0; + return false; } -/* This function requires the caller holds hdev->lock */ -int hci_remove_adv_monitor(struct hci_dev *hdev, u16 handle) +/* Returns true if request is forwarded (result is pending), false otherwise. + * This function requires the caller holds hdev->lock. + */ +bool hci_remove_single_adv_monitor(struct hci_dev *hdev, u16 handle, int *err) +{ + struct adv_monitor *monitor = idr_find(&hdev->adv_monitors_idr, handle); + bool pending; + + if (!monitor) { + *err = -EINVAL; + return false; + } + + pending = hci_remove_adv_monitor(hdev, monitor, handle, err); + if (!*err && !pending) + hci_update_background_scan(hdev); + + BT_DBG("%s remove monitor handle %d, status %d, %spending", + hdev->name, handle, *err, pending ? "" : "not "); + + return pending; +} + +/* Returns true if request is forwarded (result is pending), false otherwise. + * This function requires the caller holds hdev->lock. + */ +bool hci_remove_all_adv_monitor(struct hci_dev *hdev, int *err) { struct adv_monitor *monitor; + int idr_next_id = 0; + bool pending = false; + bool update = false; + + *err = 0; - if (handle) { - monitor = idr_find(&hdev->adv_monitors_idr, handle); + while (!*err && !pending) { + monitor = idr_get_next(&hdev->adv_monitors_idr, &idr_next_id); if (!monitor) - return -ENOENT; + break; - idr_remove(&hdev->adv_monitors_idr, monitor->handle); - hci_free_adv_monitor(monitor); - hdev->adv_monitors_cnt--; - } else { - /* Remove all monitors if handle is 0. */ - idr_for_each(&hdev->adv_monitors_idr, &free_adv_monitor, hdev); + pending = hci_remove_adv_monitor(hdev, monitor, 0, err); + + if (!*err && !pending) + update = true; } - hci_update_background_scan(hdev); + if (update) + hci_update_background_scan(hdev); - return 0; + BT_DBG("%s remove all monitors status %d, %spending", + hdev->name, *err, pending ? "" : "not "); + + return pending; } /* This function requires the caller holds hdev->lock */ diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d32761f64360..8af0ff10ee78 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4149,14 +4149,24 @@ static void mgmt_adv_monitor_added(struct sock *sk, struct hci_dev *hdev, mgmt_event(MGMT_EV_ADV_MONITOR_ADDED, hdev, &ev, sizeof(ev), sk); } -static void mgmt_adv_monitor_removed(struct sock *sk, struct hci_dev *hdev, - u16 handle) +void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle) { - struct mgmt_ev_adv_monitor_added ev; + struct mgmt_ev_adv_monitor_removed ev; + struct mgmt_pending_cmd *cmd; + struct sock *sk_skip = NULL; + struct mgmt_cp_remove_adv_monitor *cp; + + cmd = pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev); + if (cmd) { + cp = cmd->param; + + if (cp->monitor_handle) + sk_skip = cmd->sk; + } ev.monitor_handle = cpu_to_le16(handle); - mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk); + mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk_skip); } static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev, @@ -4358,48 +4368,105 @@ static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev, return 0; unlock: + hci_free_adv_monitor(hdev, m); hci_dev_unlock(hdev); - hci_free_adv_monitor(m); return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADV_PATTERNS_MONITOR, status); } +int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status) +{ + struct mgmt_rp_remove_adv_monitor rp; + struct mgmt_cp_remove_adv_monitor *cp; + struct mgmt_pending_cmd *cmd; + int err = 0; + + hci_dev_lock(hdev); + + cmd = pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev); + if (!cmd) + goto done; + + cp = cmd->param; + rp.monitor_handle = cp->monitor_handle; + + if (!status) + hci_update_background_scan(hdev); + + err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, + mgmt_status(status), &rp, sizeof(rp)); + mgmt_pending_remove(cmd); + +done: + hci_dev_unlock(hdev); + bt_dev_dbg(hdev, "remove monitor %d complete, status %d", + rp.monitor_handle, status); + + return err; +} + static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { struct mgmt_cp_remove_adv_monitor *cp = data; struct mgmt_rp_remove_adv_monitor rp; - unsigned int prev_adv_monitors_cnt; - u16 handle; - int err; + struct mgmt_pending_cmd *cmd; + u16 handle = __le16_to_cpu(cp->monitor_handle); + int err, status; + bool pending; BT_DBG("request for %s", hdev->name); + rp.monitor_handle = cp->monitor_handle; hci_dev_lock(hdev); - handle = __le16_to_cpu(cp->monitor_handle); - prev_adv_monitors_cnt = hdev->adv_monitors_cnt; + if (pending_find(MGMT_OP_SET_LE, hdev) || + pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev) || + pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev)) { + status = MGMT_STATUS_BUSY; + goto unlock; + } - err = hci_remove_adv_monitor(hdev, handle); - if (err == -ENOENT) { - err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADV_MONITOR, - MGMT_STATUS_INVALID_INDEX); + cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADV_MONITOR, hdev, data, len); + if (!cmd) { + status = MGMT_STATUS_NO_RESOURCES; goto unlock; } - if (hdev->adv_monitors_cnt < prev_adv_monitors_cnt) - mgmt_adv_monitor_removed(sk, hdev, handle); + if (handle) + pending = hci_remove_single_adv_monitor(hdev, handle, &err); + else + pending = hci_remove_all_adv_monitor(hdev, &err); - hci_dev_unlock(hdev); + if (err) { + mgmt_pending_remove(cmd); - rp.monitor_handle = cp->monitor_handle; + if (err == -ENOENT) + status = MGMT_STATUS_INVALID_INDEX; + else + status = MGMT_STATUS_FAILED; + + goto unlock; + } + + /* monitor can be removed without forwarding request to controller */ + if (!pending) { + mgmt_pending_remove(cmd); + hci_dev_unlock(hdev); - return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_ADV_MONITOR, - MGMT_STATUS_SUCCESS, &rp, sizeof(rp)); + return mgmt_cmd_complete(sk, hdev->id, + MGMT_OP_REMOVE_ADV_MONITOR, + MGMT_STATUS_SUCCESS, + &rp, sizeof(rp)); + } + + hci_dev_unlock(hdev); + return 0; unlock: hci_dev_unlock(hdev); - return err; + return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADV_MONITOR, + status); } static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status, diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c index e4b8fe71b9c3..f5aa0e3b1b9b 100644 --- a/net/bluetooth/msft.c +++ b/net/bluetooth/msft.c @@ -58,6 +58,17 @@ struct msft_rp_le_monitor_advertisement { __u8 handle; } __packed; +#define MSFT_OP_LE_CANCEL_MONITOR_ADVERTISEMENT 0x04 +struct msft_cp_le_cancel_monitor_advertisement { + __u8 sub_opcode; + __u8 handle; +} __packed; + +struct msft_rp_le_cancel_monitor_advertisement { + __u8 status; + __u8 sub_opcode; +} __packed; + struct msft_monitor_advertisement_handle_data { __u8 msft_handle; __u16 mgmt_handle; @@ -70,6 +81,7 @@ struct msft_data { __u8 *evt_prefix; struct list_head handle_map; __u16 pending_add_handle; + __u16 pending_remove_handle; }; bool msft_monitor_supported(struct hci_dev *hdev) @@ -205,6 +217,26 @@ __u64 msft_get_features(struct hci_dev *hdev) return msft ? msft->features : 0; } +/* is_mgmt = true matches the handle exposed to userspace via mgmt. + * is_mgmt = false matches the handle used by the msft controller. + * This function requires the caller holds hdev->lock + */ +static struct msft_monitor_advertisement_handle_data *msft_find_handle_data + (struct hci_dev *hdev, u16 handle, bool is_mgmt) +{ + struct msft_monitor_advertisement_handle_data *entry; + struct msft_data *msft = hdev->msft_data; + + list_for_each_entry(entry, &msft->handle_map, list) { + if (is_mgmt && entry->mgmt_handle == handle) + return entry; + if (!is_mgmt && entry->msft_handle == handle) + return entry; + } + + return NULL; +} + static void msft_le_monitor_advertisement_cb(struct hci_dev *hdev, u8 status, u16 opcode, struct sk_buff *skb) @@ -247,16 +279,71 @@ static void msft_le_monitor_advertisement_cb(struct hci_dev *hdev, monitor->state = ADV_MONITOR_STATE_OFFLOADED; unlock: - if (status && monitor) { - idr_remove(&hdev->adv_monitors_idr, monitor->handle); - hci_free_adv_monitor(monitor); - } + if (status && monitor) + hci_free_adv_monitor(hdev, monitor); hci_dev_unlock(hdev); hci_add_adv_patterns_monitor_complete(hdev, status); } +static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev, + u8 status, u16 opcode, + struct sk_buff *skb) +{ + struct msft_cp_le_cancel_monitor_advertisement *cp; + struct msft_rp_le_cancel_monitor_advertisement *rp; + struct adv_monitor *monitor; + struct msft_monitor_advertisement_handle_data *handle_data; + struct msft_data *msft = hdev->msft_data; + int err; + bool pending; + + if (status) + goto done; + + rp = (struct msft_rp_le_cancel_monitor_advertisement *)skb->data; + if (skb->len < sizeof(*rp)) { + status = HCI_ERROR_UNSPECIFIED; + goto done; + } + + hci_dev_lock(hdev); + + cp = hci_sent_cmd_data(hdev, hdev->msft_opcode); + handle_data = msft_find_handle_data(hdev, cp->handle, false); + + if (handle_data) { + monitor = idr_find(&hdev->adv_monitors_idr, + handle_data->mgmt_handle); + if (monitor) + hci_free_adv_monitor(hdev, monitor); + + list_del(&handle_data->list); + kfree(handle_data); + } + + /* If remove all monitors is required, we need to continue the process + * here because the earlier it was paused when waiting for the + * response from controller. + */ + if (msft->pending_remove_handle == 0) { + pending = hci_remove_all_adv_monitor(hdev, &err); + if (pending) { + hci_dev_unlock(hdev); + return; + } + + if (err) + status = HCI_ERROR_UNSPECIFIED; + } + + hci_dev_unlock(hdev); + +done: + hci_remove_adv_monitor_complete(hdev, status); +} + static bool msft_monitor_rssi_valid(struct adv_monitor *monitor) { struct adv_rssi_thresholds *r = &monitor->rssi; @@ -346,3 +433,35 @@ int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor) return err; } + +/* This function requires the caller holds hdev->lock */ +int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor, + u16 handle) +{ + struct msft_cp_le_cancel_monitor_advertisement cp; + struct msft_monitor_advertisement_handle_data *handle_data; + struct hci_request req; + struct msft_data *msft = hdev->msft_data; + int err = 0; + + if (!msft) + return -EOPNOTSUPP; + + handle_data = msft_find_handle_data(hdev, monitor->handle, true); + + /* If no matched handle, just remove without telling controller */ + if (!handle_data) + return -ENOENT; + + cp.sub_opcode = MSFT_OP_LE_CANCEL_MONITOR_ADVERTISEMENT; + cp.handle = handle_data->msft_handle; + + hci_req_init(&req, hdev); + hci_req_add(&req, hdev->msft_opcode, sizeof(cp), &cp); + err = hci_req_run_skb(&req, msft_le_cancel_monitor_advertisement_cb); + + if (!err) + msft->pending_remove_handle = handle; + + return err; +} diff --git a/net/bluetooth/msft.h b/net/bluetooth/msft.h index 0ac9b15322b1..9f9a11f90b0c 100644 --- a/net/bluetooth/msft.h +++ b/net/bluetooth/msft.h @@ -18,6 +18,8 @@ void msft_do_close(struct hci_dev *hdev); void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb); __u64 msft_get_features(struct hci_dev *hdev); int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor); +int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor, + u16 handle); #else @@ -36,4 +38,11 @@ static inline int msft_add_monitor_pattern(struct hci_dev *hdev, return -EOPNOTSUPP; } +static inline bool msft_remove_monitor(struct hci_dev *hdev, + struct adv_monitor *monitor, + u16 handle) +{ + return -EOPNOTSUPP; +} + #endif From patchwork Thu Dec 3 10:29:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Archie Pusaka X-Patchwork-Id: 11948397 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-26.2 required=3.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 814E1C63777 for ; Thu, 3 Dec 2020 10:31:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CF765206E3 for ; Thu, 3 Dec 2020 10:31:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388849AbgLCKbT (ORCPT ); Thu, 3 Dec 2020 05:31:19 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59052 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388826AbgLCKbJ (ORCPT ); Thu, 3 Dec 2020 05:31:09 -0500 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id ECCF7C08E864 for ; Thu, 3 Dec 2020 02:30:06 -0800 (PST) Received: by mail-yb1-xb49.google.com with SMTP id k7so2068249ybm.13 for ; Thu, 03 Dec 2020 02:30:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=jf3xqOMWhJU59CQEGfc2W5FIupVcxg39ApE0Yc87ACg=; b=hBZd3YsAKn9EnsYeFA+Ddgq9R46FigcL7DLl+Gdyu1VkNJF+/Mq+YKDuZ5mEzbXfjn PGTAV1TAWQLrGXY52KA/liTpzykI5w8r2qoimXGjlt87RmL2YirjK3aN9s1jWvnVgBbV XiDwN+f/aNpYL93si/Y8fmU6dHCwKsKyPvnagA8Z+4jfTPvGC73sRhcryJCl3PzFLooW ct27V9pmaITsrpxiHcUly1RA3P9026CLVpTBz5tXJnReNmWYIOd8qSSPgT6j78H5I14D wINXajP3aRG0l3waynZQn82p6s5xIMJ9ft/XgcU57g8Ci66292TQqhhGGkfNmbmHEOCB Fdhw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=jf3xqOMWhJU59CQEGfc2W5FIupVcxg39ApE0Yc87ACg=; b=GX3SY2A5FgToMMZIJ+EtZyOtckFaVZjwyyzi+7N2H7eUrZTxnFf/CiyYxzziJtn2Rp c9zpjyzQT4Fec2zWQEXfGJe7u8sK5YgkvwmwFiUE952QhEFCzn2NRkH+miRrpiyU/Uxa VCFqpF8hC3kQFL/EVmBgPOQkZd4YZ6fxQFBMfRvDqduL2HJZWIM/Mm1kP3y8rOu3N9Yb kAf2epBIwRYGSNqdEmMY+L6lUCeEu5I6L+XBcoM9e6tAg2CdmhNQ7VM6IbUvMZlDbYDz LAzNjSaXTKuIMJlUVxf+qBpkL4gk6VteGg/spn65BXzN0pdFd9xOyzAQwXurIvzt/m4r 7AbA== X-Gm-Message-State: AOAM531E85V+w+IkXUzoEzsexI4ow7AMYPSbY2Fb/lKDtQBI/nB+Xr9E buDOY8jvs4aHJ94/c7PX79fWEzdnlmSmOfzAsgbUdH6IAQwPYflQIpKHLwKzAWbSA+cSDeOftRV rDTp1x+H5fgV9r6W5QbsQZFQAh97wKMYvs2hDdjxsLxcSNajCovQ/7VymUX/0dsvX20Z7z7p1hE nB X-Google-Smtp-Source: ABdhPJy9/EMB+PocbzZriZX7p/IxoRJ0xJUny6YUuIBKgZDvJP6xcnpXXu3oG+1DG+WuzGh74O96lV1Yc/ov Sender: "apusaka via sendgmr" X-Received: from apusaka-p920.tpe.corp.google.com ([2401:fa00:1:b:f693:9fff:fef4:2347]) (user=apusaka job=sendgmr) by 2002:a25:340c:: with SMTP id b12mr3539517yba.417.1606991406110; Thu, 03 Dec 2020 02:30:06 -0800 (PST) Date: Thu, 3 Dec 2020 18:29:34 +0800 In-Reply-To: <20201203102936.4049556-1-apusaka@google.com> Message-Id: <20201203182903.v1.4.I215b0904cb68d68ac780a0c75c06f7d12e6147b7@changeid> Mime-Version: 1.0 References: <20201203102936.4049556-1-apusaka@google.com> X-Mailer: git-send-email 2.29.2.454.gaff20da3a2-goog Subject: [PATCH v1 4/5] Bluetooth: advmon offload MSFT handle controller reset From: Archie Pusaka To: linux-bluetooth , Marcel Holtmann Cc: CrosBT Upstreaming , Archie Pusaka , Miao-chen Chou , Yun-Hao Chung , "David S. Miller" , Jakub Kicinski , Johan Hedberg , linux-kernel@vger.kernel.org, netdev@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Archie Pusaka When the controller is powered off, the registered advertising monitor is removed from the controller. This patch handles the re-registration of those monitors when the power is on. Signed-off-by: Archie Pusaka Reviewed-by: Miao-chen Chou Reviewed-by: Yun-Hao Chung --- net/bluetooth/msft.c | 79 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 74 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c index f5aa0e3b1b9b..7e33a85c3f1c 100644 --- a/net/bluetooth/msft.c +++ b/net/bluetooth/msft.c @@ -82,8 +82,15 @@ struct msft_data { struct list_head handle_map; __u16 pending_add_handle; __u16 pending_remove_handle; + + struct { + u8 reregistering:1; + } flags; }; +static int __msft_add_monitor_pattern(struct hci_dev *hdev, + struct adv_monitor *monitor); + bool msft_monitor_supported(struct hci_dev *hdev) { return !!(msft_get_features(hdev) & MSFT_FEATURE_MASK_LE_ADV_MONITOR); @@ -134,6 +141,35 @@ static bool read_supported_features(struct hci_dev *hdev, return false; } +/* This function requires the caller holds hdev->lock */ +static void reregister_monitor_on_restart(struct hci_dev *hdev, int handle) +{ + struct adv_monitor *monitor; + struct msft_data *msft = hdev->msft_data; + int err; + + while (1) { + monitor = idr_get_next(&hdev->adv_monitors_idr, &handle); + if (!monitor) { + /* All monitors have been reregistered */ + msft->flags.reregistering = false; + hci_update_background_scan(hdev); + return; + } + + msft->pending_add_handle = (u16)handle; + err = __msft_add_monitor_pattern(hdev, monitor); + + /* If success, we return and wait for monitor added callback */ + if (!err) + return; + + /* Otherwise remove the monitor and keep registering */ + hci_free_adv_monitor(hdev, monitor); + handle++; + } +} + void msft_do_open(struct hci_dev *hdev) { struct msft_data *msft; @@ -154,12 +190,18 @@ void msft_do_open(struct hci_dev *hdev) INIT_LIST_HEAD(&msft->handle_map); hdev->msft_data = msft; + + if (msft_monitor_supported(hdev)) { + msft->flags.reregistering = true; + reregister_monitor_on_restart(hdev, 0); + } } void msft_do_close(struct hci_dev *hdev) { struct msft_data *msft = hdev->msft_data; struct msft_monitor_advertisement_handle_data *handle_data, *tmp; + struct adv_monitor *monitor; if (!msft) return; @@ -169,6 +211,12 @@ void msft_do_close(struct hci_dev *hdev) hdev->msft_data = NULL; list_for_each_entry_safe(handle_data, tmp, &msft->handle_map, list) { + monitor = idr_find(&hdev->adv_monitors_idr, + handle_data->mgmt_handle); + + if (monitor && monitor->state == ADV_MONITOR_STATE_OFFLOADED) + monitor->state = ADV_MONITOR_STATE_REGISTERED; + list_del(&handle_data->list); kfree(handle_data); } @@ -282,9 +330,15 @@ static void msft_le_monitor_advertisement_cb(struct hci_dev *hdev, if (status && monitor) hci_free_adv_monitor(hdev, monitor); + /* If in restart/reregister sequence, keep registering. */ + if (msft->flags.reregistering) + reregister_monitor_on_restart(hdev, + msft->pending_add_handle + 1); + hci_dev_unlock(hdev); - hci_add_adv_patterns_monitor_complete(hdev, status); + if (!msft->flags.reregistering) + hci_add_adv_patterns_monitor_complete(hdev, status); } static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev, @@ -374,7 +428,8 @@ static bool msft_monitor_pattern_valid(struct adv_monitor *monitor) } /* This function requires the caller holds hdev->lock */ -int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor) +static int __msft_add_monitor_pattern(struct hci_dev *hdev, + struct adv_monitor *monitor) { struct msft_cp_le_monitor_advertisement *cp; struct msft_le_monitor_advertisement_pattern_data *pattern_data; @@ -387,9 +442,6 @@ int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor) u8 pattern_count = 0; int err = 0; - if (!msft) - return -EOPNOTSUPP; - if (!msft_monitor_pattern_valid(monitor)) return -EINVAL; @@ -434,6 +486,20 @@ int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor) return err; } +/* This function requires the caller holds hdev->lock */ +int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor) +{ + struct msft_data *msft = hdev->msft_data; + + if (!msft) + return -EOPNOTSUPP; + + if (msft->flags.reregistering) + return -EBUSY; + + return __msft_add_monitor_pattern(hdev, monitor); +} + /* This function requires the caller holds hdev->lock */ int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor, u16 handle) @@ -447,6 +513,9 @@ int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor, if (!msft) return -EOPNOTSUPP; + if (msft->flags.reregistering) + return -EBUSY; + handle_data = msft_find_handle_data(hdev, monitor->handle, true); /* If no matched handle, just remove without telling controller */ From patchwork Thu Dec 3 10:29:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Archie Pusaka X-Patchwork-Id: 11948399 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-26.2 required=3.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A5C3FC64E8A for ; Thu, 3 Dec 2020 10:31:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4F14320705 for ; Thu, 3 Dec 2020 10:31:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388826AbgLCKbW (ORCPT ); Thu, 3 Dec 2020 05:31:22 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59104 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388276AbgLCKbV (ORCPT ); Thu, 3 Dec 2020 05:31:21 -0500 Received: from mail-yb1-xb4a.google.com (mail-yb1-xb4a.google.com [IPv6:2607:f8b0:4864:20::b4a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 91D44C08ED7E for ; Thu, 3 Dec 2020 02:30:11 -0800 (PST) Received: by mail-yb1-xb4a.google.com with SMTP id c9so2077365ybs.8 for ; Thu, 03 Dec 2020 02:30:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=Uusy26fxweBxaYqTbY3aM4ThUJItFnRbtIun3wbJYAA=; b=F6gxjT1zu2MhqGPp0OAKuwreTuhBbhBTKr7/SSXi8b/2w2/yQ2GQy2oWzpCU01GRWk ot/9HuxJEaqIPZ1bdq1KvAKfwEDXymq9uoDBSMI7gAdL8JDS5D2rEZdqjBE0qSk+aed5 PnBb0H/XpMAe6Wo16zSM/BQHjwiPogGE+lakki6pUJCROIY0hjz6zi5wSBV65OV6erDP lAedw0ob/Myt3sE0mTM/KU3MT09LmJm8Qzvx+bVEwKvOUaCCNWnU+DG8P3rOdhS1+VRi 7JNJ0VoF8EWci9eSexTEMFOEcX47dtl4XaBvsQwosSqAOIbia5McIh+6Z8vc/y1rTaSP 0uxg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=Uusy26fxweBxaYqTbY3aM4ThUJItFnRbtIun3wbJYAA=; b=RsUunZUyToXeOS/+Lvgbc2FdKzuqHnsXweJJ4nPZX8hfAUmUPjdL2p6CQ4SNwP2D1t EK7ZeXQbWmDbskrgJZ3BynIWy2PN6yI9IAKL4bb9Lqy1vtCrqnqzp2HQx8vPxwSbwJP8 hW/I2hZY8R/n4hC6fs6aIf9qW7COkC9N7mcPuGawEXrICC4gMEBxnPXJahLnmyw/KhV2 RKddvuldIkIdWApveV4A58GBtB6haqH4/OPu6+HYHAjghi7vD0Tz/rT/0wedHgQCYoI6 9d2NijcMMsUH6i4WB4j0FjpmAIvgnXMc+3RN+stJwNqpylOxvu03dW1suOZKE1yg2RpH vXzg== X-Gm-Message-State: AOAM533GVrnex3rszCmTY/GfvIGxYapg8dGH+8cigxUmuaOnaCQGRo80 dMDgx/HV49Q2K9F5YG8eCew33VzwtbWdqJxz9n8+Z9Z4b32P5VWNA+eeiPAnaQKLwCwTHHUQ+E2 fLJe6NVUIhlyg6CqVbbYY2Qf/2XbCpTvDFCN4O/VKldfunlMTfcNkpFlKSZ8DUgKvwdm5kFZBOm +h X-Google-Smtp-Source: ABdhPJxzCBzy9YNWRm7NhHb4c8ir/aZGj5PiFMWk6k3YtggbFw5zNyOFfYTyVvMerIzfVJVxuNXG7nez6yGH Sender: "apusaka via sendgmr" X-Received: from apusaka-p920.tpe.corp.google.com ([2401:fa00:1:b:f693:9fff:fef4:2347]) (user=apusaka job=sendgmr) by 2002:a25:c6d5:: with SMTP id k204mr3446133ybf.363.1606991410787; Thu, 03 Dec 2020 02:30:10 -0800 (PST) Date: Thu, 3 Dec 2020 18:29:35 +0800 In-Reply-To: <20201203102936.4049556-1-apusaka@google.com> Message-Id: <20201203182903.v1.5.I96e97067afe1635dbda036b881ba2a01f37cd343@changeid> Mime-Version: 1.0 References: <20201203102936.4049556-1-apusaka@google.com> X-Mailer: git-send-email 2.29.2.454.gaff20da3a2-goog Subject: [PATCH v1 5/5] Bluetooth: advmon offload MSFT handle filter enablement From: Archie Pusaka To: linux-bluetooth , Marcel Holtmann Cc: CrosBT Upstreaming , Archie Pusaka , Miao-chen Chou , Yun-Hao Chung , "David S. Miller" , Jakub Kicinski , Johan Hedberg , linux-kernel@vger.kernel.org, netdev@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Archie Pusaka Implements the feature to disable/enable the filter used for advertising monitor on MSFT controller, effectively have the same effect as "remove all monitors" and "add all previously removed monitors". This feature would be needed when suspending, where we would not want to get packets from anything outside the allowlist. Note that the integration with the suspending part is not included in this patch. Signed-off-by: Archie Pusaka Reviewed-by: Miao-chen Chou Reviewed-by: Yun-Hao Chung --- net/bluetooth/msft.c | 67 ++++++++++++++++++++++++++++++++++++++++++++ net/bluetooth/msft.h | 6 ++++ 2 files changed, 73 insertions(+) diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c index 7e33a85c3f1c..055cc5a260df 100644 --- a/net/bluetooth/msft.c +++ b/net/bluetooth/msft.c @@ -69,6 +69,17 @@ struct msft_rp_le_cancel_monitor_advertisement { __u8 sub_opcode; } __packed; +#define MSFT_OP_LE_SET_ADVERTISEMENT_FILTER_ENABLE 0x05 +struct msft_cp_le_set_advertisement_filter_enable { + __u8 sub_opcode; + __u8 enable; +} __packed; + +struct msft_rp_le_set_advertisement_filter_enable { + __u8 status; + __u8 sub_opcode; +} __packed; + struct msft_monitor_advertisement_handle_data { __u8 msft_handle; __u16 mgmt_handle; @@ -85,6 +96,7 @@ struct msft_data { struct { u8 reregistering:1; + u8 filter_enabled:1; } flags; }; @@ -193,6 +205,7 @@ void msft_do_open(struct hci_dev *hdev) if (msft_monitor_supported(hdev)) { msft->flags.reregistering = true; + msft_set_filter_enable(hdev, true); reregister_monitor_on_restart(hdev, 0); } } @@ -398,6 +411,40 @@ static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev, hci_remove_adv_monitor_complete(hdev, status); } +static void msft_le_set_advertisement_filter_enable_cb(struct hci_dev *hdev, + u8 status, u16 opcode, + struct sk_buff *skb) +{ + struct msft_cp_le_set_advertisement_filter_enable *cp; + struct msft_rp_le_set_advertisement_filter_enable *rp; + struct msft_data *msft = hdev->msft_data; + + rp = (struct msft_rp_le_set_advertisement_filter_enable *)skb->data; + if (skb->len < sizeof(*rp)) + return; + + /* Error 0x0C would be returned if the filter enabled status is + * already set to whatever we were trying to set. + * Although the default state should be disabled, some controller set + * the initial value to enabled. Because there is no way to know the + * actual initial value before sending this command, here we also treat + * error 0x0C as success. + */ + if (status != 0x00 && status != 0x0C) + return; + + hci_dev_lock(hdev); + + cp = hci_sent_cmd_data(hdev, hdev->msft_opcode); + msft->flags.filter_enabled = cp->enable; + + if (status == 0x0C) + bt_dev_warn(hdev, "MSFT filter_enable is already %s", + cp->enable ? "on" : "off"); + + hci_dev_unlock(hdev); +} + static bool msft_monitor_rssi_valid(struct adv_monitor *monitor) { struct adv_rssi_thresholds *r = &monitor->rssi; @@ -534,3 +581,23 @@ int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor, return err; } + +int msft_set_filter_enable(struct hci_dev *hdev, bool enable) +{ + struct msft_cp_le_set_advertisement_filter_enable cp; + struct hci_request req; + struct msft_data *msft = hdev->msft_data; + int err; + + if (!msft) + return -EOPNOTSUPP; + + cp.sub_opcode = MSFT_OP_LE_SET_ADVERTISEMENT_FILTER_ENABLE; + cp.enable = enable; + + hci_req_init(&req, hdev); + hci_req_add(&req, hdev->msft_opcode, sizeof(cp), &cp); + err = hci_req_run_skb(&req, msft_le_set_advertisement_filter_enable_cb); + + return err; +} diff --git a/net/bluetooth/msft.h b/net/bluetooth/msft.h index 9f9a11f90b0c..44bee705c16d 100644 --- a/net/bluetooth/msft.h +++ b/net/bluetooth/msft.h @@ -20,6 +20,7 @@ __u64 msft_get_features(struct hci_dev *hdev); int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor); int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor, u16 handle); +int msft_set_filter_enable(struct hci_dev *hdev, bool enable); #else @@ -45,4 +46,9 @@ static inline bool msft_remove_monitor(struct hci_dev *hdev, return -EOPNOTSUPP; } +static inline int msft_set_filter_enable(struct hci_dev *hdev, bool enable) +{ + return -EOPNOTSUPP; +} + #endif