diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index 02d024d..5318d40 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
.device_remove = batt_remove,
.accept = batt_accept,
.disconnect = batt_disconnect,
- .external = true,
};
static int batt_init(void)
diff --git a/profiles/deviceinfo/deviceinfo.c b/profiles/deviceinfo/deviceinfo.c
index b6dc0ab..0cdf294 100644
--- a/profiles/deviceinfo/deviceinfo.c
+++ b/profiles/deviceinfo/deviceinfo.c
static struct btd_profile deviceinfo_profile = {
.name = "deviceinfo",
.remote_uuid = DEVICE_INFORMATION_UUID,
- .external = true,
.device_probe = deviceinfo_probe,
.device_remove = deviceinfo_remove,
.accept = deviceinfo_accept,
diff --git a/src/btd.h b/src/btd.h
index 07205aa..a443f66 100644
--- a/src/btd.h
+++ b/src/btd.h
SC_ONLY,
};
+enum bt_gatt_export_t {
+ BT_GATT_EXPORT_OFF,
+ BT_GATT_EXPORT_READ_ONLY,
+ BT_GATT_EXPORT_READ_WRITE,
+};
+
struct btd_br_defaults {
uint16_t page_scan_type;
uint16_t page_scan_interval;
uint16_t gatt_mtu;
uint8_t gatt_channels;
bool gatt_client;
+ enum bt_gatt_export_t gatt_export;
enum mps_mode_t mps;
struct btd_avdtp_opts avdtp;
diff --git a/src/gatt-client.c b/src/gatt-client.c
index a67e04e..6f22bbb 100644
--- a/src/gatt-client.c
+++ b/src/gatt-client.c
struct service {
struct btd_gatt_client *client;
bool primary;
+ bool claimed;
uint16_t start_handle;
uint16_t end_handle;
bt_uuid_t uuid;
return btd_error_invalid_args(msg);
/*
+ * Check if service was previously claimed by a plugin and if we shall
+ * consider it read-only, in that case return not authorized.
+ */
+ if (desc->chrc->service->claimed &&
+ btd_opts.gatt_export == BT_GATT_EXPORT_READ_ONLY)
+ return btd_error_not_authorized(msg);
+
+ /*
* Don't allow writing to Client Characteristic Configuration
* descriptors. We achieve this through the StartNotify and StopNotify
* methods on GattCharacteristic1.
return btd_error_invalid_args(msg);
/*
+ * Check if service was previously claimed by a plugin and if we shall
+ * consider it read-only, in that case return not authorized.
+ */
+ if (chrc->service->claimed &&
+ btd_opts.gatt_export == BT_GATT_EXPORT_READ_ONLY)
+ return btd_error_not_authorized(msg);
+
+ /*
* Decide which write to use based on characteristic properties. For now
* we don't perform signed writes since gatt-client doesn't support them
* and the user can always encrypt the through pairing. The procedure to
if (!gatt)
return btd_error_failed(msg, "Not connected");
+ /*
+ * Check if service was previously claimed by a plugin and if we shall
+ * consider it read-only, in that case return not authorized.
+ */
+ if (chrc->service->claimed &&
+ btd_opts.gatt_export == BT_GATT_EXPORT_READ_ONLY)
+ return btd_error_not_authorized(msg);
+
if (chrc->write_io)
return btd_error_not_permitted(msg, "Write acquired");
service->chrcs = queue_new();
service->incl_services = queue_new();
service->client = client;
+ service->claimed = gatt_db_service_get_claimed(attr);
gatt_db_attribute_get_service_data(attr, &service->start_handle,
&service->end_handle,
struct btd_gatt_client *client = user_data;
struct service *service;
- if (gatt_db_service_get_claimed(attr))
- return;
+ if (gatt_db_service_get_claimed(attr)) {
+ switch (btd_opts.gatt_export) {
+ case BT_GATT_EXPORT_OFF:
+ return;
+ case BT_GATT_EXPORT_READ_ONLY:
+ case BT_GATT_EXPORT_READ_WRITE:
+ break;
+ }
+ }
service = service_create(attr, client);
if (!service)
diff --git a/src/main.c b/src/main.c
index 41c3271..b92b22e 100644
--- a/src/main.c
+++ b/src/main.c
"ExchangeMTU",
"Channels",
"Client",
+ "ExportClaimedServices",
NULL
};
g_free(str);
}
+static enum bt_gatt_export_t parse_gatt_export_str(const char *str)
+{
+ if (!strcmp(str, "no") || !strcmp(str, "false") ||
+ !strcmp(str, "off")) {
+ return BT_GATT_EXPORT_OFF;
+ } else if (!strcmp(str, "read-only")) {
+ return BT_GATT_EXPORT_READ_ONLY;
+ } else if (!strcmp(str, "read-write")) {
+ return BT_GATT_EXPORT_READ_WRITE;
+ }
+
+ DBG("Invalid value for ExportClaimedServices=%s", str);
+ return BT_GATT_EXPORT_READ_ONLY;
+}
+
+static void parse_gatt_export(GKeyFile *config)
+{
+ char *str = NULL;
+
+ parse_config_string(config, "GATT", "ExportClaimedServices", &str);
+ if (!str)
+ return;
+
+ btd_opts.gatt_export = parse_gatt_export_str(str);
+ g_free(str);
+}
+
static void parse_gatt(GKeyFile *config)
{
parse_gatt_cache(config);
parse_config_u8(config, "GATT", "Channels", &btd_opts.gatt_channels,
1, 5);
parse_config_bool(config, "GATT", "Client", &btd_opts.gatt_client);
+ parse_gatt_export(config);
}
static void parse_csis_sirk(GKeyFile *config)
btd_opts.gatt_mtu = BT_ATT_MAX_LE_MTU;
btd_opts.gatt_channels = 1;
btd_opts.gatt_client = true;
+ btd_opts.gatt_export = BT_GATT_EXPORT_READ_ONLY;
btd_opts.avdtp.session_mode = BT_IO_MODE_BASIC;
btd_opts.avdtp.stream_mode = BT_IO_MODE_BASIC;
diff --git a/src/main.conf b/src/main.conf
index fff13ed..80e72e1 100644
--- a/src/main.conf
+++ b/src/main.conf
# Default to 1
#Channels = 1
+# Export claimed services by plugins
+# Possible values: no, read-only, read-write
+# Default: read-only
+#ExportClaimedServices = read-only
+
[CSIS]
# SIRK - Set Identification Resolution Key which is common for all the
# sets. They SIRK key is used to identify its sets. This can be any