Received: by 2002:a6b:fb09:0:0:0:0:0 with SMTP id h9csp1747822iog; Thu, 16 Jun 2022 13:00:32 -0700 (PDT) X-Google-Smtp-Source: AGRyM1uG9FLTav2mIUy4gtCcOoyJj4T9tHOqkGbFNI/s4ovUmiLgtd+vIa4aXw9Oj5I9d625ugYw X-Received: by 2002:a05:6402:5412:b0:435:5997:ccb5 with SMTP id ev18-20020a056402541200b004355997ccb5mr3071766edb.167.1655409632099; Thu, 16 Jun 2022 13:00:32 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1655409632; cv=none; d=google.com; s=arc-20160816; b=0QiY/yvBg+03UVp/iqWF6rnvMQFGEKDHSJpi19uMt2sL1AnRIdm68QCy0XyZZEzimS DLVG81ReLnLOUMjpKtB+stE+vsf7445SYkIv6AeZBLWcGYjoAJ/MKbPocWhH2dXdixZm Vwk1n5sP7mkee8TxYwD+Wc7wDcElP6rdoBUee0lxbDUjs2YFBGLJwCuYCDeDDv5bMFHz MeNczovrS+a/I1GU46krrcImct+kUENL9knFwbevnci81giQwD7zAjqdAHYLhZCxFsK4 n35QSKMSM5gXNJwtvLHTLe24eEOPOtT80a/SQhpEO/IfL9KYCtsZimuGWDdrriiWn9gX LWTQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:to:from :dkim-signature; bh=BYvMPzooqLhsj7GljNraofl+4iLwxPDzg6NSJeDYJCA=; b=n8voSj/UZCO+6lhDIbJJ3x0v7Dl3hv9f5s4Orh8P4+T+PISfjrPXsY5vTVDt6itOl/ uWOuIl4P4FyPsjJ7bd2/COFklKtmL7/r4r357sfeO9TjuTONgpEKRltCBNssC+xgf+RB eyaj0IzbWAbpMUaL3GRTyJcWJQSFDbKthCIJ7m35m14Y5TkGJ4eGctATq7JEpHUG2iM+ 7Skc25iVYCOBrUWnh0BeeVXFqLT0rNC/yhgdNfs4q3npFthQywcrp7hjT0quNSVHcBhZ i3liZrgv1TtHY70G8EdLP2jRZ1E3SjHgbMfOyF1GJkS8H/KK9jtOX7OJOwZ9g4DRxp7y 5Udg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b="NlSl/bkn"; spf=pass (google.com: domain of linux-bluetooth-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-bluetooth-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id z30-20020a509e21000000b0042dd0747a72si3501840ede.114.2022.06.16.13.00.06; Thu, 16 Jun 2022 13:00:32 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-bluetooth-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b="NlSl/bkn"; spf=pass (google.com: domain of linux-bluetooth-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-bluetooth-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1378479AbiFPT6T (ORCPT + 99 others); Thu, 16 Jun 2022 15:58:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44888 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1378469AbiFPT6N (ORCPT ); Thu, 16 Jun 2022 15:58:13 -0400 Received: from mail-pl1-x629.google.com (mail-pl1-x629.google.com [IPv6:2607:f8b0:4864:20::629]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F31762A719 for ; Thu, 16 Jun 2022 12:58:11 -0700 (PDT) Received: by mail-pl1-x629.google.com with SMTP id r1so2083030plo.10 for ; Thu, 16 Jun 2022 12:58:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=BYvMPzooqLhsj7GljNraofl+4iLwxPDzg6NSJeDYJCA=; b=NlSl/bknRQIumhPMB3WwbSvg+EyyddWI8p+FIs1PWQpTLF6yGJVVYKIztt/FOcKrI3 QlhsN5EW4/8f8ZstRAEmeY8eYdXIbowF0Y4WJY/GGLunz8pgshYHmsdgLwVrpdk0XH/x PiWImXAkcfXp99A2aceAvOmwDWQpX1fbn5iisGmcV8ClcLfYlDt8Iw7p/kmEA5jaqdvz POM7Rw9ch6sAIr5NkuKSCkgISbJ7We0UMfc1CZS+uHSuDLY0hMzmsrkyNdJIdMARGld+ c6kyjU3x4KouGlfkWh+v3guQft57soy1AjWbnXf4EnuUcS8nULhzMOrb/KdJir2siIYQ ErCA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=BYvMPzooqLhsj7GljNraofl+4iLwxPDzg6NSJeDYJCA=; b=u1nSWoM2WGIg4A5c+PNmxCcbRwpnvJkH1RgoA6i7Dk2E9neGAtvlHVRFXnOU+tXw+T D4CzkFnK58f4YN7WwSTD+YU9crkGkYQVyEYy9mt9p2xj2AUz4te5xsDB0B7U2j8QSF9t s48EVWMRCYPflnPvl8robM4AcbQ7K8stc9c/LLzhwF22bJomxtuD98gv+UZjeC3H57je cZVCq5dAibWX/GMUKwB5IsbKVy41Cuth/bZkHfir4f7/2JpXem5KmzlFd7yO/RLusSYP J/Rtf9/HRsHMgyvT12x+tRqjg4iHJLcdoQtKpI13CjG5H8jMZxQVpsx+wPIuDA/IIU8i UCCQ== X-Gm-Message-State: AJIora/5o+wF2Ku2uDhy3l2Co2vmJfaTVabqRMxW/ny/ajw90Es+ppLt D5eFVvqmkfzd2JMeDcCrxDk8xXEnrDI= X-Received: by 2002:a17:902:f60c:b0:16a:239:bcf7 with SMTP id n12-20020a170902f60c00b0016a0239bcf7mr933405plg.130.1655409491172; Thu, 16 Jun 2022 12:58:11 -0700 (PDT) Received: from han1-ubuntu-dev.. ([192.102.209.8]) by smtp.gmail.com with ESMTPSA id q23-20020a170902edd700b0016a034ae481sm89285plk.176.2022.06.16.12.58.10 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Jun 2022 12:58:10 -0700 (PDT) From: Tedd Ho-Jeong An To: linux-bluetooth@vger.kernel.org Subject: [BlueZ PATCH 3/3] tools/btmgmt: Add support Add Ext Adv command Date: Thu, 16 Jun 2022 12:58:03 -0700 Message-Id: <20220616195803.99346-3-hj.tedd.an@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220616195803.99346-1-hj.tedd.an@gmail.com> References: <20220616195803.99346-1-hj.tedd.an@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM, RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Tedd Ho-Jeong An This patch adds new command to support the following MGMT API: Add Extended Advertising Parameters Command Add Extended Advertising Data Command --- tools/btmgmt.c | 377 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 377 insertions(+) diff --git a/tools/btmgmt.c b/tools/btmgmt.c index 8f63f12ba..3bf2c21c1 100644 --- a/tools/btmgmt.c +++ b/tools/btmgmt.c @@ -4891,6 +4891,377 @@ static void cmd_clr_adv(int argc, char **argv) cmd_rm_adv(2, rm_argv); } +static void add_ext_adv_params_rsp(uint8_t status, uint16_t len, + const void *param, void *user_data) +{ + const struct mgmt_rp_add_ext_adv_params *rp = param; + + if (status != 0) { + error("Add Ext Adv Params failed status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len != sizeof(*rp)) { + error("Invalid Add Ext Adv Params response length (%u)", len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("Instance added: %u", rp->instance); + print("Tx Power: %u", rp->tx_power); + print("Max adv data len: %u", rp->max_adv_data_len); + print("Max scan resp len: %u", rp->max_scan_rsp_len); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void add_ext_adv_params_usage(void) +{ + bt_shell_usage(); + print("Options:\n" + "\t -d, --duration Duration in seconds\n" + "\t -t, --timeout Timeout in seconds\n" + "\t -r, --min-interval Minimum interval\n" + "\t -x, --max-interval Maximum interval\n" + "\t -w, --tx-power Tx power\n" + "\t -P, --phy Phy type, Specify 1M/2M/CODED\n" + "\t -c, --connectable \"connectable\" flag\n" + "\t -g, --general-discov \"general-discoverable\" flag\n" + "\t -l, --limited-discov \"limited-discoverable\" flag\n" + "\t -m, --managed-flags \"managed-flags\" flag\n" + "\t -p, --add-tx-power \"tx-power\" flag\n" + "\t -a, --scan-rsp-appearance \"appearance\" flag\n" + "\t -n, --scan-rsp-local-name \"local-name\" flag\n" + "\t -s, --adv-scan-rsp \"scan resp in adv\" flag\n" + "\t -h, --help Show help\n" + "e.g.:\n" + "\tadd-ext-adv-params -r 0x801 -x 0x802 -P 2M -g 1"); +} + +static struct option add_ext_adv_params_options[] = { + { "help", 0, 0, 'h' }, + { "duration", 1, 0, 'd' }, + { "timeout", 1, 0, 't' }, + { "min-internal", 1, 0, 'r' }, + { "max-interval", 1, 0, 'x' }, + { "tx-power", 1, 0, 'w' }, + { "phy", 1, 0, 'P' }, + { "connectable", 0, 0, 'c' }, + { "general-discov", 0, 0, 'g' }, + { "limited-discov", 0, 0, 'l' }, + { "scan-rsp-local-name", 0, 0, 'n' }, + { "scan-rsp-appearance", 0, 0, 'a' }, + { "managed-flags", 0, 0, 'm' }, + { "add-tx-power", 0, 0, 'p' }, + { "adv-scan-rsp", 0, 0, 's' }, + { 0, 0, 0, 0} +}; + +static void cmd_add_ext_adv_params(int argc, char **argv) +{ + struct mgmt_cp_add_ext_adv_params *cp = NULL; + int opt; + uint16_t timeout = 0, duration = 0; + uint8_t instance; + bool success = false; + bool quit = true; + uint32_t flags = 0; + uint32_t min_interval = 0; + uint32_t max_interval = 0; + uint8_t tx_power = 0; + uint16_t index; + + while ((opt = getopt_long(argc, argv, "d:t:r:x:w:P:cglmpansh", + add_ext_adv_params_options, NULL)) != -1) { + switch (opt) { + case 'd': + duration = strtol(optarg, NULL, 0); + flags |= MGMT_ADV_PARAM_DURATION; + break; + case 't': + timeout = strtol(optarg, NULL, 0); + flags |= MGMT_ADV_PARAM_TIMEOUT; + break; + case 'r': + min_interval = strtol(optarg, NULL, 0); + break; + case 'x': + max_interval = strtol(optarg, NULL, 0); + break; + case 'w': + tx_power = strtol(optarg, NULL, 0); + flags |= MGMT_ADV_PARAM_TX_POWER; + break; + case 'P': + if (strcasecmp(optarg, "1M") == 0) + flags |= MGMT_ADV_FLAG_SEC_1M; + else if (strcasecmp(optarg, "2M") == 0) + flags |= MGMT_ADV_FLAG_SEC_2M; + else if (strcasecmp(optarg, "CODED") == 0) + flags |= MGMT_ADV_FLAG_SEC_CODED; + else + goto done; + break; + case 'c': + flags |= MGMT_ADV_FLAG_CONNECTABLE; + break; + case 'g': + flags |= MGMT_ADV_FLAG_DISCOV; + break; + case 'l': + flags |= MGMT_ADV_FLAG_LIMITED_DISCOV; + break; + case 'n': + flags |= MGMT_ADV_FLAG_LOCAL_NAME; + break; + case 'a': + flags |= MGMT_ADV_FLAG_APPEARANCE; + break; + case 'm': + flags |= MGMT_ADV_FLAG_MANAGED_FLAGS; + break; + case 'p': + flags |= MGMT_ADV_FLAG_TX_POWER; + break; + case 's': + flags |= MGMT_ADV_PARAM_SCAN_RSP; + break; + case 'h': + success = true; + /* fall through */ + default: + add_ext_adv_params_usage(); + optind = 0; + goto done; + } + } + + argc -= optind; + argv += optind; + optind = 0; + + if (argc != 1) { + add_ext_adv_params_usage(); + goto done; + } + + /* Only if both min_interval and max_interval are defined */ + if (min_interval && max_interval) + flags |= MGMT_ADV_PARAM_INTERVALS; + + instance = strtol(argv[0], NULL, 0); + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + cp = malloc0(sizeof(*cp)); + if (!cp) + goto done; + + cp->instance = instance; + put_le32(flags, &cp->flags); + put_le16(timeout, &cp->timeout); + put_le16(duration, &cp->duration); + put_le32(min_interval, &cp->min_interval); + put_le32(max_interval, &cp->max_interval); + cp->tx_power = tx_power; + + if (!mgmt_send(mgmt, MGMT_OP_ADD_EXT_ADV_PARAMS, index, sizeof(*cp), cp, + add_ext_adv_params_rsp, NULL, NULL)) { + error("Unable to send \"Add Ext Advertising Params\" command"); + goto done; + } + + quit = false; + +done: + free(cp); + + if (quit) + bt_shell_noninteractive_quit(success ? + EXIT_SUCCESS : EXIT_FAILURE); +} + +static void add_ext_adv_data_rsp(uint8_t status, uint16_t len, + const void *param, void *user_data) +{ + const struct mgmt_rp_add_ext_adv_data *rp = param; + + if (status != 0) { + error("Add Ext Advertising Data failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len != sizeof(*rp)) { + error("Invalid Add Ext Advertising Data response length (%u)", + len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("Instance added: %u", rp->instance); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void add_ext_adv_data_usage(void) +{ + bt_shell_usage(); + print("Options:\n" + "\t -u, --uuid Service UUID\n" + "\t -d, --adv-data Advertising Data bytes\n" + "\t -s, --scan-rsp Scan Response Data bytes\n" + "e.g.:\n" + "\tadd-ext-adv-data -u 180d -u 180f -d 080954657374204C45 1"); +} + +static struct option add_ext_adv_data_options[] = { + { "help", 0, 0, 'h' }, + { "uuid", 1, 0, 'u' }, + { "adv-data", 1, 0, 'd' }, + { "scan-rsp", 1, 0, 's' }, + { 0, 0, 0, 0} +}; + +static void cmd_add_ext_adv_data(int argc, char **argv) +{ + struct mgmt_cp_add_ext_adv_data *cp = NULL; + int opt; + uint8_t *adv_data = NULL, *scan_rsp = NULL; + size_t adv_len = 0, scan_rsp_len = 0; + size_t cp_len; + uint8_t uuids[MAX_AD_UUID_BYTES]; + size_t uuid_bytes = 0; + uint8_t uuid_type = 0; + uint8_t instance; + uuid_t uuid; + bool success = false; + bool quit = true; + uint16_t index; + + while ((opt = getopt_long(argc, argv, "+u:d:s:h", + add_ext_adv_data_options, NULL)) != -1) { + switch (opt) { + case 'u': + if (bt_string2uuid(&uuid, optarg) < 0) { + print("Invalid UUID: %s", optarg); + goto done; + } + + if (uuid_type && uuid_type != uuid.type) { + print("UUID types must be consistent"); + goto done; + } + + if (uuid.type == SDP_UUID16) { + if (uuid_bytes + 2 >= MAX_AD_UUID_BYTES) { + print("Too many UUIDs"); + goto done; + } + + put_le16(uuid.value.uuid16, uuids + uuid_bytes); + uuid_bytes += 2; + } else if (uuid.type == SDP_UUID128) { + if (uuid_bytes + 16 >= MAX_AD_UUID_BYTES) { + print("Too many UUIDs"); + goto done; + } + + bswap_128(uuid.value.uuid128.data, + uuids + uuid_bytes); + uuid_bytes += 16; + } else { + printf("Unsupported UUID type"); + goto done; + } + + if (!uuid_type) + uuid_type = uuid.type; + + break; + case 'd': + if (adv_len) { + print("Only one adv-data option allowed"); + goto done; + } + + if (!parse_bytes(optarg, &adv_data, &adv_len)) + goto done; + break; + case 's': + if (scan_rsp_len) { + print("Only one scan-rsp option allowed"); + goto done; + } + + if (!parse_bytes(optarg, &scan_rsp, &scan_rsp_len)) + goto done; + break; + case 'h': + success = true; + /* fall through */ + default: + add_ext_adv_data_usage(); + optind = 0; + goto done; + } + } + + argc -= optind; + argv += optind; + optind = 0; + + if (argc != 1) { + add_ext_adv_data_usage(); + goto done; + } + + if (uuid_bytes) + uuid_bytes += 2; + + instance = strtol(argv[0], NULL, 0); + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + cp_len = sizeof(*cp) + uuid_bytes + adv_len + scan_rsp_len; + cp = malloc0(cp_len); + if (!cp) + goto done; + + cp->instance = instance; + cp->adv_data_len = adv_len + uuid_bytes; + cp->scan_rsp_len = scan_rsp_len; + + if (uuid_bytes) { + cp->data[0] = uuid_bytes - 1; + cp->data[1] = uuid_type == SDP_UUID16 ? 0x03 : 0x07; + memcpy(cp->data + 2, uuids, uuid_bytes - 2); + } + + memcpy(cp->data + uuid_bytes, adv_data, adv_len); + memcpy(cp->data + uuid_bytes + adv_len, scan_rsp, scan_rsp_len); + + if (!mgmt_send(mgmt, MGMT_OP_ADD_EXT_ADV_DATA, index, cp_len, cp, + add_ext_adv_data_rsp, NULL, NULL)) { + error("Unable to send \"Add Ext Advertising Data\" command"); + goto done; + } + + quit = false; + +done: + free(adv_data); + free(scan_rsp); + free(cp); + + if (quit) + bt_shell_noninteractive_quit(success ? + EXIT_SUCCESS : EXIT_FAILURE); +} + static void appearance_rsp(uint8_t status, uint16_t len, const void *param, void *user_data) { @@ -5618,6 +5989,12 @@ static const struct bt_shell_menu main_menu = { cmd_rm_adv, "Remove advertising instance" }, { "clr-adv", NULL, cmd_clr_adv, "Clear advertising instances" }, + { "add-ext-adv-params", "[options] ", + cmd_add_ext_adv_params, + "Add extended advertising params" }, + { "add-ext-adv-data", "[options] ", + cmd_add_ext_adv_data, + "Add extended advertising data" }, { "appearance", "", cmd_appearance, "Set appearance" }, { "phy", "[LE1MTX] [LE1MRX] [LE2MTX] [LE2MRX] " -- 2.34.1