From patchwork Fri Sep 25 00:40:03 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Winkler X-Patchwork-Id: 11798547 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 7A0A2618 for ; Fri, 25 Sep 2020 00:40:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 57045238D6 for ; Fri, 25 Sep 2020 00:40:37 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="RRNSN2v/" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726876AbgIYAk0 (ORCPT ); Thu, 24 Sep 2020 20:40:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39084 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726860AbgIYAkY (ORCPT ); Thu, 24 Sep 2020 20:40:24 -0400 Received: from mail-qk1-x74a.google.com (mail-qk1-x74a.google.com [IPv6:2607:f8b0:4864:20::74a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B3C5CC0613D3 for ; Thu, 24 Sep 2020 17:40:23 -0700 (PDT) Received: by mail-qk1-x74a.google.com with SMTP id w126so843426qka.5 for ; Thu, 24 Sep 2020 17:40:23 -0700 (PDT) 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=Z8efH0VT0gu9mhE3Qe4fVs6J3IFKx4DbBtzU2cWSOyc=; b=RRNSN2v/SyaYP2fZsZh2mG7mDOWv4UWpwlF4ah5Ah7pxNRp4gjq5SRIjmzOqEvtuNg o2sZIvQXtBPsbhmZxlSWBHeRJtBCSS/DQpLgpUmZKrrP9dyXTU0506LL192MiSvzY4l2 P55P5nHR+wxjI1Gs0ydUIf0fyYUrBmK8XHfyFu/oVSqqsdXZLjYLyGdtBus6B1Plui3C CSJdObmJswm4v5Y8kYvKlCq08vWHXbwA4lohzsyPJ5WcMX8mnTYWlvKJlxpb0vkoSfEY 6ovwP5H3ioE2gnIgIBVtS4T5+9afRYesMgJ5C5MXE8gLn+NyaeMfENu8SJHiHwrYMxdj 4idQ== 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=Z8efH0VT0gu9mhE3Qe4fVs6J3IFKx4DbBtzU2cWSOyc=; b=GtTeRdOC85diAYNq8AKw6DdtfUGqZSob0EfSxTaOZXMZ2X8v+BXrfjjKtu+u57gYYQ hPRq0iNLVkZHndDQU3DOXkYqJArN3zB9PG809M2Gp/QcjQkRvn7L6L8VElH9kcnwFZql ZVGIBZ6IaBu+KyLI7DPheYTTVfmkT7pBcB8Li+UPWdNgHScizWjXWjd1JzpRQmt1nPBn ev7Vwg96swp7VXr4X/MBBcN1TrDNpQP0HtSxXiqLKk2eYtNK+kZufDL5d5Hs6sOtxpIW F6r/ZRBskej7gDV9zkFYqPGs9N0C1SJI8BgWzxCEIwXaHKRN4AfFqHdrziXtO/10Sahi xcmQ== X-Gm-Message-State: AOAM5302InPyoZCgwsmaIYZItR37nI7YttExpvmWqmXg5FMLueXtOiCZ 4rYKEXKR1HF7FD69cRa6eAN13URG4vaJ5N+KMlbn X-Google-Smtp-Source: ABdhPJyV/rAxfDsY0L/wJmbvjNXMni1QAb7QYZR3zx5lVh17Q9z49dofhpNr8cuz5voKcmUTwrMX5BPRRI2y94zqSYmw Sender: "danielwinkler via sendgmr" X-Received: from danielwinkler-linux.mtv.corp.google.com ([2620:15c:202:201:f693:9fff:fef4:4e59]) (user=danielwinkler job=sendgmr) by 2002:ad4:4f30:: with SMTP id fc16mr1922865qvb.6.1600994422858; Thu, 24 Sep 2020 17:40:22 -0700 (PDT) Date: Thu, 24 Sep 2020 17:40:03 -0700 In-Reply-To: <20200925004007.2378410-1-danielwinkler@google.com> Message-Id: <20200924173752.v3.1.I5f4fa6a76fe81f977f78f06b7e68ff1c76c6bddf@changeid> Mime-Version: 1.0 References: <20200925004007.2378410-1-danielwinkler@google.com> X-Mailer: git-send-email 2.28.0.709.gb0816b6eb0-goog Subject: [PATCH v3 1/5] Bluetooth: Add helper to set adv data From: Daniel Winkler To: marcel@holtmann.org Cc: chromeos-bluetooth-upstreaming@chromium.org, linux-bluetooth@vger.kernel.org, Daniel Winkler , Sonny Sasaka , "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 We wish to handle advertising data separately from advertising parameters in our new MGMT requests. This change adds a helper that allows the advertising data and scan response to be updated for an existing advertising instance. Reviewed-by: Sonny Sasaka Signed-off-by: Daniel Winkler --- Changes in v3: None Changes in v2: None include/net/bluetooth/hci_core.h | 3 +++ net/bluetooth/hci_core.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9873e1c8cd163b..300b3572d479e1 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1291,6 +1291,9 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags, u16 adv_data_len, u8 *adv_data, u16 scan_rsp_len, u8 *scan_rsp_data, u16 timeout, u16 duration); +int hci_set_adv_instance_data(struct hci_dev *hdev, u8 instance, + u16 adv_data_len, u8 *adv_data, + u16 scan_rsp_len, u8 *scan_rsp_data); 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); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 8a2645a8330137..3f73f147826409 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3005,6 +3005,37 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags, return 0; } +/* This function requires the caller holds hdev->lock */ +int hci_set_adv_instance_data(struct hci_dev *hdev, u8 instance, + u16 adv_data_len, u8 *adv_data, + u16 scan_rsp_len, u8 *scan_rsp_data) +{ + struct adv_info *adv_instance; + + adv_instance = hci_find_adv_instance(hdev, instance); + + /* If advertisement doesn't exist, we can't modify its data */ + if (!adv_instance) + return -ENOENT; + + if (adv_data_len) { + memset(adv_instance->adv_data, 0, + sizeof(adv_instance->adv_data)); + memcpy(adv_instance->adv_data, adv_data, adv_data_len); + adv_instance->adv_data_len = adv_data_len; + } + + if (scan_rsp_len) { + memset(adv_instance->scan_rsp_data, 0, + sizeof(adv_instance->scan_rsp_data)); + memcpy(adv_instance->scan_rsp_data, + scan_rsp_data, scan_rsp_len); + adv_instance->scan_rsp_len = scan_rsp_len; + } + + return 0; +} + /* This function requires the caller holds hdev->lock */ void hci_adv_monitors_clear(struct hci_dev *hdev) { From patchwork Fri Sep 25 00:40:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Winkler X-Patchwork-Id: 11798545 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 4C497618 for ; Fri, 25 Sep 2020 00:40:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1AB642371F for ; Fri, 25 Sep 2020 00:40:36 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="usIZdSAs" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726935AbgIYAkb (ORCPT ); Thu, 24 Sep 2020 20:40:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39100 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726867AbgIYAk0 (ORCPT ); Thu, 24 Sep 2020 20:40:26 -0400 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 D60BDC0613D3 for ; Thu, 24 Sep 2020 17:40:25 -0700 (PDT) Received: by mail-yb1-xb49.google.com with SMTP id x1so1075536ybi.4 for ; Thu, 24 Sep 2020 17:40:25 -0700 (PDT) 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=fYl5lM0Fn6DS4iK0oFZUAw+DA01KyIzNf6yDjoDQYi4=; b=usIZdSAsc/LONzBr7dmNq1nDo2wHoIGz0+EsgrpeOlG7GaOd5fjzVhGKyn8xTOGCoA qUVM0nYWsFDwpDikhFFchIT37tOt0E/CSxkCRePi/9eXsOFpjSBJRnOQpwEihOLsuyrn w/JNDU9svxW7A+JGXa9mjZUVC3XdRVoTRz01ah2UEupqU14ixemAoQ2vmWOYRZTNBbsd GeDxldFCHF9bvaOBdaC+rtL1wrTKnlNiyQ/6mGU5wYVyIcB7XWIL+kqA2pFAsXaac8U5 TihDEkqxK3MT/4kQ53wRcjwWZfgP8zpO7yM9D4U1rw7WFxiE2WW1yI3cD5BIREl6sW6v YZPw== 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=fYl5lM0Fn6DS4iK0oFZUAw+DA01KyIzNf6yDjoDQYi4=; b=nisUgpJ0B7WHb04hRCsIFjHgwAB5Xsk/c1dTo+0YaTAFTXWOwiuAgzyRbhgRPM2oeJ MPUpRNPTS8pjNW4lg0zDlKjgeGrYXY4I3QH5gyxvn38dnrwzAFEfpYtzFnGPM0Ao4a21 +PUsC+/4/cmr4Ws/U4UkD4g+K7sFw1O32W3WBXS/+N4HO9c6XtOj8FpfC05SXhWMztjN Y9z0BsVsEQg/1hy9zPdN3eqwGUHEUnUtSk13+m6qfl0mw/5hErLfOrCulqKXilvOU0QP GJc9JtsQc3iZG45FkcfprlSmWYSU+uAR+IPKx0A1sVO8IEZ0CLafsEttSaXMJ8DtsGoc nCxQ== X-Gm-Message-State: AOAM5324hUZn7FhsrwZf17E5gwgXCFbMkPoJghkVpT2pjlmjiItXiQ9W GtPtHf4wS/a9TcyzLj24Upy1fH6N52755Ne464bF X-Google-Smtp-Source: ABdhPJx1GMLRW4TL0sTFCj5xA6AShOE5omxytNHdYjpCv9qugy/sA8zZyu6IHAc9YbBCDleNlL3nOWr1POlmyXa34trX Sender: "danielwinkler via sendgmr" X-Received: from danielwinkler-linux.mtv.corp.google.com ([2620:15c:202:201:f693:9fff:fef4:4e59]) (user=danielwinkler job=sendgmr) by 2002:a25:e0d2:: with SMTP id x201mr2071788ybg.180.1600994425045; Thu, 24 Sep 2020 17:40:25 -0700 (PDT) Date: Thu, 24 Sep 2020 17:40:04 -0700 In-Reply-To: <20200925004007.2378410-1-danielwinkler@google.com> Message-Id: <20200924173752.v3.2.Id8bee28ed00d158d0894b32c0cd94baa5a012605@changeid> Mime-Version: 1.0 References: <20200925004007.2378410-1-danielwinkler@google.com> X-Mailer: git-send-email 2.28.0.709.gb0816b6eb0-goog Subject: [PATCH v3 2/5] Bluetooth: Break add adv into two mgmt commands From: Daniel Winkler To: marcel@holtmann.org Cc: chromeos-bluetooth-upstreaming@chromium.org, linux-bluetooth@vger.kernel.org, Daniel Winkler , Sonny Sasaka , "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 This patch adds support for the new advertising add interface, with the first command setting advertising parameters and the second to set advertising data. The set parameters command allows the caller to leave some fields "unset", with a params bitfield defining which params were purposefully set. Unset parameters will be given defaults when calling hci_add_adv_instance. The data passed to the param mgmt command is allowed to be flexible, so in the future if bluetoothd passes a larger structure with new params, the mgmt command will ignore the unknown members at the end. This change has been validated on both hatch (extended advertising) and kukui (no extended advertising) chromebooks running bluetoothd that support this new interface. I ran the following manual tests: - Set several (3) advertisements using modified test_advertisement.py - For each, validate correct data and parameters in btmon trace - Verified both for software rotation and extended adv Automatic test suite also run, testing many (25) scenarios of single and multi-advertising for data/parameter correctness. Reviewed-by: Sonny Sasaka Signed-off-by: Daniel Winkler --- Changes in v3: - Adding selected tx power to adv params mgmt response, removing event Changes in v2: None include/net/bluetooth/hci_core.h | 2 + include/net/bluetooth/mgmt.h | 34 +++ net/bluetooth/hci_event.c | 1 + net/bluetooth/mgmt.c | 368 ++++++++++++++++++++++++++++++- 4 files changed, 394 insertions(+), 11 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 300b3572d479e1..48d144ae8b57d6 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -238,6 +238,8 @@ struct adv_info { #define HCI_MAX_ADV_INSTANCES 5 #define HCI_DEFAULT_ADV_DURATION 2 +#define HCI_ADV_TX_POWER_NO_PREFERENCE 0x7F + struct adv_pattern { struct list_head list; __u8 ad_type; diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 6b55155e05e977..83f684af3ae843 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -782,6 +782,40 @@ struct mgmt_rp_remove_adv_monitor { __le16 monitor_handle; } __packed; +#define MGMT_ADV_PARAM_DURATION BIT(0) +#define MGMT_ADV_PARAM_TIMEOUT BIT(1) +#define MGMT_ADV_PARAM_INTERVALS BIT(2) +#define MGMT_ADV_PARAM_TX_POWER BIT(3) + +#define MGMT_OP_ADD_EXT_ADV_PARAMS 0x0054 +struct mgmt_cp_add_ext_adv_params { + __u8 instance; + __le32 flags; + __le16 params; + __le16 duration; + __le16 timeout; + __le32 min_interval; + __le32 max_interval; + __s8 tx_power; +} __packed; +#define MGMT_ADD_EXT_ADV_PARAMS_MIN_SIZE 20 +struct mgmt_rp_add_ext_adv_params { + __u8 instance; + __s8 tx_power; +} __packed; + +#define MGMT_OP_ADD_EXT_ADV_DATA 0x0055 +struct mgmt_cp_add_ext_adv_data { + __u8 instance; + __u8 adv_data_len; + __u8 scan_rsp_len; + __u8 data[]; +} __packed; +#define MGMT_ADD_EXT_ADV_DATA_SIZE 3 +struct mgmt_rp_add_ext_adv_data { + __u8 instance; +} __packed; + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index bd306ba3ade545..4281f4ac6700d4 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1749,6 +1749,7 @@ static void hci_cc_set_ext_adv_param(struct hci_dev *hdev, struct sk_buff *skb) } /* Update adv data as tx power is known now */ hci_req_update_adv_data(hdev, hdev->cur_adv_instance); + hci_dev_unlock(hdev); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 0b711ad80f6bd1..ee425fec43bf1b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -122,6 +122,8 @@ static const u16 mgmt_commands[] = { MGMT_OP_READ_ADV_MONITOR_FEATURES, MGMT_OP_ADD_ADV_PATTERNS_MONITOR, MGMT_OP_REMOVE_ADV_MONITOR, + MGMT_OP_ADD_EXT_ADV_PARAMS, + MGMT_OP_ADD_EXT_ADV_DATA, }; static const u16 mgmt_events[] = { @@ -7372,6 +7374,31 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data, return true; } +static bool requested_adv_flags_are_valid(struct hci_dev *hdev, u32 adv_flags) +{ + u32 supported_flags, phy_flags; + + /* The current implementation only supports a subset of the specified + * flags. Also need to check mutual exclusiveness of sec flags. + */ + supported_flags = get_supported_adv_flags(hdev); + phy_flags = adv_flags & MGMT_ADV_FLAG_SEC_MASK; + if (adv_flags & ~supported_flags || + ((phy_flags && (phy_flags ^ (phy_flags & -phy_flags))))) + return false; + + return true; +} + +static bool adv_busy(struct hci_dev *hdev) +{ + return (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) || + pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) || + pending_find(MGMT_OP_SET_LE, hdev) || + pending_find(MGMT_OP_ADD_EXT_ADV_PARAMS, hdev) || + pending_find(MGMT_OP_ADD_EXT_ADV_DATA, hdev)); +} + static void add_advertising_complete(struct hci_dev *hdev, u8 status, u16 opcode) { @@ -7386,6 +7413,8 @@ static void add_advertising_complete(struct hci_dev *hdev, u8 status, hci_dev_lock(hdev); cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev); + if (!cmd) + cmd = pending_find(MGMT_OP_ADD_EXT_ADV_DATA, hdev); list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) { if (!adv_instance->pending) @@ -7430,7 +7459,6 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev, struct mgmt_cp_add_advertising *cp = data; struct mgmt_rp_add_advertising rp; u32 flags; - u32 supported_flags, phy_flags; u8 status; u16 timeout, duration; unsigned int prev_instance_cnt = hdev->adv_instance_cnt; @@ -7466,13 +7494,7 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev, timeout = __le16_to_cpu(cp->timeout); duration = __le16_to_cpu(cp->duration); - /* The current implementation only supports a subset of the specified - * flags. Also need to check mutual exclusiveness of sec flags. - */ - supported_flags = get_supported_adv_flags(hdev); - phy_flags = flags & MGMT_ADV_FLAG_SEC_MASK; - if (flags & ~supported_flags || - ((phy_flags && (phy_flags ^ (phy_flags & -phy_flags))))) + if (!requested_adv_flags_are_valid(hdev, flags)) return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING, MGMT_STATUS_INVALID_PARAMS); @@ -7484,9 +7506,7 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev, goto unlock; } - if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) || - pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) || - pending_find(MGMT_OP_SET_LE, hdev)) { + if (adv_busy(hdev)) { err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING, MGMT_STATUS_BUSY); goto unlock; @@ -7577,6 +7597,328 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev, return err; } +static void add_ext_adv_params_complete(struct hci_dev *hdev, u8 status, + u16 opcode) +{ + struct mgmt_pending_cmd *cmd; + struct mgmt_cp_add_ext_adv_params *cp; + struct mgmt_rp_add_ext_adv_params rp; + struct adv_info *adv_instance; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + cmd = pending_find(MGMT_OP_ADD_EXT_ADV_PARAMS, hdev); + if (!cmd) + goto unlock; + + cp = cmd->param; + adv_instance = hci_find_adv_instance(hdev, cp->instance); + if (!adv_instance) + goto unlock; + + rp.instance = cp->instance; + rp.tx_power = adv_instance->tx_power; + + if (status) { + /* If this advertisement was previously advertising and we + * failed to update it, we signal that it has been removed and + * delete its structure + */ + if (!adv_instance->pending) + mgmt_advertising_removed(cmd->sk, hdev, cp->instance); + + hci_remove_adv_instance(hdev, cp->instance); + + mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, + mgmt_status(status)); + + } else { + mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, + mgmt_status(status), &rp, sizeof(rp)); + } + +unlock: + if (cmd) + mgmt_pending_remove(cmd); + + hci_dev_unlock(hdev); +} + +static int add_ext_adv_params(struct sock *sk, struct hci_dev *hdev, + void *data, u16 data_len) +{ + struct mgmt_cp_add_ext_adv_params *cp = data; + struct mgmt_rp_add_ext_adv_params rp; + struct mgmt_pending_cmd *cmd = NULL; + struct adv_info *adv_instance; + struct hci_request req; + u32 flags, min_interval, max_interval; + u16 params, timeout, duration; + u8 status; + s8 tx_power; + int err; + + BT_DBG("%s", hdev->name); + + status = mgmt_le_support(hdev); + if (status) + return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS, + status); + + if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets) + return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS, + MGMT_STATUS_INVALID_PARAMS); + + /* The purpose of breaking add_advertising into two separate MGMT calls + * for params and data is to allow more parameters to be added to this + * structure in the future. For this reason, we verify that we have the + * bare minimum structure we know of when the interface was defined. Any + * extra parameters we don't know about will be ignored in this request. + */ + if (data_len < MGMT_ADD_EXT_ADV_PARAMS_MIN_SIZE) + return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING, + MGMT_STATUS_INVALID_PARAMS); + + flags = __le32_to_cpu(cp->flags); + params = __le16_to_cpu(cp->params); + + if (!requested_adv_flags_are_valid(hdev, flags)) + return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS, + MGMT_STATUS_INVALID_PARAMS); + + hci_dev_lock(hdev); + + /* In new interface, we require that we are powered to register */ + if (!hdev_is_powered(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS, + MGMT_STATUS_REJECTED); + goto unlock; + } + + if (adv_busy(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS, + MGMT_STATUS_BUSY); + goto unlock; + } + + /* Parse defined parameters from request, use defaults otherwise */ + timeout = (params & MGMT_ADV_PARAM_TIMEOUT) ? + __le16_to_cpu(cp->timeout) : 0; + + duration = (params & MGMT_ADV_PARAM_DURATION) ? + __le16_to_cpu(cp->duration) : + hdev->def_multi_adv_rotation_duration; + + min_interval = (params & MGMT_ADV_PARAM_INTERVALS) ? + __le32_to_cpu(cp->min_interval) : + hdev->le_adv_min_interval; + + max_interval = (params & MGMT_ADV_PARAM_INTERVALS) ? + __le32_to_cpu(cp->max_interval) : + hdev->le_adv_max_interval; + + tx_power = (params & MGMT_ADV_PARAM_TX_POWER) ? + cp->tx_power : + HCI_ADV_TX_POWER_NO_PREFERENCE; + + /* Create advertising instance with no advertising or response data */ + err = hci_add_adv_instance(hdev, cp->instance, flags, + 0, NULL, 0, NULL, timeout, duration); + + if (err < 0) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS, + MGMT_STATUS_FAILED); + goto unlock; + } + + hdev->cur_adv_instance = cp->instance; + /* Submit request for advertising params if ext adv available */ + if (ext_adv_capable(hdev)) { + hci_req_init(&req, hdev); + adv_instance = hci_find_adv_instance(hdev, cp->instance); + + /* Updating parameters of an active instance will return a + * Command Disallowed error, so we must first disable the + * instance if it is active. + */ + if (!adv_instance->pending) + __hci_req_disable_ext_adv_instance(&req, cp->instance); + + __hci_req_setup_ext_adv_instance(&req, cp->instance); + + err = hci_req_run(&req, add_ext_adv_params_complete); + + if (!err) + cmd = mgmt_pending_add(sk, MGMT_OP_ADD_EXT_ADV_PARAMS, + hdev, data, data_len); + if (!cmd) { + err = -ENOMEM; + hci_remove_adv_instance(hdev, cp->instance); + goto unlock; + } + + } else { + rp.instance = cp->instance; + rp.tx_power = HCI_ADV_TX_POWER_NO_PREFERENCE; + err = mgmt_cmd_complete(sk, hdev->id, + MGMT_OP_ADD_EXT_ADV_PARAMS, + MGMT_STATUS_SUCCESS, &rp, sizeof(rp)); + } + +unlock: + hci_dev_unlock(hdev); + + return err; +} + +static int add_ext_adv_data(struct sock *sk, struct hci_dev *hdev, void *data, + u16 data_len) +{ + struct mgmt_cp_add_ext_adv_data *cp = data; + struct mgmt_rp_add_ext_adv_data rp; + u8 schedule_instance = 0; + struct adv_info *next_instance; + struct adv_info *adv_instance; + int err = 0; + struct mgmt_pending_cmd *cmd; + struct hci_request req; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + adv_instance = hci_find_adv_instance(hdev, cp->instance); + + if (!adv_instance) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA, + MGMT_STATUS_INVALID_PARAMS); + goto unlock; + } + + /* In new interface, we require that we are powered to register */ + if (!hdev_is_powered(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA, + MGMT_STATUS_REJECTED); + goto clear_new_instance; + } + + if (adv_busy(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA, + MGMT_STATUS_BUSY); + goto clear_new_instance; + } + + /* Validate new data */ + if (!tlv_data_is_valid(hdev, adv_instance->flags, cp->data, + cp->adv_data_len, true) || + !tlv_data_is_valid(hdev, adv_instance->flags, cp->data + + cp->adv_data_len, cp->scan_rsp_len, false)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA, + MGMT_STATUS_INVALID_PARAMS); + goto clear_new_instance; + } + + /* Set the data in the advertising instance */ + hci_set_adv_instance_data(hdev, cp->instance, cp->adv_data_len, + cp->data, cp->scan_rsp_len, + cp->data + cp->adv_data_len); + + /* We're good to go, update advertising data, parameters, and start + * advertising. + */ + + hci_req_init(&req, hdev); + + hci_req_add(&req, HCI_OP_READ_LOCAL_NAME, 0, NULL); + + if (ext_adv_capable(hdev)) { + __hci_req_update_adv_data(&req, cp->instance); + __hci_req_update_scan_rsp_data(&req, cp->instance); + __hci_req_enable_ext_advertising(&req, cp->instance); + + } else { + /* If using software rotation, determine next instance to use */ + + if (hdev->cur_adv_instance == cp->instance) { + /* If the currently advertised instance is being changed + * then cancel the current advertising and schedule the + * next instance. If there is only one instance then the + * overridden advertising data will be visible right + * away + */ + cancel_adv_timeout(hdev); + + next_instance = hci_get_next_instance(hdev, + cp->instance); + if (next_instance) + schedule_instance = next_instance->instance; + } else if (!hdev->adv_instance_timeout) { + /* Immediately advertise the new instance if no other + * instance is currently being advertised. + */ + schedule_instance = cp->instance; + } + + /* If the HCI_ADVERTISING flag is set or there is no instance to + * be advertised then we have no HCI communication to make. + * Simply return. + */ + if (hci_dev_test_flag(hdev, HCI_ADVERTISING) || + !schedule_instance) { + if (adv_instance->pending) { + mgmt_advertising_added(sk, hdev, cp->instance); + adv_instance->pending = false; + } + rp.instance = cp->instance; + err = mgmt_cmd_complete(sk, hdev->id, + MGMT_OP_ADD_EXT_ADV_DATA, + MGMT_STATUS_SUCCESS, &rp, + sizeof(rp)); + goto unlock; + } + + err = __hci_req_schedule_adv_instance(&req, schedule_instance, + true); + } + + cmd = mgmt_pending_add(sk, MGMT_OP_ADD_EXT_ADV_DATA, hdev, data, + data_len); + if (!cmd) { + err = -ENOMEM; + goto clear_new_instance; + } + + if (!err) + err = hci_req_run(&req, add_advertising_complete); + + if (err < 0) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA, + MGMT_STATUS_FAILED); + mgmt_pending_remove(cmd); + goto clear_new_instance; + } + + /* We were successful in updating data, so trigger advertising_added + * event if this is an instance that wasn't previously advertising. If + * a failure occurs in the requests we initiated, we will remove the + * instance again in add_advertising_complete + */ + if (adv_instance->pending) + mgmt_advertising_added(sk, hdev, cp->instance); + + goto unlock; + +clear_new_instance: + hci_remove_adv_instance(hdev, cp->instance); + +unlock: + hci_dev_unlock(hdev); + + return err; +} + static void remove_advertising_complete(struct hci_dev *hdev, u8 status, u16 opcode) { @@ -7851,6 +8193,10 @@ static const struct hci_mgmt_handler mgmt_handlers[] = { { add_adv_patterns_monitor,MGMT_ADD_ADV_PATTERNS_MONITOR_SIZE, HCI_MGMT_VAR_LEN }, { remove_adv_monitor, MGMT_REMOVE_ADV_MONITOR_SIZE }, + { add_ext_adv_params, MGMT_ADD_EXT_ADV_PARAMS_MIN_SIZE, + HCI_MGMT_VAR_LEN }, + { add_ext_adv_data, MGMT_ADD_EXT_ADV_DATA_SIZE, + HCI_MGMT_VAR_LEN }, }; void mgmt_index_added(struct hci_dev *hdev) From patchwork Fri Sep 25 00:40:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Winkler X-Patchwork-Id: 11798551 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 6FD90618 for ; Fri, 25 Sep 2020 00:40:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4D26C238D6 for ; Fri, 25 Sep 2020 00:40:44 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="o9s0lmUG" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726963AbgIYAkj (ORCPT ); Thu, 24 Sep 2020 20:40:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39108 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726762AbgIYAk2 (ORCPT ); Thu, 24 Sep 2020 20:40:28 -0400 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 E4366C0613D6 for ; Thu, 24 Sep 2020 17:40:27 -0700 (PDT) Received: by mail-yb1-xb4a.google.com with SMTP id x10so1003664ybj.19 for ; Thu, 24 Sep 2020 17:40:27 -0700 (PDT) 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=tBY3Ix9d0bZ6yJodesZtGMd1wuLGTKSUpwbupAMO6qI=; b=o9s0lmUGZh7rS8TA9vSIikZI74mDgu9c0zI0gRqtwoQy206ulW955+SxC3PL2ONd14 G+F9aB0ZEZqOJh+lC5Z7ndWcpum0EWZvj4WJZ8BHY7tlTb1tu+HjLIaHCF7hdheDditM QihYcCjMMGFG3Q+Gx8CIZWUNWSqi3/WfzBAWO8y1aJI9L1UGngkqGyzGiEMMi33C3ec/ 4r8LcID4dau3SysUEx7KxFc+BsovWi8Hf9m3MHfUHemab0PMaqugyifG5rBnHdwN2it6 tW2+6mnWD/FaVPq3RAoY7bqn6oI+Z6cQMfY1irCx9PxBnYZjAl1/4obOvY054CcrJo3Z 00Fg== 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=tBY3Ix9d0bZ6yJodesZtGMd1wuLGTKSUpwbupAMO6qI=; b=sW7mrZm68eLO/JccqKoV4JHQLBLZssSGfozHtrFGuc7A6onUVHpB60bB051/YUR5LG 0rlX5y0bYTPn36wi70eLF2T8YYAY7LrMaFgR+5dJvICp4STmAwvV1qNJjt4maT+040av B8F08wQT/2+f1Z7+Ok/6YY5m1dTRQ5WujabewDakLAvaTRXSI1BUXCPouIACGPqkChpr GiwdC0IrFYGeyMwFkY2+aP8rVdeQeR+/LAsOxNWNYLx/kFbDh+08KSrYWVHmb1hc4d6I W14ta73g5nnczwNnJSUCvpi0TB3UivT8l4XM4BrGFTgI+X31249weehculZdOm/+GgUV rI8w== X-Gm-Message-State: AOAM531FuAv4Hmx8Vy/R95TWd5XJFtJI5GpGl/1pabmHYWrNk5wzye6B HMMNw8V/iRgXttqXU05L25SFVjrchIZon7HmewLi X-Google-Smtp-Source: ABdhPJym9apUaqg568q4PbWCEIvl2klDBJI1etSTJaui0lWEFke5EbCX9BuC9MBBwRUgNbc2nq7yb0oigm9hSKf9fnHR Sender: "danielwinkler via sendgmr" X-Received: from danielwinkler-linux.mtv.corp.google.com ([2620:15c:202:201:f693:9fff:fef4:4e59]) (user=danielwinkler job=sendgmr) by 2002:a25:2a55:: with SMTP id q82mr2184982ybq.160.1600994427100; Thu, 24 Sep 2020 17:40:27 -0700 (PDT) Date: Thu, 24 Sep 2020 17:40:05 -0700 In-Reply-To: <20200925004007.2378410-1-danielwinkler@google.com> Message-Id: <20200924173752.v3.3.I74255537fa99ed3c0025321008b361c6ad90a431@changeid> Mime-Version: 1.0 References: <20200925004007.2378410-1-danielwinkler@google.com> X-Mailer: git-send-email 2.28.0.709.gb0816b6eb0-goog Subject: [PATCH v3 3/5] Bluetooth: Use intervals and tx power from mgmt cmds From: Daniel Winkler To: marcel@holtmann.org Cc: chromeos-bluetooth-upstreaming@chromium.org, linux-bluetooth@vger.kernel.org, Daniel Winkler , Sonny Sasaka , "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 This patch takes the min/max intervals and tx power optionally provided in mgmt interface, stores them in the advertisement struct, and uses them when configuring the hci requests. While tx power is not used if extended advertising is unavailable, software rotation will use the min and max advertising intervals specified by the client. This change is validated manually by ensuring the min/max intervals are propagated to the controller on both hatch (extended advertising) and kukui (no extended advertising) chromebooks, and that tx power is propagated correctly on hatch. These tests are performed with multiple advertisements simultaneously. Reviewed-by: Sonny Sasaka Signed-off-by: Daniel Winkler --- Changes in v3: None Changes in v2: None include/net/bluetooth/hci_core.h | 5 ++++- net/bluetooth/hci_core.c | 8 +++++--- net/bluetooth/hci_request.c | 29 +++++++++++++++++++---------- net/bluetooth/mgmt.c | 8 ++++++-- 4 files changed, 34 insertions(+), 16 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 48d144ae8b57d6..ab168f46b6d909 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -230,6 +230,8 @@ struct adv_info { __u16 scan_rsp_len; __u8 scan_rsp_data[HCI_MAX_AD_LENGTH]; __s8 tx_power; + __u32 min_interval; + __u32 max_interval; bdaddr_t random_addr; bool rpa_expired; struct delayed_work rpa_expired_cb; @@ -1292,7 +1294,8 @@ struct adv_info *hci_get_next_instance(struct hci_dev *hdev, u8 instance); int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags, u16 adv_data_len, u8 *adv_data, u16 scan_rsp_len, u8 *scan_rsp_data, - u16 timeout, u16 duration); + u16 timeout, u16 duration, s8 tx_power, + u32 min_interval, u32 max_interval); int hci_set_adv_instance_data(struct hci_dev *hdev, u8 instance, u16 adv_data_len, u8 *adv_data, u16 scan_rsp_len, u8 *scan_rsp_data); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3f73f147826409..3a2332f4a9bba2 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2951,7 +2951,8 @@ static void adv_instance_rpa_expired(struct work_struct *work) int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags, u16 adv_data_len, u8 *adv_data, u16 scan_rsp_len, u8 *scan_rsp_data, - u16 timeout, u16 duration) + u16 timeout, u16 duration, s8 tx_power, + u32 min_interval, u32 max_interval) { struct adv_info *adv_instance; @@ -2979,6 +2980,9 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags, adv_instance->flags = flags; adv_instance->adv_data_len = adv_data_len; adv_instance->scan_rsp_len = scan_rsp_len; + adv_instance->min_interval = min_interval; + adv_instance->max_interval = max_interval; + adv_instance->tx_power = tx_power; if (adv_data_len) memcpy(adv_instance->adv_data, adv_data, adv_data_len); @@ -2995,8 +2999,6 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags, else adv_instance->duration = duration; - adv_instance->tx_power = HCI_TX_POWER_INVALID; - INIT_DELAYED_WORK(&adv_instance->rpa_expired_cb, adv_instance_rpa_expired); diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index 413e3a5aabf544..bd984b32e07553 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -1425,6 +1425,7 @@ static bool is_advertising_allowed(struct hci_dev *hdev, bool connectable) void __hci_req_enable_advertising(struct hci_request *req) { struct hci_dev *hdev = req->hdev; + struct adv_info *adv_instance; struct hci_cp_le_set_adv_param cp; u8 own_addr_type, enable = 0x01; bool connectable; @@ -1432,6 +1433,7 @@ void __hci_req_enable_advertising(struct hci_request *req) u32 flags; flags = get_adv_instance_flags(hdev, hdev->cur_adv_instance); + adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance); /* If the "connectable" instance flag was not set, then choose between * ADV_IND and ADV_NONCONN_IND based on the global connectable setting. @@ -1463,11 +1465,16 @@ void __hci_req_enable_advertising(struct hci_request *req) memset(&cp, 0, sizeof(cp)); - if (connectable) { - cp.type = LE_ADV_IND; - + if (adv_instance) { + adv_min_interval = adv_instance->min_interval; + adv_max_interval = adv_instance->max_interval; + } else { adv_min_interval = hdev->le_adv_min_interval; adv_max_interval = hdev->le_adv_max_interval; + } + + if (connectable) { + cp.type = LE_ADV_IND; } else { if (get_cur_adv_instance_scan_rsp_len(hdev)) cp.type = LE_ADV_SCAN_IND; @@ -1478,9 +1485,6 @@ void __hci_req_enable_advertising(struct hci_request *req) hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE)) { adv_min_interval = DISCOV_LE_FAST_ADV_INT_MIN; adv_max_interval = DISCOV_LE_FAST_ADV_INT_MAX; - } else { - adv_min_interval = hdev->le_adv_min_interval; - adv_max_interval = hdev->le_adv_max_interval; } } @@ -1997,9 +2001,15 @@ int __hci_req_setup_ext_adv_instance(struct hci_request *req, u8 instance) memset(&cp, 0, sizeof(cp)); - /* In ext adv set param interval is 3 octets */ - hci_cpu_to_le24(hdev->le_adv_min_interval, cp.min_interval); - hci_cpu_to_le24(hdev->le_adv_max_interval, cp.max_interval); + if (adv_instance) { + hci_cpu_to_le24(adv_instance->min_interval, cp.min_interval); + hci_cpu_to_le24(adv_instance->max_interval, cp.max_interval); + cp.tx_power = adv_instance->tx_power; + } else { + hci_cpu_to_le24(hdev->le_adv_min_interval, cp.min_interval); + hci_cpu_to_le24(hdev->le_adv_max_interval, cp.max_interval); + cp.tx_power = HCI_ADV_TX_POWER_NO_PREFERENCE; + } secondary_adv = (flags & MGMT_ADV_FLAG_SEC_MASK); @@ -2022,7 +2032,6 @@ int __hci_req_setup_ext_adv_instance(struct hci_request *req, u8 instance) cp.own_addr_type = own_addr_type; cp.channel_map = hdev->le_adv_channel_map; - cp.tx_power = 127; cp.handle = instance; if (flags & MGMT_ADV_FLAG_SEC_2M) { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ee425fec43bf1b..c92b809a5e086d 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -7524,7 +7524,10 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev, cp->adv_data_len, cp->data, cp->scan_rsp_len, cp->data + cp->adv_data_len, - timeout, duration); + timeout, duration, + HCI_ADV_TX_POWER_NO_PREFERENCE, + hdev->le_adv_min_interval, + hdev->le_adv_max_interval); if (err < 0) { err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING, MGMT_STATUS_FAILED); @@ -7725,7 +7728,8 @@ static int add_ext_adv_params(struct sock *sk, struct hci_dev *hdev, /* Create advertising instance with no advertising or response data */ err = hci_add_adv_instance(hdev, cp->instance, flags, - 0, NULL, 0, NULL, timeout, duration); + 0, NULL, 0, NULL, timeout, duration, + tx_power, min_interval, max_interval); if (err < 0) { err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS, From patchwork Fri Sep 25 00:40:06 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Winkler X-Patchwork-Id: 11798549 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 8A086618 for ; Fri, 25 Sep 2020 00:40:42 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 64C9C23A34 for ; Fri, 25 Sep 2020 00:40:42 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Ltzx186I" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726986AbgIYAkj (ORCPT ); Thu, 24 Sep 2020 20:40:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39118 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726921AbgIYAka (ORCPT ); Thu, 24 Sep 2020 20:40:30 -0400 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 EE3DEC0613CE for ; Thu, 24 Sep 2020 17:40:29 -0700 (PDT) Received: by mail-yb1-xb4a.google.com with SMTP id n13so1035598ybk.9 for ; Thu, 24 Sep 2020 17:40:29 -0700 (PDT) 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=9vNEvvUIDBOqKQiSXDRUkR6P7PLe/wNVFPtGBFmmkGE=; b=Ltzx186IEAfhs/TM0zNVgVXblVxhmnDnbLh+h3NX3PcWhWVYnDb7FHwyZN89gHT9/F JcBO/jnp0iV4fMuRgaY1Ruy5D1kXwZdA+w8bzuO5kOP/Ki/hrvSXzDaI2X4GFtqT86bz gds3FfFHyHe8xSOcvZPmv0N7c9Fg1ronyrkVH2R03fj5vbqjbC2KjH5mDJRijkAlBb8T ZLjhuww6ukHgZ6icY0oavEtJN9Rnt+uPL5UNBXVcVkUfVoURdG5iY2IAiLWiLN1Q6P3/ eFX1QfSY3xnvB48imWRaQ0tDpLNGkpPkeDuTXXuILz3Fv4T2x9KOlWP2ouCAoYcVOL8v NYdw== 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=9vNEvvUIDBOqKQiSXDRUkR6P7PLe/wNVFPtGBFmmkGE=; b=PGZFwKutKmIttf6eSp2+e2DpE78ah3olIEgnJ0PXI1yDXlMJMfBiwVlJS/Hr+EeY84 fZ7N1OEl4dsD9cKffV6nM9/ktQ2424SIg4/2i/HWwUXZRLTuDhKeMy50CHY0bFTvCyRQ POJKNz/Eo/g5OkvehUVsehYxlyIPu/dEsJ7cI8U93GtxPQucAUP7C/ltIUwekcro+QpU MUxH1KPGHI/9nfe1PubJqUDS09Pi8SYoqbSo/1MDG5gjXXiqQ2pYKFfmfgk/3/7syjhS KNRFHHOV9RAOScC7pakI9jSbEHEMbYqB+MD8MnVC3q4FGgzTH68e/DYMPRaptjtu8Wt/ Q13Q== X-Gm-Message-State: AOAM533EIGasYX6OxM5xStBmIJrr6P2q6cfAogis4JI/IdBx3qYZbpsI 3VQoItatfkc2tMuZ81BMPH3Wsf0FCL6nKiI31iQ6 X-Google-Smtp-Source: ABdhPJycwEOeq9SoiVUtSLz9NGhsj5V36ZAhSTBYnN71PhiOT1PfnTNHTpGxsWQ85zjR36NxW/+EvexKxNEv1ymQ7zT2 Sender: "danielwinkler via sendgmr" X-Received: from danielwinkler-linux.mtv.corp.google.com ([2620:15c:202:201:f693:9fff:fef4:4e59]) (user=danielwinkler job=sendgmr) by 2002:a25:2388:: with SMTP id j130mr2252062ybj.40.1600994429153; Thu, 24 Sep 2020 17:40:29 -0700 (PDT) Date: Thu, 24 Sep 2020 17:40:06 -0700 In-Reply-To: <20200925004007.2378410-1-danielwinkler@google.com> Message-Id: <20200924173752.v3.4.Ibedcb7af24f1c01a680de4cc8cc5a98951588393@changeid> Mime-Version: 1.0 References: <20200925004007.2378410-1-danielwinkler@google.com> X-Mailer: git-send-email 2.28.0.709.gb0816b6eb0-goog Subject: [PATCH v3 4/5] Bluetooth: Query LE tx power on startup From: Daniel Winkler To: marcel@holtmann.org Cc: chromeos-bluetooth-upstreaming@chromium.org, linux-bluetooth@vger.kernel.org, Daniel Winkler , Sonny Sasaka , "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 Queries tx power via HCI_LE_Read_Transmit_Power command when the hci device is initialized, and stores resulting min/max LE power in hdev struct. If command isn't available (< BT5 support), min/max values both default to HCI_TX_POWER_INVALID. This patch is manually verified by ensuring BT5 devices correctly query and receive controller tx power range. Reviewed-by: Sonny Sasaka Signed-off-by: Daniel Winkler --- Changes in v3: None Changes in v2: None include/net/bluetooth/hci.h | 7 +++++++ include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_core.c | 8 ++++++++ net/bluetooth/hci_event.c | 18 ++++++++++++++++++ 4 files changed, 35 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index c8e67042a3b14c..c1504aa3d9cfd5 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1797,6 +1797,13 @@ struct hci_cp_le_set_adv_set_rand_addr { bdaddr_t bdaddr; } __packed; +#define HCI_OP_LE_READ_TRANSMIT_POWER 0x204b +struct hci_rp_le_read_transmit_power { + __u8 status; + __s8 min_le_tx_power; + __s8 max_le_tx_power; +} __packed; + #define HCI_OP_LE_READ_BUFFER_SIZE_V2 0x2060 struct hci_rp_le_read_buffer_size_v2 { __u8 status; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ab168f46b6d909..9463039f85442c 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -381,6 +381,8 @@ struct hci_dev { __u16 def_page_timeout; __u16 def_multi_adv_rotation_duration; __u16 def_le_autoconnect_timeout; + __s8 min_le_tx_power; + __s8 max_le_tx_power; __u16 pkt_type; __u16 esco_type; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3a2332f4a9bba2..6bff1c09be3b42 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -741,6 +741,12 @@ static int hci_init3_req(struct hci_request *req, unsigned long opt) hci_req_add(req, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL); } + if (hdev->commands[38] & 0x80) { + /* Read LE Min/Max Tx Power*/ + hci_req_add(req, HCI_OP_LE_READ_TRANSMIT_POWER, + 0, NULL); + } + if (hdev->commands[26] & 0x40) { /* Read LE White List Size */ hci_req_add(req, HCI_OP_LE_READ_WHITE_LIST_SIZE, @@ -3654,6 +3660,8 @@ struct hci_dev *hci_alloc_dev(void) hdev->le_num_of_adv_sets = HCI_MAX_ADV_INSTANCES; hdev->def_multi_adv_rotation_duration = HCI_DEFAULT_ADV_DURATION; hdev->def_le_autoconnect_timeout = HCI_LE_AUTOCONN_TIMEOUT; + hdev->min_le_tx_power = HCI_TX_POWER_INVALID; + hdev->max_le_tx_power = HCI_TX_POWER_INVALID; hdev->rpa_timeout = HCI_DEFAULT_RPA_TIMEOUT; hdev->discov_interleaved_timeout = DISCOV_INTERLEAVED_TIMEOUT; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 4281f4ac6700d4..de51188a3dc15d 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1202,6 +1202,20 @@ static void hci_cc_le_set_adv_set_random_addr(struct hci_dev *hdev, hci_dev_unlock(hdev); } +static void hci_cc_le_read_transmit_power(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_rp_le_read_transmit_power *rp = (void *)skb->data; + + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); + + if (rp->status) + return; + + hdev->min_le_tx_power = rp->min_le_tx_power; + hdev->max_le_tx_power = rp->max_le_tx_power; +} + static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb) { __u8 *sent, status = *((__u8 *) skb->data); @@ -3574,6 +3588,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb, hci_cc_le_set_adv_set_random_addr(hdev, skb); break; + case HCI_OP_LE_READ_TRANSMIT_POWER: + hci_cc_le_read_transmit_power(hdev, skb); + break; + default: BT_DBG("%s opcode 0x%4.4x", hdev->name, *opcode); break; From patchwork Fri Sep 25 00:40:07 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Winkler X-Patchwork-Id: 11798553 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 D0FF36CB for ; Fri, 25 Sep 2020 00:40:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AE3D82371F for ; Fri, 25 Sep 2020 00:40:59 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="qAda9XVd" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727017AbgIYAkz (ORCPT ); Thu, 24 Sep 2020 20:40:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39128 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726955AbgIYAkc (ORCPT ); Thu, 24 Sep 2020 20:40:32 -0400 Received: from mail-qk1-x74a.google.com (mail-qk1-x74a.google.com [IPv6:2607:f8b0:4864:20::74a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 09F35C0613D8 for ; Thu, 24 Sep 2020 17:40:32 -0700 (PDT) Received: by mail-qk1-x74a.google.com with SMTP id m186so827380qkf.12 for ; Thu, 24 Sep 2020 17:40:32 -0700 (PDT) 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=ym8U+dwqfwoXbaZ4eGDN89zEbFIj2x2Xco/pSegZvU8=; b=qAda9XVdrKcfYMQhfPlM8CzSUlmPqDPoZbQDU3d6MNXtiQqYbHgJ1ztsc3xEsHmhPq USutwJe5qnTB2r/MX1glKTpiTa7UnQfnklh+vmgKDrSaaiiS0nDJ1cp7bffo5Mh3q1ST aTnpAmXxYuWfF0j6k9ZEmIGK6ikctUrchJt1ZtO2EJYTJhNSek5LHiEx04nZYEigFJBJ DJfe7EqTnlw2nl36OjLgq/OYnINKOYf56cQlL5U6/Y42R960LuZ4FuUqT0xqx1y6QoL+ E8fb30kz9KISUERvV3h9zFK39A6vJRv+dXSmNr7W6wsKpzRlWtABF0wZArXIxIFZaSSg 76xA== 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=ym8U+dwqfwoXbaZ4eGDN89zEbFIj2x2Xco/pSegZvU8=; b=HFNcZOtq+4vZrNjMdjSo/XWMWygvFAcw0PDdAxK4J+WS4jn36CpHd23KF5hJhBj7HW uGxr/5ToR8aZCbyf2p16A3RDuUipae64dk6ZSk8dpC6YoS3MVLQ2mR7+ZpGQSUY8Gqmm 43Y/dWZTKdOXVYvWHAAL1dWOxRBzPESUo3huKq/pXcANu7H9WdonU+eWEu2WEq8/GoG0 WdaJ117LymwjucrR8x2ZfsTYbHyIAuYo6WElfUwvgyY5bI/jCX4cT3E5OLxjx+tLmSqO OCR+muxs+WRWk/WkkiIuptkPEdegze9BabRGPqaHZXyk6ISNCb5wwnrP3rUPnsH6hvh6 zbRw== X-Gm-Message-State: AOAM530hnczJT7NYthCrTGU0MnypnL6XmerxUceTaYjCYSgd0PL36Cca iGpXdkTcsj8AksC7wvi1IOrchrMNloPvSMuDquBd X-Google-Smtp-Source: ABdhPJxCvkd8bpMZshJUQOwHsBojF327K1ufob/lxs13aaYhWVJpooN1G020XYNMkfGHrP5m/sFXpV0lVA16me/8nzJR Sender: "danielwinkler via sendgmr" X-Received: from danielwinkler-linux.mtv.corp.google.com ([2620:15c:202:201:f693:9fff:fef4:4e59]) (user=danielwinkler job=sendgmr) by 2002:a0c:8091:: with SMTP id 17mr1944004qvb.19.1600994431147; Thu, 24 Sep 2020 17:40:31 -0700 (PDT) Date: Thu, 24 Sep 2020 17:40:07 -0700 In-Reply-To: <20200925004007.2378410-1-danielwinkler@google.com> Message-Id: <20200924173752.v3.5.I5068c01cae3cea674a96e103a0cf4d8c81425a4f@changeid> Mime-Version: 1.0 References: <20200925004007.2378410-1-danielwinkler@google.com> X-Mailer: git-send-email 2.28.0.709.gb0816b6eb0-goog Subject: [PATCH v3 5/5] Bluetooth: Change MGMT security info CMD to be more generic From: Daniel Winkler To: marcel@holtmann.org Cc: chromeos-bluetooth-upstreaming@chromium.org, linux-bluetooth@vger.kernel.org, Daniel Winkler , Sonny Sasaka , "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 For advertising, we wish to know the LE tx power capabilities of the controller in userspace, so this patch edits the Security Info MGMT command to be more generic, such that other various controller capabilities can be included in the EIR data. This change also includes the LE min and max tx power into this newly-named command. The change was tested by manually verifying that the MGMT command returns the tx power range as expected in userspace. Reviewed-by: Sonny Sasaka Signed-off-by: Daniel Winkler --- Changes in v3: - Re-using security info MGMT command to carry controller capabilities Changes in v2: - Fixed sparse error in Capabilities MGMT command include/net/bluetooth/mgmt.h | 16 ++++++++++----- net/bluetooth/mgmt.c | 38 +++++++++++++++++++++++------------- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 83f684af3ae843..1f7dbecae21a76 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -682,11 +682,17 @@ struct mgmt_cp_set_blocked_keys { #define MGMT_OP_SET_WIDEBAND_SPEECH 0x0047 -#define MGMT_OP_READ_SECURITY_INFO 0x0048 -#define MGMT_READ_SECURITY_INFO_SIZE 0 -struct mgmt_rp_read_security_info { - __le16 sec_len; - __u8 sec[]; +#define MGMT_CAP_SEC_FLAGS 0x01 +#define MGMT_CAP_MAX_ENC_KEY_SIZE 0x02 +#define MGMT_CAP_SMP_MAX_ENC_KEY_SIZE 0x03 +#define MGMT_CAP_LE_TX_PWR_MIN 0x04 +#define MGMT_CAP_LE_TX_PWR_MAX 0x05 + +#define MGMT_OP_READ_CONTROLLER_CAP 0x0048 +#define MGMT_READ_CONTROLLER_CAP_SIZE 0 +struct mgmt_rp_read_controller_cap { + __le16 cap_len; + __u8 cap[0]; } __packed; #define MGMT_OP_READ_EXP_FEATURES_INFO 0x0049 diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c92b809a5e086d..eefd60fe624320 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -110,7 +110,7 @@ static const u16 mgmt_commands[] = { MGMT_OP_SET_APPEARANCE, MGMT_OP_SET_BLOCKED_KEYS, MGMT_OP_SET_WIDEBAND_SPEECH, - MGMT_OP_READ_SECURITY_INFO, + MGMT_OP_READ_CONTROLLER_CAP, MGMT_OP_READ_EXP_FEATURES_INFO, MGMT_OP_SET_EXP_FEATURE, MGMT_OP_READ_DEF_SYSTEM_CONFIG, @@ -176,7 +176,7 @@ static const u16 mgmt_untrusted_commands[] = { MGMT_OP_READ_CONFIG_INFO, MGMT_OP_READ_EXT_INDEX_LIST, MGMT_OP_READ_EXT_INFO, - MGMT_OP_READ_SECURITY_INFO, + MGMT_OP_READ_CONTROLLER_CAP, MGMT_OP_READ_EXP_FEATURES_INFO, MGMT_OP_READ_DEF_SYSTEM_CONFIG, MGMT_OP_READ_DEF_RUNTIME_CONFIG, @@ -3705,12 +3705,12 @@ static int set_wideband_speech(struct sock *sk, struct hci_dev *hdev, return err; } -static int read_security_info(struct sock *sk, struct hci_dev *hdev, - void *data, u16 data_len) +static int read_controller_cap(struct sock *sk, struct hci_dev *hdev, + void *data, u16 data_len) { - char buf[16]; - struct mgmt_rp_read_security_info *rp = (void *)buf; - u16 sec_len = 0; + char buf[20]; + struct mgmt_rp_read_controller_cap *rp = (void *)buf; + u16 cap_len = 0; u8 flags = 0; bt_dev_dbg(hdev, "sock %p", sk); @@ -3735,23 +3735,33 @@ static int read_security_info(struct sock *sk, struct hci_dev *hdev, flags |= 0x08; /* Encryption key size enforcement (LE) */ - sec_len = eir_append_data(rp->sec, sec_len, 0x01, &flags, 1); + cap_len = eir_append_data(rp->cap, cap_len, MGMT_CAP_SEC_FLAGS, + &flags, 1); /* When the Read Simple Pairing Options command is supported, then * also max encryption key size information is provided. */ if (hdev->commands[41] & 0x08) - sec_len = eir_append_le16(rp->sec, sec_len, 0x02, + cap_len = eir_append_le16(rp->cap, cap_len, + MGMT_CAP_MAX_ENC_KEY_SIZE, hdev->max_enc_key_size); - sec_len = eir_append_le16(rp->sec, sec_len, 0x03, SMP_MAX_ENC_KEY_SIZE); + cap_len = eir_append_le16(rp->cap, cap_len, + MGMT_CAP_SMP_MAX_ENC_KEY_SIZE, + SMP_MAX_ENC_KEY_SIZE); + + /* Append the min/max LE tx power parameters */ + cap_len = eir_append_data(rp->cap, cap_len, MGMT_CAP_LE_TX_PWR_MIN, + &hdev->min_le_tx_power, 1); + cap_len = eir_append_data(rp->cap, cap_len, MGMT_CAP_LE_TX_PWR_MAX, + &hdev->max_le_tx_power, 1); - rp->sec_len = cpu_to_le16(sec_len); + rp->cap_len = cpu_to_le16(cap_len); hci_dev_unlock(hdev); - return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_SECURITY_INFO, 0, - rp, sizeof(*rp) + sec_len); + return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONTROLLER_CAP, 0, + rp, sizeof(*rp) + cap_len); } #ifdef CONFIG_BT_FEATURE_DEBUG @@ -8175,7 +8185,7 @@ static const struct hci_mgmt_handler mgmt_handlers[] = { { set_blocked_keys, MGMT_OP_SET_BLOCKED_KEYS_SIZE, HCI_MGMT_VAR_LEN }, { set_wideband_speech, MGMT_SETTING_SIZE }, - { read_security_info, MGMT_READ_SECURITY_INFO_SIZE, + { read_controller_cap, MGMT_READ_CONTROLLER_CAP_SIZE, HCI_MGMT_UNTRUSTED }, { read_exp_features_info, MGMT_READ_EXP_FEATURES_INFO_SIZE, HCI_MGMT_UNTRUSTED |