[PATCH v5 3/6] Add support for Out of Band (OOB) association model in hciops

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



---
 plugins/hciops.c |  118 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 110 insertions(+), 8 deletions(-)

diff --git a/plugins/hciops.c b/plugins/hciops.c
index 74ff7d5..9013694 100644
--- a/plugins/hciops.c
+++ b/plugins/hciops.c
@@ -50,6 +50,7 @@
 #include "storage.h"
 #include "event.h"
 #include "manager.h"
+#include "oob.h"
 
 static int child_pipe[2] = { -1, -1 };
 
@@ -77,11 +78,18 @@ struct bt_conn {
 	uint8_t loc_auth;
 	uint8_t rem_cap;
 	uint8_t rem_auth;
+	uint8_t rem_oob_data;
 	gboolean bonding_initiator;
 	gboolean secmode3;
 	GIOChannel *io; /* For raw L2CAP socket (bonding) */
 };
 
+struct oob_data {
+	bdaddr_t bdaddr;
+	uint8_t hash[16];
+	uint8_t randomizer[16];
+};
+
 static int max_dev = -1;
 static struct dev_info {
 	int id;
@@ -120,6 +128,8 @@ static struct dev_info {
 	GSList *keys;
 	uint8_t pin_length;
 
+	GSList *oob_data;
+
 	GSList *uuids;
 
 	GSList *connections;
@@ -1053,14 +1063,43 @@ static void user_passkey_notify(int index, void *ptr)
 						btohl(req->passkey));
 }
 
-static void remote_oob_data_request(int index, void *ptr)
+static gint oob_bdaddr_cmp(gconstpointer a, gconstpointer b)
+{
+	const struct oob_data *data = a;
+	const bdaddr_t *bdaddr = b;
+
+	return bacmp(&data->bdaddr, bdaddr);
+}
+
+static void remote_oob_data_request(int index, bdaddr_t *bdaddr)
 {
 	struct dev_info *dev = &devs[index];
+	GSList *match;
 
 	DBG("hci%d", index);
 
-	hci_send_cmd(dev->sk, OGF_LINK_CTL,
-				OCF_REMOTE_OOB_DATA_NEG_REPLY, 6, ptr);
+	match = g_slist_find_custom(dev->oob_data, bdaddr, oob_bdaddr_cmp);
+
+	if (match) {
+		struct oob_data *data;
+		remote_oob_data_reply_cp cp;
+
+		data = match->data;
+
+		bacpy(&cp.bdaddr, &data->bdaddr);
+		memcpy(cp.hash, data->hash, sizeof(cp.hash));
+		memcpy(cp.randomizer, data->randomizer, sizeof(cp.randomizer));
+
+		dev->oob_data = g_slist_delete_link(dev->oob_data, match);
+
+		hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_REMOTE_OOB_DATA_REPLY,
+				REMOTE_OOB_DATA_REPLY_CP_SIZE, &cp);
+
+	} else {
+		hci_send_cmd(dev->sk, OGF_LINK_CTL,
+				OCF_REMOTE_OOB_DATA_NEG_REPLY, 6, bdaddr);
+	}
+
 }
 
 static int get_io_cap(int index, bdaddr_t *bdaddr, uint8_t *cap, uint8_t *auth)
@@ -1158,11 +1197,23 @@ static void io_capa_request(int index, void *ptr)
 					IO_CAPABILITY_NEG_REPLY_CP_SIZE, &cp);
 	} else {
 		io_capability_reply_cp cp;
+		struct bt_conn *conn;
+		GSList *match;
+
 		memset(&cp, 0, sizeof(cp));
 		bacpy(&cp.bdaddr, dba);
 		cp.capability = cap;
-		cp.oob_data = 0x00;
 		cp.authentication = auth;
+
+		conn = find_connection(dev, dba);
+		match = g_slist_find_custom(dev->oob_data, dba, oob_bdaddr_cmp);
+
+		if ((conn->bonding_initiator || conn->rem_oob_data == 0x01) &&
+				match)
+			cp.oob_data = 0x01;
+		else
+			cp.oob_data = 0x00;
+
 		hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_IO_CAPABILITY_REPLY,
 					IO_CAPABILITY_REPLY_CP_SIZE, &cp);
 	}
