diff --git a/src/advertising.c b/src/advertising.c
index 78178f2..8e803cb 100644
--- a/src/advertising.c
+++ b/src/advertising.c
struct queue *ads;
struct mgmt *mgmt;
uint16_t mgmt_index;
+ uint8_t max_adv_len;
};
#define AD_TYPE_BROADCAST 0
GDBusProxy *proxy;
DBusMessage *reg;
uint8_t type; /* Advertising type */
+ bool include_tx_power;
struct bt_ad *data;
uint8_t instance;
};
return false;
}
+static bool parse_advertising_include_tx_power(GDBusProxy *proxy,
+ bool *included)
+{
+ DBusMessageIter iter;
+ dbus_bool_t b;
+
+ if (!g_dbus_proxy_get_property(proxy, "IncludeTXPower", &iter))
+ return true;
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
+ return false;
+
+ dbus_message_iter_get_basic(&iter, &b);
+
+ *included = b;
+
+ return true;
+}
+
static void add_advertising_callback(uint8_t status, uint16_t length,
const void *param, void *user_data)
{
ad->instance = rp->instance;
}
+static size_t calc_max_adv_len(struct advertisement *ad, uint32_t flags)
+{
+ size_t max = ad->manager->max_adv_len;
+
+ /*
+ * Flags which reduce the amount of space available for advertising.
+ * See doc/mgmt-api.txt
+ */
+ if (flags & MGMT_ADV_FLAG_TX_POWER)
+ max -= 3;
+
+ if (flags & (MGMT_ADV_FLAG_DISCOV | MGMT_ADV_FLAG_LIMITED_DISCOV |
+ MGMT_ADV_FLAG_MANAGED_FLAGS))
+ max -= 3;
+
+ if (flags & MGMT_ADV_FLAG_APPEARANCE)
+ max -= 4;
+
+ return max;
+}
+
static DBusMessage *refresh_advertisement(struct advertisement *ad)
{
struct mgmt_cp_add_advertising *cp;
uint8_t param_len;
uint8_t *adv_data;
size_t adv_data_len;
+ uint32_t flags = 0;
DBG("Refreshing advertisement: %s", ad->path);
+ if (ad->type == AD_TYPE_PERIPHERAL)
+ flags = MGMT_ADV_FLAG_CONNECTABLE | MGMT_ADV_FLAG_DISCOV;
+
+ if (ad->include_tx_power)
+ flags |= MGMT_ADV_FLAG_TX_POWER;
+
adv_data = bt_ad_generate(ad->data, &adv_data_len);
- if (!adv_data) {
- error("Advertising data couldn't be generated.");
+ if (!adv_data || (adv_data_len > calc_max_adv_len(ad, flags))) {
+ error("Advertising data too long or couldn't be generated.");
return g_dbus_create_error(ad->reg, ERROR_INTERFACE
".InvalidLength",
return btd_error_failed(ad->reg, "Failed");
}
- if (ad->type == AD_TYPE_PERIPHERAL)
- cp->flags = MGMT_ADV_FLAG_CONNECTABLE | MGMT_ADV_FLAG_DISCOV;
-
+ cp->flags = flags;
cp->instance = ad->instance;
cp->adv_data_len = adv_data_len;
memcpy(cp->data, adv_data, adv_data_len);
goto fail;
}
+ if (!parse_advertising_include_tx_power(ad->proxy,
+ &ad->include_tx_power)) {
+ error("Property \"IncludeTXPower\" failed to parse");
+ goto fail;
+ }
+
return refresh_advertisement(ad);
fail:
free(manager);
}
+static void read_adv_features_callback(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct btd_advertising *manager = user_data;
+ const struct mgmt_rp_read_adv_features *feat = param;
+
+ if (status || !param) {
+ error("Failed to read advertising features: %s (0x%02x)",
+ mgmt_errstr(status), status);
+ return;
+ }
+
+ if (length < sizeof(*feat)) {
+ error("Wrong size of read adv features response");
+ return;
+ }
+
+ manager->max_adv_len = feat->max_adv_data_len;
+}
+
static struct btd_advertising *
advertising_manager_create(struct btd_adapter *adapter)
{
manager->mgmt_index = btd_adapter_get_index(adapter);
+ if (!mgmt_send(manager->mgmt, MGMT_OP_READ_ADV_FEATURES,
+ manager->mgmt_index, 0, NULL,
+ read_adv_features_callback, manager, NULL)) {
+ error("Failed to read advertising features");
+ advertising_manager_destroy(manager);
+ return NULL;
+ }
+
if (!g_dbus_register_interface(btd_get_dbus_connection(),
adapter_get_path(adapter),
LE_ADVERTISING_MGR_IFACE,