Implement a new dbus method to set advertising intervals. The advertising inervals are sent through a new mgmt method with the opcode MGMT_OP_SET_ADVERTISING_INTERVALS to bluetooth kernel subsystem. Signed-off-by: Howard Chung <howardchung@xxxxxxxxxx> --- Changes in v2: None src/advertising.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/src/advertising.c b/src/advertising.c index 45ff19fa0..444969f04 100644 --- a/src/advertising.c +++ b/src/advertising.c @@ -1342,6 +1342,92 @@ static const GDBusPropertyTable properties[] = { { } }; +static void set_advertising_intervals_callback(uint8_t status, uint16_t length, + const void *param, void *user_data) +{ + DBusMessage *msg = user_data; + DBusMessage *reply; + + switch (status) { + case MGMT_STATUS_SUCCESS: + reply = dbus_message_new_method_return(msg); + break; + case MGMT_STATUS_REJECTED: + reply = btd_error_failed( + msg, "A non-BLE device should not advertise!"); + break; + case MGMT_STATUS_INVALID_PARAMS: + reply = btd_error_invalid_args(msg); + break; + case MGMT_STATUS_BUSY: + reply = btd_error_busy(msg); + break; + default: + reply = btd_error_failed( + msg, "failed to set advertising intervals"); + } + + g_dbus_send_message(btd_get_dbus_connection(), reply); + dbus_message_unref(msg); +} + +static int adapter_set_advertising_intervals(struct btd_adv_manager *manager, + DBusMessage *msg, + uint16_t min_interval_ms, + uint16_t max_interval_ms) +{ + struct mgmt_cp_set_advertising_intervals cp; + + memset(&cp, 0, sizeof(cp)); + + /* Convert milli-seconds to multiples of 0.625 ms which are used + * in kernel. + */ + cp.min_interval = min_interval_ms / ADVERTISING_INTERVAL_UNIT_TIME; + cp.max_interval = max_interval_ms / ADVERTISING_INTERVAL_UNIT_TIME; + + btd_info(manager->mgmt_index, + "Set Advertising Intervals: 0x%04x, 0x%04x", + cp.min_interval, cp.max_interval); + + if (mgmt_send(manager->mgmt, + MGMT_OP_SET_ADVERTISING_INTERVALS, manager->mgmt_index, + sizeof(cp), &cp, set_advertising_intervals_callback, + dbus_message_ref(msg), NULL) > 0) { + return true; + } + + return false; +} + +static DBusMessage *set_advertising_intervals(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + struct btd_adv_manager *manager = user_data; + const char *sender = dbus_message_get_sender(msg); + dbus_uint16_t min_interval_ms, max_interval_ms; + + DBG("set_advertising_intervals: sender %s", sender); + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_UINT16, &min_interval_ms, + DBUS_TYPE_UINT16, &max_interval_ms, + DBUS_TYPE_INVALID)) { + return btd_error_invalid_args(msg); + } + + /* The adapter is not required to be powered to set advertising + * intervals. Hence, just go ahead to set the intervals. + */ + if (!adapter_set_advertising_intervals(manager, msg, min_interval_ms, + max_interval_ms)) { + return btd_error_failed(msg, + "failed to set advertising intervals"); + } + + return NULL; +} + static const GDBusMethodTable methods[] = { { GDBUS_ASYNC_METHOD("RegisterAdvertisement", GDBUS_ARGS({ "advertisement", "o" }, @@ -1351,6 +1437,10 @@ static const GDBusMethodTable methods[] = { GDBUS_ARGS({ "service", "o" }), NULL, unregister_advertisement) }, + { GDBUS_ASYNC_METHOD("SetAdvertisingIntervals", + GDBUS_ARGS({"min_interval_ms", "q"}, + {"max_interval_ms", "q"}), + NULL, set_advertising_intervals)}, { } }; -- 2.26.0.rc2.310.g2932bb562d-goog