2016-08-09 19:32:46 +08:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* BlueZ - Bluetooth protocol stack for Linux
|
|
|
|
*
|
|
|
|
* Copyright (C) 2016 Intel Corporation. All rights reserved.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#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;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct ad {
|
|
|
|
bool registered;
|
|
|
|
char *type;
|
2017-08-10 17:30:57 +08:00
|
|
|
char *local_name;
|
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;
|
2017-08-09 16:34:12 +08:00
|
|
|
char **uuids;
|
|
|
|
size_t uuids_len;
|
|
|
|
struct service_data service;
|
|
|
|
struct manufacturer_data manufacturer;
|
|
|
|
bool tx_power;
|
|
|
|
bool name;
|
|
|
|
bool appearance;
|
2017-08-10 19:15:49 +08:00
|
|
|
} ad = {
|
|
|
|
.local_appearance = UINT16_MAX,
|
|
|
|
};
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
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");
|
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");
|
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 void append_array_variant(DBusMessageIter *iter, int type, void *val,
|
|
|
|
int n_elements)
|
|
|
|
{
|
|
|
|
DBusMessageIter variant, array;
|
|
|
|
char type_sig[2] = { type, '\0' };
|
|
|
|
char array_sig[3] = { DBUS_TYPE_ARRAY, type, '\0' };
|
|
|
|
|
|
|
|
dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
|
|
|
|
array_sig, &variant);
|
|
|
|
|
|
|
|
dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
|
|
|
|
type_sig, &array);
|
|
|
|
|
|
|
|
if (dbus_type_is_fixed(type) == TRUE) {
|
|
|
|
dbus_message_iter_append_fixed_array(&array, type, val,
|
|
|
|
n_elements);
|
|
|
|
} else if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) {
|
|
|
|
const char ***str_array = val;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < n_elements; i++)
|
|
|
|
dbus_message_iter_append_basic(&array, type,
|
|
|
|
&((*str_array)[i]));
|
|
|
|
}
|
|
|
|
|
|
|
|
dbus_message_iter_close_container(&variant, &array);
|
|
|
|
|
|
|
|
dbus_message_iter_close_container(iter, &variant);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dict_append_basic_array(DBusMessageIter *dict, int key_type,
|
|
|
|
const void *key, int type, void *val,
|
|
|
|
int n_elements)
|
|
|
|
{
|
|
|
|
DBusMessageIter entry;
|
|
|
|
|
|
|
|
dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
|
|
|
|
NULL, &entry);
|
|
|
|
|
|
|
|
dbus_message_iter_append_basic(&entry, key_type, key);
|
|
|
|
|
|
|
|
append_array_variant(&entry, type, val, n_elements);
|
|
|
|
|
|
|
|
dbus_message_iter_close_container(dict, &entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dict_append_array(DBusMessageIter *dict, const char *key, int type,
|
|
|
|
void *val, int n_elements)
|
|
|
|
{
|
|
|
|
dict_append_basic_array(dict, DBUS_TYPE_STRING, &key, type, val,
|
|
|
|
n_elements);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
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
|
|
|
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);
|
|
|
|
|
2017-08-09 16:34:12 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
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 },
|
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 },
|
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");
|
2016-08-09 19:32:46 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
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");
|
2016-08-09 19:32:46 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
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");
|
2016-08-09 19:32:46 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2017-11-09 22:29:39 +08:00
|
|
|
bt_shell_printf("Failed to unregister advertising object\n");
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ad_unregister(DBusConnection *conn, GDBusProxy *manager)
|
|
|
|
{
|
|
|
|
if (!manager)
|
|
|
|
ad_release(conn);
|
|
|
|
|
2017-08-09 16:34:12 +08:00
|
|
|
if (!ad.registered)
|
2017-02-14 17:27:50 +08:00
|
|
|
return;
|
|
|
|
|
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");
|
2016-08-09 19:32:46 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2016-08-09 20:16:58 +08:00
|
|
|
|
2017-12-15 02:09:39 +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("\tUUID: %s(%s)\n", str, uuid);
|
|
|
|
} else
|
|
|
|
bt_shell_printf("\tUUID: (%s)\n", uuid);
|
|
|
|
}
|
|
|
|
|
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])) {
|
|
|
|
char **uuid;
|
|
|
|
|
|
|
|
for (uuid = ad.uuids; uuid && *uuid; uuid++)
|
|
|
|
print_uuid(*uuid);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-08-09 16:34:12 +08:00
|
|
|
g_strfreev(ad.uuids);
|
|
|
|
ad.uuids = NULL;
|
|
|
|
ad.uuids_len = 0;
|
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");
|
2016-08-09 20:16:58 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
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");
|
2016-08-09 20:16:58 +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));
|
2016-08-10 18:55:46 +08:00
|
|
|
}
|
|
|
|
|
2017-11-17 17:35:12 +08:00
|
|
|
void ad_advertise_service(DBusConnection *conn, int argc, char *argv[])
|
2016-08-10 18:55:46 +08:00
|
|
|
{
|
|
|
|
unsigned int i;
|
2017-08-09 16:34:12 +08:00
|
|
|
struct ad_data *data;
|
2016-08-10 18:55:46 +08:00
|
|
|
|
2017-12-15 02:24:44 +08:00
|
|
|
if (argc < 2 || !strlen(argv[1])) {
|
|
|
|
print_uuid(ad.service.uuid);
|
|
|
|
bt_shell_hexdump(ad.service.data.data, ad.service.data.len);
|
2017-11-17 17:35:12 +08:00
|
|
|
return;
|
2017-12-15 02:24:44 +08:00
|
|
|
}
|
2016-08-10 18:55:46 +08:00
|
|
|
|
2017-12-08 18:52:48 +08:00
|
|
|
ad.service.uuid = g_strdup(argv[1]);
|
2017-08-09 16:34:12 +08:00
|
|
|
data = &ad.service.data;
|
2016-08-10 18:55:46 +08:00
|
|
|
|
2017-12-15 02:24:44 +08:00
|
|
|
for (i = 2; 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");
|
2017-11-02 15:50:32 +08:00
|
|
|
ad_clear_service();
|
2017-11-17 17:35:12 +08:00
|
|
|
return;
|
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);
|
2016-08-10 18:55:46 +08:00
|
|
|
ad_clear_service();
|
2017-11-17 17:35:12 +08:00
|
|
|
return;
|
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
|
|
|
}
|
|
|
|
|
2017-08-14 21:29:03 +08:00
|
|
|
g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "ServiceData");
|
2016-08-10 18:55:46 +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));
|
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
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
char *endptr = NULL;
|
|
|
|
long int val;
|
2017-08-09 16:34:12 +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
|
|
|
|
2017-11-17 17:35:12 +08:00
|
|
|
return;
|
2017-12-18 19:49:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ad_clear_manufacturer();
|
2016-08-10 20:15:46 +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");
|
2017-11-17 17:35:12 +08:00
|
|
|
return;
|
2016-08-10 20:15:46 +08:00
|
|
|
}
|
|
|
|
|
2017-08-09 16:34:12 +08:00
|
|
|
ad.manufacturer.id = val;
|
|
|
|
data = &ad.manufacturer.data;
|
2016-08-10 20:15:46 +08:00
|
|
|
|
2017-12-08 18:52:48 +08:00
|
|
|
for (i = 2; i < (unsigned int) argc; i++) {
|
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");
|
2017-11-02 15:50:32 +08:00
|
|
|
ad_clear_manufacturer();
|
2017-11-17 17:35:12 +08:00
|
|
|
return;
|
2016-08-10 20:15:46 +08:00
|
|
|
}
|
|
|
|
|
2017-11-17 17:35:12 +08:00
|
|
|
val = strtol(argv[i], &endptr, 0);
|
2016-08-10 20:15: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);
|
2017-11-02 15:46:33 +08:00
|
|
|
ad_clear_manufacturer();
|
2017-11-17 17:35:12 +08:00
|
|
|
return;
|
2016-08-10 20:15:46 +08:00
|
|
|
}
|
|
|
|
|
2017-08-09 16:34:12 +08:00
|
|
|
data->data[data->len] = val;
|
|
|
|
data->len++;
|
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");
|
2016-08-10 20:15:46 +08:00
|
|
|
}
|
2016-08-11 18:38:36 +08:00
|
|
|
|
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");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ad.tx_power == *value)
|
2017-08-14 21:29:03 +08:00
|
|
|
return;
|
|
|
|
|
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");
|
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)
|
|
|
|
return;
|
|
|
|
|
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) {
|
|
|
|
g_free(ad.local_name);
|
|
|
|
ad.local_name = NULL;
|
|
|
|
}
|
2017-08-14 21:29:03 +08:00
|
|
|
|
|
|
|
g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "Includes");
|
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");
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
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");
|
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)
|
|
|
|
return;
|
|
|
|
|
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");
|
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
|
|
|
|
bt_shell_printf("Apperance: %s\n",
|
|
|
|
ad.appearance ? "on" : "off");
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ad.local_appearance == *value)
|
2017-08-14 21:29:03 +08:00
|
|
|
return;
|
|
|
|
|
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");
|
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);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ad.duration == *value)
|
2017-11-02 22:03:41 +08:00
|
|
|
return;
|
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
|
|
|
void ad_advertise_timeout(DBusConnection *conn, uint16_t value)
|
|
|
|
{
|
|
|
|
if (ad.timeout == value)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ad.timeout = value;
|
|
|
|
|
|
|
|
g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "Timeout");
|
|
|
|
}
|