main.conf: Allow passing a list of UUIDs to Experimental
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Tue, 7 Sep 2021 21:05:38 +0000 (14:05 -0700)
committerAyush Garg <ayush.garg@samsung.com>
Fri, 11 Mar 2022 13:38:36 +0000 (19:08 +0530)
This allows the user to enable a subset of the experimental features to
be enabled instead of all of them and also change -E to work in the same
way so a list of UUIDs can also be given at the command line.

Signed-off-by: Anuj Jain <anuj01.jain@samsung.com>
Signed-off-by: Ayush Garg <ayush.garg@samsung.com>
src/adapter.c
src/btd.h
src/main.c
src/main.conf

index 779f638..d16fdce 100644 (file)
@@ -116,28 +116,37 @@ static const struct mgmt_blocked_key_info blocked_keys[] = {
                 0x22, 0x8e, 0x07, 0x56, 0xb4, 0xe8, 0x5f, 0x01}},
 };
 
+struct mgmt_exp_uuid {
+       uint8_t val[16];
+       const char *str;
+};
+
 /* d4992530-b9ec-469f-ab01-6c481c47da1c */
-static const uint8_t debug_uuid[16] = {
-       0x1c, 0xda, 0x47, 0x1c, 0x48, 0x6c, 0x01, 0xab,
-       0x9f, 0x46, 0xec, 0xb9, 0x30, 0x25, 0x99, 0xd4,
+static const struct mgmt_exp_uuid debug_uuid = {
+       .val = { 0x1c, 0xda, 0x47, 0x1c, 0x48, 0x6c, 0x01, 0xab,
+               0x9f, 0x46, 0xec, 0xb9, 0x30, 0x25, 0x99, 0xd4 },
+       .str = "d4992530-b9ec-469f-ab01-6c481c47da1c"
 };
 
 /* 671b10b5-42c0-4696-9227-eb28d1b049d6 */
-static const uint8_t le_simult_central_peripheral_uuid[16] = {
-       0xd6, 0x49, 0xb0, 0xd1, 0x28, 0xeb, 0x27, 0x92,
-       0x96, 0x46, 0xc0, 0x42, 0xb5, 0x10, 0x1b, 0x67,
+static const struct mgmt_exp_uuid le_simult_central_peripheral_uuid = {
+       .val = { 0xd6, 0x49, 0xb0, 0xd1, 0x28, 0xeb, 0x27, 0x92,
+               0x96, 0x46, 0xc0, 0x42, 0xb5, 0x10, 0x1b, 0x67 },
+       .str = "671b10b5-42c0-4696-9227-eb28d1b049d6"
 };
 
 /* 330859bc-7506-492d-9370-9a6f0614037f */
-static const uint8_t quality_report_uuid[16] = {
-       0x7f, 0x03, 0x14, 0x06, 0x6f, 0x9a, 0x70, 0x93,
-       0x2d, 0x49, 0x06, 0x75, 0xbc, 0x59, 0x08, 0x33,
+static const struct mgmt_exp_uuid quality_report_uuid = {
+       .val = { 0x7f, 0x03, 0x14, 0x06, 0x6f, 0x9a, 0x70, 0x93,
+               0x2d, 0x49, 0x06, 0x75, 0xbc, 0x59, 0x08, 0x33 },
+       .str = "330859bc-7506-492d-9370-9a6f0614037f"
 };
 
 /* 15c0a148-c273-11ea-b3de-0242ac130004 */
-static const uint8_t rpa_resolution_uuid[16] = {
-       0x04, 0x00, 0x13, 0xac, 0x42, 0x02, 0xde, 0xb3,
-       0xea, 0x11, 0x73, 0xc2, 0x48, 0xa1, 0xc0, 0x15,
+static const struct mgmt_exp_uuid rpa_resolution_uuid = {
+       .val = { 0x04, 0x00, 0x13, 0xac, 0x42, 0x02, 0xde, 0xb3,
+               0xea, 0x11, 0x73, 0xc2, 0x48, 0xa1, 0xc0, 0x15 },
+       .str = "15c0a148-c273-11ea-b3de-0242ac130004"
 };
 
 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
@@ -7572,7 +7581,7 @@ static gboolean property_get_roles(const GDBusPropertyTable *property,
        }
 
        if (queue_find(adapter->exps, NULL,
-                               le_simult_central_peripheral_uuid)) {
+                               le_simult_central_peripheral_uuid.val)) {
                const char *str = "central-peripheral";
                dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &str);
        }
@@ -15748,23 +15757,15 @@ static void set_exp_debug_complete(uint8_t status, uint16_t len,
        DBG("Experimental Debug successfully set");
 
        if (action)
-               queue_push_tail(adapter->exps, (void *)debug_uuid);
+               queue_push_tail(adapter->exps, (void *)debug_uuid.val);
 }
 
-static void exp_debug_func(struct btd_adapter *adapter, uint32_t flags)
+static void exp_debug_func(struct btd_adapter *adapter, uint8_t action)
 {
        struct mgmt_cp_set_exp_feature cp;
-       uint8_t action = btd_opts.experimental ? 0x01 : 0x00;
-
-       /* If already set don't attempt to set it again */
-       if (action == (flags & BIT(0))) {
-               if (action)
-                       queue_push_tail(adapter->exps, (void *)debug_uuid);
-               return;
-       }
 
        memset(&cp, 0, sizeof(cp));
-       memcpy(cp.uuid, debug_uuid, 16);
+       memcpy(cp.uuid, debug_uuid.val, 16);
        cp.action = action;
 
        if (mgmt_send(adapter->mgmt, MGMT_OP_SET_EXP_FEATURE,
@@ -15776,17 +15777,17 @@ static void exp_debug_func(struct btd_adapter *adapter, uint32_t flags)
 }
 
 static void le_simult_central_peripheral_func(struct btd_adapter *adapter,
-                                                       uint32_t flags)
+                                                       uint8_t action)
 {
-       if (flags & 0x01)
+       if (action)
                queue_push_tail(adapter->exps,
-                               (void *)le_simult_central_peripheral_uuid);
+                               (void *)le_simult_central_peripheral_uuid.val);
 }
 
-static void quality_report_func(struct btd_adapter *adapter, uint32_t flags)
+static void quality_report_func(struct btd_adapter *adapter, uint8_t action)
 {
-       if (flags & 0x01)
-               queue_push_tail(adapter->exps, (void *)quality_report_uuid);
+       if (action)
+               queue_push_tail(adapter->exps, (void *)quality_report_uuid.val);
 }
 
 static void set_rpa_resolution_complete(uint8_t status, uint16_t len,
@@ -15804,24 +15805,15 @@ static void set_rpa_resolution_complete(uint8_t status, uint16_t len,
        DBG("RPA Resolution successfully set");
 
        if (action)
-               queue_push_tail(adapter->exps, (void *)rpa_resolution_uuid);
+               queue_push_tail(adapter->exps, (void *)rpa_resolution_uuid.val);
 }
 
-static void rpa_resolution_func(struct btd_adapter *adapter, uint32_t flags)
+static void rpa_resolution_func(struct btd_adapter *adapter, uint8_t action)
 {
        struct mgmt_cp_set_exp_feature cp;
-       uint8_t action = btd_opts.experimental ? 0x01 : 0x00;
-
-       /* If already set don't attempt to set it again */
-       if (action == (flags & BIT(0))) {
-               if (action)
-                       queue_push_tail(adapter->exps,
-                                               (void *)rpa_resolution_uuid);
-               return;
-       }
 
        memset(&cp, 0, sizeof(cp));
-       memcpy(cp.uuid, rpa_resolution_uuid, 16);
+       memcpy(cp.uuid, rpa_resolution_uuid.val, 16);
        cp.action = action;
 
        if (mgmt_send(adapter->mgmt, MGMT_OP_SET_EXP_FEATURE,
@@ -15833,14 +15825,14 @@ static void rpa_resolution_func(struct btd_adapter *adapter, uint32_t flags)
 }
 
 static const struct exp_feat {
-       const uint8_t *uuid;
-       void (*func)(struct btd_adapter *adapter, uint32_t flags);
+       const struct mgmt_exp_uuid *uuid;
+       void (*func)(struct btd_adapter *adapter, uint8_t action);
 } exp_table[] = {
-       EXP_FEAT(debug_uuid, exp_debug_func),
-       EXP_FEAT(le_simult_central_peripheral_uuid,
+       EXP_FEAT(&debug_uuid, exp_debug_func),
+       EXP_FEAT(&le_simult_central_peripheral_uuid,
                 le_simult_central_peripheral_func),
-       EXP_FEAT(quality_report_uuid, quality_report_func),
-       EXP_FEAT(rpa_resolution_uuid, rpa_resolution_func),
+       EXP_FEAT(&quality_report_uuid, quality_report_func),
+       EXP_FEAT(&rpa_resolution_uuid, rpa_resolution_func),
 };
 
 static void read_exp_features_complete(uint8_t status, uint16_t length,
@@ -15876,13 +15868,27 @@ static void read_exp_features_complete(uint8_t status, uint16_t length,
                size_t j;
                for (j = 0; j < ARRAY_SIZE(exp_table); j++) {
                        const struct exp_feat *feat = &exp_table[j];
+                       uint8_t action;
 
-                       if (memcmp(rp->features[i].uuid, feat->uuid,
+                       if (memcmp(rp->features[i].uuid, feat->uuid->val,
                                        sizeof(rp->features[i].uuid)))
                                continue;
 
+                       action = btd_experimental_enabled(feat->uuid->str);
+
+                       DBG("%s flags %u action %u", feat->uuid->str,
+                               rp->features[i].flags, action);
+
+                       /* If already set don't attempt to set it again */
+                       if (action == (rp->features[i].flags & BIT(0))) {
+                               if (action)
+                                       queue_push_tail(adapter->exps,
+                                               (void *)feat->uuid->val);
+                               continue;
+                       }
+
                        if (feat->func)
-                               feat->func(adapter, rp->features[i].flags);
+                               feat->func(adapter, action);
                }
        }
 }
index cf0574e..781f705 100755 (executable)
--- a/src/btd.h
+++ b/src/btd.h
@@ -10,6 +10,8 @@
  *
  */
 
+#include <stdbool.h>
+
 typedef enum {
        BT_MODE_DUAL,
        BT_MODE_BREDR,
@@ -109,7 +111,7 @@ struct btd_opts {
        gboolean        debug_keys;
        gboolean        fast_conn;
        gboolean        refresh_discovery;
-       gboolean        experimental;
+       struct queue    *experimental;
 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
        gboolean        le_privacy;
        char            *pin_code;
@@ -145,5 +147,6 @@ void rfkill_init(void);
 void rfkill_exit(void);
 
 GKeyFile *btd_get_main_conf(void);
+bool btd_experimental_enabled(const char *uuid);
 
 void btd_exit(void);
index 9582c29..632ed71 100755 (executable)
@@ -41,6 +41,7 @@
 #include "shared/att-types.h"
 #include "shared/mainloop.h"
 #include "shared/timeout.h"
+#include "shared/queue.h"
 #include "lib/uuid.h"
 #include "shared/util.h"
 #include "btd.h"
@@ -549,10 +550,78 @@ static void parse_le_config(GKeyFile *config)
        parse_mode_config(config, "LE", params, ARRAY_SIZE(params));
 }
 
+static bool match_experimental(const void *data, const void *match_data)
+{
+       const char *value = data;
+       const char *uuid = match_data;
+
+       if (!strcmp(value, "*"))
+               return true;
+
+       return !strcasecmp(value, uuid);
+}
+
+bool btd_experimental_enabled(const char *uuid)
+{
+       if (!btd_opts.experimental)
+               false;
+
+       return queue_find(btd_opts.experimental, match_experimental, uuid);
+}
+
+static const char *valid_uuids[] = {
+       "d4992530-b9ec-469f-ab01-6c481c47da1c",
+       "671b10b5-42c0-4696-9227-eb28d1b049d6",
+       "15c0a148-c273-11ea-b3de-0242ac130004",
+       "330859bc-7506-492d-9370-9a6f0614037f",
+       "a6695ace-ee7f-4fb9-881a-5fac66c629af",
+       "*"
+};
+
+static void btd_parse_experimental(char **list)
+{
+       int i;
+
+       if (btd_opts.experimental) {
+               warn("Unable to parse Experimental: list already set");
+               return;
+       }
+
+       btd_opts.experimental = queue_new();
+
+       for (i = 0; list[i]; i++) {
+               size_t j;
+               const char *uuid = list[i];
+
+               if (!strcasecmp("false", uuid) || !strcasecmp("off", uuid)) {
+                       queue_destroy(btd_opts.experimental, free);
+                       btd_opts.experimental = NULL;
+               }
+
+               if (!strcasecmp("true", uuid) || !strcasecmp("on", uuid))
+                       uuid = "*";
+
+               for (j = 0; j < ARRAY_SIZE(valid_uuids); j++) {
+                       if (!strcasecmp(valid_uuids[j], uuid))
+                               break;
+               }
+
+               /* Ignored if UUID is considered invalid */
+               if (j == ARRAY_SIZE(valid_uuids)) {
+                       warn("Invalid Experimental UUID: %s", uuid);
+                       continue;
+               }
+
+               DBG("%s", uuid);
+
+               queue_push_tail(btd_opts.experimental, strdup(uuid));
+       }
+}
+
 static void parse_config(GKeyFile *config)
 {
        GError *err = NULL;
-       char *str;
+       char *str, **strlist;
        int val;
        gboolean boolean;
 
@@ -726,12 +795,14 @@ static void parse_config(GKeyFile *config)
        else
                btd_opts.refresh_discovery = boolean;
 
-       boolean = g_key_file_get_boolean(config, "General",
-                                               "Experimental", &err);
+       strlist = g_key_file_get_string_list(config, "General", "Experimental",
+                                               NULL, &err);
        if (err)
                g_clear_error(&err);
-       else
-               btd_opts.experimental = boolean;
+       else {
+               btd_parse_experimental(strlist);
+               g_strfreev(strlist);
+       }
 
 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
        boolean = g_key_file_get_boolean(config, "General",
@@ -870,7 +941,6 @@ static void init_defaults(void)
        btd_opts.name_resolv = TRUE;
        btd_opts.debug_keys = FALSE;
        btd_opts.refresh_discovery = TRUE;
-       btd_opts.experimental = false;
 
        btd_opts.defaults.num_entries = 0;
        btd_opts.defaults.br.page_scan_type = 0xFFFF;
@@ -1029,6 +1099,24 @@ static gboolean parse_debug(const char *key, const char *value,
        return TRUE;
 }
 
+static gboolean parse_experimental(const char *key, const char *value,
+                                       gpointer user_data, GError **error)
+{
+       char **strlist;
+
+       if (value) {
+               strlist = g_strsplit(value, ",", -1);
+               btd_parse_experimental(strlist);
+               g_strfreev(strlist);
+       } else {
+               if (!btd_opts.experimental)
+                       btd_opts.experimental = queue_new();
+               queue_push_head(btd_opts.experimental, strdup("*"));
+       }
+
+       return TRUE;
+}
+
 static GOptionEntry options[] = {
        { "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG,
                                G_OPTION_ARG_CALLBACK, parse_debug,
@@ -1041,8 +1129,9 @@ static GOptionEntry options[] = {
                        "Specify an explicit path to the config file", "FILE"},
        { "compat", 'C', 0, G_OPTION_ARG_NONE, &option_compat,
                                "Provide deprecated command line interfaces" },
-       { "experimental", 'E', 0, G_OPTION_ARG_NONE, &btd_opts.experimental,
-                               "Enable experimental interfaces" },
+       { "experimental", 'E', G_OPTION_FLAG_OPTIONAL_ARG,
+                               G_OPTION_ARG_CALLBACK, parse_experimental,
+                               "Enable experimental features/interfaces" },
        { "nodetach", 'n', G_OPTION_FLAG_REVERSE,
                                G_OPTION_ARG_NONE, &option_detach,
                                "Run with logging in foreground" },
@@ -1174,6 +1263,9 @@ int main(int argc, char *argv[])
 
        if (btd_opts.mode != BT_MODE_LE)
                stop_sdp_server();
+
+       if (btd_opts.experimental)
+               queue_destroy(btd_opts.experimental, free);
 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
        g_free(btd_opts.pin_code);
 #endif
index 99f1664..91eee89 100755 (executable)
 # profile is connected. Defaults to true.
 #RefreshDiscovery = true
 
-# Enables experimental features and interfaces.
+# Enables experimental features and interfaces, alternatively a list of UUIDs
+# can be given.
+# Possible values: true,false,<UUID List>
+# Possible UUIDS:
+# d4992530-b9ec-469f-ab01-6c481c47da1c (BlueZ Experimental Debug)
+# 671b10b5-42c0-4696-9227-eb28d1b049d6 (BlueZ Experimental Simultaneous Central and Peripheral)
+# 15c0a148-c273-11ea-b3de-0242ac130004 (BlueZ Experimental LL privacy)
+# 330859bc-7506-492d-9370-9a6f0614037f (BlueZ Experimental Bluetooth Quality Report)
+# a6695ace-ee7f-4fb9-881a-5fac66c629af (BlueZ Experimental Offload Codecs)
 # Defaults to false.
 #Experimental = false