2020-09-22 03:00:24 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2016-08-09 19:32:46 +08:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* BlueZ - Bluetooth protocol stack for Linux
|
|
|
|
*
|
|
|
|
* Copyright (C) 2016 Intel Corporation. All rights reserved.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2018-12-07 04:28:18 +08:00
|
|
|
#define _GNU_SOURCE
|
2016-08-09 19:32:46 +08:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdint.h>
|
2017-08-09 16:34:12 +08:00
|
|
|
#include <stdbool.h>
|
2017-11-09 22:29:39 +08:00
|
|
|
#include <string.h>
|
2016-08-09 19:32:46 +08:00
|
|
|
|
|
|
|
#include "gdbus/gdbus.h"
|
2017-12-15 02:09:39 +08:00
|
|
|
#include "src/shared/util.h"
|
2017-11-09 22:29:39 +08:00
|
|
|
#include "src/shared/shell.h"
|
2016-08-09 19:32:46 +08:00
|
|
|
#include "advertising.h"
|
|
|
|
|
|
|
|
#define AD_PATH "/org/bluez/advertising"
|
|
|
|
#define AD_IFACE "org.bluez.LEAdvertisement1"
|
|
|
|
|
2017-08-09 16:34:12 +08:00
|
|
|
struct ad_data {
|
|
|
|
uint8_t data[25];
|
|
|
|
uint8_t len;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct service_data {
|
|
|
|
char *uuid;
|
|
|
|
struct ad_data data;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct manufacturer_data {
|
|
|
|
uint16_t id;
|
|
|
|
struct ad_data data;
|
|
|
|
};
|
|
|
|
|
2018-04-18 18:11:10 +08:00
|
|
|
struct data {
|
|
|
|
uint8_t type;
|
|
|
|
struct ad_data data;
|
|
|
|
};
|
|
|
|
|
2017-08-09 16:34:12 +08:00
|
|
|
static struct ad {
|
|
|
|
bool registered;
|
|
|
|
char *type;
|
2017-08-10 17:30:57 +08:00
|
|
|
char *local_name;
|
2019-02-15 22:19:59 +08:00
|
|
|
char *secondary;
|
2021-05-13 08:18:13 +08:00
|
|
|
uint32_t min_interval;
|
|
|
|
uint32_t max_interval;
|
2017-08-10 19:15:49 +08:00
|
|
|
uint16_t local_appearance;
|
2017-11-02 22:03:41 +08:00
|
|
|
uint16_t duration;
|
|
|
|
uint16_t timeout;
|
2018-05-21 21:21:05 +08:00
|
|
|
uint16_t discoverable_to;
|
2017-08-09 16:34:12 +08:00
|
|
|
char **uuids;
|
|
|
|
size_t uuids_len;
|
|
|
|
struct service_data service;
|
|
|
|
struct manufacturer_data manufacturer;
|
2018-04-18 18:11:10 +08:00
|
|
|
struct data data;
|
2018-05-07 23:41:10 +08:00
|
|
|
bool discoverable;
|
2017-08-09 16:34:12 +08:00
|
|
|
bool tx_power;
|
|
|
|
bool name;
|
|
|
|
bool appearance;
|
2017-08-10 19:15:49 +08:00
|
|
|
} ad = {
|
|
|
|
.local_appearance = UINT16_MAX,
|
2020-04-07 08:24:08 +08:00
|
|
|
.discoverable = true,
|
2017-08-10 19:15:49 +08:00
|
|
|
};
|
2016-08-09 19:32:46 +08:00
|
|
|
|
|
|
|
static void ad_release(DBusConnection *conn)
|
|
|
|
{
|
2017-08-09 16:34:12 +08:00
|
|
|
ad.registered = false;
|
2016-08-09 19:32:46 +08:00
|
|
|
|
|
|
|
g_dbus_unregister_interface(conn, AD_PATH, AD_IFACE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static DBusMessage *release_advertising(DBusConnection *conn,
|
|
|
|
DBusMessage *msg, void *user_data)
|
|
|
|
{
|
2017-11-09 22:29:39 +08:00
|
|
|
bt_shell_printf("Advertising released\n");
|
2016-08-09 19:32:46 +08:00
|
|
|
|
|
|
|
ad_release(conn);
|
|
|
|
|
|
|
|
return dbus_message_new_method_return(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const GDBusMethodTable ad_methods[] = {
|
|
|
|
{ GDBUS_METHOD("Release", NULL, NULL, release_advertising) },
|
|
|
|
{ }
|
|
|
|
};
|
|
|
|
|
|
|
|
static void register_setup(DBusMessageIter *iter, void *user_data)
|
|
|
|
{
|
|
|
|
DBusMessageIter dict;
|
|
|
|
const char *path = AD_PATH;
|
|
|
|
|
|
|
|
dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
|
|
|
|
dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
|
|
|
|
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
|
|
|
|
DBUS_TYPE_STRING_AS_STRING
|
|
|
|
DBUS_TYPE_VARIANT_AS_STRING
|
|
|
|
DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
|
|
|
|
dbus_message_iter_close_container(iter, &dict);
|
|
|
|
}
|
|
|
|
|
2018-01-19 21:12:09 +08:00
|
|
|
static void print_uuid(const char *uuid)
|
|
|
|
{
|
|
|
|
const char *text;
|
|
|
|
|
|
|
|
text = bt_uuidstr_to_str(uuid);
|
|
|
|
if (text) {
|
|
|
|
char str[26];
|
|
|
|
unsigned int n;
|
|
|
|
|
|
|
|
str[sizeof(str) - 1] = '\0';
|
|
|
|
|
|
|
|
n = snprintf(str, sizeof(str), "%s", text);
|
|
|
|
if (n > sizeof(str) - 1) {
|
|
|
|
str[sizeof(str) - 2] = '.';
|
|
|
|
str[sizeof(str) - 3] = '.';
|
|
|
|
if (str[sizeof(str) - 4] == ' ')
|
|
|
|
str[sizeof(str) - 4] = '.';
|
|
|
|
|
|
|
|
n = sizeof(str) - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_shell_printf("UUID: %s(%s)\n", str, uuid);
|
|
|
|
} else
|
2018-02-16 13:51:03 +08:00
|
|
|
bt_shell_printf("UUID: (%s)\n", uuid ? uuid : "");
|
2018-01-19 21:12:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void print_ad_uuids(void)
|
|
|
|
{
|
|
|
|
char **uuid;
|
|
|
|
|
|
|
|
for (uuid = ad.uuids; uuid && *uuid; uuid++)
|
|
|
|
print_uuid(*uuid);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void print_ad(void)
|
|
|
|
{
|
|
|
|
print_ad_uuids();
|
|
|
|
|
|
|
|
if (ad.service.uuid) {
|
|
|
|
print_uuid(ad.service.uuid);
|
|
|
|
bt_shell_hexdump(ad.service.data.data, ad.service.data.len);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ad.manufacturer.data.len) {
|
|
|
|
bt_shell_printf("Manufacturer: %u\n", ad.manufacturer.id);
|
|
|
|
bt_shell_hexdump(ad.manufacturer.data.data,
|
|
|
|
ad.manufacturer.data.len);
|
|
|
|
}
|
|
|
|
|
2018-05-07 23:52:26 +08:00
|
|
|
if (ad.data.data.len) {
|
|
|
|
bt_shell_printf("Data Type: 0x%02x\n", ad.data.type);
|
|
|
|
bt_shell_hexdump(ad.data.data.data, ad.data.data.len);
|
|
|
|
}
|
|
|
|
|
2018-01-19 21:12:09 +08:00
|
|
|
bt_shell_printf("Tx Power: %s\n", ad.tx_power ? "on" : "off");
|
|
|
|
|
|
|
|
if (ad.local_name)
|
|
|
|
bt_shell_printf("LocalName: %s\n", ad.local_name);
|
|
|
|
else
|
|
|
|
bt_shell_printf("Name: %s\n", ad.name ? "on" : "off");
|
|
|
|
|
|
|
|
if (ad.local_appearance != UINT16_MAX)
|
|
|
|
bt_shell_printf("Appearance: %s (0x%04x)\n",
|
|
|
|
bt_appear_to_str(ad.local_appearance),
|
|
|
|
ad.local_appearance);
|
|
|
|
else
|
2020-08-30 15:11:08 +08:00
|
|
|
bt_shell_printf("Appearance: %s\n",
|
2018-01-19 21:12:09 +08:00
|
|
|
ad.appearance ? "on" : "off");
|
2018-05-07 23:52:26 +08:00
|
|
|
|
|
|
|
bt_shell_printf("Discoverable: %s\n", ad.discoverable ? "on": "off");
|
2018-01-19 21:12:09 +08:00
|
|
|
|
|
|
|
if (ad.duration)
|
|
|
|
bt_shell_printf("Duration: %u sec\n", ad.duration);
|
|
|
|
|
|
|
|
if (ad.timeout)
|
|
|
|
bt_shell_printf("Timeout: %u sec\n", ad.timeout);
|
2021-05-13 08:18:13 +08:00
|
|
|
|
|
|
|
if (ad.min_interval)
|
|
|
|
bt_shell_printf("Interval: %u-%u msec\n", ad.min_interval,
|
|
|
|
ad.max_interval);
|
2018-01-19 21:12:09 +08:00
|
|
|
}
|
|
|
|
|
2016-08-09 19:32:46 +08:00
|
|
|
static void register_reply(DBusMessage *message, void *user_data)
|
|
|
|
{
|
|
|
|
DBusConnection *conn = user_data;
|
|
|
|
DBusError error;
|
|
|
|
|
|
|
|
dbus_error_init(&error);
|
|
|
|
|
|
|
|
if (dbus_set_error_from_message(&error, message) == FALSE) {
|
2017-08-09 16:34:12 +08:00
|
|
|
ad.registered = true;
|
2017-11-09 22:29:39 +08:00
|
|
|
bt_shell_printf("Advertising object registered\n");
|
2018-01-19 21:12:09 +08:00
|
|
|
print_ad();
|
2018-02-23 22:34:58 +08:00
|
|
|
/* Leave advertise running even on noninteractive mode */
|
2016-08-09 19:32:46 +08:00
|
|
|
} else {
|
2017-11-09 22:29:39 +08:00
|
|
|
bt_shell_printf("Failed to register advertisement: %s\n", error.name);
|
2016-08-09 19:32:46 +08:00
|
|
|
dbus_error_free(&error);
|
|
|
|
|
|
|
|
if (g_dbus_unregister_interface(conn, AD_PATH,
|
|
|
|
AD_IFACE) == FALSE)
|
2017-11-09 22:29:39 +08:00
|
|
|
bt_shell_printf("Failed to unregister advertising object\n");
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
2016-08-09 19:32:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean get_type(const GDBusPropertyTable *property,
|
|
|
|
DBusMessageIter *iter, void *user_data)
|
|
|
|
{
|
|
|
|
const char *type = "peripheral";
|
|
|
|
|
2017-09-25 12:33:25 +08:00
|
|
|
if (ad.type && strlen(ad.type) > 0)
|
2017-08-09 16:34:12 +08:00
|
|
|
type = ad.type;
|
2016-08-09 19:32:46 +08:00
|
|
|
|
|
|
|
dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &type);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2016-08-09 20:16:58 +08:00
|
|
|
static gboolean uuids_exists(const GDBusPropertyTable *property, void *data)
|
|
|
|
{
|
2017-08-09 16:34:12 +08:00
|
|
|
return ad.uuids_len != 0;
|
2016-08-09 20:16:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean get_uuids(const GDBusPropertyTable *property,
|
|
|
|
DBusMessageIter *iter, void *user_data)
|
|
|
|
{
|
|
|
|
DBusMessageIter array;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "as", &array);
|
|
|
|
|
2017-08-09 16:34:12 +08:00
|
|
|
for (i = 0; i < ad.uuids_len; i++)
|
2016-08-09 20:16:58 +08:00
|
|
|
dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
|
2017-08-09 16:34:12 +08:00
|
|
|
&ad.uuids[i]);
|
2016-08-09 20:16:58 +08:00
|
|
|
|
|
|
|
dbus_message_iter_close_container(iter, &array);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2016-08-10 18:55:46 +08:00
|
|
|
static gboolean service_data_exists(const GDBusPropertyTable *property,
|
|
|
|
void *data)
|
|
|
|
{
|
2017-08-09 16:34:12 +08:00
|
|
|
return ad.service.uuid != NULL;
|
2016-08-10 18:55:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean get_service_data(const GDBusPropertyTable *property,
|
|
|
|
DBusMessageIter *iter, void *user_data)
|
|
|
|
{
|
|
|
|
DBusMessageIter dict;
|
2017-08-09 16:34:12 +08:00
|
|
|
struct ad_data *data = &ad.service.data;
|
client: Fix segmentation fault while fetching advertising data
While testing advertisement, I encountered Seg fault in client, when bluetoothd
tries to fetch the Adv data set by client. It can happen either while fetching
Manufacturer specific data or Service data. Backtrace is provided below for reference
After fix is applied, advertisement works fine for me. I am sending the following patch
your review. Thank you.
Passing val instead of &val in dbus_message_iter_append_fixed_array
DBUS API causes segmentation fault while fecthing Manufacturer
data or service data set by client.
BT Before Fix:
[bluetooth]# set-advertise-name Test
[bluetooth]# set-advertise-uuids 0x1824
[bluetooth]# set-advertise-manufacturer 0x75 0x02 0x03 0x04
[bluetooth]# advertise on
Program received signal SIGSEGV, Segmentation fault.
in append_array_variant(iter=iter@entry=0x7fffffffd780,
val=val@entry=0x62485a <ad+90>, n_elements=n_elements@entry=3, type=121) at client/advertising.c:178
in dict_append_basic_array(type=121, n_elements=3,
val=0x62485a <ad+90>, key=0x624858 <ad+88>, key_type=113, dict=0x7fffffffd730) at client/advertising.c:205
get_manufacturer_data(property=<optimized out>, iter=0x7fffffffd840,
user_data=<optimized out>) at client/advertising.c:253
After Fix:
[bluetooth]# set-advertise-name Test
[bluetooth]# set-advertise-uuids 0x1824
[bluetooth]# set-advertise-manufacturer 0x75 0x02 0x03 0x04
[bluetooth]# advertise on
[CHG] Controller 00:19:0E:11:55:44 SupportedInstances: 0x04
[CHG] Controller 00:19:0E:11:55:44 ActiveInstances: 0x01
Advertising object registered
[bluetooth]#
2017-10-25 14:39:32 +08:00
|
|
|
uint8_t *val = data->data;
|
2016-08-10 18:55:46 +08:00
|
|
|
|
|
|
|
dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}", &dict);
|
|
|
|
|
2018-03-01 12:27:21 +08:00
|
|
|
g_dbus_dict_append_array(&dict, ad.service.uuid, DBUS_TYPE_BYTE, &val,
|
2017-08-09 16:34:12 +08:00
|
|
|
data->len);
|
2016-08-10 18:55:46 +08:00
|
|
|
|
|
|
|
dbus_message_iter_close_container(iter, &dict);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2016-08-10 20:15:46 +08:00
|
|
|
static gboolean manufacturer_data_exists(const GDBusPropertyTable *property,
|
|
|
|
void *data)
|
|
|
|
{
|
2017-08-09 16:34:12 +08:00
|
|
|
return ad.manufacturer.id != 0;
|
2016-08-10 20:15:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean get_manufacturer_data(const GDBusPropertyTable *property,
|
|
|
|
DBusMessageIter *iter, void *user_data)
|
|
|
|
{
|
|
|
|
DBusMessageIter dict;
|
2017-08-09 16:34:12 +08:00
|
|
|
struct ad_data *data = &ad.manufacturer.data;
|
client: Fix segmentation fault while fetching advertising data
While testing advertisement, I encountered Seg fault in client, when bluetoothd
tries to fetch the Adv data set by client. It can happen either while fetching
Manufacturer specific data or Service data. Backtrace is provided below for reference
After fix is applied, advertisement works fine for me. I am sending the following patch
your review. Thank you.
Passing val instead of &val in dbus_message_iter_append_fixed_array
DBUS API causes segmentation fault while fecthing Manufacturer
data or service data set by client.
BT Before Fix:
[bluetooth]# set-advertise-name Test
[bluetooth]# set-advertise-uuids 0x1824
[bluetooth]# set-advertise-manufacturer 0x75 0x02 0x03 0x04
[bluetooth]# advertise on
Program received signal SIGSEGV, Segmentation fault.
in append_array_variant(iter=iter@entry=0x7fffffffd780,
val=val@entry=0x62485a <ad+90>, n_elements=n_elements@entry=3, type=121) at client/advertising.c:178
in dict_append_basic_array(type=121, n_elements=3,
val=0x62485a <ad+90>, key=0x624858 <ad+88>, key_type=113, dict=0x7fffffffd730) at client/advertising.c:205
get_manufacturer_data(property=<optimized out>, iter=0x7fffffffd840,
user_data=<optimized out>) at client/advertising.c:253
After Fix:
[bluetooth]# set-advertise-name Test
[bluetooth]# set-advertise-uuids 0x1824
[bluetooth]# set-advertise-manufacturer 0x75 0x02 0x03 0x04
[bluetooth]# advertise on
[CHG] Controller 00:19:0E:11:55:44 SupportedInstances: 0x04
[CHG] Controller 00:19:0E:11:55:44 ActiveInstances: 0x01
Advertising object registered
[bluetooth]#
2017-10-25 14:39:32 +08:00
|
|
|
uint8_t *val = data->data;
|
2016-08-10 20:15:46 +08:00
|
|
|
|
|
|
|
dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{qv}", &dict);
|
|
|
|
|
2018-03-01 12:27:21 +08:00
|
|
|
g_dbus_dict_append_basic_array(&dict, DBUS_TYPE_UINT16,
|
|
|
|
&ad.manufacturer.id,
|
client: Fix segmentation fault while fetching advertising data
While testing advertisement, I encountered Seg fault in client, when bluetoothd
tries to fetch the Adv data set by client. It can happen either while fetching
Manufacturer specific data or Service data. Backtrace is provided below for reference
After fix is applied, advertisement works fine for me. I am sending the following patch
your review. Thank you.
Passing val instead of &val in dbus_message_iter_append_fixed_array
DBUS API causes segmentation fault while fecthing Manufacturer
data or service data set by client.
BT Before Fix:
[bluetooth]# set-advertise-name Test
[bluetooth]# set-advertise-uuids 0x1824
[bluetooth]# set-advertise-manufacturer 0x75 0x02 0x03 0x04
[bluetooth]# advertise on
Program received signal SIGSEGV, Segmentation fault.
in append_array_variant(iter=iter@entry=0x7fffffffd780,
val=val@entry=0x62485a <ad+90>, n_elements=n_elements@entry=3, type=121) at client/advertising.c:178
in dict_append_basic_array(type=121, n_elements=3,
val=0x62485a <ad+90>, key=0x624858 <ad+88>, key_type=113, dict=0x7fffffffd730) at client/advertising.c:205
get_manufacturer_data(property=<optimized out>, iter=0x7fffffffd840,
user_data=<optimized out>) at client/advertising.c:253
After Fix:
[bluetooth]# set-advertise-name Test
[bluetooth]# set-advertise-uuids 0x1824
[bluetooth]# set-advertise-manufacturer 0x75 0x02 0x03 0x04
[bluetooth]# advertise on
[CHG] Controller 00:19:0E:11:55:44 SupportedInstances: 0x04
[CHG] Controller 00:19:0E:11:55:44 ActiveInstances: 0x01
Advertising object registered
[bluetooth]#
2017-10-25 14:39:32 +08:00
|
|
|
DBUS_TYPE_BYTE, &val, data->len);
|
2016-08-10 20:15:46 +08:00
|
|
|
|
|
|
|
dbus_message_iter_close_container(iter, &dict);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2017-08-09 16:34:12 +08:00
|
|
|
static gboolean includes_exists(const GDBusPropertyTable *property, void *data)
|
2016-08-11 18:38:36 +08:00
|
|
|
{
|
2017-08-09 16:34:12 +08:00
|
|
|
return ad.tx_power || ad.name || ad.appearance;
|
2016-08-11 18:38:36 +08:00
|
|
|
}
|
|
|
|
|
2017-08-09 16:34:12 +08:00
|
|
|
static gboolean get_includes(const GDBusPropertyTable *property,
|
2016-08-11 18:38:36 +08:00
|
|
|
DBusMessageIter *iter, void *user_data)
|
|
|
|
{
|
2017-08-09 16:34:12 +08:00
|
|
|
DBusMessageIter array;
|
|
|
|
|
|
|
|
dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "as", &array);
|
|
|
|
|
|
|
|
if (ad.tx_power) {
|
|
|
|
const char *str = "tx-power";
|
|
|
|
|
|
|
|
dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &str);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ad.name) {
|
|
|
|
const char *str = "local-name";
|
|
|
|
|
|
|
|
dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &str);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ad.appearance) {
|
|
|
|
const char *str = "appearance";
|
|
|
|
|
|
|
|
dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &str);
|
|
|
|
}
|
|
|
|
|
|
|
|
dbus_message_iter_close_container(iter, &array);
|
|
|
|
|
2016-08-11 18:38:36 +08:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2017-08-10 17:30:57 +08:00
|
|
|
static gboolean local_name_exits(const GDBusPropertyTable *property, void *data)
|
|
|
|
{
|
|
|
|
return ad.local_name ? TRUE : FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean get_local_name(const GDBusPropertyTable *property,
|
|
|
|
DBusMessageIter *iter, void *user_data)
|
|
|
|
{
|
|
|
|
dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &ad.local_name);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2017-08-10 19:15:49 +08:00
|
|
|
static gboolean appearance_exits(const GDBusPropertyTable *property, void *data)
|
|
|
|
{
|
|
|
|
return ad.local_appearance != UINT16_MAX ? TRUE : FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean get_appearance(const GDBusPropertyTable *property,
|
|
|
|
DBusMessageIter *iter, void *user_data)
|
|
|
|
{
|
|
|
|
dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16,
|
|
|
|
&ad.local_appearance);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2017-11-02 22:03:41 +08:00
|
|
|
static gboolean duration_exits(const GDBusPropertyTable *property, void *data)
|
|
|
|
{
|
|
|
|
return ad.duration;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean get_duration(const GDBusPropertyTable *property,
|
|
|
|
DBusMessageIter *iter, void *user_data)
|
|
|
|
{
|
|
|
|
dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &ad.duration);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean timeout_exits(const GDBusPropertyTable *property, void *data)
|
|
|
|
{
|
|
|
|
return ad.timeout;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean get_timeout(const GDBusPropertyTable *property,
|
|
|
|
DBusMessageIter *iter, void *user_data)
|
|
|
|
{
|
|
|
|
dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &ad.timeout);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2018-04-18 18:11:10 +08:00
|
|
|
static gboolean data_exists(const GDBusPropertyTable *property, void *data)
|
|
|
|
{
|
|
|
|
return ad.data.type != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean get_data(const GDBusPropertyTable *property,
|
|
|
|
DBusMessageIter *iter, void *user_data)
|
|
|
|
{
|
|
|
|
DBusMessageIter dict;
|
|
|
|
struct ad_data *data = &ad.data.data;
|
|
|
|
uint8_t *val = data->data;
|
|
|
|
|
|
|
|
dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{yv}", &dict);
|
|
|
|
|
|
|
|
g_dbus_dict_append_basic_array(&dict, DBUS_TYPE_BYTE, &ad.data.type,
|
|
|
|
DBUS_TYPE_BYTE, &val, data->len);
|
|
|
|
|
|
|
|
dbus_message_iter_close_container(iter, &dict);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2018-05-07 23:41:10 +08:00
|
|
|
static gboolean discoverable_exists(const GDBusPropertyTable *property,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
return ad.discoverable;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean get_discoverable(const GDBusPropertyTable *property,
|
|
|
|
DBusMessageIter *iter, void *user_data)
|
|
|
|
{
|
2019-05-10 19:58:09 +08:00
|
|
|
dbus_bool_t value = ad.discoverable;
|
|
|
|
|
|
|
|
dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
|
2018-05-07 23:41:10 +08:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2018-05-21 21:21:05 +08:00
|
|
|
static gboolean discoverable_timeout_exits(const GDBusPropertyTable *property,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
return ad.discoverable_to;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean get_discoverable_timeout(const GDBusPropertyTable *property,
|
|
|
|
DBusMessageIter *iter, void *user_data)
|
|
|
|
{
|
|
|
|
dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16,
|
|
|
|
&ad.discoverable_to);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2019-02-15 22:19:59 +08:00
|
|
|
static gboolean secondary_exits(const GDBusPropertyTable *property, void *data)
|
|
|
|
{
|
|
|
|
return ad.secondary ? TRUE : FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean get_secondary(const GDBusPropertyTable *property,
|
|
|
|
DBusMessageIter *iter, void *user_data)
|
|
|
|
{
|
|
|
|
dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
|
|
|
|
&ad.secondary);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2021-05-13 08:18:13 +08:00
|
|
|
static gboolean min_interval_exits(const GDBusPropertyTable *property,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
return ad.min_interval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean get_min_interval(const GDBusPropertyTable *property,
|
|
|
|
DBusMessageIter *iter, void *user_data)
|
|
|
|
{
|
|
|
|
dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32,
|
|
|
|
&ad.min_interval);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean max_interval_exits(const GDBusPropertyTable *property,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
return ad.max_interval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean get_max_interval(const GDBusPropertyTable *property,
|
|
|
|
DBusMessageIter *iter, void *user_data)
|
|
|
|
{
|
|
|
|
dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32,
|
|
|
|
&ad.max_interval);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2016-08-09 19:32:46 +08:00
|
|
|
static const GDBusPropertyTable ad_props[] = {
|
|
|
|
{ "Type", "s", get_type },
|
2016-08-09 20:16:58 +08:00
|
|
|
{ "ServiceUUIDs", "as", get_uuids, NULL, uuids_exists },
|
2016-08-10 18:55:46 +08:00
|
|
|
{ "ServiceData", "a{sv}", get_service_data, NULL, service_data_exists },
|
2016-08-10 20:15:46 +08:00
|
|
|
{ "ManufacturerData", "a{qv}", get_manufacturer_data, NULL,
|
|
|
|
manufacturer_data_exists },
|
2018-04-18 18:11:10 +08:00
|
|
|
{ "Data", "a{yv}", get_data, NULL, data_exists },
|
2018-05-07 23:41:10 +08:00
|
|
|
{ "Discoverable", "b", get_discoverable, NULL, discoverable_exists },
|
2018-05-21 21:21:05 +08:00
|
|
|
{ "DiscoverableTimeout", "q", get_discoverable_timeout, NULL,
|
|
|
|
discoverable_timeout_exits },
|
2017-08-09 16:34:12 +08:00
|
|
|
{ "Includes", "as", get_includes, NULL, includes_exists },
|
2017-08-10 17:30:57 +08:00
|
|
|
{ "LocalName", "s", get_local_name, NULL, local_name_exits },
|
2017-08-10 19:15:49 +08:00
|
|
|
{ "Appearance", "q", get_appearance, NULL, appearance_exits },
|
2017-11-02 22:03:41 +08:00
|
|
|
{ "Duration", "q", get_duration, NULL, duration_exits },
|
|
|
|
{ "Timeout", "q", get_timeout, NULL, timeout_exits },
|
2021-05-13 08:18:13 +08:00
|
|
|
{ "MinInterval", "u", get_min_interval, NULL, min_interval_exits },
|
|
|
|
{ "MaxInterval", "u", get_max_interval, NULL, max_interval_exits },
|
2019-02-15 22:19:59 +08:00
|
|
|
{ "SecondaryChannel", "s", get_secondary, NULL, secondary_exits },
|
2016-08-09 19:32:46 +08:00
|
|
|
{ }
|
|
|
|
};
|
|
|
|
|
|
|
|
void ad_register(DBusConnection *conn, GDBusProxy *manager, const char *type)
|
|
|
|
{
|
2017-08-09 16:34:12 +08:00
|
|
|
if (ad.registered) {
|
2017-11-09 22:29:39 +08:00
|
|
|
bt_shell_printf("Advertisement is already registered\n");
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
2016-08-09 19:32:46 +08:00
|
|
|
}
|
|
|
|
|
2017-09-25 12:28:38 +08:00
|
|
|
g_free(ad.type);
|
2017-08-09 16:34:12 +08:00
|
|
|
ad.type = g_strdup(type);
|
2016-08-09 19:32:46 +08:00
|
|
|
|
|
|
|
if (g_dbus_register_interface(conn, AD_PATH, AD_IFACE, ad_methods,
|
|
|
|
NULL, ad_props, NULL, NULL) == FALSE) {
|
2017-11-09 22:29:39 +08:00
|
|
|
bt_shell_printf("Failed to register advertising object\n");
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
2016-08-09 19:32:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (g_dbus_proxy_method_call(manager, "RegisterAdvertisement",
|
|
|
|
register_setup, register_reply,
|
|
|
|
conn, NULL) == FALSE) {
|
2017-11-09 22:29:39 +08:00
|
|
|
bt_shell_printf("Failed to register advertising\n");
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
2016-08-09 19:32:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void unregister_setup(DBusMessageIter *iter, void *user_data)
|
|
|
|
{
|
|
|
|
const char *path = AD_PATH;
|
|
|
|
|
|
|
|
dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void unregister_reply(DBusMessage *message, void *user_data)
|
|
|
|
{
|
|
|
|
DBusConnection *conn = user_data;
|
|
|
|
DBusError error;
|
|
|
|
|
|
|
|
dbus_error_init(&error);
|
|
|
|
|
|
|
|
if (dbus_set_error_from_message(&error, message) == FALSE) {
|
2017-08-09 16:34:12 +08:00
|
|
|
ad.registered = false;
|
2017-11-09 22:29:39 +08:00
|
|
|
bt_shell_printf("Advertising object unregistered\n");
|
2016-08-09 19:32:46 +08:00
|
|
|
if (g_dbus_unregister_interface(conn, AD_PATH,
|
|
|
|
AD_IFACE) == FALSE)
|
2018-03-01 17:11:17 +08:00
|
|
|
bt_shell_printf("Failed to unregister advertising"
|
|
|
|
" object\n");
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2016-08-09 19:32:46 +08:00
|
|
|
} else {
|
2017-11-09 22:29:39 +08:00
|
|
|
bt_shell_printf("Failed to unregister advertisement: %s\n",
|
2016-08-09 19:32:46 +08:00
|
|
|
error.name);
|
|
|
|
dbus_error_free(&error);
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
2016-08-09 19:32:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ad_unregister(DBusConnection *conn, GDBusProxy *manager)
|
|
|
|
{
|
|
|
|
if (!manager)
|
|
|
|
ad_release(conn);
|
|
|
|
|
2017-08-09 16:34:12 +08:00
|
|
|
if (!ad.registered)
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2017-02-14 17:27:50 +08:00
|
|
|
|
2017-09-25 12:28:38 +08:00
|
|
|
g_free(ad.type);
|
|
|
|
ad.type = NULL;
|
|
|
|
|
2016-08-09 19:32:46 +08:00
|
|
|
if (g_dbus_proxy_method_call(manager, "UnregisterAdvertisement",
|
|
|
|
unregister_setup, unregister_reply,
|
|
|
|
conn, NULL) == FALSE) {
|
2017-11-09 22:29:39 +08:00
|
|
|
bt_shell_printf("Failed to unregister advertisement method\n");
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
2016-08-09 19:32:46 +08:00
|
|
|
}
|
|
|
|
}
|
2016-08-09 20:16:58 +08:00
|
|
|
|
2018-02-16 13:51:37 +08:00
|
|
|
static void ad_clear_uuids(void)
|
|
|
|
{
|
|
|
|
g_strfreev(ad.uuids);
|
|
|
|
ad.uuids = NULL;
|
|
|
|
ad.uuids_len = 0;
|
|
|
|
}
|
|
|
|
|
2017-11-17 17:35:12 +08:00
|
|
|
void ad_advertise_uuids(DBusConnection *conn, int argc, char *argv[])
|
2016-08-09 20:16:58 +08:00
|
|
|
{
|
2017-12-15 02:09:39 +08:00
|
|
|
if (argc < 2 || !strlen(argv[1])) {
|
2018-01-19 21:12:09 +08:00
|
|
|
print_ad_uuids();
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2017-12-15 02:09:39 +08:00
|
|
|
}
|
|
|
|
|
2018-02-16 13:51:37 +08:00
|
|
|
ad_clear_uuids();
|
2016-08-09 20:16:58 +08:00
|
|
|
|
2017-12-08 18:52:48 +08:00
|
|
|
ad.uuids = g_strdupv(&argv[1]);
|
2017-08-09 16:34:12 +08:00
|
|
|
if (!ad.uuids) {
|
2017-11-09 22:29:39 +08:00
|
|
|
bt_shell_printf("Failed to parse input\n");
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
2016-08-09 20:16:58 +08:00
|
|
|
}
|
|
|
|
|
2017-08-09 16:34:12 +08:00
|
|
|
ad.uuids_len = g_strv_length(ad.uuids);
|
2017-08-14 21:29:03 +08:00
|
|
|
|
|
|
|
g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "ServiceUUIDs");
|
2018-02-23 22:34:58 +08:00
|
|
|
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2016-08-09 20:16:58 +08:00
|
|
|
}
|
2016-08-10 18:55:46 +08:00
|
|
|
|
2018-02-16 13:51:37 +08:00
|
|
|
void ad_disable_uuids(DBusConnection *conn)
|
|
|
|
{
|
|
|
|
if (!ad.uuids)
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2018-02-16 13:51:37 +08:00
|
|
|
|
|
|
|
ad_clear_uuids();
|
|
|
|
g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "ServiceUUIDs");
|
2018-02-23 22:34:58 +08:00
|
|
|
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2018-02-16 13:51:37 +08:00
|
|
|
}
|
|
|
|
|
2016-08-10 18:55:46 +08:00
|
|
|
static void ad_clear_service(void)
|
|
|
|
{
|
2017-08-09 16:34:12 +08:00
|
|
|
g_free(ad.service.uuid);
|
|
|
|
memset(&ad.service, 0, sizeof(ad.service));
|
2018-02-23 22:34:58 +08:00
|
|
|
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2016-08-10 18:55:46 +08:00
|
|
|
}
|
|
|
|
|
2018-04-18 18:11:10 +08:00
|
|
|
static bool ad_add_data(struct ad_data *data, int argc, char *argv[])
|
2016-08-10 18:55:46 +08:00
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
2018-04-18 18:11:10 +08:00
|
|
|
memset(data, 0, sizeof(*data));
|
2016-08-10 18:55:46 +08:00
|
|
|
|
2018-04-18 18:11:10 +08:00
|
|
|
for (i = 0; i < (unsigned int) argc; i++) {
|
2016-08-10 18:55:46 +08:00
|
|
|
long int val;
|
|
|
|
char *endptr = NULL;
|
|
|
|
|
2017-08-09 16:34:12 +08:00
|
|
|
if (i >= G_N_ELEMENTS(data->data)) {
|
2017-11-09 22:29:39 +08:00
|
|
|
bt_shell_printf("Too much data\n");
|
2018-04-18 18:11:10 +08:00
|
|
|
return false;
|
2016-08-10 18:55:46 +08:00
|
|
|
}
|
|
|
|
|
2017-11-17 17:35:12 +08:00
|
|
|
val = strtol(argv[i], &endptr, 0);
|
2016-08-10 18:55:46 +08:00
|
|
|
if (!endptr || *endptr != '\0' || val > UINT8_MAX) {
|
2017-11-09 22:29:39 +08:00
|
|
|
bt_shell_printf("Invalid value at index %d\n", i);
|
2018-04-18 18:11:10 +08:00
|
|
|
return false;
|
2016-08-10 18:55:46 +08:00
|
|
|
}
|
|
|
|
|
2017-08-09 16:34:12 +08:00
|
|
|
data->data[data->len] = val;
|
|
|
|
data->len++;
|
2016-08-10 18:55:46 +08:00
|
|
|
}
|
|
|
|
|
2018-04-18 18:11:10 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ad_advertise_service(DBusConnection *conn, int argc, char *argv[])
|
|
|
|
{
|
|
|
|
struct ad_data data;
|
|
|
|
|
|
|
|
if (argc < 2 || !strlen(argv[1])) {
|
|
|
|
if (ad.service.uuid) {
|
|
|
|
print_uuid(ad.service.uuid);
|
|
|
|
bt_shell_hexdump(ad.service.data.data,
|
|
|
|
ad.service.data.len);
|
|
|
|
}
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ad_add_data(&data, argc - 2, argv + 2))
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
|
|
|
|
|
|
ad_clear_service();
|
|
|
|
|
|
|
|
ad.service.uuid = g_strdup(argv[1]);
|
|
|
|
ad.service.data = data;
|
|
|
|
|
2017-08-14 21:29:03 +08:00
|
|
|
g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "ServiceData");
|
2018-02-23 22:34:58 +08:00
|
|
|
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2016-08-10 18:55:46 +08:00
|
|
|
}
|
2016-08-10 20:15:46 +08:00
|
|
|
|
2018-02-16 13:51:37 +08:00
|
|
|
void ad_disable_service(DBusConnection *conn)
|
|
|
|
{
|
|
|
|
if (!ad.service.uuid)
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2018-02-16 13:51:37 +08:00
|
|
|
|
|
|
|
ad_clear_service();
|
|
|
|
g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "ServiceData");
|
2018-02-23 22:34:58 +08:00
|
|
|
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2018-02-16 13:51:37 +08:00
|
|
|
}
|
|
|
|
|
2016-08-10 20:15:46 +08:00
|
|
|
static void ad_clear_manufacturer(void)
|
|
|
|
{
|
2017-08-09 16:34:12 +08:00
|
|
|
memset(&ad.manufacturer, 0, sizeof(ad.manufacturer));
|
2018-02-23 22:34:58 +08:00
|
|
|
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2016-08-10 20:15:46 +08:00
|
|
|
}
|
|
|
|
|
2017-11-17 17:35:12 +08:00
|
|
|
void ad_advertise_manufacturer(DBusConnection *conn, int argc, char *argv[])
|
2016-08-10 20:15:46 +08:00
|
|
|
{
|
|
|
|
char *endptr = NULL;
|
|
|
|
long int val;
|
2018-04-18 18:11:10 +08:00
|
|
|
struct ad_data data;
|
2016-08-10 20:15:46 +08:00
|
|
|
|
2017-12-18 19:49:47 +08:00
|
|
|
if (argc < 2 || !strlen(argv[1])) {
|
|
|
|
if (ad.manufacturer.data.len) {
|
|
|
|
bt_shell_printf("Manufacturer: %u\n",
|
|
|
|
ad.manufacturer.id);
|
|
|
|
bt_shell_hexdump(ad.manufacturer.data.data,
|
|
|
|
ad.manufacturer.data.len);
|
|
|
|
}
|
2016-08-10 20:15:46 +08:00
|
|
|
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2017-12-18 19:49:47 +08:00
|
|
|
}
|
|
|
|
|
2017-12-08 18:52:48 +08:00
|
|
|
val = strtol(argv[1], &endptr, 0);
|
2016-08-10 20:15:46 +08:00
|
|
|
if (!endptr || *endptr != '\0' || val > UINT16_MAX) {
|
2017-11-09 22:29:39 +08:00
|
|
|
bt_shell_printf("Invalid manufacture id\n");
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
2016-08-10 20:15:46 +08:00
|
|
|
}
|
|
|
|
|
2018-04-18 18:11:10 +08:00
|
|
|
if (!ad_add_data(&data, argc - 2, argv + 2))
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
2016-08-10 20:15:46 +08:00
|
|
|
|
2018-04-18 18:11:10 +08:00
|
|
|
ad_clear_manufacturer();
|
|
|
|
ad.manufacturer.id = val;
|
|
|
|
ad.manufacturer.data = data;
|
2016-08-10 20:15:46 +08:00
|
|
|
|
2017-08-14 21:29:03 +08:00
|
|
|
g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE,
|
|
|
|
"ManufacturerData");
|
2018-02-23 22:34:58 +08:00
|
|
|
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2016-08-10 20:15:46 +08:00
|
|
|
}
|
2016-08-11 18:38:36 +08:00
|
|
|
|
2018-02-16 13:51:37 +08:00
|
|
|
void ad_disable_manufacturer(DBusConnection *conn)
|
|
|
|
{
|
|
|
|
if (!ad.manufacturer.id && !ad.manufacturer.data.len)
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2018-02-16 13:51:37 +08:00
|
|
|
|
|
|
|
ad_clear_manufacturer();
|
|
|
|
g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE,
|
|
|
|
"ManufacturerData");
|
2018-02-23 22:34:58 +08:00
|
|
|
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2018-02-16 13:51:37 +08:00
|
|
|
}
|
|
|
|
|
2018-04-18 18:11:10 +08:00
|
|
|
static void ad_clear_data(void)
|
|
|
|
{
|
|
|
|
memset(&ad.manufacturer, 0, sizeof(ad.manufacturer));
|
|
|
|
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ad_advertise_data(DBusConnection *conn, int argc, char *argv[])
|
|
|
|
{
|
|
|
|
char *endptr = NULL;
|
|
|
|
long int val;
|
|
|
|
struct ad_data data;
|
|
|
|
|
|
|
|
if (argc < 2 || !strlen(argv[1])) {
|
|
|
|
if (ad.manufacturer.data.len) {
|
|
|
|
bt_shell_printf("Type: 0x%02x\n", ad.data.type);
|
|
|
|
bt_shell_hexdump(ad.data.data.data, ad.data.data.len);
|
|
|
|
}
|
|
|
|
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
val = strtol(argv[1], &endptr, 0);
|
|
|
|
if (!endptr || *endptr != '\0' || val > UINT8_MAX) {
|
|
|
|
bt_shell_printf("Invalid type\n");
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ad_add_data(&data, argc - 2, argv + 2))
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
|
|
|
|
|
|
ad_clear_data();
|
|
|
|
ad.data.type = val;
|
|
|
|
ad.data.data = data;
|
|
|
|
|
|
|
|
g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "Data");
|
|
|
|
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ad_disable_data(DBusConnection *conn)
|
|
|
|
{
|
|
|
|
if (!ad.data.type && !ad.data.data.len)
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
|
|
|
|
|
|
|
ad_clear_data();
|
|
|
|
g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "Data");
|
|
|
|
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2018-05-07 23:41:10 +08:00
|
|
|
void ad_advertise_discoverable(DBusConnection *conn, dbus_bool_t *value)
|
|
|
|
{
|
|
|
|
if (!value) {
|
|
|
|
bt_shell_printf("Discoverable: %s\n",
|
|
|
|
ad.discoverable ? "on" : "off");
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ad.discoverable == *value)
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
|
|
|
|
|
|
|
ad.discoverable = *value;
|
|
|
|
|
|
|
|
g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "Discoverable");
|
|
|
|
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2018-05-21 21:21:05 +08:00
|
|
|
void ad_advertise_discoverable_timeout(DBusConnection *conn, long int *value)
|
|
|
|
{
|
|
|
|
if (!value) {
|
|
|
|
if (ad.discoverable_to)
|
|
|
|
bt_shell_printf("Timeout: %u sec\n",
|
|
|
|
ad.discoverable_to);
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ad.discoverable_to == *value)
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
|
|
|
|
|
|
|
ad.discoverable_to = *value;
|
|
|
|
|
|
|
|
g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE,
|
|
|
|
"DiscoverableTimeout");
|
|
|
|
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2017-12-18 20:03:03 +08:00
|
|
|
void ad_advertise_tx_power(DBusConnection *conn, dbus_bool_t *value)
|
2017-08-09 16:34:12 +08:00
|
|
|
{
|
2017-12-18 20:03:03 +08:00
|
|
|
if (!value) {
|
|
|
|
bt_shell_printf("Tx Power: %s\n", ad.tx_power ? "on" : "off");
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2017-12-18 20:03:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ad.tx_power == *value)
|
2018-03-19 16:40:48 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2017-08-14 21:29:03 +08:00
|
|
|
|
2017-12-18 20:03:03 +08:00
|
|
|
ad.tx_power = *value;
|
2017-08-14 21:29:03 +08:00
|
|
|
|
|
|
|
g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "Includes");
|
2018-02-23 22:34:58 +08:00
|
|
|
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2017-08-09 16:34:12 +08:00
|
|
|
}
|
|
|
|
|
2017-08-14 21:29:03 +08:00
|
|
|
void ad_advertise_name(DBusConnection *conn, bool value)
|
2017-08-09 16:34:12 +08:00
|
|
|
{
|
2017-08-14 21:29:03 +08:00
|
|
|
if (ad.name == value)
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2017-08-14 21:29:03 +08:00
|
|
|
|
2017-08-09 16:34:12 +08:00
|
|
|
ad.name = value;
|
2017-08-10 17:30:57 +08:00
|
|
|
|
2017-09-25 12:30:56 +08:00
|
|
|
if (!value) {
|
2018-05-21 16:35:06 +08:00
|
|
|
free(ad.local_name);
|
2017-09-25 12:30:56 +08:00
|
|
|
ad.local_name = NULL;
|
|
|
|
}
|
2017-08-14 21:29:03 +08:00
|
|
|
|
|
|
|
g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "Includes");
|
2018-02-23 22:34:58 +08:00
|
|
|
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2017-08-10 17:30:57 +08:00
|
|
|
}
|
|
|
|
|
2017-08-14 21:29:03 +08:00
|
|
|
void ad_advertise_local_name(DBusConnection *conn, const char *name)
|
2017-08-10 17:30:57 +08:00
|
|
|
{
|
2017-12-18 21:12:16 +08:00
|
|
|
if (!name) {
|
|
|
|
if (ad.local_name)
|
|
|
|
bt_shell_printf("LocalName: %s\n", ad.local_name);
|
|
|
|
else
|
|
|
|
bt_shell_printf("Name: %s\n", ad.name ? "on" : "off");
|
|
|
|
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2017-12-18 21:12:16 +08:00
|
|
|
}
|
|
|
|
|
2017-08-14 21:29:03 +08:00
|
|
|
if (ad.local_name && !strcmp(name, ad.local_name))
|
|
|
|
return;
|
|
|
|
|
2017-09-25 12:30:56 +08:00
|
|
|
g_free(ad.local_name);
|
2017-08-10 17:30:57 +08:00
|
|
|
ad.local_name = strdup(name);
|
2017-08-14 21:29:03 +08:00
|
|
|
|
|
|
|
g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "LocalName");
|
2018-02-23 22:34:58 +08:00
|
|
|
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2017-08-09 16:34:12 +08:00
|
|
|
}
|
|
|
|
|
2017-08-14 21:29:03 +08:00
|
|
|
void ad_advertise_appearance(DBusConnection *conn, bool value)
|
2016-08-11 18:38:36 +08:00
|
|
|
{
|
2017-08-14 21:29:03 +08:00
|
|
|
if (ad.appearance == value)
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2017-08-14 21:29:03 +08:00
|
|
|
|
2017-08-09 16:34:12 +08:00
|
|
|
ad.appearance = value;
|
2017-08-10 19:15:49 +08:00
|
|
|
|
|
|
|
if (!value)
|
|
|
|
ad.local_appearance = UINT16_MAX;
|
2017-08-14 21:29:03 +08:00
|
|
|
|
|
|
|
g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "Includes");
|
2018-02-23 22:34:58 +08:00
|
|
|
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2017-08-10 19:15:49 +08:00
|
|
|
}
|
|
|
|
|
2017-12-18 21:35:10 +08:00
|
|
|
void ad_advertise_local_appearance(DBusConnection *conn, long int *value)
|
2017-08-10 19:15:49 +08:00
|
|
|
{
|
2017-12-18 21:35:10 +08:00
|
|
|
if (!value) {
|
|
|
|
if (ad.local_appearance != UINT16_MAX)
|
|
|
|
bt_shell_printf("Appearance: %s (0x%04x)\n",
|
|
|
|
bt_appear_to_str(ad.local_appearance),
|
|
|
|
ad.local_appearance);
|
|
|
|
else
|
2020-08-30 15:11:08 +08:00
|
|
|
bt_shell_printf("Appearance: %s\n",
|
2017-12-18 21:35:10 +08:00
|
|
|
ad.appearance ? "on" : "off");
|
|
|
|
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2017-12-18 21:35:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ad.local_appearance == *value)
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2017-08-14 21:29:03 +08:00
|
|
|
|
2017-12-18 21:35:10 +08:00
|
|
|
ad.local_appearance = *value;
|
2017-08-14 21:29:03 +08:00
|
|
|
|
|
|
|
g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "Appearance");
|
2018-02-23 22:34:58 +08:00
|
|
|
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2016-08-11 18:38:36 +08:00
|
|
|
}
|
2017-11-02 22:03:41 +08:00
|
|
|
|
2018-01-15 23:36:26 +08:00
|
|
|
void ad_advertise_duration(DBusConnection *conn, long int *value)
|
2017-11-02 22:03:41 +08:00
|
|
|
{
|
2018-01-15 23:36:26 +08:00
|
|
|
if (!value) {
|
|
|
|
if (ad.duration)
|
|
|
|
bt_shell_printf("Duration: %u sec\n", ad.duration);
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2018-01-15 23:36:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ad.duration == *value)
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2017-11-02 22:03:41 +08:00
|
|
|
|
2018-01-15 23:36:26 +08:00
|
|
|
ad.duration = *value;
|
2017-11-02 22:03:41 +08:00
|
|
|
|
|
|
|
g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "Duration");
|
2018-02-23 22:34:58 +08:00
|
|
|
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2017-11-02 22:03:41 +08:00
|
|
|
}
|
|
|
|
|
2018-01-17 02:48:17 +08:00
|
|
|
void ad_advertise_timeout(DBusConnection *conn, long int *value)
|
2017-11-02 22:03:41 +08:00
|
|
|
{
|
2018-01-17 02:48:17 +08:00
|
|
|
if (!value) {
|
|
|
|
if (ad.timeout)
|
|
|
|
bt_shell_printf("Timeout: %u sec\n", ad.timeout);
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2018-01-17 02:48:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ad.timeout == *value)
|
2018-02-23 22:34:58 +08:00
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2017-11-02 22:03:41 +08:00
|
|
|
|
2018-01-17 02:48:17 +08:00
|
|
|
ad.timeout = *value;
|
2017-11-02 22:03:41 +08:00
|
|
|
|
|
|
|
g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "Timeout");
|
2018-02-23 22:34:58 +08:00
|
|
|
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
2017-11-02 22:03:41 +08:00
|
|
|
}
|
2019-02-15 22:19:59 +08:00
|
|
|
|
|
|
|
void ad_advertise_secondary(DBusConnection *conn, const char *value)
|
|
|
|
{
|
|
|
|
if (!value) {
|
|
|
|
if (ad.secondary)
|
|
|
|
bt_shell_printf("Secondary Channel: %s\n",
|
|
|
|
ad.secondary);
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ad.secondary && !strcmp(value, ad.secondary))
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
|
|
|
|
|
|
|
free(ad.secondary);
|
|
|
|
|
|
|
|
if (value[0] == '\0') {
|
|
|
|
ad.secondary = NULL;
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
ad.secondary = strdup(value);
|
|
|
|
|
|
|
|
g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE,
|
|
|
|
"SecondaryChannel");
|
|
|
|
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
|
|
|
}
|
2021-05-13 08:18:13 +08:00
|
|
|
|
|
|
|
void ad_advertise_interval(DBusConnection *conn, uint32_t *min, uint32_t *max)
|
|
|
|
{
|
|
|
|
if (!min && !max) {
|
|
|
|
if (ad.min_interval && ad.max_interval)
|
|
|
|
bt_shell_printf("Interval: %u-%u msec\n",
|
|
|
|
ad.min_interval, ad.max_interval);
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ad.min_interval != *min) {
|
|
|
|
ad.min_interval = *min;
|
|
|
|
g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE,
|
|
|
|
"MinInterval");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ad.max_interval != *max) {
|
|
|
|
ad.max_interval = *max;
|
|
|
|
g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE,
|
|
|
|
"MaxInterval");
|
|
|
|
}
|
|
|
|
|
|
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
|
|
|
}
|