@@ -1182,6 +1233,7 @@ static void io_capa_response(int index, void *ptr)
 	if (conn) {
 		conn->rem_cap = evt->capability;
 		conn->rem_auth = evt->authentication;
+		conn->rem_oob_data = evt->oob_data;
 	}
 }
 
@@ -1788,6 +1840,20 @@ static void write_class_complete(int index, uint8_t status)
 		write_class(index, dev->wanted_cod);
 }
 
+static void read_local_oob_data_complete(int index, uint8_t status,
+						read_local_oob_data_rp *rp)
+{
+	struct btd_adapter *adapter = manager_find_adapter_by_id(index);
+
+	if (!adapter)
+		return;
+
+	if (status)
+		oob_local_data_read(adapter, NULL, NULL);
+	else
+		oob_local_data_read(adapter, rp->hash, rp->randomizer);
+}
+
 static inline void cmd_complete(int index, void *ptr)
 {
 	struct dev_info *dev = &devs[index];
@@ -1861,6 +1927,10 @@ static inline void cmd_complete(int index, void *ptr)
 		ptr += sizeof(evt_cmd_complete);
 		read_tx_power_complete(index, ptr);
 		break;
+	case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_LOCAL_OOB_DATA):
+		ptr += sizeof(evt_cmd_complete);
+		read_local_oob_data_complete(index, status, ptr);
+		break;
 	};
 }
 
@@ -2390,7 +2460,7 @@ static gboolean io_security_event(GIOChannel *chan, GIOCondition cond,
 		break;
 
 	case EVT_REMOTE_OOB_DATA_REQUEST:
-		remote_oob_data_request(index, ptr);
+		remote_oob_data_request(index, (bdaddr_t *) ptr);
 		break;
 	}
 
@@ -3560,30 +3630,62 @@ static int hciops_cancel_bonding(int index, bdaddr_t *bdaddr)
 
 static int hciops_read_local_oob_data (int index)
 {
+	struct dev_info *dev = &devs[index];
+
 	DBG("hci%d", index);
 
-	return -ENOSYS;
+	if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_READ_LOCAL_OOB_DATA, 0, 0)
+									< 0)
+		return -errno;
+
+	return 0;
 }
 
 static int hciops_add_remote_oob_data (int index, bdaddr_t *bdaddr,
 					uint8_t *hash, uint8_t *randomizer)
 {
 	char addr[18];
+	struct dev_info *dev = &devs[index];
+	GSList *match;
+	struct oob_data *data;
 
 	ba2str(bdaddr, addr);
 	DBG("hci%d bdaddr %s", index, addr);
 
-	return -ENOSYS;
+	match = g_slist_find_custom(dev->oob_data, &bdaddr, oob_bdaddr_cmp);
+
+	if (match) {
+		data = match->data;
+	} else {
+		data = g_new(struct oob_data, 1);
+		bacpy(&data->bdaddr, bdaddr);
+		dev->oob_data = g_slist_prepend(dev->oob_data, data);
+	}
+
+	memcpy(data->hash, hash, sizeof(data->hash));
+	memcpy(data->randomizer, randomizer, sizeof(data->randomizer));
+
+	return 0;
 }
 
 static int hciops_remove_remote_oob_data (int index, bdaddr_t *bdaddr)
 {
 	char addr[18];
+	struct dev_info *dev = &devs[index];
+	GSList *match;
 
 	ba2str(bdaddr, addr);
 	DBG("hci%d bdaddr %s", index, addr);
 
-	return -ENOSYS;
+	match = g_slist_find_custom(dev->oob_data, &bdaddr, oob_bdaddr_cmp);
+
+	if (!match)
+		return -ENOENT;
+
+	g_free(match->data);
+	dev->oob_data = g_slist_delete_link(dev->oob_data, match);
+
+	return 0;
 }
 
 static struct btd_adapter_ops hci_ops = {
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux