#define ADAPTER_INTERFACE "org.bluez.Adapter1"
+#ifdef __TIZEN_PATCH__
+#ifdef TIZEN_WEARABLE
+#define DEVICED_DEST "org.tizen.system.deviced"
+#define DEVICED_BATT_INTERFACE "org.tizen.system.deviced.Battery"
+#define DEVICED_BATT_OBJECT_PATH "/Org/Tizen/System/DeviceD/Battery"
+#endif /* TIZEN_WEARABLE */
+#endif
+
#define MODE_OFF 0x00
#define MODE_CONNECTABLE 0x01
#define MODE_DISCOVERABLE 0x02
#define IDLE_DISCOV_TIMEOUT (5)
#define TEMP_DEV_TIMEOUT (3 * 60)
#define BONDING_TIMEOUT (2 * 60)
+
+#define SCAN_TYPE_BREDR (1 << BDADDR_BREDR)
+#define SCAN_TYPE_LE ((1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM))
+#define SCAN_TYPE_DUAL (SCAN_TYPE_BREDR | SCAN_TYPE_LE)
+
+#define HCI_RSSI_INVALID 127
+#define DISTANCE_VAL_INVALID 0x7FFF
+#define PATHLOSS_MAX 137
+
#ifdef __TIZEN_PATCH__
#define check_address(address) bachk(address)
#define ADV_DATA_MAX_LENGTH 31
#define DISCOV_TYPE_LE 6
#endif /* __TIZEN_PATCH__ */
+
+
static DBusConnection *dbus_conn = NULL;
static bool kernel_conn_control = false;
static uint8_t mgmt_version = 0;
static uint8_t mgmt_revision = 0;
-#if 0 // Not used
-#ifdef __TIZEN_PATCH__
-static DBusMessage *write_sec_conn_host_support(DBusConnection *conn,
- DBusMessage *msg, void *user_data);
-#endif /* __TIZEN_PATCH__ */
-#endif
-
static GSList *adapter_drivers = NULL;
static GSList *disconnect_list = NULL;
uint16_t timeout;
};
+struct discovery_filter {
+ uint8_t type;
+ uint16_t pathloss;
+ int16_t rssi;
+ GSList *uuids;
+};
+
struct watch_client {
struct btd_adapter *adapter;
char *owner;
guint watch;
+ struct discovery_filter *discovery_filter;
};
struct service_auth {
bdaddr_t bdaddr; /* controller Bluetooth address */
#ifdef __TIZEN_PATCH__
+ bdaddr_t le_static_addr;
bdaddr_t rpaddr; /* controller RPA */
#endif
uint32_t dev_class; /* controller class of device */
bool ipsp_intialized; /* Ipsp Initialization state */
struct le_data_length_read_handler *read_handler;
struct le_data_length_read_default_data_length_handler *def_read_handler;
+#ifdef TIZEN_WEARABLE
+ guint charging_watch;
+ guint charging_timeout;
+ charging_state_e charging;
+#endif /* TIZEN_WEARABLE */
#endif
bool discovering; /* discovering property state */
+ bool filtered_discovery; /* we are doing filtered discovery */
+ bool no_scan_restart_delay; /* when this flag is set, restart scan
+ * without delay */
uint8_t discovery_type; /* current active discovery type */
uint8_t discovery_enable; /* discovery enabled/disabled */
bool discovery_suspended; /* discovery has been suspended */
GSList *discovery_list; /* list of discovery clients */
+ GSList *set_filter_list; /* list of clients that specified
+ * filter, but don't scan yet
+ */
+ /* current discovery filter, if any */
+ struct mgmt_cp_start_service_discovery *current_discovery_filter;
+
GSList *discovery_found; /* list of found devices */
guint discovery_idle_timeout; /* timeout between discovery runs */
guint passive_scan_timeout; /* timeout between passive scans */
uint8_t adv_tx_power;
- gboolean le_discovering; /* LE Discovery active */
+ bool le_discovering; /* LE Discovery active */
GSList *le_discovery_list; /* list of LE discovery clients */
gboolean le_auto_connect; /* LE Auto connection */
#endif
uint32_t dev_class;
if (length < sizeof(*rp)) {
- error("Wrong size of class of device changed parameters");
+ btd_error(adapter->dev_id,
+ "Wrong size of class of device changed parameters");
return;
}
struct btd_adapter *adapter = user_data;
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to set device class: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Failed to set device class: %s (0x%02x)",
mgmt_errstr(status), status);
return;
}
set_dev_class_complete, adapter, NULL) > 0)
return;
- error("Failed to set class of device for index %u", adapter->dev_id);
+ btd_error(adapter->dev_id,
+ "Failed to set class of device for index %u", adapter->dev_id);
}
void btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major,
#endif
#ifdef __TIZEN_PATCH__
+#ifdef TIZEN_WEARABLE
+static gboolean charging_state_timeout_cb(gpointer user_data)
+{
+ struct btd_adapter *adapter = user_data;
+ int bredr_pkt_type = ACL_PTYPE_MASK;
+
+ adapter->charging_timeout = 0;
+
+ DBG("Set all connections to BR/EDR type");
+ g_slist_foreach(adapter->devices, device_change_pkt_type,
+ (gpointer)bredr_pkt_type);
+
+ return FALSE;
+}
+
+static void set_charging_state(struct btd_adapter *adapter,
+ charging_state_e state)
+{
+ int br_pkt_type = ACL_PTYPE_MASK |
+ HCI_2DH1 | HCI_2DH3 | HCI_2DH5 |
+ HCI_3DH1 | HCI_3DH3 | HCI_3DH5;
+
+ if (adapter->charging == state)
+ return;
+
+ DBG("old charging state : %d, new charging_state : %d",
+ adapter->charging, state);
+
+ /*
+ * Only none / wire charging <-> wireless charging state change should
+ * be handled.
+ */
+ if ((adapter->charging == NONE_CHARGING && state == WIRE_CHARGING) ||
+ (adapter->charging == WIRE_CHARGING && state == NONE_CHARGING)) {
+ DBG("Just update charging state");
+ adapter->charging = state;
+ return;
+ }
+
+ if (adapter->charging_timeout) {
+ g_source_remove(adapter->charging_timeout);
+ adapter->charging_timeout = 0;
+ }
+
+ adapter->charging = state;
+ if (adapter->charging == NONE_CHARGING ||
+ adapter->charging == WIRE_CHARGING) {
+ DBG("Trigger timeout to set connection to BR/EDR type");
+ adapter->charging_timeout = g_timeout_add(2000,
+ charging_state_timeout_cb, adapter);
+ } else if (adapter->charging == WIRELESS_CHARGING) {
+ DBG("Set all connections to BR type");
+ g_slist_foreach(adapter->devices, device_change_pkt_type,
+ (gpointer)br_pkt_type);
+ }
+
+ return;
+}
+
+static gboolean charging_state_changed(DBusConnection *connection,
+ DBusMessage *msg, void *user_data)
+{
+ struct btd_adapter *adapter = user_data;
+ int state = 0;
+
+ DBG("charging_state_changed");
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &state,
+ DBUS_TYPE_INVALID))
+ return TRUE;
+
+ set_charging_state(adapter, state);
+
+ return TRUE;
+}
+
+charging_state_e get_charging_state(struct btd_adapter *adapter)
+{
+ DBG("charging_state: %d", adapter->charging);
+ return adapter->charging;
+}
+#endif /* TIZEN_WEARABLE */
+
static int compare_slot(gconstpointer a, gconstpointer b)
{
const struct adv_info *adv = a;
return;
}
-#ifndef __TIZEN_PATCH__
-/* There is no caller of this function */
-static void destroy_advertiser(struct btd_adapter *adapter,
- int slot_id)
-{
- struct adv_info *adv;
-
- if (!adapter)
- return;
-
- adv = find_advertiser(adapter, slot_id);
- if (!adv) {
- DBG("Unable to find advertiser [%d]", slot_id);
- return;
- }
-
- adapter->adv_list = g_slist_remove(adapter->adv_list,
- adv);
-}
-#endif
static void advertising_state_changed(struct btd_adapter *adapter,
int slot_id, bool enabled)
}
#endif
+#if defined __TIZEN_PATCH__ && defined __SPRD_PAGE_SCAN_PATCH__
+#define OCF_PAGE_SCAN_TIMEOUT 0x0018
+#define OGF_PAGE_SCAN_TIMEOUT 0x03
+
+typedef struct {
+ uint16_t timeout; /* Value */
+} __attribute__ ((packed)) hci_page_scan_timeout;
+#define HCI_PAGE_SCAN_TIMEOUT_CP_SIZE 2
+
+static gboolean send_sprd_page_scan_timeout(gint value)
+{
+ int dd;
+ hci_page_scan_timeout cp;
+ DBG("+");
+ dd = hci_open_dev(0);
+ cp.timeout = value;
+ if (hci_send_cmd(dd, OGF_PAGE_SCAN_TIMEOUT, OCF_PAGE_SCAN_TIMEOUT,
+ HCI_PAGE_SCAN_TIMEOUT_CP_SIZE, &cp) < 0) {
+ DBG("Error: While setting Page Timeout value");
+ hci_close_dev(dd);
+ return FALSE;
+ }
+ DBG("Page Scan Timeout Value Patch %d", value);
+
+ hci_close_dev(dd);
+
+ return TRUE;
+}
+#endif
+
static void settings_changed(struct btd_adapter *adapter, uint32_t settings)
{
uint32_t changed_mask;
if (adapter->current_settings & MGMT_SETTING_POWERED) {
adapter_start(adapter);
+#if defined __TIZEN_PATCH__ && defined __SPRD_PAGE_SCAN_PATCH__
+ /* Approx 6.4 Seconds of timeout */
+ /* This Added because Z3 device was not able to connect with
+ * some device as it was getting Page Timeout
+ * (LG HBS800, sony carkit) etc. So, Increasing Page timeout value
+ * from 5.12 Sec (which is default) to ~6.4sec*/
+ DBG("Setting value");
+ send_sprd_page_scan_timeout(10240);
+#endif /* __SPRD_QOS_PATCH__ */
} else {
adapter_stop(adapter);
uint32_t settings;
if (length < sizeof(settings)) {
- error("Wrong size of new settings parameters");
+ btd_error(adapter->dev_id,
+ "Wrong size of new settings parameters");
return;
}
struct btd_adapter *adapter = user_data;
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to set mode: %s (0x%02x)",
+ btd_error(adapter->dev_id, "Failed to set mode: %s (0x%02x)",
mgmt_errstr(status), status);
return;
}
set_mode_complete, adapter, NULL) > 0)
return true;
- error("Failed to set mode for index %u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to set mode for index %u",
+ adapter->dev_id);
return false;
}
set_mode_complete, adapter, NULL) > 0)
return true;
- error("Failed to set mode for index %u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to set mode for index %u",
+ adapter->dev_id);
return false;
}
const struct mgmt_cp_set_local_name *rp = param;
if (length < sizeof(*rp)) {
- error("Wrong size of local name changed parameters");
+ btd_error(adapter->dev_id,
+ "Wrong size of local name changed parameters");
return;
}
struct btd_adapter *adapter = user_data;
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to set local name: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Failed to set local name: %s (0x%02x)",
mgmt_errstr(status), status);
return;
}
strncpy(maxname, name, MAX_NAME_LENGTH);
if (!g_utf8_validate(maxname, -1, NULL)) {
- error("Name change failed: supplied name isn't valid UTF-8");
+ btd_error(adapter->dev_id,
+ "Name change failed: supplied name isn't valid UTF-8");
return -EINVAL;
}
set_local_name_complete, adapter, NULL) > 0)
return 0;
- error("Failed to set local name for index %u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to set local name for index %u",
+ adapter->dev_id);
return -EIO;
}
list = g_slist_find_custom(adapter->devices, &addr,
device_addr_type_cmp);
+
+/* Find the device based on RPA */
+#ifdef __TIZEN_PATCH__
+ if (!list) {
+ uint8_t msb = 0x00;
+ char address[18];
+
+ ba2str(&addr.bdaddr, address);
+
+ msb = addr.bdaddr.b[5] >> 6;
+
+ /* Check whether address is RPA */
+ if (msb == 0x00 || msb == 0x01) {
+ list = g_slist_find_custom(adapter->devices,
+ address, (GCompareFunc) device_rpa_cmp);
+ }
+ } else {
+ device = list->data;
+
+ if (device_get_rpa_exist(device) == true) {
+ GSList *rpa_list;
+
+ rpa_list = g_slist_find_custom(adapter->devices,
+ device_get_address(device),
+ device_addr_cmp);
+ if (rpa_list) {
+ list = rpa_list;
+ bdaddr_type = BDADDR_LE_RANDOM;
+ }
+ }
+ }
+#endif
+
if (!list)
return NULL;
struct btd_adapter *adapter = user_data;
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to add UUID: %s (0x%02x)",
+ btd_error(adapter->dev_id, "Failed to add UUID: %s (0x%02x)",
mgmt_errstr(status), status);
return;
}
uint128_t uint128;
if (!is_supported_uuid(uuid)) {
- warn("Ignoring unsupported UUID for addition");
+ btd_warn(adapter->dev_id,
+ "Ignoring unsupported UUID for addition");
return 0;
}
add_uuid_complete, adapter, NULL) > 0)
return 0;
- error("Failed to add UUID for index %u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to add UUID for index %u",
+ adapter->dev_id);
return -EIO;
}
struct btd_adapter *adapter = user_data;
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to remove UUID: %s (0x%02x)",
+ btd_error(adapter->dev_id, "Failed to remove UUID: %s (0x%02x)",
mgmt_errstr(status), status);
return;
}
uint128_t uint128;
if (!is_supported_uuid(uuid)) {
- warn("Ignoring unsupported UUID for removal");
+ btd_warn(adapter->dev_id,
+ "Ignoring unsupported UUID for removal");
return 0;
}
remove_uuid_complete, adapter, NULL) > 0)
return 0;
- error("Failed to remove UUID for index %u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to remove UUID for index %u",
+ adapter->dev_id);
return -EIO;
}
struct btd_adapter *adapter = user_data;
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to clear UUIDs: %s (0x%02x)",
+ btd_error(adapter->dev_id, "Failed to clear UUIDs: %s (0x%02x)",
mgmt_errstr(status), status);
return;
}
clear_uuids_complete, adapter, NULL) > 0)
return 0;
- error("Failed to clear UUIDs for index %u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to clear UUIDs for index %u",
+ adapter->dev_id);
return -EIO;
}
if (!adapter)
return NULL;
+#ifdef __TIZEN_PATCH__
+ if (!bacmp(addr, BDADDR_ANY))
+ return NULL;
+#endif
+
device = btd_adapter_find_device(adapter, addr, addr_type);
if (device)
return device;
DBG("status 0x%02x", status);
if (length < sizeof(*rp)) {
- error("Wrong size of start scanning return parameters");
+ btd_error(adapter->dev_id,
+ "Wrong size of start scanning return parameters");
return;
}
adapter->passive_scan_timeout = 0;
- cp.type = (1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM);
+ cp.type = SCAN_TYPE_LE;
#ifdef __TIZEN_PATCH__
mgmt_send(adapter->mgmt, MGMT_OP_START_LE_DISCOVERY,
adapter->dev_id, sizeof(cp), &cp,
* around the time we called stop_passive_scanning().
*/
if (status != MGMT_STATUS_SUCCESS && status != MGMT_STATUS_REJECTED) {
- error("Stopping passive scanning failed: %s",
+ btd_error(adapter->dev_id, "Stopping passive scanning failed: %s",
mgmt_errstr(status));
return;
}
err = device_connect_le(dev);
if (err < 0) {
- error("LE auto connection failed: %s (%d)",
- strerror(-err), -err);
+ btd_error(adapter->dev_id, "LE auto connection failed: %s (%d)",
+ strerror(-err), -err);
trigger_passive_scanning(adapter);
}
}
}
}
+static uint8_t get_scan_type(struct btd_adapter *adapter)
+{
+ uint8_t type;
+
+ if (adapter->current_settings & MGMT_SETTING_BREDR)
+ type = SCAN_TYPE_BREDR;
+ else
+ type = 0;
+
+ if (adapter->current_settings & MGMT_SETTING_LE)
+ type |= SCAN_TYPE_LE;
+
+ return type;
+}
+
+static void free_discovery_filter(struct discovery_filter *discovery_filter)
+{
+ if (!discovery_filter)
+ return;
+
+ g_slist_free_full(discovery_filter->uuids, g_free);
+ g_free(discovery_filter);
+}
+
static void trigger_start_discovery(struct btd_adapter *adapter, guint delay);
static void start_discovery_complete(uint8_t status, uint16_t length,
#endif
if (length < sizeof(*rp)) {
- error("Wrong size of start discovery return parameters");
+ btd_error(adapter->dev_id,
+ "Wrong size of start discovery return parameters");
return;
}
adapter->discovery_type = rp->type;
#endif
adapter->discovery_enable = 0x01;
- DBG("Discovery Type 0x%02x", adapter->discovery_type);
+
+ if (adapter->current_discovery_filter)
+ adapter->filtered_discovery = true;
+ else
+ adapter->filtered_discovery = false;
if (adapter->discovering)
return;
const struct mgmt_cp_start_discovery *rp = param;
DBG("status 0x%02x", status);
- DBG("Discovery Type 0x%02x", rp->type);
if (length < sizeof(*rp)) {
error("Wrong size of start discovery return parameters");
return;
adapter->discovery_type |= rp->type;
adapter->discovery_enable = 0x01;
+ DBG("Discovery Type 0x%02x", rp->type);
+
if (adapter->le_discovering)
return;
return;
} else {
- adapter->discovering = false;
+ adapter->le_discovering = false;
g_dbus_emit_property_changed(dbus_conn, adapter->path,
ADAPTER_INTERFACE, "LEDiscovering");
static gboolean start_discovery_timeout(gpointer user_data)
{
struct btd_adapter *adapter = user_data;
- struct mgmt_cp_start_discovery cp;
#ifdef __TIZEN_PATCH__
+ struct mgmt_cp_start_discovery cp;
uint8_t new_type = 0;
#else
+ struct mgmt_cp_start_service_discovery *sd_cp;
uint8_t new_type;
#endif
new_type |= (1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM);
}
-
if (adapter->discovery_enable == 0x01) {
/*
* If there is an already running discovery and it has the
return FALSE;
}
-
}
}
start_le_discovery_complete, adapter, NULL);
}
#else
- if (adapter->current_settings & MGMT_SETTING_BREDR)
- new_type = (1 << BDADDR_BREDR);
- else
- new_type = 0;
+ /* If we're doing filtered discovery, it must be quickly restarted */
+ adapter->no_scan_restart_delay = !!adapter->current_discovery_filter;
- if (adapter->current_settings & MGMT_SETTING_LE)
- new_type |= (1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM);
+ DBG("adapter->current_discovery_filter == %d",
+ !!adapter->current_discovery_filter);
+
+ new_type = get_scan_type(adapter);
if (adapter->discovery_enable == 0x01) {
+ struct mgmt_cp_stop_discovery cp;
+
/*
- * If there is an already running discovery and it has the
- * same type, then just keep it.
+ * If we're asked to start regular discovery, and there is an
+ * already running regular discovery and it has the same type,
+ * then just keep it.
*/
- if (adapter->discovery_type == new_type) {
+ if (!adapter->current_discovery_filter &&
+ !adapter->filtered_discovery &&
+ adapter->discovery_type == new_type) {
if (adapter->discovering)
return FALSE;
* queue up a stop discovery command.
*
* This can happen if a passive scanning for Low Energy
- * devices is ongoing.
+ * devices is ongoing, or scan type is changed between
+ * regular and filtered, or filter was updated.
*/
cp.type = adapter->discovery_type;
-
mgmt_send(adapter->mgmt, MGMT_OP_STOP_DISCOVERY,
adapter->dev_id, sizeof(cp), &cp,
NULL, NULL, NULL);
+
+ /* Don't even bother to try to quickly start discovery
+ * just after stopping it, it would fail with status
+ * MGMT_BUSY. Instead discovering_callback will take
+ * care of that.
+ */
+ return FALSE;
+
}
- cp.type = new_type;
+ /* Regular discovery is required */
+ if (!adapter->current_discovery_filter) {
+ struct mgmt_cp_start_discovery cp;
- mgmt_send(adapter->mgmt, MGMT_OP_START_DISCOVERY,
+ cp.type = new_type;
+ mgmt_send(adapter->mgmt, MGMT_OP_START_DISCOVERY,
adapter->dev_id, sizeof(cp), &cp,
start_discovery_complete, adapter, NULL);
-#endif //end of __TIZEN_PATCH__
+ return FALSE;
+ }
+
+ /* Filtered discovery is required */
+ sd_cp = adapter->current_discovery_filter;
+
+ DBG("sending MGMT_OP_START_SERVICE_DISCOVERY %d, %d, %d",
+ sd_cp->rssi, sd_cp->type, sd_cp->uuid_count);
+
+ mgmt_send(adapter->mgmt, MGMT_OP_START_SERVICE_DISCOVERY,
+ adapter->dev_id, sizeof(*sd_cp) + sd_cp->uuid_count * 16,
+ sd_cp, start_discovery_complete, adapter, NULL);
+
+#endif
return FALSE;
}
}
#endif
#endif
+
static void discovering_callback(uint16_t index, uint16_t length,
const void *param, void *user_data)
{
struct btd_adapter *adapter = user_data;
if (length < sizeof(*ev)) {
- error("Too small discovering event");
+ btd_error(adapter->dev_id, "Too small discovering event");
return;
}
- DBG("hci%u type %u discovering %u", adapter->dev_id,
- ev->type, ev->discovering);
+ DBG("hci%u type %u discovering %u method %d", adapter->dev_id, ev->type,
+ ev->discovering, adapter->filtered_discovery);
#ifdef __TIZEN_PATCH__
DBG("info discov_type %d", adapter->discovery_type);
if (ev->type == DISCOV_TYPE_BREDR) {
if (ev->discovering == FALSE) {
hci_clear_bit(BDADDR_BREDR, &adapter->discovery_type);
- adapter->discovering = FALSE;
+ adapter->discovering = false;
} else {
hci_set_bit(BDADDR_BREDR, &adapter->discovery_type);
- adapter->discovering = TRUE;
+ adapter->discovering = true;
}
g_dbus_emit_property_changed(dbus_conn, adapter->path,
ADAPTER_INTERFACE, "Discovering");
if (ev->discovering == FALSE) {
hci_clear_bit(BDADDR_LE_PUBLIC, &adapter->discovery_type);
hci_clear_bit(BDADDR_LE_RANDOM, &adapter->discovery_type);
- adapter->le_discovering = FALSE;
+ adapter->le_discovering = false;
} else {
hci_set_bit(BDADDR_LE_PUBLIC, &adapter->discovery_type);
hci_set_bit(BDADDR_LE_RANDOM, &adapter->discovery_type);
- adapter->le_discovering = TRUE;
+ adapter->le_discovering = true;
}
g_dbus_emit_property_changed(dbus_conn, adapter->path,
adapter->discovery_type = ev->type;
adapter->discovery_enable = ev->discovering;
#endif
+
/*
* Check for existing discoveries triggered by client applications
* and ignore all others.
switch (adapter->discovery_enable) {
case 0x00:
- trigger_start_discovery(adapter, IDLE_DISCOV_TIMEOUT);
+ if (adapter->no_scan_restart_delay)
+ trigger_start_discovery(adapter, 0);
+ else
+ trigger_start_discovery(adapter, IDLE_DISCOV_TIMEOUT);
break;
case 0x01:
g_source_remove(adapter->discovery_idle_timeout);
adapter->discovery_idle_timeout = 0;
}
+
break;
}
}
adapter->discovery_type &= (~0x01);
DBG("Discovery Type 0x%02x", adapter->discovery_type);
+ adapter->filtered_discovery = false;
+ adapter->no_scan_restart_delay = false;
adapter->discovering = false;
g_dbus_emit_property_changed(dbus_conn, adapter->path,
ADAPTER_INTERFACE, "Discovering");
adapter->discovery_type &= (~0x06);
DBG("Discovery Type 0x%02x", adapter->discovery_type);
+ adapter->filtered_discovery = false;
+ adapter->no_scan_restart_delay = false;
adapter->le_discovering = false;
g_dbus_emit_property_changed(dbus_conn, adapter->path,
ADAPTER_INTERFACE, "LEDiscovering");
if (status == MGMT_STATUS_SUCCESS) {
adapter->discovery_type = 0x00;
adapter->discovery_enable = 0x00;
- DBG("Discovery Type 0x%02x", adapter->discovery_type);
-
+ adapter->filtered_discovery = false;
+ adapter->no_scan_restart_delay = false;
adapter->discovering = false;
g_dbus_emit_property_changed(dbus_conn, adapter->path,
ADAPTER_INTERFACE, "Discovering");
return g_strcmp0(client->owner, sender);
}
-static void invalidate_rssi(gpointer a)
+static void invalidate_rssi_and_tx_power(gpointer a)
{
struct btd_device *dev = a;
device_set_rssi(dev, 0);
+ device_set_tx_power(dev, 127);
}
static void discovery_cleanup(struct btd_adapter *adapter)
{
- g_slist_free_full(adapter->discovery_found, invalidate_rssi);
+ g_slist_free_full(adapter->discovery_found,
+ invalidate_rssi_and_tx_power);
adapter->discovery_found = NULL;
}
next = g_slist_next(l);
- if (device_is_temporary(dev))
+ if (device_is_temporary(dev) && !btd_device_is_connected(dev))
btd_adapter_remove_device(adapter, dev);
}
}
#endif
+static gint g_strcmp(gconstpointer a, gconstpointer b)
+{
+ return strcmp(a, b);
+}
+
+static void extract_unique_uuids(gpointer data, gpointer user_data)
+{
+ char *uuid_str = data;
+ GSList **uuids = user_data;
+
+ if (!g_slist_find_custom(*uuids, uuid_str, g_strcmp))
+ *uuids = g_slist_insert_sorted(*uuids, uuid_str, g_strcmp);
+}
+
+/*
+ * This method merges all adapter filters into rssi, transport and uuids.
+ * Returns 1 if there was no filtered scan, 0 otherwise.
+ */
+static int merge_discovery_filters(struct btd_adapter *adapter, int *rssi,
+ uint8_t *transport, GSList **uuids)
+{
+ GSList *l;
+ bool empty_uuid = false;
+ bool has_regular_discovery = false;
+ bool has_filtered_discovery = false;
+
+ for (l = adapter->discovery_list; l != NULL; l = g_slist_next(l)) {
+ struct watch_client *client = l->data;
+ struct discovery_filter *item = client->discovery_filter;
+
+ if (!item) {
+ has_regular_discovery = true;
+ continue;
+ }
+
+ has_filtered_discovery = true;
+
+ *transport |= item->type;
+
+ /*
+ * Rule for merging rssi and pathloss into rssi field of kernel
+ * filter is as follow:
+ * - if there's any client without proximity filter, then do no
+ * proximity filtering,
+ * - if all clients specified RSSI, then use lowest value,
+ * - if any client specified pathloss, then kernel filter should
+ * do no proximity, as kernel can't compute pathloss. We'll do
+ * filtering on our own.
+ */
+ if (item->rssi == DISTANCE_VAL_INVALID)
+ *rssi = HCI_RSSI_INVALID;
+ else if (*rssi != HCI_RSSI_INVALID && *rssi >= item->rssi)
+ *rssi = item->rssi;
+ else if (item->pathloss != DISTANCE_VAL_INVALID)
+ *rssi = HCI_RSSI_INVALID;
+
+ if (!g_slist_length(item->uuids))
+ empty_uuid = true;
+
+ g_slist_foreach(item->uuids, extract_unique_uuids, uuids);
+ }
+
+ /* If no proximity filtering is set, disable it */
+ if (*rssi == DISTANCE_VAL_INVALID)
+ *rssi = HCI_RSSI_INVALID;
+
+ /*
+ * Empty_uuid variable determines wether there was any filter with no
+ * uuids. In this case someone might be looking for all devices in
+ * certain proximity, and we need to have empty uuids in kernel filter.
+ */
+ if (empty_uuid) {
+ g_slist_free(*uuids);
+ *uuids = NULL;
+ }
+
+ if (has_regular_discovery) {
+ if (!has_filtered_discovery)
+ return 1;
+
+ /*
+ * It there is both regular and filtered scan running, then
+ * clear whole fitler to report all devices.
+ */
+ *transport = get_scan_type(adapter);
+ *rssi = HCI_RSSI_INVALID;
+ g_slist_free(*uuids);
+ *uuids = NULL;
+ }
+
+ return 0;
+}
+
+static void populate_mgmt_filter_uuids(uint8_t (*mgmt_uuids)[16], GSList *uuids)
+{
+ GSList *l;
+
+ for (l = uuids; l != NULL; l = g_slist_next(l)) {
+ bt_uuid_t uuid, u128;
+ uint128_t uint128;
+
+ bt_string_to_uuid(&uuid, l->data);
+ bt_uuid_to_uuid128(&uuid, &u128);
+
+ ntoh128((uint128_t *) u128.value.u128.data, &uint128);
+ htob128(&uint128, (uint128_t *) mgmt_uuids);
+
+ mgmt_uuids++;
+ }
+}
+
+/*
+ * This method merges all adapter filters into one that will be send to kernel.
+ * cp_ptr is set to null when regular non-filtered discovery is needed,
+ * otherwise it's pointing to filter. Returns 0 on succes, -1 on error
+ */
+static int discovery_filter_to_mgmt_cp(struct btd_adapter *adapter,
+ struct mgmt_cp_start_service_discovery **cp_ptr)
+{
+ GSList *uuids = NULL;
+ struct mgmt_cp_start_service_discovery *cp;
+ int rssi = DISTANCE_VAL_INVALID;
+ int uuid_count;
+ uint8_t discovery_type = 0;
+
+ DBG("");
+
+ if (merge_discovery_filters(adapter, &rssi, &discovery_type, &uuids)) {
+ /* There are only regular scans, run just regular scan. */
+ *cp_ptr = NULL;
+ return 0;
+ }
+
+ uuid_count = g_slist_length(uuids);
+
+ cp = g_try_malloc(sizeof(*cp) + 16*uuid_count);
+ *cp_ptr = cp;
+ if (!cp) {
+ g_slist_free(uuids);
+ return -1;
+ }
+
+ cp->type = discovery_type;
+ cp->rssi = rssi;
+ cp->uuid_count = uuid_count;
+ populate_mgmt_filter_uuids(cp->uuids, uuids);
+
+ g_slist_free(uuids);
+ return 0;
+}
+
+static bool filters_equal(struct mgmt_cp_start_service_discovery *a,
+ struct mgmt_cp_start_service_discovery *b) {
+ if (!a && !b)
+ return true;
+
+ if ((!a && b) || (a && !b))
+ return false;
+
+ if (a->type != b->type)
+ return false;
+
+ if (a->rssi != b->rssi)
+ return false;
+
+ /*
+ * When we create mgmt_cp_start_service_discovery structure inside
+ * discovery_filter_to_mgmt_cp, we always keep uuids sorted, and
+ * unique, so we're safe to compare uuid_count, and uuids like that.
+ */
+ if (a->uuid_count != b->uuid_count)
+ return false;
+
+ if (memcmp(a->uuids, b->uuids, 16 * a->uuid_count) != 0)
+ return false;
+
+ return true;
+}
+
+static void update_discovery_filter(struct btd_adapter *adapter)
+{
+ struct mgmt_cp_start_service_discovery *sd_cp;
+
+ DBG("");
+
+ if (discovery_filter_to_mgmt_cp(adapter, &sd_cp)) {
+ btd_error(adapter->dev_id,
+ "discovery_filter_to_mgmt_cp returned error");
+ return;
+ }
+
+ /*
+ * If filters are equal, then don't update scan, except for when
+ * starting discovery.
+ */
+ if (filters_equal(adapter->current_discovery_filter, sd_cp) &&
+ adapter->discovering != 0) {
+ DBG("filters were equal, deciding to not restart the scan.");
+ g_free(sd_cp);
+ return;
+ }
+
+ g_free(adapter->current_discovery_filter);
+ adapter->current_discovery_filter = sd_cp;
+
+ trigger_start_discovery(adapter, 0);
+}
+
static void discovery_destroy(void *user_data)
{
struct watch_client *client = user_data;
DBG("owner %s", client->owner);
+ adapter->set_filter_list = g_slist_remove(adapter->set_filter_list,
+ client);
+
adapter->discovery_list = g_slist_remove(adapter->discovery_list,
client);
+ if (client->discovery_filter) {
+ free_discovery_filter(client->discovery_filter);
+ client->discovery_filter = NULL;
+ }
+
g_free(client->owner);
g_free(client);
#endif
}
+/*
+ * Returns true if client was already discovering, false otherwise. *client
+ * will point to discovering client, or client that have pre-set his filter.
+ */
+static bool get_discovery_client(struct btd_adapter *adapter,
+ const char *owner,
+ struct watch_client **client)
+{
+ GSList *list = g_slist_find_custom(adapter->discovery_list, owner,
+ compare_sender);
+ if (list) {
+ *client = list->data;
+ return true;
+ }
+
+ list = g_slist_find_custom(adapter->set_filter_list, owner,
+ compare_sender);
+ if (list) {
+ *client = list->data;
+ return false;
+ }
+
+ *client = NULL;
+ return false;
+}
+
+
#ifdef __TIZEN_PATCH__
static void le_discovery_destroy(void *user_data)
{
DBG("owner %s", client->owner);
+ adapter->set_filter_list = g_slist_remove(adapter->set_filter_list,
+ client);
+
adapter->discovery_list = g_slist_remove(adapter->discovery_list,
client);
* However in case this is the last client, the discovery in
* the kernel needs to be disabled.
*/
- if (adapter->discovery_list)
+ if (adapter->discovery_list) {
+ update_discovery_filter(adapter);
return;
+ }
/*
* In the idle phase of a discovery, there is no need to stop it
struct btd_adapter *adapter = user_data;
const char *sender = dbus_message_get_sender(msg);
struct watch_client *client;
- GSList *list;
+ bool is_discovering;
DBG("sender %s", sender);
if (!(adapter->current_settings & MGMT_SETTING_POWERED))
return btd_error_not_ready(msg);
+ is_discovering = get_discovery_client(adapter, sender, &client);
+
/*
* Every client can only start one discovery, if the client
* already started a discovery then return an error.
*/
-#ifdef __TIZEN_PATCH__
- adapter->disc_type = BT_DISC_TYPE_BREDR_ONLY;
-#endif
-
- list = g_slist_find_custom(adapter->discovery_list, sender,
- compare_sender);
- if (list)
+ if (is_discovering)
return btd_error_busy(msg);
+ /*
+ * If there was pre-set filter, just reconnect it to discovery_list,
+ * and trigger scan.
+ */
+ if (client) {
+ adapter->set_filter_list = g_slist_remove(
+ adapter->set_filter_list, client);
+ adapter->discovery_list = g_slist_prepend(
+ adapter->discovery_list, client);
+ update_discovery_filter(adapter);
+ return dbus_message_new_method_return(msg);
+ }
+
client = g_new0(struct watch_client, 1);
client->adapter = adapter;
client->owner = g_strdup(sender);
+ client->discovery_filter = NULL;
client->watch = g_dbus_add_disconnect_watch(dbus_conn, sender,
discovery_disconnect, client,
discovery_destroy);
-
adapter->discovery_list = g_slist_prepend(adapter->discovery_list,
client);
+#ifdef __TIZEN_PATCH__
+ adapter->disc_type = BT_DISC_TYPE_BREDR_ONLY;
+#endif
+
/*
* Just trigger the discovery here. In case an already running
* discovery in idle phase exists, it will be restarted right
* away.
*/
- trigger_start_discovery(adapter, 0);
+ update_discovery_filter(adapter);
return dbus_message_new_method_return(msg);
}
int name_len;
uint8_t *data = NULL;
- data = g_memdup(adv_data, adv_len);
+ if (!name)
+ return adv_len;
- if (!data || !name)
+ data = g_memdup(adv_data, adv_len);
+ if (!data)
return adv_len;
name_len = strlen(name);
for (j = i; j < adv_len - 2; j++)
adv_data[j] = data[j + 2];
+ adv_data[j] = name_len + 1;
if (name_len > ADV_DATA_MAX_LENGTH - adv_len) {
+ adv_data[j] = ADV_DATA_MAX_LENGTH - adv_len + 1;
adv_data[j + 1] = EIR_NAME_SHORT;
- name_len = ADV_DATA_MAX_LENGTH - adv_len;
+ memcpy(adv_data + j + 2, name, ADV_DATA_MAX_LENGTH - adv_len);
+ g_free(data);
+ return ADV_DATA_MAX_LENGTH;
} else {
adv_data[j + 1] = EIR_NAME_COMPLETE;
+ memcpy(adv_data + j + 2, name, name_len);
+ g_free(data);
+ return adv_len + name_len;
}
- adv_data[j] = name_len + 1;
- memcpy(adv_data + j + 2, name, name_len);
- g_free(data);
- return adv_len + name_len;
} else {
memcpy(adv_data + i, &data[i], ad_len + 1);
i = i + data[i];
return adv_len;
}
-static gboolean adapter_le_set_missed_adv_data(uint8_t *p_data, uint8_t data_len,
+
+int adapter_le_set_missed_adv_data(uint8_t *p_data, uint8_t data_len,
gboolean is_scan_rsp, char *adapter_name, int8_t tx_power, uint8_t **adv_data, int *adv_len)
{
uint8_t *data;
data = g_malloc0(ADV_DATA_MAX_LENGTH);
/* Fix : NULL_RETURNS */
if (data == NULL) {
- return FALSE;
+ return -1;
}
+
memcpy(data, p_data, data_len);
len = data_len;
*adv_data = data;
*adv_len = len;
- return TRUE;
+ return 0;
}
static DBusMessage *adapter_start_custom_discovery(DBusConnection *conn,
p_params->channel_map = 0x07; /* fixed channel :: will be used all */
p_params->adv_filter_policy = filter_policy;
p_params->tx_power = BLE_ADV_TX_POWER_MID; /* TODO:need to optimize */
- p_inst->bdaddr_type = 0x00;
- bacpy(&p_inst->bdaddr, &adapter->bdaddr);
+ if (adapter->le_static_addr.b[5] != 0) {
+ p_inst->bdaddr_type = 0x01;
+ bacpy(&p_inst->bdaddr, &adapter->le_static_addr);
+ } else {
+ p_inst->bdaddr_type = 0x00;
+ bacpy(&p_inst->bdaddr, &adapter->bdaddr);
+ }
ret = adapter_le_set_multi_adv_params(p_inst, p_params);
if (len > ADV_DATA_MAX_LENGTH - 3)
return btd_error_invalid_args(msg);
- if (adapter_le_set_missed_adv_data(value, len, FALSE,
- adapter->name, adapter->adv_tx_power, &adv_data, &adv_len) != TRUE)
- return btd_error_failed(msg, "set advertising data failed");
+ adapter_le_set_missed_adv_data(value, len, FALSE,
+ adapter->name, adapter->adv_tx_power, &adv_data, &adv_len);
if (adapter_le_is_supported_multi_advertising() && slot_id > 0) {
if (adapter_le_set_multi_adv_data(slot_id, FALSE, adv_len, adv_data)) {
DBusMessage *msg, void *data)
{
struct btd_adapter *adapter = data;
+ struct btd_device *dev;
+ bdaddr_t bdaddr;
dbus_bool_t err;
dbus_int32_t client_if, action, filt_type, filt_index;
dbus_int32_t company_id, company_id_mask;
gchar *string;
+ char ida_string[18];
dbus_uint32_t address_type;
uint8_t *p_uuid, *p_uuid_mask, *p_data, *p_mask;
int32_t uuid_len = 0, uuid_mask_len = 0, data_len = 0, mask_len = 0;
DBUS_TYPE_INVALID))
return btd_error_invalid_args(msg);
+ DBG("addr %s, type %d", string, address_type);
+
+ str2ba(string, &bdaddr);
+
+ dev = btd_adapter_find_device(adapter, &bdaddr, address_type);
+ if (dev && device_get_rpa_exist(dev) == true) {
+ ba2str(device_get_address(dev), ida_string);
+ if (btd_device_get_bdaddr_type(dev) == BDADDR_LE_PUBLIC)
+ address_type = 0x0;
+ else
+ address_type = 0x1;
+ } else {
+ memcpy(ida_string, string, sizeof(ida_string));
+ }
+
err = adapter_le_set_scan_filter_data(client_if, action, filt_type,
filt_index, company_id, company_id_mask,
uuid_len, p_uuid, uuid_mask_len, p_uuid_mask,
- string, address_type, data_len, p_data, mask_len, p_mask);
+ ida_string, address_type, data_len, p_data, mask_len, p_mask);
if (!err)
return btd_error_failed(msg, "Failed to add/remove filter");
if (len > SCAN_RESPONSE_DATA_LENGTH_MAX)
return btd_error_invalid_args(msg);
- if (adapter_le_set_missed_adv_data(value, len, TRUE,
- adapter->name, adapter->adv_tx_power, &adv_data, &adv_len) != TRUE)
- return btd_error_failed(msg, "set advertising data failed");
+ adapter_le_set_missed_adv_data(value, len, TRUE,
+ adapter->name, adapter->adv_tx_power, &adv_data, &adv_len);
if (adapter_le_is_supported_multi_advertising() && slot_id > 0) {
if (adapter_le_set_multi_adv_data(slot_id, TRUE, adv_len, (uint8_t *)adv_data)) {
const gchar *address;
bdaddr_t bdaddr;
dbus_uint32_t address_type;
+ struct btd_device *dev;
DBG("Add device whie list");
if (dbus_message_get_args(msg, NULL,
if (!(adapter->current_settings & MGMT_SETTING_POWERED))
return btd_error_not_ready(msg);
+
DBG("addr %s, type %d", address, address_type);
str2ba(address, &bdaddr);
+ dev = btd_adapter_find_device(adapter, &bdaddr, address_type);
+ if (dev && device_get_rpa_exist(dev) == true) {
+ if (adapter_le_is_supported_offloading() == FALSE) {
+ error("Spec based command is not supported yet");
+ return btd_error_not_supported(msg);
+ }
+
+ /* Add IRK value to list */
+ if (adapter_le_add_irk_to_list(device_get_irk_value(dev),
+ device_get_address(dev),
+ btd_device_get_bdaddr_type(dev))) {
+ return dbus_message_new_method_return(msg);
+ } else {
+ return btd_error_failed(msg, "Add LE IRK to list failed");
+ }
+ }
+
memset(&cp, 0, sizeof(cp));
cp.bdaddr_type = address_type;
const gchar *address;
bdaddr_t bdaddr;
dbus_uint32_t address_type;
+ struct btd_device *dev;
DBG("Remove device whie list");
DBG("addr %s, type %d", address, address_type);
str2ba(address, &bdaddr);
+ dev = btd_adapter_find_device(adapter, &bdaddr, address_type);
+ if (dev && device_get_rpa_exist(dev) == true) {
+ if (adapter_le_is_supported_offloading() == FALSE) {
+ error("Spec based command is not supported yet");
+ return btd_error_not_supported(msg);
+ }
+
+ /* Remove IRK value to list */
+ if (adapter_le_remove_irk_to_list(device_get_address(dev),
+ btd_device_get_bdaddr_type(dev))) {
+ return dbus_message_new_method_return(msg);
+ } else {
+ return btd_error_failed(msg, "Remove LE IRK to list failed");
+ }
+ }
+
memset(&cp, 0, sizeof(cp));
cp.bdaddr_type = address_type;
return dbus_message_new_method_return(msg);
}
+static void set_le_static_address(struct btd_adapter *adapter)
+{
+ int fd;
+ int ret;
+ char address[18];
+ char dirname[PATH_MAX];
+
+ snprintf(dirname, PATH_MAX, STORAGEDIR "/%s", "le_static_addr");
+ if (access(dirname, F_OK) < 0) {
+ int i;
+ bdaddr_t le_static_addr;
+
+ le_static_addr.b[5] = adapter->bdaddr.b[5] | 0xc0;
+ for (i = 0; i < 5; i++) {
+ le_static_addr.b[i] =
+ (adapter->bdaddr.b[i] & 0x7f) << 1 |
+ (adapter->bdaddr.b[i] & 0x80) >> 7;
+ }
+
+ /*
+ * < How to get Public address from above static address >
+ *
+ * for (i = 0; i < 5; i++) {
+ * bredr_addr.b[i] =
+ * (adapter->le_static_addr.b[i] & 0xfe) >> 1 |
+ * (adapter->le_static_addr.b[i] & 0x01) << 7;
+ * }
+ * bredr_addr.b[5] = {the value from advertising data}
+ */
+
+ fd = open(dirname, O_WRONLY | O_CREAT, 0644);
+ if (fd >= 0) {
+ ba2str(&le_static_addr, address);
+ DBG("LE static random : %s", address);
+ ret = write(fd, address, strlen(address));
+ if (ret < 0) {
+ error("Cannot save LE address : %s",
+ strerror(errno));
+ }
+ close(fd);
+ } else {
+ error("Cannot save LE address");
+ }
+ bacpy(&adapter->le_static_addr, &le_static_addr);
+ } else {
+ fd = open(dirname, O_RDONLY);
+ if (fd >= 0) {
+ ret = read(fd, address, sizeof(address));
+ if (ret >= 17) {
+ /* xx:xx:xx:xx:xx:xx */
+ address[17] = '\0';
+ DBG("LE static random : %s", address);
+ str2ba(address, &adapter->le_static_addr);
+ adapter->le_static_addr.b[5] |= 0xc0;
+ } else
+ error("Invalid LE address");
+ close(fd);
+ } else {
+ error("Cannot get LE address");
+ }
+ }
+
+ return;
+}
+
+static void set_le_static_address_complete(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct btd_adapter *adapter = user_data;
+
+ DBG("index %u status 0x%02x", adapter->dev_id, status);
+
+ if (status != MGMT_STATUS_SUCCESS) {
+ error("Failed to set static address for index %u: %s (0x%02x)",
+ adapter->dev_id, mgmt_errstr(status), status);
+ if (adapter->le_static_addr.b[5] != 0)
+ bacpy(&adapter->le_static_addr, BDADDR_ANY);
+ else
+ set_le_static_address(adapter);
+ return;
+ }
+
+ return;
+}
+
+static DBusMessage *adapter_set_le_static_address(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct btd_adapter *adapter = data;
+ dbus_bool_t is_enable = FALSE;
+ struct mgmt_cp_set_static_address cp;
+
+ if (!(adapter->supported_settings & MGMT_OP_SET_STATIC_ADDRESS)) {
+ error("LE static address is not supported");
+ return btd_error_not_supported(msg);
+ }
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &is_enable,
+ DBUS_TYPE_INVALID)) {
+ error("Invalid arguments");
+ return btd_error_invalid_args(msg);
+ }
+
+ memset(&cp, 0x00, sizeof(cp));
+ if (is_enable) {
+ if (adapter->le_static_addr.b[5] != 0) {
+ DBG("LE static address is already configured");
+ return dbus_message_new_method_return(msg);
+ }
+ set_le_static_address(adapter);
+ bacpy(&cp.bdaddr, &adapter->le_static_addr);
+ } else {
+ if (adapter->le_static_addr.b[5] == 0) {
+ DBG("LE static address is not configured");
+ return dbus_message_new_method_return(msg);
+ }
+ bacpy(&adapter->le_static_addr, BDADDR_ANY);
+ }
+ DBG("Set static random address : %d", is_enable);
+
+ if (mgmt_send(mgmt_master, MGMT_OP_SET_STATIC_ADDRESS, adapter->dev_id,
+ sizeof(cp), &cp,
+ set_le_static_address_complete, adapter, NULL) <= 0) {
+ error("Failed to set static address : %d", is_enable);
+ if (is_enable)
+ bacpy(&adapter->le_static_addr, BDADDR_ANY);
+ else
+ set_le_static_address(adapter);
+ return btd_error_failed(msg, "Unable to set static address");
+ }
+
+ return dbus_message_new_method_return(msg);
+}
+
#if 0 // Not used
static void read_sec_conn_host_support_complete(uint8_t status, uint16_t length,
const void *param, void *user_data)
return btd_error_failed(msg, "Get Raw RSSI Failed");
}
+#if !defined(__SPRD_PATCH__)
static void get_adv_tx_power_complete(uint8_t status, uint16_t length,
const void *param, void *user_data)
{
get_adv_tx_power_complete, adapter, NULL);
return;
}
+#endif
#ifdef __BROADCOM_PATCH__
static DBusMessage *set_wbs_parameters(DBusConnection *conn,
}
#endif /* __TIZEN_PATCH__ */
+static bool parse_uuids(DBusMessageIter *value, GSList **uuids)
+{
+ DBusMessageIter arriter;
+
+ if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_ARRAY)
+ return false;
+
+ dbus_message_iter_recurse(value, &arriter);
+ while (dbus_message_iter_get_arg_type(&arriter) != DBUS_TYPE_INVALID) {
+ bt_uuid_t uuid, u128;
+ char uuidstr[MAX_LEN_UUID_STR + 1];
+ char *uuid_param;
+
+ if (dbus_message_iter_get_arg_type(&arriter) !=
+ DBUS_TYPE_STRING)
+ return false;
+
+ dbus_message_iter_get_basic(&arriter, &uuid_param);
+
+ if (bt_string_to_uuid(&uuid, uuid_param))
+ return false;
+
+ bt_uuid_to_uuid128(&uuid, &u128);
+ bt_uuid_to_string(&u128, uuidstr, sizeof(uuidstr));
+
+ *uuids = g_slist_prepend(*uuids, strdup(uuidstr));
+
+ dbus_message_iter_next(&arriter);
+ }
+
+ return true;
+}
+
+static bool parse_rssi(DBusMessageIter *value, int16_t *rssi)
+{
+ if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_INT16)
+ return false;
+
+ dbus_message_iter_get_basic(value, rssi);
+ /* -127 <= RSSI <= +20 (spec V4.2 [Vol 2, Part E] 7.7.65.2) */
+ if (*rssi > 20 || *rssi < -127)
+ return false;
+
+ return true;
+}
+
+static bool parse_pathloss(DBusMessageIter *value, uint16_t *pathloss)
+{
+ if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_UINT16)
+ return false;
+
+ dbus_message_iter_get_basic(value, pathloss);
+ /* pathloss filter must be smaller that PATHLOSS_MAX */
+ if (*pathloss > PATHLOSS_MAX)
+ return false;
+
+ return true;
+}
+
+static bool parse_transport(DBusMessageIter *value, uint8_t *transport)
+{
+ char *transport_str;
+
+ if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_STRING)
+ return false;
+
+ dbus_message_iter_get_basic(value, &transport_str);
+
+ if (!strcmp(transport_str, "bredr"))
+ *transport = SCAN_TYPE_BREDR;
+ else if (!strcmp(transport_str, "le"))
+ *transport = SCAN_TYPE_LE;
+ else if (!strcmp(transport_str, "auto"))
+ *transport = SCAN_TYPE_DUAL;
+ else
+ return false;
+
+ return true;
+}
+
+static bool parse_discovery_filter_entry(char *key, DBusMessageIter *value,
+ struct discovery_filter *filter)
+{
+ if (!strcmp("UUIDs", key))
+ return parse_uuids(value, &filter->uuids);
+
+ if (!strcmp("RSSI", key))
+ return parse_rssi(value, &filter->rssi);
+
+ if (!strcmp("Pathloss", key))
+ return parse_pathloss(value, &filter->pathloss);
+
+ if (!strcmp("Transport", key))
+ return parse_transport(value, &filter->type);
+
+ DBG("Unknown key parameter: %s!\n", key);
+ return false;
+}
+
+/*
+ * This method is responsible for parsing parameters to SetDiscoveryFilter. If
+ * filter in msg was empty, sets *filter to NULL. If whole parsing was
+ * successful, sets *filter to proper value.
+ * Returns false on any error, and true on success.
+ */
+static bool parse_discovery_filter_dict(struct discovery_filter **filter,
+ DBusMessage *msg)
+{
+ DBusMessageIter iter, subiter, dictiter, variantiter;
+ bool is_empty = true;
+
+ *filter = g_try_malloc(sizeof(**filter));
+ if (!*filter)
+ return false;
+
+ (*filter)->uuids = NULL;
+ (*filter)->pathloss = DISTANCE_VAL_INVALID;
+ (*filter)->rssi = DISTANCE_VAL_INVALID;
+ (*filter)->type = SCAN_TYPE_DUAL;
+
+ dbus_message_iter_init(msg, &iter);
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
+ dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)
+ goto invalid_args;
+
+ dbus_message_iter_recurse(&iter, &subiter);
+ do {
+ int type = dbus_message_iter_get_arg_type(&subiter);
+ char *key;
+
+ if (type == DBUS_TYPE_INVALID)
+ break;
+
+ is_empty = false;
+ dbus_message_iter_recurse(&subiter, &dictiter);
+
+ dbus_message_iter_get_basic(&dictiter, &key);
+ if (!dbus_message_iter_next(&dictiter))
+ goto invalid_args;
+
+ if (dbus_message_iter_get_arg_type(&dictiter) !=
+ DBUS_TYPE_VARIANT)
+ goto invalid_args;
+
+ dbus_message_iter_recurse(&dictiter, &variantiter);
+
+ if (!parse_discovery_filter_entry(key, &variantiter, *filter))
+ goto invalid_args;
+
+ dbus_message_iter_next(&subiter);
+ } while (true);
+
+ if (is_empty) {
+ g_free(*filter);
+ *filter = NULL;
+ return true;
+ }
+
+ /* only pathlos or rssi can be set, never both */
+ if ((*filter)->pathloss != DISTANCE_VAL_INVALID &&
+ (*filter)->rssi != DISTANCE_VAL_INVALID)
+ goto invalid_args;
+
+ DBG("filtered discovery params: transport: %d rssi: %d pathloss: %d",
+ (*filter)->type, (*filter)->rssi, (*filter)->pathloss);
+
+ return true;
+
+invalid_args:
+ g_slist_free_full((*filter)->uuids, g_free);
+ g_free(*filter);
+ *filter = NULL;
+ return false;
+}
+
+static DBusMessage *set_discovery_filter(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct btd_adapter *adapter = user_data;
+ struct watch_client *client;
+ struct discovery_filter *discovery_filter;
+ const char *sender = dbus_message_get_sender(msg);
+ bool is_discovering;
+
+ DBG("sender %s", sender);
+
+ if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+ return btd_error_not_ready(msg);
+
+ if (MGMT_VERSION(mgmt_version, mgmt_revision) < MGMT_VERSION(1, 8))
+ return btd_error_not_supported(msg);
+
+ /* parse parameters */
+ if (!parse_discovery_filter_dict(&discovery_filter, msg))
+ return btd_error_invalid_args(msg);
+
+ is_discovering = get_discovery_client(adapter, sender, &client);
+
+ if (client) {
+ free_discovery_filter(client->discovery_filter);
+ client->discovery_filter = discovery_filter;
+
+ if (is_discovering)
+ update_discovery_filter(adapter);
+
+ if (discovery_filter || is_discovering)
+ return dbus_message_new_method_return(msg);
+
+ /* Removing pre-set filter */
+ adapter->set_filter_list = g_slist_remove(
+ adapter->set_filter_list,
+ client);
+ g_free(client->owner);
+ g_free(client);
+ DBG("successfully cleared pre-set filter");
+ } else if (discovery_filter) {
+ /* Client pre-setting his filter for first time */
+ client = g_new0(struct watch_client, 1);
+ client->adapter = adapter;
+ client->owner = g_strdup(sender);
+ client->discovery_filter = discovery_filter;
+ client->watch = g_dbus_add_disconnect_watch(dbus_conn, sender,
+ discovery_disconnect, client,
+ discovery_destroy);
+ adapter->set_filter_list = g_slist_prepend(
+ adapter->set_filter_list, client);
+
+ DBG("successfully pre-set filter");
+ }
+
+ return dbus_message_new_method_return(msg);
+}
+
static DBusMessage *stop_discovery(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
*/
g_dbus_remove_watch(dbus_conn, client->watch);
- /*
- * As long as other discovery clients are still active, just
- * return success.
- */
- if (adapter->discovery_list)
+ if (adapter->discovery_list) {
+ update_discovery_filter(adapter);
return dbus_message_new_method_return(msg);
+ }
/*
* In the idle phase of a discovery, there is no need to stop it
return TRUE;
}
+#ifdef __TIZEN_PATCH__
+static gboolean property_get_le_address(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct btd_adapter *adapter = user_data;
+ DBusMessageIter entry;
+ char addr[18];
+ const char *str = addr;
+ char *type = NULL;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &entry);
+
+ if (adapter->le_static_addr.b[5] != 0) {
+ ba2str(&adapter->le_static_addr, addr);
+ type = g_strdup_printf("%d", BDADDR_LE_RANDOM);
+ } else {
+ ba2str(&adapter->bdaddr, addr);
+ type = g_strdup_printf("%d", BDADDR_LE_PUBLIC);
+ }
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &type);
+ g_free((void *)type);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &str);
+
+ dbus_message_iter_close_container(iter, &entry);
+
+ return TRUE;
+}
+#endif
+
static gboolean property_get_name(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *user_data)
{
if (status != MGMT_STATUS_SUCCESS) {
const char *dbus_err;
- error("Failed to set mode: %s (0x%02x)",
+ btd_error(adapter->dev_id, "Failed to set mode: %s (0x%02x)",
mgmt_errstr(status), status);
if (status == MGMT_STATUS_RFKILLED)
g_free(data);
failed:
- error("Failed to set mode for index %u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to set mode for index %u",
+ adapter->dev_id);
g_dbus_pending_property_error(id, ERROR_INTERFACE ".Failed", NULL);
}
val = g_strdup_printf("%d", value);
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &val);
- free((void *)str);
- free((void *)val);
+ g_free((void *)str);
+ g_free((void *)val);
}
value = adapter_le_is_supported_offloading();
val = g_strdup_printf("%d", value);
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &val);
- free((void *)str);
- free((void *)val);
+ g_free((void *)str);
+ g_free((void *)val);
}
value = adapter_le_get_scan_filter_size();
val = g_strdup_printf("%d", value);
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &val);
- free((void *)str);
- free((void *)val);
+ g_free((void *)str);
+ g_free((void *)val);
}
dbus_message_iter_close_container(iter, &entry);
const gchar *address;
GSList *l;
const gchar *dev_path;
+ bdaddr_t rpa;
+ uint8_t msb = 0x00;
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
DBUS_TYPE_INVALID))
return btd_error_invalid_args(msg);
+ str2ba(address, &rpa);
+
l = g_slist_find_custom(adapter->devices,
address, (GCompareFunc) device_address_cmp);
+
+ if (!l) {
+ msb = rpa.b[5] >> 6;
+
+ /* Check whether address is RPA */
+ if (msb == 0x00 || msb == 0x01)
+ l = g_slist_find_custom(adapter->devices,
+ address, (GCompareFunc) device_rpa_cmp);
+ }
+
if (!l)
- return btd_error_does_not_exist(msg);
+ return btd_error_does_not_exist(msg);
device = l->data;
static const GDBusMethodTable adapter_methods[] = {
{ GDBUS_METHOD("StartDiscovery", NULL, NULL, start_discovery) },
+ { GDBUS_METHOD("SetDiscoveryFilter",
+ GDBUS_ARGS({ "properties", "a{sv}" }), NULL,
+ set_discovery_filter) },
{ GDBUS_METHOD("StopDiscovery", NULL, NULL, stop_discovery) },
#ifdef __TIZEN_PATCH__
{ GDBUS_METHOD("StartCustomDiscovery",
{ GDBUS_METHOD("SetLePrivacy",
GDBUS_ARGS({ "enable", "b" }), NULL,
adapter_set_le_privacy) },
+ { GDBUS_METHOD("SetLeStaticRandomAddress",
+ GDBUS_ARGS({ "enable", "b" }), NULL,
+ adapter_set_le_static_address) },
{ GDBUS_ASYNC_METHOD("EnableRssi",
GDBUS_ARGS({ "bt_address", "s" },
{ "link_type", "i" },
{ "Version", "s", property_get_version },
{ "SupportedLEFeatures", "as", property_get_supported_le_features},
{ "IpspInitStateChanged", "b", property_get_ipsp_init_state},
+ { "LEAddress", "as", property_get_le_address },
#endif
{ }
char *str;
str = g_key_file_get_string(key_file, "IdentityResolvingKey", "Key", NULL);
+#ifdef __TIZEN_PATCH__
+ if (!str)
+ return NULL;
+ if (strlen(str) < 32) {
+ g_free(str);
+ return NULL;
+ }
+#else
if (!str || strlen(str) < 32)
return NULL;
-
+#endif
irk = g_new0(struct irk_info, 1);
str2ba(peer, &irk->bdaddr);
struct btd_adapter *adapter = user_data;
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to load link keys for hci%u: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Failed to load link keys for hci%u: %s (0x%02x)",
adapter->dev_id, mgmt_errstr(status), status);
return;
}
cp = g_try_malloc0(cp_size);
if (cp == NULL) {
- error("No memory for link keys for hci%u", adapter->dev_id);
+ btd_error(adapter->dev_id, "No memory for link keys for hci%u",
+ adapter->dev_id);
return;
}
g_free(cp);
if (id == 0)
- error("Failed to load link keys for hci%u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to load link keys for hci%u",
+ adapter->dev_id);
}
static gboolean load_ltks_timeout(gpointer user_data)
{
struct btd_adapter *adapter = user_data;
- error("Loading LTKs timed out for hci%u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Loading LTKs timed out for hci%u",
+ adapter->dev_id);
adapter->load_ltks_timeout = 0;
struct btd_adapter *adapter = user_data;
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to load LTKs for hci%u: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Failed to load LTKs for hci%u: %s (0x%02x)",
adapter->dev_id, mgmt_errstr(status), status);
}
cp = g_try_malloc0(cp_size);
if (cp == NULL) {
- error("No memory for LTKs for hci%u", adapter->dev_id);
+ btd_error(adapter->dev_id, "No memory for LTKs for hci%u",
+ adapter->dev_id);
return;
}
g_free(cp);
if (adapter->load_ltks_id == 0) {
- error("Failed to load LTKs for hci%u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to load LTKs for hci%u",
+ adapter->dev_id);
return;
}
struct btd_adapter *adapter = user_data;
if (status == MGMT_STATUS_UNKNOWN_COMMAND) {
- info("Load IRKs failed: Kernel doesn't support LE Privacy");
+ btd_info(adapter->dev_id,
+ "Load IRKs failed: Kernel doesn't support LE Privacy");
return;
}
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to load IRKs for hci%u: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Failed to load IRKs for hci%u: %s (0x%02x)",
adapter->dev_id, mgmt_errstr(status), status);
return;
}
cp = g_try_malloc0(cp_size);
if (cp == NULL) {
- error("No memory for IRKs for hci%u", adapter->dev_id);
+ btd_error(adapter->dev_id, "No memory for IRKs for hci%u",
+ adapter->dev_id);
return;
}
g_free(cp);
if (id == 0)
- error("Failed to IRKs for hci%u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to IRKs for hci%u",
+ adapter->dev_id);
}
static void load_conn_params_complete(uint8_t status, uint16_t length,
struct btd_adapter *adapter = user_data;
if (status != MGMT_STATUS_SUCCESS) {
- error("hci%u Load Connection Parameters failed: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "hci%u Load Connection Parameters failed: %s (0x%02x)",
adapter->dev_id, mgmt_errstr(status), status);
return;
}
cp = g_try_malloc0(cp_size);
if (cp == NULL) {
- error("Failed to allocate memory for connection parameters");
+ btd_error(adapter->dev_id,
+ "Failed to allocate memory for connection parameters");
return;
}
g_free(cp);
if (id == 0)
- error("Load connection parameters failed");
+ btd_error(adapter->dev_id, "Load connection parameters failed");
}
static uint8_t get_le_addr_type(GKeyFile *keyfile)
return addr_type;
}
+static void probe_devices(void *user_data)
+{
+ struct btd_device *device = user_data;
+
+ device_probe_profiles(device, btd_device_get_uuids(device));
+}
+
static void load_devices(struct btd_adapter *adapter)
{
char dirname[PATH_MAX];
GSList *ltks = NULL;
GSList *irks = NULL;
GSList *params = NULL;
+ GSList *added_devices = NULL;
DIR *dir;
struct dirent *entry;
dir = opendir(dirname);
if (!dir) {
- error("Unable to open adapter storage directory: %s", dirname);
+ btd_error(adapter->dev_id,
+ "Unable to open adapter storage directory: %s",
+ dirname);
return;
}
struct btd_device *device;
char filename[PATH_MAX];
GKeyFile *key_file;
+#ifdef __TIZEN_PATCH__
+ struct link_key_info *key_info = NULL;
+ GSList *list, *ltk_info = NULL;
+#else
struct link_key_info *key_info;
GSList *list, *ltk_info;
+#endif
struct irk_info *irk_info;
struct conn_param *param;
uint8_t bdaddr_type;
if (entry->d_type != DT_DIR || bachk(entry->d_name) < 0)
continue;
+#ifdef __TIZEN_PATCH__
+{
+ bdaddr_t bdaddr;
+
+ str2ba(entry->d_name, &bdaddr);
+
+ if (!bacmp(&bdaddr, BDADDR_ANY)) {
+ error("No Bluetooth address");
+ continue;
+ }
+}
+#endif
snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", srcaddr,
entry->d_name);
if (!device)
goto free;
+#ifdef __TIZEN_PATCH__
+{
+ char irk_addr[18];
+
+ /* After load IRK information from file, store it into device->bdaddr
+ RPA is stored in device->rpa_addr */
+ ba2str(device_get_address(device), irk_addr);
+
+ DBG("irk address: %s, rpa_exist %d", irk_addr, device_get_rpa_exist(device));
+
+ if (device_get_rpa_exist(device) == true) {
+ if (key_info)
+ str2ba(irk_addr, &key_info->bdaddr);
+
+ if (ltk_info) {
+ ltks = g_slist_remove(ltks, ltk_info);
+ ltk_info = get_ltk_info(key_file, irk_addr, bdaddr_type);
+ ltks = g_slist_concat(ltks, ltk_info);
+ }
+
+ if (irk_info) {
+ str2ba(irk_addr, &irk_info->bdaddr);
+ device_set_irk_value(device, irk_info->val);
+ }
+
+ if (param)
+ str2ba(irk_addr, ¶m->bdaddr);
+ }
+}
+#endif
+
btd_device_set_temporary(device, false);
adapter->devices = g_slist_append(adapter->devices, device);
/* TODO: register services from pre-loaded list of primaries */
- list = btd_device_get_uuids(device);
- if (list)
- device_probe_profiles(device, list);
+ added_devices = g_slist_append(added_devices, device);
device_exist:
if (key_info) {
load_conn_params(adapter, params);
g_slist_free_full(params, g_free);
+ g_slist_free_full(added_devices, probe_devices);
+
#ifdef __TIZEN_PATCH__
load_devices_rpa_res_support(adapter);
#endif
err = driver->probe(adapter);
if (err < 0) {
- error("%s: %s (%d)", driver->name, strerror(-err), -err);
+ btd_error(adapter->dev_id, "%s: %s (%d)", driver->name,
+ strerror(-err), -err);
return;
}
err = profile->adapter_probe(profile, adapter);
if (err < 0) {
- error("%s: %s (%d)", profile->name, strerror(-err), -err);
+ btd_error(adapter->dev_id, "%s: %s (%d)", profile->name,
+ strerror(-err), -err);
return;
}
device_add_connection(device, bdaddr_type);
if (g_slist_find(adapter->connections, device)) {
- error("Device is already marked as connected");
+ btd_error(adapter->dev_id,
+ "Device is already marked as connected");
return;
}
uint16_t i, conn_count;
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to get connections: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Failed to get connections: %s (0x%02x)",
mgmt_errstr(status), status);
return;
}
if (length < sizeof(*rp)) {
- error("Wrong size of get connections response");
+ btd_error(adapter->dev_id,
+ "Wrong size of get connections response");
return;
}
if (conn_count * sizeof(struct mgmt_addr_info) +
sizeof(*rp) != length) {
- error("Incorrect packet size for get connections response");
+ btd_error(adapter->dev_id,
+ "Incorrect packet size for get connections response");
return;
}
get_connections_complete, adapter, NULL) > 0)
return;
- error("Failed to get connections for index %u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to get connections for index %u",
+ adapter->dev_id);
}
bool btd_adapter_get_pairable(struct btd_adapter *adapter)
}
if (!(adapter->supported_settings & MGMT_SETTING_LE)) {
- error("Can't add %s to non-LE capable adapter connect list",
+ btd_error(adapter->dev_id,
+ "Can't add %s to non-LE capable adapter connect list",
device_get_path(device));
return -ENOTSUP;
}
char addr[18];
if (length < sizeof(*rp)) {
- error("Too small Add Device complete event");
+ btd_error(adapter->dev_id,
+ "Too small Add Device complete event");
return;
}
dev = btd_adapter_find_device(adapter, &rp->addr.bdaddr,
rp->addr.type);
if (!dev) {
- error("Add Device complete for unknown device %s", addr);
+ btd_error(adapter->dev_id,
+ "Add Device complete for unknown device %s", addr);
return;
}
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to add device %s: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Failed to add device %s: %s (0x%02x)",
addr, mgmt_errstr(status), status);
return;
}
char addr[18];
if (length < sizeof(*rp)) {
- error("Too small Add Device complete event");
+ btd_error(adapter->dev_id,
+ "Too small Add Device complete event");
return;
}
dev = btd_adapter_find_device(adapter, &rp->addr.bdaddr,
rp->addr.type);
if (!dev) {
- error("Add Device complete for unknown device %s", addr);
+ btd_error(adapter->dev_id,
+ "Add Device complete for unknown device %s", addr);
return;
}
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to add device %s (%u): %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Failed to add device %s (%u): %s (0x%02x)",
addr, rp->addr.type, mgmt_errstr(status), status);
adapter->connect_list = g_slist_remove(adapter->connect_list,
dev);
static void adapter_start(struct btd_adapter *adapter)
{
-#ifdef __TIZEN_PATCH__
+#if defined(__TIZEN_PATCH__) && !defined(__SPRD_PATCH__)
if (adapter_le_read_ble_feature_info())
g_dbus_emit_property_changed(dbus_conn, adapter->path,
ADAPTER_INTERFACE, "SupportedLEFeatures");
adapter_get_adv_tx_power(adapter);
+
+ /* By default enable offloading for testing, this should be modified */
+ if (adapter_le_is_supported_offloading())
+ adapter_le_enable_offloading(TRUE);
#endif
+#ifndef __TIZEN_PATCH__
g_dbus_emit_property_changed(dbus_conn, adapter->path,
ADAPTER_INTERFACE, "Powered");
+#else
+ g_dbus_emit_property_changed_full(dbus_conn, adapter->path,
+ ADAPTER_INTERFACE, "Powered", 1);
+#endif
DBG("adapter %s has been enabled", adapter->path);
static struct btd_adapter *btd_adapter_new(uint16_t index)
{
struct btd_adapter *adapter;
+#ifdef __TIZEN_PATCH__
+#ifdef TIZEN_WEARABLE
+ DBusConnection *conn = btd_get_dbus_connection();
+ DBusMessage *msg = NULL;
+ DBusMessage *reply = NULL;
+ int charging_state = 0;
+#endif /* TIZEN_WEARABLE */
+#endif
adapter = g_try_new0(struct btd_adapter, 1);
if (!adapter)
#endif
adapter->auths = g_queue_new();
+#ifdef __TIZEN_PATCH__
+#ifdef TIZEN_WEARABLE
+ adapter->charging_watch = g_dbus_add_signal_watch(conn, DEVICED_DEST,
+ DEVICED_BATT_OBJECT_PATH,
+ DEVICED_BATT_INTERFACE, "ChargerType",
+ charging_state_changed, adapter, NULL);
+ if (adapter->charging_watch == 0)
+ error("Cannot add signal watch for ChargerType");
+
+ msg = dbus_message_new_method_call(DEVICED_DEST,
+ DEVICED_BATT_OBJECT_PATH,
+ DEVICED_BATT_INTERFACE, "ChargerType");
+ if (msg) {
+ reply = dbus_connection_send_with_reply_and_block(conn,
+ msg, 1000, NULL);
+ if (reply) {
+ if (dbus_message_get_args(reply, NULL,
+ DBUS_TYPE_INT32, &charging_state,
+ DBUS_TYPE_INVALID) == TRUE) {
+ set_charging_state(adapter, charging_state);
+ }
+ dbus_message_unref(reply);
+ } else {
+ error("Reply is NULL");
+ }
+ dbus_message_unref(msg);
+ } else {
+ error("Unable to create dbus message for charging state");
+ }
+#endif /* TIZEN_WEARABLE */
+#endif
+
return btd_adapter_ref(adapter);
}
DBG("Removing adapter %s", adapter->path);
+#ifdef __TIZEN_PATCH__
+#ifdef TIZEN_WEARABLE
+ if (adapter->charging_watch > 0) {
+ g_dbus_remove_watch(btd_get_dbus_connection(),
+ adapter->charging_watch);
+ adapter->charging_watch = 0;
+ }
+
+ if (adapter->charging_timeout) {
+ g_source_remove(adapter->charging_timeout);
+ adapter->charging_timeout = 0;
+ }
+#endif /* TIZEN_WEARABLE */
+#endif
+
if (adapter->discovery_idle_timeout > 0) {
g_source_remove(adapter->discovery_idle_timeout);
adapter->discovery_idle_timeout = 0;
{
struct btd_adapter *adapter = user_data;
- error("Confirm name timed out for hci%u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Confirm name timed out for hci%u",
+ adapter->dev_id);
adapter->confirm_name_timeout = 0;
struct btd_adapter *adapter = user_data;
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to confirm name for hci%u: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Failed to confirm name for hci%u: %s (0x%02x)",
adapter->dev_id, mgmt_errstr(status), status);
}
* cancel it to be safe here.
*/
if (adapter->confirm_name_id > 0) {
- warn("Found pending confirm name for hci%u", adapter->dev_id);
+ btd_warn(adapter->dev_id,
+ "Found pending confirm name for hci%u",
+ adapter->dev_id);
mgmt_cancel(adapter->mgmt, adapter->confirm_name_id);
}
confirm_name_complete, adapter, NULL);
if (adapter->confirm_name_id == 0) {
- error("Failed to confirm name for hci%u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to confirm name for hci%u",
+ adapter->dev_id);
return;
}
}
}
+static bool is_filter_match(GSList *discovery_filter, struct eir_data *eir_data,
+ int8_t rssi)
+{
+ GSList *l, *m;
+ bool got_match = false;
+
+ for (l = discovery_filter; l != NULL && got_match != true;
+ l = g_slist_next(l)) {
+ struct watch_client *client = l->data;
+ struct discovery_filter *item = client->discovery_filter;
+
+ /*
+ * If one of currently running scans is regular scan, then
+ * return all devices as matches
+ */
+ if (!item) {
+ got_match = true;
+ continue;
+ }
+
+ /* if someone started discovery with empty uuids, he wants all
+ * devices in given proximity.
+ */
+ if (!item->uuids)
+ got_match = true;
+ else {
+ for (m = item->uuids; m != NULL && got_match != true;
+ m = g_slist_next(m)) {
+ /* m->data contains string representation of
+ * uuid.
+ */
+ if (g_slist_find_custom(eir_data->services,
+ m->data,
+ g_strcmp) != NULL)
+ got_match = true;
+ }
+ }
+
+ if (got_match) {
+ /* we have service match, check proximity */
+ if (item->rssi == DISTANCE_VAL_INVALID ||
+ item->rssi <= rssi ||
+ item->pathloss == DISTANCE_VAL_INVALID ||
+ (eir_data->tx_power != 127 &&
+ eir_data->tx_power - rssi <= item->pathloss))
+ return true;
+
+ got_match = false;
+ }
+ }
+
+ return got_match;
+}
+
#ifdef __TIZEN_PATCH__
static void update_found_devices(struct btd_adapter *adapter,
const bdaddr_t *bdaddr,
const bdaddr_t *bdaddr,
uint8_t bdaddr_type, int8_t rssi,
bool confirm, bool legacy,
+ bool not_connectable,
const uint8_t *data, uint8_t data_len)
#endif
{
}
if (!dev) {
- error("Unable to create object for found device %s", addr);
+ btd_error(adapter->dev_id,
+ "Unable to create object for found device %s", addr);
eir_data_free(&eir_data);
return;
}
+#ifdef __TIZEN_PATCH__
+ if(device_get_rpa_exist(dev) == true)
+ bdaddr_type = BDADDR_LE_RANDOM;
+#endif
+
device_update_last_seen(dev, bdaddr_type);
/*
}
#endif
+#ifdef __TIZEN_PATCH__
+ if (bdaddr_type == BDADDR_BREDR) {
+#endif
+ if (adapter->filtered_discovery &&
+ !is_filter_match(adapter->discovery_list, &eir_data, rssi)) {
+ eir_data_free(&eir_data);
+ return;
+ }
+
device_set_legacy(dev, legacy);
- device_set_rssi(dev, rssi);
+
+ if (adapter->filtered_discovery)
+ device_set_rssi_with_delta(dev, rssi, 0);
+ else
+ device_set_rssi(dev, rssi);
+
+ if (eir_data.tx_power != 127)
+ device_set_tx_power(dev, eir_data.tx_power);
+#ifdef __TIZEN_PATCH__
+ }
+#endif
if (eir_data.appearance != 0)
device_set_appearance(dev, eir_data.appearance);
/* Report an unknown name to the kernel even if there is a short name
* known, but still update the name with the known short name. */
- name_known = device_name_known(dev);
-
- if (eir_data.name && (eir_data.name_complete || !name_known))
- btd_device_device_set_name(dev, eir_data.name);
-
#ifdef __TIZEN_PATCH__
- /* As this logic, (eir_data.name_complete || !name_known) is always true.
- So some abnormal UI bug occurs. Such like complete name display and
- next time short name display.
- */
if (eir_data.name_complete)
name_known = device_name_known(dev);
else
name_known = false;
+#else
+ name_known = device_name_known(dev);
#endif
+ if (eir_data.name && (eir_data.name_complete || !name_known))
+ btd_device_device_set_name(dev, eir_data.name);
+
if (eir_data.class != 0)
device_set_class(dev, eir_data.class);
if (bdaddr_type == BDADDR_BREDR)
device_set_manufacturer_info(dev, &eir_data);
else
- device_set_adv_report_info(dev, (void*)data, data_len, adv_type);
+ device_set_adv_report_info(dev, (void*)data, data_len, adv_type, rssi);
#endif
- if (eir_data.msd_list)
+ if (eir_data.msd_list) {
+ device_set_manufacturer_data(dev, eir_data.msd_list);
adapter_msd_notify(adapter, dev, eir_data.msd_list);
+ }
+
+ if (eir_data.sd_list)
+ device_set_service_data(dev, eir_data.sd_list);
eir_data_free(&eir_data);
return;
connect_le:
+#ifndef __TIZEN_PATCH__
+ /* Ignore non-connectable events */
+ if (not_connectable)
+ return;
+#endif
+
/*
* If we're in the process of stopping passive scanning and
* connecting another (or maybe even the same) LE device just
char addr[18];
if (length < sizeof(*ev)) {
- error("Too short device found event (%u bytes)", length);
+ btd_error(adapter->dev_id,
+ "Too short device found event (%u bytes)", length);
return;
}
eir_len = btohs(ev->eir_len);
if (length != sizeof(*ev) + eir_len) {
- error("Device found event size mismatch (%u != %zu)",
+ btd_error(adapter->dev_id,
+ "Device found event size mismatch (%u != %zu)",
length, sizeof(*ev) + eir_len);
return;
}
DBG("hci%u addr %s, rssi %d flags 0x%04x eir_len %u",
index, addr, ev->rssi, flags, eir_len);
-#ifndef __TIZEN_PATCH__
- /* Ignore non-connectable events for now */
- if (flags & MGMT_DEV_FOUND_NOT_CONNECTABLE)
- return;
-#endif
-
confirm_name = (flags & MGMT_DEV_FOUND_CONFIRM_NAME);
legacy = (flags & MGMT_DEV_FOUND_LEGACY_PAIRING);
#else
update_found_devices(adapter, &ev->addr.bdaddr, ev->addr.type,
ev->rssi, confirm_name, legacy,
+ flags & MGMT_DEV_FOUND_NOT_CONNECTABLE,
eir, eir_len);
#endif
}
flags = btohl(ev->flags);
ba2str(&ev->addr.bdaddr, addr);
- DBG("hci%u addr %s, rssi %d flags 0x%04x eir_len %u",
- index, addr, ev->rssi, flags, eir_len);
+ /*DBG("hci%u addr %s, rssi %d flags 0x%04x eir_len %u",
+ index, addr, ev->rssi, flags, eir_len);*/
confirm_name = (flags & MGMT_DEV_FOUND_CONFIRM_NAME);
legacy = (flags & MGMT_DEV_FOUND_LEGACY_PAIRING);
DBG("");
if (!g_slist_find(adapter->connections, device)) {
- error("No matching connection for device");
+ btd_error(adapter->dev_id, "No matching connection for device");
return;
}
device_remove_connection(device, bdaddr_type);
+#ifdef __TIZEN_PATCH__
+ if (device_is_authenticating(device, bdaddr_type))
+#else
if (device_is_authenticating(device))
+#endif
device_cancel_authentication(device, TRUE);
/* If another bearer is still connected */
cancel_passive_scanning(adapter);
- while (adapter->discovery_list) {
+ while (adapter->set_filter_list) {
struct watch_client *client;
- client = adapter->discovery_list->data;
+ client = adapter->set_filter_list->data;
/* g_dbus_remove_watch will remove the client from the
* adapter's list and free it using the discovery_destroy
g_dbus_remove_watch(dbus_conn, client->watch);
}
- adapter->discovering = false;
-
-#ifdef __TIZEN_PATCH__
- while (adapter->le_discovery_list) {
+ while (adapter->discovery_list) {
struct watch_client *client;
- client = adapter->le_discovery_list->data;
+ client = adapter->discovery_list->data;
/* g_dbus_remove_watch will remove the client from the
* adapter's list and free it using the discovery_destroy
g_dbus_remove_watch(dbus_conn, client->watch);
}
- adapter->le_discovering = false;
-#endif
+ adapter->filtered_discovery = false;
+ adapter->no_scan_restart_delay = false;
+ g_free(adapter->current_discovery_filter);
+ adapter->current_discovery_filter = NULL;
+
+ adapter->discovering = false;
while (adapter->connections) {
struct btd_device *device = adapter->connections->data;
const char *dev_path;
/* Wait services to be resolved before asking authorization */
- if (auth->svc_id > 0)
+ if (auth->svc_id > 0) {
+#ifdef __TIZEN_PATCH__
+ DBG("Wait services to be resolved before asking authorization");
+#endif
return FALSE;
+ }
+#ifndef __TIZEN_PATCH__
if (device_is_trusted(device) == TRUE) {
+#else
+ if (device_is_trusted(device) == TRUE ||
+ device_is_profile_trusted(device, auth->uuid)) {
+#endif
auth->cb(NULL, auth->user_data);
goto next;
}
+#ifdef __TIZEN_PATCH__
+ /* If Profile is Blocked, Simply reject Authorization*/
+ if (device_is_profile_blocked(device, auth->uuid) == TRUE) {
+ auth->cb(&err, auth->user_data);
+ goto next;
+ }
+#endif
+
/* If agent is set authorization is already ongoing */
if (auth->agent)
return FALSE;
auth->agent = agent_get(NULL);
if (auth->agent == NULL) {
- warn("Authentication attempt without agent");
+ btd_warn(adapter->dev_id,
+ "Authentication attempt without agent");
auth->cb(&err, auth->user_data);
goto next;
}
if (!device)
return 0;
+ if (device_is_disconnecting(device)) {
+ DBG("Authorization request while disconnecting");
+ return 0;
+ }
+
/* Device connected? */
if (!g_slist_find(adapter->connections, device))
- error("Authorization request for non-connected device!?");
+ btd_error(adapter->dev_id,
+ "Authorization request for non-connected device!?");
auth = g_try_new0(struct service_auth, 1);
if (!auth)
int err;
if (length < sizeof(*ev)) {
- error("Too small user confirm request event");
+ btd_error(adapter->dev_id,
+ "Too small user confirm request event");
return;
}
device = btd_adapter_get_device(adapter, &ev->addr.bdaddr,
ev->addr.type);
if (!device) {
- error("Unable to get device object for %s", addr);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", addr);
return;
}
+#ifdef __TIZEN_PATCH__
+ device_set_auth_addr_type(device, ev->addr.type);
+#endif
+
err = device_confirm_passkey(device, btohl(ev->value),
ev->confirm_hint);
if (err < 0) {
- error("device_confirm_passkey: %s", strerror(-err));
+ btd_error(adapter->dev_id,
+ "device_confirm_passkey: %s", strerror(-err));
btd_adapter_confirm_reply(adapter, &ev->addr.bdaddr,
ev->addr.type, FALSE);
}
int err;
if (length < sizeof(*ev)) {
- error("Too small passkey request event");
+ btd_error(adapter->dev_id, "Too small passkey request event");
return;
}
device = btd_adapter_get_device(adapter, &ev->addr.bdaddr,
ev->addr.type);
if (!device) {
- error("Unable to get device object for %s", addr);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", addr);
return;
}
+#ifdef __TIZEN_PATCH__
+ device_set_auth_addr_type(device, ev->addr.type);
+#endif
+
err = device_request_passkey(device);
if (err < 0) {
- error("device_request_passkey: %s", strerror(-err));
+ btd_error(adapter->dev_id,
+ "device_request_passkey: %s", strerror(-err));
btd_adapter_passkey_reply(adapter, &ev->addr.bdaddr,
ev->addr.type, INVALID_PASSKEY);
}
int err;
if (length < sizeof(*ev)) {
- error("Too small passkey notify event");
+ btd_error(adapter->dev_id, "Too small passkey notify event");
return;
}
device = btd_adapter_get_device(adapter, &ev->addr.bdaddr,
ev->addr.type);
if (!device) {
- error("Unable to get device object for %s", addr);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", addr);
return;
}
err = device_notify_passkey(device, passkey, ev->entered);
if (err < 0)
- error("device_notify_passkey: %s", strerror(-err));
+ btd_error(adapter->dev_id,
+ "device_notify_passkey: %s", strerror(-err));
}
#ifdef __TIZEN_PATCH__
gboolean connected = 0;
if (length < sizeof(*ev)) {
- error("Too small device connected event");
+ btd_error(adapter->dev_id,
+ "Too small device connected event");
return;
}
device = btd_adapter_find_device(adapter, &ev->addr.bdaddr,
ev->addr.type);
if (!device) {
- error("Unable to get device object for %s", addr);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", addr);
return;
}
char addr[18];
if (length < sizeof(*ev)) {
- error("Too small data length changed event");
+ btd_error(adapter->dev_id,
+ "Too small data length changed event");
return;
}
device = btd_adapter_find_device(adapter, &ev->addr.bdaddr,
ev->addr.type);
if (!device) {
- error("Unable to get device object for %s", addr);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", addr);
return;
}
device_le_data_length_changed(device, ev->max_tx_octets, ev->max_tx_time,
ev->max_rx_octets, ev->max_rx_time);
}
+
+static void le_conn_update_completed_callback(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ const struct mgmt_ev_conn_updated *ev = param;
+ struct btd_adapter *adapter = user_data;
+ struct btd_device *device;
+ char addr[18];
+ GSList *list;
+
+ if (length < sizeof(*ev)) {
+ error("Too small le conn update completed event");
+ return;
+ }
+
+ ba2str(&ev->addr.bdaddr, addr);
+ list = g_slist_find_custom(adapter->devices, addr,
+ device_address_cmp);
+ if (list) {
+ device = list->data;
+ if (device_get_conn_update_state(device))
+ device_set_conn_update_state(device, false);
+ }
+}
#endif
struct btd_adapter_pin_cb_iter *btd_adapter_pin_cb_iter_new(
struct btd_adapter_pin_cb_iter *iter;
if (length < sizeof(*ev)) {
- error("Too small PIN code request event");
+ btd_error(adapter->dev_id, "Too small PIN code request event");
return;
}
device = btd_adapter_get_device(adapter, &ev->addr.bdaddr,
ev->addr.type);
if (!device) {
- error("Unable to get device object for %s", addr);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", addr);
return;
}
if (display && device_is_bonding(device, NULL)) {
err = device_notify_pincode(device, ev->secure, pin);
if (err < 0) {
- error("device_notify_pin: %s", strerror(-err));
+ btd_error(adapter->dev_id,
+ "device_notify_pin: %s",
+ strerror(-err));
btd_adapter_pincode_reply(adapter,
&ev->addr.bdaddr,
NULL, 0);
err = device_request_pincode(device, ev->secure);
if (err < 0) {
- error("device_request_pin: %s", strerror(-err));
+ btd_error(adapter->dev_id, "device_request_pin: %s",
+ strerror(-err));
btd_adapter_pincode_reply(adapter, &ev->addr.bdaddr, NULL, 0);
}
}
struct pair_device_data *data = user_data;
struct btd_adapter *adapter = data->adapter;
- error("Pair device timed out for hci%u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Pair device timed out for hci%u",
+ adapter->dev_id);
adapter->pair_device_timeout = 0;
* powered.
*/
if (status != MGMT_STATUS_SUCCESS && length < sizeof(*rp)) {
- error("Pair device failed: %s (0x%02x)",
+ btd_error(adapter->dev_id, "Pair device failed: %s (0x%02x)",
mgmt_errstr(status), status);
bonding_attempt_complete(adapter, &data->bdaddr,
}
if (length < sizeof(*rp)) {
- error("Too small pair device response");
+ btd_error(adapter->dev_id, "Too small pair device response");
return;
}
uint8_t addr_type, uint8_t io_cap)
{
if (adapter->pair_device_id > 0) {
- error("Unable pair since another pairing is in progress");
+ btd_error(adapter->dev_id,
+ "Unable pair since another pairing is in progress");
return -EBUSY;
}
free_pair_device_data);
if (id == 0) {
- error("Failed to pair %s for hci%u", addr, adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to pair %s for hci%u",
+ addr, adapter->dev_id);
free_pair_device_data(data);
return -EIO;
}
struct btd_adapter *adapter = user_data;
if (status == MGMT_STATUS_NOT_CONNECTED) {
- warn("Disconnecting failed: already disconnected");
+ btd_warn(adapter->dev_id,
+ "Disconnecting failed: already disconnected");
} else if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to disconnect device: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Failed to disconnect device: %s (0x%02x)",
mgmt_errstr(status), status);
return;
}
if (length < sizeof(*rp)) {
- error("Too small device disconnect response");
+ btd_error(adapter->dev_id,
+ "Too small device disconnect response");
return;
}
+#ifdef __TIZEN_PATCH__
+ /* Use HCI error code instead of MGMT disconnection reason */
+ dev_disconnected(adapter, &rp->addr, 0x16);
+#else
dev_disconnected(adapter, &rp->addr, MGMT_DEV_DISCONN_LOCAL_HOST);
+#endif
}
int btd_adapter_disconnect_device(struct btd_adapter *adapter,
struct btd_adapter *adapter = user_data;
if (length < sizeof(*ev)) {
- error("Too small auth failed mgmt event");
+ btd_error(adapter->dev_id, "Too small auth failed mgmt event");
return;
}
ba2str(btd_adapter_get_address(adapter), adapter_addr);
ba2str(device_get_address(device), device_addr);
+#ifdef __TIZEN_PATCH__
+ if (device_get_rpa_exist(device) == true)
+ ba2str(device_get_rpa(device), device_addr);
+#endif
+
snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", adapter_addr,
device_addr);
key_file = g_key_file_new();
g_key_file_free(key_file);
}
+#ifdef __TIZEN_PATCH__
+static struct link_key_info *load_link_key(struct btd_adapter *adapter,
+ const char *peer)
+{
+ struct link_key_info *key_info;
+ GKeyFile *key_file;
+ char filename[PATH_MAX];
+ char srcaddr[18];
+
+ ba2str(&adapter->bdaddr, srcaddr);
+
+ snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", srcaddr, peer);
+
+ key_file = g_key_file_new();
+ g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+ key_info = get_key_info(key_file, peer);
+
+ return key_info;
+}
+#endif
+
static void new_link_key_callback(uint16_t index, uint16_t length,
const void *param, void *user_data)
{
char dst[18];
if (length < sizeof(*ev)) {
- error("Too small new link key event");
+ btd_error(adapter->dev_id, "Too small new link key event");
return;
}
ba2str(&addr->bdaddr, dst);
- DBG("hci%u new key for %s type %u pin_len %u", adapter->dev_id,
- dst, ev->key.type, ev->key.pin_len);
+ DBG("hci%u new key for %s type %u pin_len %u store_hint %u",
+ adapter->dev_id, dst, ev->key.type, ev->key.pin_len,
+ ev->store_hint);
if (ev->key.pin_len > 16) {
- error("Invalid PIN length (%u) in new_key event",
+ btd_error(adapter->dev_id,
+ "Invalid PIN length (%u) in new_key event",
ev->key.pin_len);
return;
}
device = btd_adapter_get_device(adapter, &addr->bdaddr, addr->type);
if (!device) {
- error("Unable to get device object for %s", dst);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", dst);
return;
}
key->pin_len);
device_set_bonded(device, BDADDR_BREDR);
+#if defined(__TIZEN_PATCH__) && defined(SUPPORT_LOCAL_DEVICE_A2DP_SINK)
+ } else {
+ DBG("store_hint %d", ev->store_hint);
+ btd_device_set_temporary(device, false);
+ }
+#else
+ }
+#endif
+
+ /* If BR/EDR linkkey exists in previous, update the linkkey into RPA based folder info */
+#ifdef __TIZEN_PATCH__
+ if (device_get_rpa_exist(device) == true) {
+ struct link_key_info *key_info;
+
+ key_info = load_link_key(adapter, dst);
+ if (key_info && key_info->type == 0x05) {
+ DBG("Replace linkkey!");
+
+ /* #define HCI_LK_AUTH_COMBINATION_P192 0x05
+ Replace the linkkey as the orginal one
+ */
+ store_link_key(adapter, device, key_info->key,
+ key_info->type, key_info->pin_len);
+
+ /* Delete irk based folder */
+ device_remove_stored_folder(device);
+ } else {
+ DBG("There is no original linkkey or type is not 0x05");
+ }
}
+#endif
bonding_complete(adapter, &addr->bdaddr, addr->type, 0);
}
char dst[18];
if (length < sizeof(*ev)) {
- error("Too small long term key event");
+ btd_error(adapter->dev_id, "Too small long term key event");
return;
}
device = btd_adapter_get_device(adapter, &addr->bdaddr, addr->type);
if (!device) {
- error("Unable to get device object for %s", dst);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", dst);
return;
}
ediv = le16_to_cpu(key->ediv);
rand = le64_to_cpu(key->rand);
+#ifdef __TIZEN_PATCH__
+ if (device_get_rpa_exist(device) == true) {
+ store_longtermkey(bdaddr, device_get_rpa(device),
+ key->addr.type, key->val, key->master,
+ key->type, key->enc_size, ediv, rand);
+ } else {
+ store_longtermkey(bdaddr, &key->addr.bdaddr,
+ key->addr.type, key->val, key->master,
+ key->type, key->enc_size, ediv, rand);
+ }
+#else
store_longtermkey(bdaddr, &key->addr.bdaddr,
key->addr.type, key->val, key->master,
key->type, key->enc_size, ediv, rand);
+#endif
device_set_bonded(device, addr->type);
}
char dst[18];
if (length < sizeof(*ev)) {
- error("Too small CSRK event");
+ btd_error(adapter->dev_id, "Too small CSRK event");
return;
}
device = btd_adapter_get_device(adapter, &addr->bdaddr, addr->type);
if (!device) {
- error("Unable to get device object for %s", dst);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", dst);
return;
}
char dst[18], rpa[18];
if (length < sizeof(*ev)) {
- error("Too small New IRK event");
+ btd_error(adapter->dev_id, "Too small New IRK event");
return;
}
DBG("hci%u new IRK for %s RPA %s", adapter->dev_id, dst, rpa);
if (bacmp(&ev->rpa, BDADDR_ANY)) {
+#ifdef __TIZEN_PATCH__
+ /*
+ * With new RPA, existing device can be found only when bonding is
+ * initiated from local side using remote RPA; so first find the device
+ * with RPA. If device is not found then find the device with IDA.
+ */
+
+ device = btd_adapter_find_device(adapter, &ev->rpa,
+ BDADDR_LE_RANDOM);
+ if (device == NULL)
+ device = btd_adapter_find_device(adapter, &addr->bdaddr,
+ addr->type);
+ if (device == NULL)
+ device = btd_adapter_get_device(adapter, &ev->rpa,
+ BDADDR_LE_RANDOM);
+#else
+
device = btd_adapter_get_device(adapter, &ev->rpa,
- BDADDR_LE_RANDOM);
+ BDADDR_LE_RANDOM);
+#endif
+
duplicate = btd_adapter_find_device(adapter, &addr->bdaddr,
addr->type);
if (duplicate == device)
}
if (!device) {
- error("Unable to get device object for %s", dst);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", dst);
return;
}
+#ifdef __TIZEN_PATCH__
+ if (bacmp(&ev->rpa, BDADDR_ANY) != 0) {
+ device_set_rpa(device, &ev->rpa);
+
+ if (duplicate)
+ device_set_rpa(duplicate, &ev->rpa);
+ }
+#endif
+
device_update_addr(device, &addr->bdaddr, addr->type);
+#ifdef __TIZEN_PATCH__
+ if (duplicate) {
+ device_merge_duplicate(device, duplicate);
+ device_set_irk_value(duplicate, irk->val);
+
+ /* If BR/EDR linkkey exists in previous, update the linkkey into RPA based folder info */
+ if (device_get_rpa_exist(device) == true) {
+ struct link_key_info *key_info;
+
+ key_info = load_link_key(adapter, dst);
+ if (key_info && key_info->type == 0x05) {
+ DBG("Add linkkey of BR/EDR");
+
+ /* #define HCI_LK_AUTH_COMBINATION_P192 0x05 */
+ store_link_key(adapter, device, key_info->key,
+ key_info->type, key_info->pin_len);
+
+ /* Delete IDA based folder */
+ device_remove_stored_folder(duplicate);
+ } else {
+ DBG("There is no original linkkey or type is not 0x05");
+ }
+ }
+ }
+#else
if (duplicate)
device_merge_duplicate(device, duplicate);
+#endif
persistent = !!ev->store_hint;
if (!persistent)
return;
+#ifdef __TIZEN_PATCH__
+ if (bacmp(&ev->rpa, BDADDR_ANY) != 0)
+ store_irk(adapter, device_get_rpa(device), addr->type, irk->val);
+ else
+ store_irk(adapter, &addr->bdaddr, addr->type, irk->val);
+
+ device_set_irk_value(device, irk->val);
+#else
store_irk(adapter, &addr->bdaddr, addr->type, irk->val);
+#endif
btd_device_set_temporary(device, false);
if (length < sizeof(*ev)) {
- error("Too small New Connection Parameter event");
+ btd_error(adapter->dev_id,
+ "Too small New Connection Parameter event");
return;
}
dev = btd_adapter_get_device(adapter, &ev->addr.bdaddr, ev->addr.type);
if (!dev) {
- error("Unable to get device object for %s", dst);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", dst);
return;
}
const uint8_t *hash, *randomizer;
if (status != MGMT_STATUS_SUCCESS) {
- error("Read local OOB data failed: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Read local OOB data failed: %s (0x%02x)",
mgmt_errstr(status), status);
hash = NULL;
randomizer = NULL;
-#ifndef __TIZEN_PATCH__
+#ifdef __TIZEN_PATCH__
+ } else if (length < 32) {
+#else
} else if (length < sizeof(*rp)) {
- error("Too small read local OOB data response");
- return;
#endif
+ btd_error(adapter->dev_id,
+ "Too small read local OOB data response");
+ return;
} else {
hash = rp->hash192;
randomizer = rp->rand192;
#endif
adapter_properties, adapter,
adapter_free)) {
- error("Adapter interface init failed on path %s",
+ btd_error(adapter->dev_id,
+ "Adapter interface init failed on path %s",
adapter->path);
g_free(adapter->path);
adapter->path = NULL;
adapter->database = btd_gatt_database_new(adapter);
if (!adapter->database) {
- error("Failed to create GATT database for adapter");
+ btd_error(adapter->dev_id,
+ "Failed to create GATT database for adapter");
adapters = g_slist_remove(adapters, adapter);
return -EINVAL;
}
+ if (g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL) {
+ /* Don't start advertising managers on non-LE controllers. */
+ if (adapter->supported_settings & MGMT_SETTING_LE) {
+ adapter->adv_manager =
+ btd_advertising_manager_new(adapter);
+ } else {
+ btd_info(adapter->dev_id,
+ "LEAdvertisingManager skipped, LE unavailable");
+ }
+ }
+
db = btd_gatt_database_get_db(adapter->database);
adapter->db_id = gatt_db_register(db, services_modified,
services_modified,
adapter, NULL);
-/* Disable Old GATT Server */
-#if 0
- btd_adapter_gatt_server_start(adapter);
-#endif
-
- /* Don't start advertising managers on non-LE controllers. */
- if (adapter->supported_settings & MGMT_SETTING_LE) {
- adapter->adv_manager = btd_advertising_manager_new(adapter);
-
- /* LEAdvertisingManager1 is experimental so optional */
- if (!adapter->adv_manager)
- error("Failed to register LEAdvertisingManager1 "
- "interface for adapter");
- } else {
- info("Not starting LEAdvertisingManager, LE not supported");
- }
load_config(adapter);
fix_storage(adapter);
load_drivers(adapter);
uint8_t reason;
if (length < sizeof(struct mgmt_addr_info)) {
- error("Too small device disconnected event");
+ btd_error(adapter->dev_id,
+ "Too small device disconnected event");
return;
}
bool name_known;
if (length < sizeof(*ev)) {
- error("Too small device connected event");
+ btd_error(adapter->dev_id, "Too small device connected event");
return;
}
eir_len = btohs(ev->eir_len);
if (length < sizeof(*ev) + eir_len) {
- error("Too small device connected event");
+ btd_error(adapter->dev_id, "Too small device connected event");
return;
}
device = btd_adapter_get_device(adapter, &ev->addr.bdaddr,
ev->addr.type);
if (!device) {
- error("Unable to get device object for %s", addr);
+ btd_error(adapter->dev_id,
+ "Unable to get device object for %s", addr);
return;
}
char addr[18];
if (length < sizeof(*ev)) {
- error("Too small device blocked event");
+ btd_error(adapter->dev_id, "Too small device blocked event");
return;
}
char addr[18];
if (length < sizeof(*ev)) {
- error("Too small device unblocked event");
+ btd_error(adapter->dev_id, "Too small device unblocked event");
return;
}
char addr[18];
if (length < sizeof(*ev)) {
- error("Too small connect failed event");
+ btd_error(adapter->dev_id, "Too small connect failed event");
return;
}
ba2str(btd_adapter_get_address(adapter), adapter_addr);
ba2str(device_get_address(device), device_addr);
+#ifdef __TIZEN_PATCH__
+ if (device_get_rpa_exist(device) == true)
+ ba2str(device_get_rpa(device), device_addr);
+#endif
+
snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", adapter_addr,
device_addr);
key_file = g_key_file_new();
char addr[18];
if (length < sizeof(*ev)) {
- error("Too small device unpaired event");
+ btd_error(adapter->dev_id, "Too small device unpaired event");
return;
}
device = btd_adapter_find_device(adapter, &ev->addr.bdaddr,
ev->addr.type);
if (!device) {
- warn("No device object for unpaired device %s", addr);
+ btd_warn(adapter->dev_id,
+ "No device object for unpaired device %s", addr);
return;
}
clear_devices_complete, adapter, NULL) > 0)
return 0;
- error("Failed to clear devices for index %u", adapter->dev_id);
+ btd_error(adapter->dev_id, "Failed to clear devices for index %u",
+ adapter->dev_id);
return -EIO;
}
DBG("index %u status 0x%02x", adapter->dev_id, status);
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to read info for index %u: %s (0x%02x)",
+ btd_error(adapter->dev_id,
+ "Failed to read info for index %u: %s (0x%02x)",
adapter->dev_id, mgmt_errstr(status), status);
goto failed;
}
if (length < sizeof(*rp)) {
- error("Too small read info complete response");
+ btd_error(adapter->dev_id,
+ "Too small read info complete response");
goto failed;
}
if (bacmp(&rp->bdaddr, BDADDR_ANY) == 0) {
- error("No Bluetooth address for index %u", adapter->dev_id);
+ btd_error(adapter->dev_id, "No Bluetooth address for index %u",
+ adapter->dev_id);
goto failed;
}
break;
case BT_MODE_BREDR:
if (!(adapter->supported_settings & MGMT_SETTING_BREDR)) {
- error("Ignoring adapter withouth BR/EDR support");
+ btd_error(adapter->dev_id,
+ "Ignoring adapter withouth BR/EDR support");
goto failed;
}
break;
case BT_MODE_LE:
if (!(adapter->supported_settings & MGMT_SETTING_LE)) {
- error("Ignoring adapter withouth LE support");
+ btd_error(adapter->dev_id,
+ "Ignoring adapter withouth LE support");
goto failed;
}
if (missing_settings & MGMT_SETTING_SECURE_CONN)
set_mode(adapter, MGMT_OP_SET_SECURE_CONN, 0x01);
+
if (main_opts.fast_conn &&
(missing_settings & MGMT_SETTING_FAST_CONNECTABLE))
set_mode(adapter, MGMT_OP_SET_FAST_CONNECTABLE, 0x01);
err = adapter_register(adapter);
if (err < 0) {
- error("Unable to register new adapter");
+ btd_error(adapter->dev_id, "Unable to register new adapter");
goto failed;
}
adapter, NULL);
mgmt_register(adapter->mgmt, MGMT_EV_MULTI_ADV_STATE_CHANGED,
- adapter->dev_id,
- multi_adv_state_change_callback,
- adapter, NULL);
+ adapter->dev_id,
+ multi_adv_state_change_callback,
+ adapter, NULL);
mgmt_register(adapter->mgmt, MGMT_EV_6LOWPAN_CONN_STATE_CHANGED,
adapter->dev_id,
adapter->dev_id,
bt_le_data_length_changed_callback,
adapter, NULL);
+
+ mgmt_register(adapter->mgmt, MGMT_EV_CONN_UPDATED,
+ adapter->dev_id,
+ le_conn_update_completed_callback,
+ adapter, NULL);
#endif
set_dev_class(adapter);
adapter = btd_adapter_lookup(index);
if (adapter) {
- warn("Ignoring index added for an already existing adapter");
+ btd_warn(adapter->dev_id,
+ "Ignoring index added for an already existing adapter");
return;
}
adapter = btd_adapter_new(index);
if (!adapter) {
- error("Unable to create new adapter for index %u", index);
+ btd_error(adapter->dev_id,
+ "Unable to create new adapter for index %u", index);
return;
}
read_info_complete, adapter, NULL) > 0)
return;
- error("Failed to read controller info for index %u", index);
+ btd_error(adapter->dev_id,
+ "Failed to read controller info for index %u", index);
adapter_list = g_list_remove(adapter_list, adapter);