Diff between d4358b06c51de5141b7ac57b094b19494bb07519 and 8ae5c861adf788893fffaf74c1c44a3c9d35a4af

Changed Files

File Additions Deletions Status
src/adapter.c +98 -8 modified
src/adapter.h +1 -2 modified
src/mgmt.c +1 -23 modified

Full Patch

diff --git a/src/adapter.c b/src/adapter.c
index e5da2e4..562b660 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -177,6 +177,57 @@ struct btd_adapter {
 
 static gboolean process_auth_queue(gpointer user_data);
 
+static void set_dev_class_complete(uint16_t index, uint8_t status,
+					uint16_t length, const void *param,
+					void *user_data)
+{
+	struct btd_adapter *adapter = user_data;
+	const struct mgmt_cod *rp = param;
+
+	if (status != 0) {
+		error("mgmt_set_dev_class failed: %s (0x%02x)",
+						mgmt_errstr(status), status);
+		return;
+	}
+
+	if (length < sizeof(*rp)) {
+		error("Unexpected length in mgmt_set_dev_class response");
+		return;
+	}
+
+	btd_adapter_class_changed(adapter, rp->val);
+}
+
+static int set_dev_class(struct btd_adapter *adapter, uint8_t major,
+							uint8_t minor)
+{
+	struct mgmt_cp_set_dev_class cp;
+	unsigned int id;
+
+	memset(&cp, 0, sizeof(cp));
+
+	/*
+	 * Silly workaround for a really stupid kernel bug :(
+	 *
+	 * All current kernel versions assign the major and minor numbers
+	 * straight to dev_class[0] and dev_class[1] without considering
+	 * the proper bit shifting.
+	 *
+	 * To make this work, shift the value in userspace for now until
+	 * we get a fixed kernel version.
+	 */
+	cp.major = major & 0x1f;
+	cp.minor = minor << 2;
+
+	id = mgmt_send(mgmt, MGMT_OP_SET_DEV_CLASS, adapter->dev_id,
+				sizeof(cp), &cp, set_dev_class_complete,
+				adapter, NULL);
+	if (id == 0)
+		return -EIO;
+
+	return 0;
+}
+
 int btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major,
 							uint8_t minor)
 {
@@ -188,7 +239,7 @@ int btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major,
 	adapter->major_class = major;
 	adapter->minor_class = minor;
 
-	return mgmt_set_dev_class(adapter->dev_id, major, minor);
+	return set_dev_class(adapter, major, minor);
 }
 
 static uint8_t get_mode(const char *mode)
@@ -552,7 +603,8 @@ static void set_pairable_timeout(struct btd_adapter *adapter,
 	g_dbus_pending_property_success(id);
 }
 
-void btd_adapter_class_changed(struct btd_adapter *adapter, uint8_t *new_class)
+void btd_adapter_class_changed(struct btd_adapter *adapter,
+						const uint8_t *new_class)
 {
 	uint32_t dev_class;
 	uint8_t cls[3];
@@ -589,7 +641,9 @@ void adapter_name_changed(struct btd_adapter *adapter, const char *name)
 
 static int set_name(struct btd_adapter *adapter, const char *name)
 {
+	struct mgmt_cp_set_local_name cp;
 	char maxname[MAX_NAME_LENGTH + 1];
+	unsigned int id;
 
 	memset(maxname, 0, sizeof(maxname));
 	strncpy(maxname, name, MAX_NAME_LENGTH);
@@ -599,7 +653,17 @@ static int set_name(struct btd_adapter *adapter, const char *name)
 		return -EINVAL;
 	}
 
-	return mgmt_set_name(adapter->dev_id, maxname);
+	memset(&cp, 0, sizeof(cp));
+	strncpy((char *) cp.name, maxname, sizeof(cp.name) - 1);
+
+	id = mgmt_send(mgmt, MGMT_OP_SET_LOCAL_NAME, adapter->dev_id,
+					sizeof(cp), &cp, NULL, NULL, NULL);
+	if (id == 0) {
+		error("mgmt_send(READ_INDEX_LIST) failed");
+		return -EIO;
+	}
+
+	return 0;
 }
 
 int adapter_set_name(struct btd_adapter *adapter, const char *name)
@@ -1847,6 +1911,8 @@ static void adapter_free(gpointer user_data)
 	g_queue_foreach(adapter->auths, free_service_auth, NULL);
 	g_queue_free(adapter->auths);
 
+	mgmt_unref(adapter->mgmt);
+
 	sdp_list_free(adapter->services, NULL);
 
 	g_slist_free(adapter->connections);
@@ -2820,8 +2886,7 @@ static gboolean adapter_setup(struct btd_adapter *adapter, uint32_t settings)
 	adapter->powered = mgmt_powered(settings);
 	adapter->connectable = mgmt_connectable(settings);
 	adapter->discoverable = mgmt_discoverable(settings);
-
-	mgmt_read_bdaddr(adapter->dev_id, &adapter->bdaddr);
+	adapter->pairable = mgmt_pairable(settings);
 
 	if (bacmp(&adapter->bdaddr, BDADDR_ANY) == 0) {
 		error("No address available for hci%d", adapter->dev_id);
@@ -2855,7 +2920,7 @@ static gboolean adapter_setup(struct btd_adapter *adapter, uint32_t settings)
 	return TRUE;
 }
 
