@@ -63,6 +63,11 @@ struct btd_adv_manager {
#define AD_TYPE_BROADCAST 0
#define AD_TYPE_PERIPHERAL 1
+/* BLUETOOTH SPECIFICATION Version 5.2 | Vol 4, Part E, page 2585
+ * defines tx power value indicating no preference
+ */
+#define ADV_TX_POWER_NO_PREFERENCE 0x7F
+
struct btd_adv_client {
struct btd_adv_manager *manager;
char *owner;
@@ -83,6 +88,9 @@ struct btd_adv_client {
struct bt_ad *data;
struct bt_ad *scan;
uint8_t instance;
+ uint32_t min_interval;
+ uint32_t max_interval;
+ int8_t tx_power;
};
struct dbus_obj_match {
@@ -946,6 +954,74 @@ static bool parse_secondary(DBusMessageIter *iter,
return false;
}
+static bool parse_min_interval(DBusMessageIter *iter,
+ struct btd_adv_client *client)
+{
+ if (!iter)
+ return false;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT32)
+ return false;
+
+ dbus_message_iter_get_basic(iter, &client->min_interval);
+
+ /* BLUETOOTH SPECIFICATION Version 5.2 | Vol 4, Part E, page 2584
+ * defines acceptable interval range
+ */
+ if (client->min_interval < 0x20 || client->min_interval > 0xFFFFFF) {
+ client->min_interval = 0;
+ return false;
+ }
+
+ return true;
+}
+
+static bool parse_max_interval(DBusMessageIter *iter,
+ struct btd_adv_client *client)
+{
+ if (!iter)
+ return false;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT32)
+ return false;
+
+ dbus_message_iter_get_basic(iter, &client->max_interval);
+
+ /* BLUETOOTH SPECIFICATION Version 5.2 | Vol 4, Part E, page 2584
+ * defines acceptable interval range
+ */
+ if (client->max_interval < 0x20 || client->max_interval > 0xFFFFFF) {
+ client->max_interval = 0;
+ return false;
+ }
+
+ return true;
+}
+
+static bool parse_tx_power(DBusMessageIter *iter,
+ struct btd_adv_client *client)
+{
+ int16_t val;
+
+ if (!iter)
+ return false;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INT16)
+ return false;
+
+ dbus_message_iter_get_basic(iter, &val);
+
+ /* BLUETOOTH SPECIFICATION Version 5.2 | Vol 4, Part E, page 2585
+ * defines acceptable tx power range
+ */
+ if (val < -127 || val > 20)
+ return false;
+
+ client->tx_power = val;
+
+ return true;
+}
+
static struct adv_parser {
const char *name;
bool (*func)(DBusMessageIter *iter, struct btd_adv_client *client);
@@ -964,6 +1040,9 @@ static struct adv_parser {
{ "Discoverable", parse_discoverable },
{ "DiscoverableTimeout", parse_discoverable_timeout },
{ "SecondaryChannel", parse_secondary },
+ { "MinInterval", parse_min_interval },
+ { "MaxInterval", parse_max_interval },
+ { "TxPower", parse_tx_power },
{ },
};
@@ -1092,6 +1171,13 @@ static DBusMessage *parse_advertisement(struct btd_adv_client *client)
goto fail;
}
+ if (client->min_interval > client->max_interval) {
+ /* Min interval must not be bigger than max interval */
+ error("MinInterval must be less than MaxInterval (%lu > %lu)",
+ client->min_interval, client->max_interval);
+ goto fail;
+ }
+
err = refresh_adv(client, add_adv_callback, &client->add_adv_id);
if (!err)
return NULL;
@@ -1167,6 +1253,9 @@ static struct btd_adv_client *client_create(struct btd_adv_manager *manager,
client->manager = manager;
client->appearance = UINT16_MAX;
+ client->tx_power = ADV_TX_POWER_NO_PREFERENCE;
+ client->min_interval = 0;
+ client->max_interval = 0;
return client;