mirror of
https://git.kernel.org/pub/scm/bluetooth/bluez.git
synced 2024-11-15 16:24:28 +08:00
tools/btmgmt: Add support Add Ext Adv command
This patch adds new command to support the following MGMT API: Add Extended Advertising Parameters Command Add Extended Advertising Data Command
This commit is contained in:
parent
2479a013a2
commit
3075ff8fff
377
tools/btmgmt.c
377
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> Duration in seconds\n"
|
||||
"\t -t, --timeout <timeout> Timeout in seconds\n"
|
||||
"\t -r, --min-interval <valr> Minimum interval\n"
|
||||
"\t -x, --max-interval <valr> Maximum interval\n"
|
||||
"\t -w, --tx-power <power> Tx power\n"
|
||||
"\t -P, --phy <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 <uuid> Service UUID\n"
|
||||
"\t -d, --adv-data <data> Advertising Data bytes\n"
|
||||
"\t -s, --scan-rsp <data> 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] <instance_id>",
|
||||
cmd_add_ext_adv_params,
|
||||
"Add extended advertising params" },
|
||||
{ "add-ext-adv-data", "[options] <instance_id>",
|
||||
cmd_add_ext_adv_data,
|
||||
"Add extended advertising data" },
|
||||
{ "appearance", "<appearance>",
|
||||
cmd_appearance, "Set appearance" },
|
||||
{ "phy", "[LE1MTX] [LE1MRX] [LE2MTX] [LE2MRX] "
|
||||
|
Loading…
Reference in New Issue
Block a user