-static struct btd_adapter *adapter_create(int id)
+static struct btd_adapter *adapter_create(int id, const bdaddr_t *bdaddr)
 {
 	char path[MAX_PATH_LENGTH];
 	struct btd_adapter *adapter;
@@ -2868,6 +2933,9 @@ static struct btd_adapter *adapter_create(int id)
 
 	adapter->dev_id = id;
 	adapter->auths = g_queue_new();
+	adapter->mgmt = mgmt_ref(mgmt);
+
+	bacpy(&adapter->bdaddr, bdaddr);
 
 	snprintf(path, sizeof(path), "%s/hci%d", base_path, id);
 	adapter->path = g_strdup(path);
@@ -3682,7 +3750,8 @@ void adapter_foreach(adapter_cb func, gpointer user_data)
 	g_slist_foreach(adapters, (GFunc) func, user_data);
 }
 
-struct btd_adapter *adapter_register(int id, uint32_t settings)
+static struct btd_adapter *adapter_register(int id, const bdaddr_t *bdaddr,
+							uint32_t settings)
 {
 	struct btd_adapter *adapter;
 
@@ -3692,7 +3761,7 @@ struct btd_adapter *adapter_register(int id, uint32_t settings)
 		return NULL;
 	}
 
-	adapter = adapter_create(id);
+	adapter = adapter_create(id, bdaddr);
 	if (!adapter)
 		return NULL;
 
@@ -3742,6 +3811,7 @@ int adapter_unregister(int id)
 static void read_info_complete(uint16_t index, uint8_t status, uint16_t length,
 					const void *param, void *user_data)
 {
+	const struct mgmt_rp_read_info *rp = param;
 	struct btd_adapter *adapter;
 
 	DBG("index %u", index);
@@ -3752,11 +3822,31 @@ static void read_info_complete(uint16_t index, uint8_t status, uint16_t length,
 		return;
 	}
 
+	if (length < sizeof(*rp)) {
+		error("Too small read info complete response");
+		return;
+	}
+
 	adapter = adapter_find_by_id(index);
 	if (adapter != NULL) {
 		warn("mgmt_read_info for an already existing adapter");
 		return;
 	}
+
+	adapter = adapter_register(index, &rp->bdaddr, rp->current_settings);
+	if (adapter == NULL) {
+		error("Unable to register new adapter");
+		return;
+	}
+
+	set_name(adapter, btd_adapter_get_name(adapter));
+
+	set_dev_class(adapter, adapter->major_class, adapter->minor_class);
+
+	if (mgmt_powered(rp->current_settings))
+		btd_adapter_start(adapter);
+
+	btd_adapter_unref(adapter);
 }
 
 static void index_added(uint16_t index, uint16_t length, const void *param,
diff --git a/src/adapter.h b/src/adapter.h
index fe69166..7761efb 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -79,7 +79,6 @@ struct btd_adapter *adapter_find(const bdaddr_t *sba);
 struct btd_adapter *adapter_find_by_id(int id);
 struct btd_adapter *adapter_get_default(void);
 void adapter_foreach(adapter_cb func, gpointer user_data);
-struct btd_adapter *adapter_register(int id, uint32_t settings);
 int adapter_unregister(int id);
 
 void btd_adapter_start(struct btd_adapter *adapter);
@@ -121,7 +120,7 @@ void adapter_name_changed(struct btd_adapter *adapter, const char *name);
 void adapter_service_insert(struct btd_adapter *adapter, void *rec);
 void adapter_service_remove(struct btd_adapter *adapter, void *rec);
 void btd_adapter_class_changed(struct btd_adapter *adapter,
-							uint8_t *new_class);
+						const uint8_t *new_class);
 void adapter_update_pairable(struct btd_adapter *adapter, bool pairable);
 
 struct agent *adapter_get_agent(struct btd_adapter *adapter);
diff --git a/src/mgmt.c b/src/mgmt.c
index 105fc30..2ea89e1 100644
--- a/src/mgmt.c
+++ b/src/mgmt.c
@@ -1144,9 +1144,6 @@ static void read_info_complete(uint16_t index, void *buf, size_t len)
 {
 	struct mgmt_rp_read_info *rp = buf;
 	struct controller_info *info;
-	struct btd_adapter *adapter;
-	const char *name;
-	uint8_t major, minor;
 	char addr[18];
 
 	if (len < sizeof(*rp)) {
@@ -1178,21 +1175,6 @@ static void read_info_complete(uint16_t index, void *buf, size_t len)
 
 	clear_uuids(index);
 
-	adapter = adapter_register(index, info->current_settings);
-	if (adapter == NULL) {
-		error("mgmt: unable to register adapter");
-		return;
-	}
-
-	update_settings(adapter, info->current_settings);
-
-	name = btd_adapter_get_name(adapter);
-	if (name)
-		mgmt_set_name(index, name);
-
-	btd_adapter_get_major_minor(adapter, &major, &minor);
-	mgmt_set_dev_class(index, major, minor);
-
 	if (!mgmt_pairable(info->current_settings))
 		mgmt_set_pairable(index, TRUE);
 
@@ -1204,12 +1186,8 @@ static void read_info_complete(uint16_t index, void *buf, size_t len)
 				!mgmt_low_energy(info->current_settings))
 		mgmt_set_low_energy(index, TRUE);
 
-	if (mgmt_powered(info->current_settings)) {
+	if (mgmt_powered(info->current_settings))
 		get_connections(index);
-		btd_adapter_start(adapter);
-	}
-
-	btd_adapter_unref(adapter);
 }
 
 static void disconnect_complete(uint16_t index, uint8_t status,