From: Luiz Augusto von Dentz <luiz.von.dentz@xxxxxxxxx> This adds initial implementation of PreferredBearer. --- src/device.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 96 insertions(+), 3 deletions(-) diff --git a/src/device.c b/src/device.c index ec97fc889056..de92e68d2780 100644 --- a/src/device.c +++ b/src/device.c @@ -152,6 +152,7 @@ struct svc_callback { /* Per-bearer (LE or BR/EDR) device state */ struct bearer_state { + bool prefer; bool paired; bool bonded; bool connected; @@ -2543,10 +2544,12 @@ static uint8_t select_conn_bearer(struct btd_device *dev) time_t bredr_last = NVAL_TIME, le_last = NVAL_TIME; time_t current = time(NULL); - /* Prefer bonded bearer in case only one is bonded */ - if (dev->bredr_state.bonded && !dev->le_state.bonded ) + /* Use preferred bearer or bonded bearer in case only one is bonded */ + if (dev->bredr_state.prefer || + (dev->bredr_state.bonded && !dev->le_state.bonded)) return BDADDR_BREDR; - else if (!dev->bredr_state.bonded && dev->le_state.bonded) + else if (dev->le_state.prefer || + (!dev->bredr_state.bonded && dev->le_state.bonded)) return dev->bdaddr_type; /* If the address is random it can only be connected over LE */ @@ -3340,6 +3343,92 @@ static const GDBusMethodTable device_methods[] = { { } }; +static const char *device_prefer_bearer_str(struct btd_device *device) +{ + if (device->bredr_state.prefer) + return "bredr"; + else if (device->le_state.prefer) + return "le"; + else + return "last-seen"; +} + +static gboolean +dev_property_get_prefer_bearer(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct btd_device *device = data; + const char *str = device_prefer_bearer_str(device); + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str); + + return TRUE; +} + +static void +dev_property_set_prefer_bearer(const GDBusPropertyTable *property, + DBusMessageIter *value, + GDBusPendingPropertySet id, void *data) +{ + struct btd_device *device = data; + const char *str; + + if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_STRING) { + g_dbus_pending_property_error(id, + ERROR_INTERFACE ".InvalidArguments", + "Invalid arguments in method call"); + return; + } + + dbus_message_iter_get_basic(value, &str); + + if (!strcasecmp(device_prefer_bearer_str(device), str)) + goto done; + + if (!strcasecmp(str, "last-seen")) { + device->bredr_state.prefer = false; + device->le_state.prefer = false; + } else if (!strcasecmp(str, "bredr")) { + device->bredr_state.prefer = true; + device->le_state.prefer = false; + /* Remove device from auto-connect list so the kernel does not + * attempt to auto-connect to it in case it starts advertising. + */ + device_set_auto_connect(device, FALSE); + } else if (!strcasecmp(str, "le")) { + device->le_state.prefer = true; + device->bredr_state.prefer = false; + /* Add device to auto-connect list */ + device_set_auto_connect(device, TRUE); + } else { + g_dbus_pending_property_error(id, + ERROR_INTERFACE ".InvalidArguments", + "Invalid arguments in method call"); + return; + } + + g_dbus_emit_property_changed(dbus_conn, device->path, + DEVICE_INTERFACE, "PreferredBearer"); + +done: + g_dbus_pending_property_success(id); +} + +static gboolean +dev_property_prefer_bearer_exists(const GDBusPropertyTable *property, + void *data) +{ + struct btd_device *device = data; + + /* Check if both BR/EDR and LE bearer are connected/bonded */ + if ((device->bredr_state.connected || device->bredr_state.bonded) && + (device->le_state.connected || device->le_state.bonded)) + return TRUE; + + /* Check if both BR/EDR and LE are connectable */ + return device->bredr_state.connectable && device->le_state.connectable; +} + static const GDBusPropertyTable device_properties[] = { { "Address", "s", dev_property_get_address }, { "AddressType", "s", property_get_address_type }, @@ -3378,6 +3467,10 @@ static const GDBusPropertyTable device_properties[] = { dev_property_wake_allowed_exist }, { "Sets", "a{oa{sv}}", dev_property_get_set, NULL, dev_property_set_exists }, + { "PreferredBearer", "s", dev_property_get_prefer_bearer, + dev_property_set_prefer_bearer, + dev_property_prefer_bearer_exists, + G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, { } }; -- 2.48.1