From patchwork Wed Sep 16 20:15:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Winkler X-Patchwork-Id: 11780743 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 F1E6F59D for ; Wed, 16 Sep 2020 20:20:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CA0CF20936 for ; Wed, 16 Sep 2020 20:20:51 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=google.com header.i=@google.com header.b="UH8BwLtk" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728326AbgIPUUJ (ORCPT ); Wed, 16 Sep 2020 16:20:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58880 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728273AbgIPUQN (ORCPT ); Wed, 16 Sep 2020 16:16:13 -0400 Received: from mail-qt1-x84a.google.com (mail-qt1-x84a.google.com [IPv6:2607:f8b0:4864:20::84a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 67FCFC06178B for ; Wed, 16 Sep 2020 13:16:12 -0700 (PDT) Received: by mail-qt1-x84a.google.com with SMTP id 60so7063076qtf.21 for ; Wed, 16 Sep 2020 13:16:12 -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=ouJiHCy9pxH2T5sj1WvYnJy8YM/MOUySnAX+tlwL2Gg=; b=UH8BwLtkHWhbvtlrnOx6o/E+DHvd5pUr9rXriuBNxKQ8cgR4HYRcjlG+1Uhz8PsJmJ iszKYxgls1Lm7qMJE++pD96lGlHyUh6T0EQt7h+KYlbxQNyRF/225JVRS1z1M+f2ktnv am1k7dS8Ju9FsCpWZDUHpgA7ZyF8ETcqT5BSEwwzq33wM3QmAAsObTZHr7aAmTnsrdX5 ePRCv3rBzh64mrTm/pMOgQ8mi7T/yuxblGUjCdKoGi1ZXR6paZ3NSB+GlzlHa5GUrs2l df5UN0cmCy7Wd7NDRDmV/WikaCe3inVRL2MehUEmzlsWoAxkHQ7m7YNdNN65NsAGLy/E qb6A== 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=ouJiHCy9pxH2T5sj1WvYnJy8YM/MOUySnAX+tlwL2Gg=; b=Xk6oJDNin+aOa5Sz7gftQP/BaFEuNvmjXoNh7XmeamqAKCJfZ1IETvTab5m3naSLpc XG3wlGS72sOrDG1Vtd9pq2ZkAnYsEtgu+xvCdgVIijyPEhBctmDzYLRpGsN81ARr4Vzk K1LYDNeOrKEs9dLSQtmJrEc+XNEVxI31LYWWDXA3nVHsjKBmHTMJZwqnZhkBN2SKS9qZ YeSJpRjKWTo7jPpEHSIxx/e2pinga1dbLo666Q3/Fsoy+Zl42RWj7fIfwfp5zF8IZyRU yGmBKl7fWakxLfbQq9NhaMptMu85tf0s2OPgU1s0IrifVOa2G4g9Zn2bQJpb2qZwqmYl yktQ== X-Gm-Message-State: AOAM530T1wE+lC+5axP41+D+DAbpu8R39FEDfzA+aQiDr6IMI9v4RSl4 eLrabE8Rm3Hz8Bm0nC3di81HSzpEOsxSkSxTGm1AYmmv0d327drIVp+glXzWY8XjPqRx64Wl2W2 RIHLUoB2CHC2BSHYFM3ZyBFQMr+RXx34ANSfo1AQbYjsR/k+1Q0D/BRtwjhiO2b+13Qdj7olVAe 00jiXAH1J77/7BRQG1 X-Google-Smtp-Source: ABdhPJyOpQ4N29pZDC8hPDv7B7QRLfS+4nlHD81FOSX8Yz1lGNTqb8jjD+/PxRtpoZl1uLpN42r/+zYEa3sofnMw/bLj X-Received: from danielwinkler-linux.mtv.corp.google.com ([2620:15c:202:201:f693:9fff:fef4:4e59]) (user=danielwinkler job=sendgmr) by 2002:ad4:57cc:: with SMTP id y12mr8902976qvx.48.1600287371193; Wed, 16 Sep 2020 13:16:11 -0700 (PDT) Date: Wed, 16 Sep 2020 13:15:57 -0700 In-Reply-To: <20200916201602.1223002-1-danielwinkler@google.com> Message-Id: <20200916131430.1.I5f4fa6a76fe81f977f78f06b7e68ff1c76c6bddf@changeid> Mime-Version: 1.0 References: <20200916201602.1223002-1-danielwinkler@google.com> X-Mailer: git-send-email 2.28.0.618.gf4bc123cb7-goog Subject: [PATCH 1/6] Bluetooth: Add helper to set adv data From: Daniel Winkler To: linux-bluetooth@vger.kernel.org, marcel@holtmann.org Cc: chromeos-bluetooth-upstreaming@chromium.org, Daniel Winkler , Sonny Sasaka , "David S. Miller" , Jakub Kicinski , Johan Hedberg , linux-kernel@vger.kernel.org, netdev@vger.kernel.org Sender: linux-bluetooth-owner@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 --- 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 Wed Sep 16 20:15:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Winkler X-Patchwork-Id: 11780741 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 9D0CD59D for ; Wed, 16 Sep 2020 20:19:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 67ECA21941 for ; Wed, 16 Sep 2020 20:19:32 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=google.com header.i=@google.com header.b="VHs8qMsn" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728365AbgIPUT3 (ORCPT ); Wed, 16 Sep 2020 16:19:29 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58902 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728287AbgIPUQS (ORCPT ); Wed, 16 Sep 2020 16:16:18 -0400 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 915BCC061352 for ; Wed, 16 Sep 2020 13:16:15 -0700 (PDT) Received: by mail-pl1-x649.google.com with SMTP id b14so3912613pls.12 for ; Wed, 16 Sep 2020 13:16:15 -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=bBclFmx7g5tiBe29zWHfbwOtKlTZdcXOCblGDGmxSug=; b=VHs8qMsnXmgCv0zbl+CE6dYNvrRlwFPN7+6U9mZ2Yi2BtBkhTa6qtlKbR/oVVOzCgm IYK+a6N+kPZGAIMo4OOKw+8KZdlqlMuS3nonlX8Fp+0VaT9hQlg4bJEXxRtwTTCHNH2y zQ84QZepwK1U3GnAi7WMN9RgLzurzqIuRD5d16IIqUYBkjLv6hs8rn1gnHOht+BRO2/J vKFrw0K7+QYCIwyJ34x3ef/y6cs7oVIekNRqDh2NQ6XTrXbCyKsZN361R1l+qcspv2RP HKB7NzWS24yLTqc8jNdP6Sj96C7G4G1YTtFHiib32UHB5YMSATGaaHofPLVuyKsfX04w tb4w== 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=bBclFmx7g5tiBe29zWHfbwOtKlTZdcXOCblGDGmxSug=; b=svfXHZRTYqyUyup0LhBqtJDYBaJTvhSjk0gZ5s5//ghOKgspt3hYaq9oA30Iuophxn 91Fbm8v1u60ueE1V+MM90F6bUHUIIqTYOUC6Gs9dEkK8XFEJadHKYzuU30RBg9vKCxZx S8kjS6FWOdj6XZVD/JZ31EUWQwOuUskcyEQm/UJiF19NPWlVAx6/Xtt7rndV3KwLNVIx l7TXSvqiZX4Rm5qQLJ2P2Ws/niSnlcr3EQl/FYeLxjgrz5fGQRIQJSqG84P1fj4xy2rE ySFtKbPldEj0DT92ksxCEl0vTxCHJBdyEij5RLepfBwP9mwk6Vx/vT58+naNP7yZh31z D8tA== X-Gm-Message-State: AOAM530CZbCnd8KHuMqI7O5Z9Rm/GPjx6baGXs83dMes7c7rtSWp1B8H cESpu6hm0dfQr7gF/cnjFiSp2tQjXtE7CxoSi402NTJhjyADksaFuoJ2zsVNSmt/UfbXbX0K8vv Ht0xWKjqGZ050GczzWIRQL4SA7CcV3iawMme0KV1ij66rgElCiasAAEm40+Cw+tddF/N4zsa4Nb amHviUuUgpIpr0kUNB X-Google-Smtp-Source: ABdhPJzsrkaDe43Z64eHp/v1Nu1OnKW4yZSVY9tilgz3Y0d1IavkoPo6JFta0XpNZt16rh34+K+or8PKYhW3WBv18TL9 X-Received: from danielwinkler-linux.mtv.corp.google.com ([2620:15c:202:201:f693:9fff:fef4:4e59]) (user=danielwinkler job=sendgmr) by 2002:a17:902:eb54:b029:d1:f365:a668 with SMTP id i20-20020a170902eb54b02900d1f365a668mr3009819pli.69.1600287373580; Wed, 16 Sep 2020 13:16:13 -0700 (PDT) Date: Wed, 16 Sep 2020 13:15:58 -0700 In-Reply-To: <20200916201602.1223002-1-danielwinkler@google.com> Message-Id: <20200916131430.2.Id8bee28ed00d158d0894b32c0cd94baa5a012605@changeid> Mime-Version: 1.0 References: <20200916201602.1223002-1-danielwinkler@google.com> X-Mailer: git-send-email 2.28.0.618.gf4bc123cb7-goog Subject: [PATCH 2/6] Bluetooth: Break add adv into two mgmt commands From: Daniel Winkler To: linux-bluetooth@vger.kernel.org, marcel@holtmann.org Cc: chromeos-bluetooth-upstreaming@chromium.org, Daniel Winkler , Sonny Sasaka , "David S. Miller" , Jakub Kicinski , Johan Hedberg , linux-kernel@vger.kernel.org, netdev@vger.kernel.org Sender: linux-bluetooth-owner@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 --- include/net/bluetooth/hci_core.h | 2 + include/net/bluetooth/mgmt.h | 33 +++ net/bluetooth/mgmt.c | 364 ++++++++++++++++++++++++++++++- 3 files changed, 388 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..859f0d3cd6ea38 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -782,6 +782,39 @@ 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; +} __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/mgmt.c b/net/bluetooth/mgmt.c index 0b711ad80f6bd1..421b6784a114f9 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,324 @@ 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; + rp.instance = cp->instance; + + if (status) { + adv_instance = hci_find_adv_instance(hdev, cp->instance); + + /* 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)); + } + + mgmt_pending_remove(cmd); + +unlock: + 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_INTERVALS) ? + 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; + 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 +8189,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 Wed Sep 16 20:15:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Winkler X-Patchwork-Id: 11780727 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 2883D92C for ; Wed, 16 Sep 2020 20:17:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 037EF21655 for ; Wed, 16 Sep 2020 20:17:16 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=google.com header.i=@google.com header.b="vL478tsY" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727219AbgIPUQv (ORCPT ); Wed, 16 Sep 2020 16:16:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58944 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727145AbgIPUQe (ORCPT ); Wed, 16 Sep 2020 16:16:34 -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 8CEF9C06174A for ; Wed, 16 Sep 2020 13:16:17 -0700 (PDT) Received: by mail-yb1-xb4a.google.com with SMTP id i199so8167138ybg.22 for ; Wed, 16 Sep 2020 13:16:17 -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=ToSnX8V2D1upjBIlNrW3uCJ/HI8k/JL9fDv0qFjO2D8=; b=vL478tsYWA7BYu1aZHIUiFUWgq91HuXU6OODg57Tk1DU6ydUDA5yOGsIL9LbiP7Xr4 xFytVQ4xxYX7vWxhaUm1pJaLRWb+2zCr3n7cUHPLdVKUPD7RlBKVnPNUbdV49+PJKOjy iye/rD2uBv2e6s+Yp3MM8HwaoiBdvJsx/OZawOsuDnWFMLjoObfgTWTX2k+PRCHSJ/9B OSKWJl0AKvVfsH+ffdJ1DmbWRG33VJS2oYrilrWSlvcgqfW516P6PDVYR6wWK6WNEu0u +PxLbVk38T6XTX7U/oqYolb1/H1D8/Euc6fKHvHtRjFcAo+rstDiI1MFT08KqlFZq29h 4tYA== 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=ToSnX8V2D1upjBIlNrW3uCJ/HI8k/JL9fDv0qFjO2D8=; b=rYZXmcqZQO0iTcs/YkUmXhAitbLqtMJoxjVXoiq3fAVCyJbKSvNxp+bOaekTgyiemX sAP7IuOrRWuDywvIAiLgsrUfvL1o+D/fNB+4DuYnP20iOljsu929HU+EOC13P7HW1IMH fhfO1smtf6iaHT0OYTqqX6E9w+BaE3yjQs5AwI3MIfiyq4RWhJU71yFftxRtK5h7PxJ3 3a8J3xAYBvMLiUxlPIrpFBqcFLbpSxKnkvuXP0XuW6qbDsXlRbD3NghRZLT7tgfcb0mL mEK9eG+0dlV1SqoBX7fNxjYWpzza/TffvM5zNelf8CMjg0Ax/PLBfBZ8zGelLiavYLyJ 3iEw== X-Gm-Message-State: AOAM530qfnRrsgj3IBrR4/zeTTmWdis2ImO2VyPTqezqpzyQSanUUDkJ 38daK7hFe7OAcaW5BW4+IPZ6agGsetPc0kpi8RFd7D1cIpEMOus7M3UV4NcdCetS7ak85IAlCGl 6vXUvqs228IljaeUvr2m8hjV7G8eBnC+SzsigR5tF92VxIhEdBYrRApEppxdktxrFtTYkW/4KSW zYiEACzasyy6s190mT X-Google-Smtp-Source: ABdhPJynIOAOT3cKcE9mOpi1dSkkWI0SRrZTVfjc8VgXXHGlnRPdBQ1yOcqAflqyWjz6Nx1NH+/JZna8iwQK8WOVQsyB X-Received: from danielwinkler-linux.mtv.corp.google.com ([2620:15c:202:201:f693:9fff:fef4:4e59]) (user=danielwinkler job=sendgmr) by 2002:a05:6902:4d1:: with SMTP id v17mr35743659ybs.389.1600287375986; Wed, 16 Sep 2020 13:16:15 -0700 (PDT) Date: Wed, 16 Sep 2020 13:15:59 -0700 In-Reply-To: <20200916201602.1223002-1-danielwinkler@google.com> Message-Id: <20200916131430.3.I74255537fa99ed3c0025321008b361c6ad90a431@changeid> Mime-Version: 1.0 References: <20200916201602.1223002-1-danielwinkler@google.com> X-Mailer: git-send-email 2.28.0.618.gf4bc123cb7-goog Subject: [PATCH 3/6] Bluetooth: Use intervals and tx power from mgmt cmds From: Daniel Winkler To: linux-bluetooth@vger.kernel.org, marcel@holtmann.org Cc: chromeos-bluetooth-upstreaming@chromium.org, Daniel Winkler , Sonny Sasaka , "David S. Miller" , Jakub Kicinski , Johan Hedberg , linux-kernel@vger.kernel.org, netdev@vger.kernel.org Sender: linux-bluetooth-owner@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 --- 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 e17bc8a1c66ddd..30bf0d0e406d9a 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -1370,6 +1370,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; @@ -1377,6 +1378,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. @@ -1408,11 +1410,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; @@ -1423,9 +1430,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; } } @@ -1942,9 +1946,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); @@ -1967,7 +1977,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 421b6784a114f9..717c97affb1554 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); @@ -7722,7 +7725,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 Wed Sep 16 20:16:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Winkler X-Patchwork-Id: 11780739 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 A581C92C for ; Wed, 16 Sep 2020 20:19:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 83EBC221EF for ; Wed, 16 Sep 2020 20:19:25 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=google.com header.i=@google.com header.b="eA0nBtfT" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727725AbgIPUTM (ORCPT ); Wed, 16 Sep 2020 16:19:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58978 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728309AbgIPUQq (ORCPT ); Wed, 16 Sep 2020 16:16:46 -0400 Received: from mail-qt1-x849.google.com (mail-qt1-x849.google.com [IPv6:2607:f8b0:4864:20::849]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 16875C061355 for ; Wed, 16 Sep 2020 13:16:19 -0700 (PDT) Received: by mail-qt1-x849.google.com with SMTP id g10so7156968qto.1 for ; Wed, 16 Sep 2020 13:16:19 -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=a60adGDxqttpuFcY7jkALjROpt4E168K4TU36LymXcQ=; b=eA0nBtfTtG7rvNCSw/DDYVnI09PSqUgQFZkOgBxrmPPULPry28kBQ0zp0YUbhQRjOY X/E8NDeG2osSs/7lD3gCsOLOu6QL8awcC5TyO4wVvGV1l4WEs3zzPorZGkf+tG0Ri2c8 j/KmtiLW/tqXu9JkGdHN2Ul/PEKR3PGhKDj8Y56rE96mQ5a4BD1wPiIY9/IcPJHyLeFS iHodk/vtswNP5kuPqaFTYFghWdGKDEh6aPduQ6vJLD5OsSPO1fMQXHjQ1TxAOR1+lU6P J/WzPQC5hevNpKvZmCd5aQ8LADPabI+kYKMJuoI+pPQhlN8YDxjFM4IfqB3WMIsxuGR2 uVow== 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=a60adGDxqttpuFcY7jkALjROpt4E168K4TU36LymXcQ=; b=A12CVnNGMYm4j6oEXIyMEVnQXxIpl8eglxa72TAlXD4E/V8oyypTAlalmXVkptoULF VadGJzEDw4+gqRAhLPICuDcLI/L9vD/ZWGkz9Mt2FlDGOlF/ZSXal5Ny7R6T8fJ74vRl IB70udsNlxglyq3t+V9MuTDqKye389e0dYMHTu9ZYmvlXw7bXrx+gOvZq4/mBVoFetDu cXEowIoTVCMFgvQspGYggZvUrLzwiGPjOKZwfhjr3J8KN6mnbsdxlQHx0Xlj5DPpyn0u NpmGTk5X4N6xpVnrKPzN7uJhHIZ+6rzvofuqYfwlgIESsqUanP6i8lgy9m2w2Z0fplb2 YY5g== X-Gm-Message-State: AOAM531ljk5bju/2s7VeRERJEjaEaG1CgbkXGJ7Hg9NVBxAIeaXdS8ge tJwJlFhErr5G4DMEUGgVwcUfz0fxpe4DzrDLHaeLJzXGu+2FsZzgQhNe8EZRTpW6PE74Ex+blAz 3Jdgni0OkIT2Q+BDY0Lx7d7j8qT+Ijcr39oWv1ziSUQME0ZGKP44EQNmB+hSj9CNMSBwKtE94Qj vTZKyJTo5UnhngZLDe X-Google-Smtp-Source: ABdhPJzfBMACV3i9Ag2je48WjOHXDjCnBloIo08bMmmfrF6UQkcJ9p9JN/Tx9z7Yh/AB7BqsJ+OmUXhXeqT6/JFDXhz1 X-Received: from danielwinkler-linux.mtv.corp.google.com ([2620:15c:202:201:f693:9fff:fef4:4e59]) (user=danielwinkler job=sendgmr) by 2002:ad4:5653:: with SMTP id bl19mr24887200qvb.7.1600287378198; Wed, 16 Sep 2020 13:16:18 -0700 (PDT) Date: Wed, 16 Sep 2020 13:16:00 -0700 In-Reply-To: <20200916201602.1223002-1-danielwinkler@google.com> Message-Id: <20200916131430.4.I34169001276125c476e86ece0b4802c36aa08bca@changeid> Mime-Version: 1.0 References: <20200916201602.1223002-1-danielwinkler@google.com> X-Mailer: git-send-email 2.28.0.618.gf4bc123cb7-goog Subject: [PATCH 4/6] Bluetooth: Emit tx power chosen on ext adv params completion From: Daniel Winkler To: linux-bluetooth@vger.kernel.org, marcel@holtmann.org Cc: chromeos-bluetooth-upstreaming@chromium.org, Daniel Winkler , Sonny Sasaka , "David S. Miller" , Jakub Kicinski , Johan Hedberg , linux-kernel@vger.kernel.org, netdev@vger.kernel.org Sender: linux-bluetooth-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org Our hci call to set extended advertising parameters returns the actual tx power selected by the controller. This patch signals a new TX_POWER_SELECTED mgmt event to alert the caller of the actual tx power that is being used. This is important because the power selected will not necessarily match the power requested by the user. This patch is manually verified by ensuring the tx power selected event is signalled and caught by bluetoothd. Reviewed-by: Sonny Sasaka Signed-off-by: Daniel Winkler --- include/net/bluetooth/hci_core.h | 2 ++ include/net/bluetooth/mgmt.h | 6 ++++++ net/bluetooth/hci_event.c | 4 ++++ net/bluetooth/mgmt.c | 11 +++++++++++ 4 files changed, 23 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ab168f46b6d909..667b9d37099dec 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1781,6 +1781,8 @@ 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_tx_power_selected(struct hci_dev *hdev, u8 instance, + s8 tx_power); int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip); u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 859f0d3cd6ea38..db64cf4747554c 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -1079,3 +1079,9 @@ struct mgmt_ev_controller_resume { #define MGMT_WAKE_REASON_NON_BT_WAKE 0x0 #define MGMT_WAKE_REASON_UNEXPECTED 0x1 #define MGMT_WAKE_REASON_REMOTE_WAKE 0x2 + +#define MGMT_EV_ADV_TX_POWER_SELECTED 0x002f +struct mgmt_ev_adv_tx_power_selected { + __u8 instance; + __s8 tx_power; +} __packed; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index bd306ba3ade545..9a24fd99d9e08e 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1749,6 +1749,10 @@ 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); + + if (cp->handle) + mgmt_adv_tx_power_selected(hdev, cp->handle, rp->tx_power); + hci_dev_unlock(hdev); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 717c97affb1554..b9347ff1a1e961 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -167,6 +167,7 @@ static const u16 mgmt_events[] = { MGMT_EV_DEVICE_FLAGS_CHANGED, MGMT_EV_CONTROLLER_SUSPEND, MGMT_EV_CONTROLLER_RESUME, + MGMT_EV_ADV_TX_POWER_SELECTED, }; static const u16 mgmt_untrusted_commands[] = { @@ -1152,6 +1153,16 @@ void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev, mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk); } +void mgmt_adv_tx_power_selected(struct hci_dev *hdev, u8 instance, s8 tx_power) +{ + struct mgmt_ev_adv_tx_power_selected ev; + + ev.instance = instance; + ev.tx_power = tx_power; + + mgmt_event(MGMT_EV_ADV_TX_POWER_SELECTED, hdev, &ev, sizeof(ev), NULL); +} + static void cancel_adv_timeout(struct hci_dev *hdev) { if (hdev->adv_instance_timeout) { From patchwork Wed Sep 16 20:16:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Winkler X-Patchwork-Id: 11780733 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 70DC659D for ; Wed, 16 Sep 2020 20:17:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4461620936 for ; Wed, 16 Sep 2020 20:17:59 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=google.com header.i=@google.com header.b="Cr0pbVi/" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728224AbgIPURy (ORCPT ); Wed, 16 Sep 2020 16:17:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58900 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727725AbgIPUQq (ORCPT ); Wed, 16 Sep 2020 16:16:46 -0400 Received: from mail-qv1-xf49.google.com (mail-qv1-xf49.google.com [IPv6:2607:f8b0:4864:20::f49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2F4C0C06121E for ; Wed, 16 Sep 2020 13:16:21 -0700 (PDT) Received: by mail-qv1-xf49.google.com with SMTP id di5so5516448qvb.13 for ; Wed, 16 Sep 2020 13:16:21 -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=JEGDhDy0i0NXGVogNpEKp6N3BhWlDVgJ1Ss+eXstDS8=; b=Cr0pbVi/P8EJnHlXGCs6MoDzp6ikdg7g9weO0ajM9wg7h12zQtMVqRq8k4pOdQKwTb 7ftjslmmczWg8PBJagPtJ9YFKljqpRsM/Tq1mE0S7ct3bVlz2yJFplk3yr1yt2MbLFFh 48LtzIoHhTwfi9ZiDpbVked8e3L3fgkLP16LEULNLeCWqntrU0QbcLmJ/8a2u80xwM7j 6Dl/BYP5x0SzYNssjpzXI2IYFxcpiU/0FpYQ2LpioIDHCS+c+uLkt/PduxRB6VWXF3so tpgSjCtFtmdz6ASPmJDX7nJNQGHGMqzE8n1J4lx33fvDS14475vkP83oGOYh/th9RkjT 03MA== 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=JEGDhDy0i0NXGVogNpEKp6N3BhWlDVgJ1Ss+eXstDS8=; b=a50XGjWSbwPkUYTKXDFF7XOgzE85viLlC4u8FHSpPadUCuen1J4+XPNNRXBmoywMhU whRCpYukEx0NnlKcRUS5FczLVnE1FihXEDhKJ7LBI81PWsR59kC/nPXe/PAHlPIq79Dh uLkoYmCebrSMJearPYYUQDZLsokMS617A8D7OkksAln+4zNrhMM2fyVhw9KkBEDBpbgB 0FQ4NFMzc4EdMKf7LFe4VS6t22C+9glwSAhJXOsage1Zk5DV/cmH2sh547NcDmQ/jkns fF2jGFQFkTBOdh+0IIdT+fXbyfR3dSDBqInVEWki/NF0NhrnkE+X7uOHLC6vghOOMaN7 MNXQ== X-Gm-Message-State: AOAM5310Ewsf/9Tjq8WbRnrsi2i6s5QfJ4iNWvTdFssWoKgLlt0ABLK5 J0+n/gmb2goPJBainqX+B4zQN+thTXq3PLGBo9eYyapCK89SVuJljfKUU+GMFVBGeX0PKKiPU+U Pbg1LEJEqEgMj+l1l5K720CuZR7DqIQ9nGOBkk8VZZiBITSFD2LbwLuC96wMWeZEXHXcxvS2LXf WSrQDKH/UTgj/6NxQm X-Google-Smtp-Source: ABdhPJwRasF3+ybFhcwR2eBIZaGWRgKaYBBuDmJGK4uF+WJlagHiIvooM9IhAqq257N5hWKnFmDtqegPm4TTFBubAGKI X-Received: from danielwinkler-linux.mtv.corp.google.com ([2620:15c:202:201:f693:9fff:fef4:4e59]) (user=danielwinkler job=sendgmr) by 2002:ad4:58aa:: with SMTP id ea10mr8827403qvb.58.1600287380260; Wed, 16 Sep 2020 13:16:20 -0700 (PDT) Date: Wed, 16 Sep 2020 13:16:01 -0700 In-Reply-To: <20200916201602.1223002-1-danielwinkler@google.com> Message-Id: <20200916131430.5.Ibedcb7af24f1c01a680de4cc8cc5a98951588393@changeid> Mime-Version: 1.0 References: <20200916201602.1223002-1-danielwinkler@google.com> X-Mailer: git-send-email 2.28.0.618.gf4bc123cb7-goog Subject: [PATCH 5/6] Bluetooth: Query LE tx power on startup From: Daniel Winkler To: linux-bluetooth@vger.kernel.org, marcel@holtmann.org Cc: chromeos-bluetooth-upstreaming@chromium.org, Daniel Winkler , Sonny Sasaka , "David S. Miller" , Jakub Kicinski , Johan Hedberg , linux-kernel@vger.kernel.org, netdev@vger.kernel.org Sender: linux-bluetooth-owner@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 --- 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 667b9d37099dec..c1f5b5c4109215 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 9a24fd99d9e08e..beb35680f3a83a 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); @@ -3577,6 +3591,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 Wed Sep 16 20:16:02 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Winkler X-Patchwork-Id: 11780731 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 D3F3559D for ; Wed, 16 Sep 2020 20:17:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AEA6621974 for ; Wed, 16 Sep 2020 20:17:40 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=google.com header.i=@google.com header.b="EQRl+RIO" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726890AbgIPURi (ORCPT ); Wed, 16 Sep 2020 16:17:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58980 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728326AbgIPUQq (ORCPT ); Wed, 16 Sep 2020 16:16:46 -0400 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 4B66AC061220 for ; Wed, 16 Sep 2020 13:16:23 -0700 (PDT) Received: by mail-qv1-xf4a.google.com with SMTP id di5so5516499qvb.13 for ; Wed, 16 Sep 2020 13:16: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=mV/LFuTshHzotksH3grmXFg7Xs0h6PleCimRLiw3IeY=; b=EQRl+RIO/iMmVWfKcZ8ED17Om52TeR9DzT0HzQt62GI8XYzbTx4iSE/e53TWLeRrC4 SinrfVtyjrg8237Bs3Z5Y6SWftmvQrUM2sPw4RnMoJ5vk10M2ZWGgSsoXIBGfqPA3DZW dRiCE4KtBUMZZNXBlXikUyz/9lx9HSLDr/p1IjtZnwFCNbEYGhOtEnek7cUlCDGJ81RW byBJJkGtNWPwky/MpFaZ8fHoDZpF4odneqa6wytQFAdaoV5xhvHMH8Nm5kYI/J+BiSyH BThka3ZSKn46911pMjZGg8Q+1xXtdHCnJDIMl/URjQcO3oXG6Fpo6hfqmf9FQwAApsZL mGzw== 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=mV/LFuTshHzotksH3grmXFg7Xs0h6PleCimRLiw3IeY=; b=tLlgR8/VWwIJg4eO58wXER+8OkHlj9HieASLa4di3m5a40duWQ7Iv3b0A+m+rhkPE1 mZ/nPR5xzoYoKc7p5gyavK0WNd/tqhbRVNBz5g6GoSQW29jrBcHRo4NSt44Ju2IBqarv OgBilYGJmg8s5Mb6g0jImsNECRlv4wtJrQ6PUAxi+mon2T94Zm87IhUZvtQSrFX+b+Sm e3aL1e9/tLlCsZ4atkcUMWNPHVoH8RgWlyPMBPKffl1pY5FnqIZH/Vg81ou48V7ZItK8 15ryixKRF2hLASsJWMtByhnZ79pB8d6vnRFLFhVhWZCNfQJ2iWqQiQ0UJakFiSwpWrzE NjRg== X-Gm-Message-State: AOAM530GRZ184EVblYinnAdok9HT3Slz/ovowvCb4vSE1/pdgTNooZ3O JyWD00imF29pHNTWoyE58X2OtpCG/I3Ih4Sz6aCl0W3X71yGqPpX3oY/+CXDETku9YI6MoR8xIE TdEOsJEvotPouViFpC38ozG8yYmvsoEtZe44L5yEe7A6d5uVO3Dlcu7LD1OgFxMM2SPOSjQLfWu b3BGPtSk1QlZMbDTD1 X-Google-Smtp-Source: ABdhPJx9rr/wInvexTzLGszPhP52de+s7E+VegnMknnOC50bFToSeEmk3oEZlbiKA9jVdE7FHbXQXJRUfSF8TKP5DSid X-Received: from danielwinkler-linux.mtv.corp.google.com ([2620:15c:202:201:f693:9fff:fef4:4e59]) (user=danielwinkler job=sendgmr) by 2002:a0c:c244:: with SMTP id w4mr25344793qvh.12.1600287382444; Wed, 16 Sep 2020 13:16:22 -0700 (PDT) Date: Wed, 16 Sep 2020 13:16:02 -0700 In-Reply-To: <20200916201602.1223002-1-danielwinkler@google.com> Message-Id: <20200916131430.6.I5068c01cae3cea674a96e103a0cf4d8c81425a4f@changeid> Mime-Version: 1.0 References: <20200916201602.1223002-1-danielwinkler@google.com> X-Mailer: git-send-email 2.28.0.618.gf4bc123cb7-goog Subject: [PATCH 6/6] Bluetooth: Add MGMT command for controller capabilities From: Daniel Winkler To: linux-bluetooth@vger.kernel.org, marcel@holtmann.org Cc: chromeos-bluetooth-upstreaming@chromium.org, Daniel Winkler , Sonny Sasaka , "David S. Miller" , Jakub Kicinski , Johan Hedberg , linux-kernel@vger.kernel.org, netdev@vger.kernel.org Sender: linux-bluetooth-owner@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 adds a new MGMT command to query controller capabilities. The data returned is in TLV format, so it can be easily used to convey any data determined to be useful in the future, but for now it simply contains LE min and max tx power. The change was tested by manually verifying that the new MGMT command returns the tx power range as expected in userspace. Reviewed-by: Sonny Sasaka Signed-off-by: Daniel Winkler Reported-by: kernel test robot --- include/net/bluetooth/mgmt.h | 9 +++++++++ net/bluetooth/mgmt.c | 39 ++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index db64cf4747554c..9aa792e5efc8d0 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -815,6 +815,15 @@ struct mgmt_rp_add_ext_adv_data { __u8 instance; } __packed; +#define MGMT_CAP_LE_TX_PWR_MIN 0x0000 +#define MGMT_CAP_LE_TX_PWR_MAX 0x0001 + +#define MGMT_OP_READ_CONTROLLER_CAP 0x0056 +#define MGMT_OP_READ_CONTROLLER_CAP_SIZE 0 +struct mgmt_rp_read_controller_cap { + __u8 capabilities[0]; +} __packed; + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index b9347ff1a1e961..d2e5bc4b3ddb8f 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -124,6 +124,7 @@ static const u16 mgmt_commands[] = { MGMT_OP_REMOVE_ADV_MONITOR, MGMT_OP_ADD_EXT_ADV_PARAMS, MGMT_OP_ADD_EXT_ADV_DATA, + MGMT_OP_READ_CONTROLLER_CAP, }; static const u16 mgmt_events[] = { @@ -181,6 +182,7 @@ static const u16 mgmt_untrusted_commands[] = { MGMT_OP_READ_EXP_FEATURES_INFO, MGMT_OP_READ_DEF_SYSTEM_CONFIG, MGMT_OP_READ_DEF_RUNTIME_CONFIG, + MGMT_OP_READ_CONTROLLER_CAP, }; static const u16 mgmt_untrusted_events[] = { @@ -4356,6 +4358,42 @@ static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev, return err; } +static int read_controller_cap(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + u8 i = 0; + + /* This command will return its data in TVL format. Currently we only + * wish to include LE tx power parameters, so this struct can be given + * a fixed size as data types are not changing. + */ + struct { + struct mgmt_tlv entry; + __s8 value; + } __packed cap[2]; + + BT_DBG("request for %s", hdev->name); + memset(cap, 0, sizeof(cap)); + + hci_dev_lock(hdev); + + /* Append LE tx power bounds */ + cap[i].entry.type = MGMT_CAP_LE_TX_PWR_MIN; + cap[i].entry.length = sizeof(__s8); + cap[i].value = hdev->min_le_tx_power; + i++; + + cap[i].entry.type = MGMT_CAP_LE_TX_PWR_MAX; + cap[i].entry.length = sizeof(__s8); + cap[i].value = hdev->max_le_tx_power; + i++; + + hci_dev_unlock(hdev); + + return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONTROLLER_CAP, + MGMT_STATUS_SUCCESS, cap, sizeof(cap)); +} + static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status, u16 opcode, struct sk_buff *skb) { @@ -8208,6 +8246,7 @@ static const struct hci_mgmt_handler mgmt_handlers[] = { HCI_MGMT_VAR_LEN }, { add_ext_adv_data, MGMT_ADD_EXT_ADV_DATA_SIZE, HCI_MGMT_VAR_LEN }, + { read_controller_cap, MGMT_OP_READ_CONTROLLER_CAP_SIZE }, }; void mgmt_index_added(struct hci_dev *hdev)