[RFC v2 1/3] Add HCI commands to enable address resolution in controller

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

 



Add HCI commands  : LE Read Resolving List Size,
LE Add Device to Resolving List, LE Delete Device from Resolving List,
LE Clear Resolving List, LE Set Address Resolution Enable

Signed-off-by: Shermin Joy <shermin.joy@xxxxxxxxx>
---
 include/net/bluetooth/hci.h      | 25 ++++++++++
 include/net/bluetooth/hci_core.h | 12 +++++
 net/bluetooth/hci_core.c         | 20 ++++++++
 net/bluetooth/hci_event.c        | 98 ++++++++++++++++++++++++++++++++++++++++
 net/bluetooth/hci_request.c      | 62 +++++++++++++++++++++++++
 net/bluetooth/hci_request.h      |  8 ++++
 6 files changed, 225 insertions(+)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index fe98f0a..1ef3ae8 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -398,6 +398,7 @@ enum {
 #define HCI_LE_SLAVE_FEATURES		0x08
 #define HCI_LE_PING			0x10
 #define HCI_LE_DATA_LEN_EXT		0x20
+#define HCI_LE_LL_PRIVACY		0x40
 #define HCI_LE_EXT_SCAN_POLICY		0x80
 #define HCI_LE_CHAN_SEL_ALG2		0x40
 
@@ -1506,6 +1507,30 @@ struct hci_cp_le_set_default_phy {
 	__u8    rx_phys;
 } __packed;
 
+#define HCI_OP_LE_ADD_TO_RESOLVING_LIST		0x2027
+struct hci_cp_le_add_to_resolving_list {
+	__u8		peer_bdaddr_type;
+	bdaddr_t	peer_bdaddr;
+	__u8		peer_irk[16];
+	__u8		local_irk[16];
+} __packed;
+
+#define HCI_OP_LE_DEL_FROM_RESOLVING_LIST	0x2028
+struct hci_cp_le_del_from_resolving_list {
+	__u8		peer_bdaddr_type;
+	bdaddr_t	peer_bdaddr;
+} __packed;
+
+#define HCI_OP_LE_CLEAR_RESOLVING_LIST		0x2029
+
+#define HCI_OP_LE_READ_RESOLVING_LIST_SIZE	0x202A
+struct hci_rp_le_read_resolving_list_size {
+	__u8	status;
+	__u8	size;
+} __packed;
+
+#define HCI_OP_LE_SET_ADDR_RESOL_ENABLE		0x202D
+
 /* ---- HCI Events ---- */
 #define HCI_EV_INQUIRY_COMPLETE		0x01
 
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 95ccc1e..65ba086 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -139,6 +139,13 @@ struct smp_irk {
 	u8 val[16];
 };
 
+struct hci_irk {
+	struct list_head list;
+	bdaddr_t bdaddr;
+	u8 addr_type;
+	u8 val[16];
+};
+
 struct link_key {
 	struct list_head list;
 	struct rcu_head rcu;
@@ -221,6 +228,7 @@ struct hci_dev {
 	__u8		features[HCI_MAX_PAGES][8];
 	__u8		le_features[8];
 	__u8		le_white_list_size;
+	__u8		le_resolving_list_size;
 	__u8		le_states[8];
 	__u8		commands[64];
 	__u8		hci_ver;
@@ -259,6 +267,7 @@ struct hci_dev {
 	__u8		ssp_debug_mode;
 	__u8		hw_error_code;
 	__u32		clock;
+	bool		le_ll_addr_resolve_enabled;
 
 	__u16		devid_source;
 	__u16		devid_vendor;
@@ -361,6 +370,7 @@ struct hci_dev {
 	struct list_head	mgmt_pending;
 	struct list_head	blacklist;
 	struct list_head	whitelist;
+	struct list_head	resolvinglist;
 	struct list_head	uuids;
 	struct list_head	link_keys;
 	struct list_head	long_term_keys;
@@ -1536,6 +1546,8 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand,
 void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr,
 			       u8 *bdaddr_type);
 
+void hci_clear_resolving_list(struct hci_dev *hdev);
+
 #define SCO_AIRMODE_MASK       0x0003
 #define SCO_AIRMODE_CVSD       0x0000
 #define SCO_AIRMODE_TRANSP     0x0003
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 6bc679c..bfeeb18 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -731,6 +731,24 @@ static int hci_init3_req(struct hci_request *req, unsigned long opt)
 			hci_req_add(req, HCI_OP_LE_READ_DEF_DATA_LEN, 0, NULL);
 		}
 
+		if (hdev->le_features[0] & HCI_LE_LL_PRIVACY) {
+			if (hdev->commands[34] & 0x40)
+				/* Read LE Resolving List Size */
+				hci_req_add(req,
+					    HCI_OP_LE_READ_RESOLVING_LIST_SIZE,
+					    0, NULL);
+			if (hdev->commands[35] & 0x02)
+				/* Enable Address Resolution in Controller */
+				hci_req_add(req,
+					    HCI_OP_LE_SET_ADDR_RESOL_ENABLE,
+					    0, NULL);
+			if (hdev->commands[34] & 0x20)
+				/* Clear LE Resolving List */
+				hci_req_add(req,
+					    HCI_OP_LE_CLEAR_RESOLVING_LIST,
+					    0, NULL);
+			}
+
 		hci_set_le_support(req);
 	}
 
@@ -3021,6 +3039,7 @@ struct hci_dev *hci_alloc_dev(void)
 	INIT_LIST_HEAD(&hdev->mgmt_pending);
 	INIT_LIST_HEAD(&hdev->blacklist);
 	INIT_LIST_HEAD(&hdev->whitelist);
+	INIT_LIST_HEAD(&hdev->resolvinglist);
 	INIT_LIST_HEAD(&hdev->uuids);
 	INIT_LIST_HEAD(&hdev->link_keys);
 	INIT_LIST_HEAD(&hdev->long_term_keys);
@@ -3221,6 +3240,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
 	hci_dev_lock(hdev);
 	hci_bdaddr_list_clear(&hdev->blacklist);
 	hci_bdaddr_list_clear(&hdev->whitelist);
+	hci_clear_resolving_list(hdev);
 	hci_uuids_clear(hdev);
 	hci_link_keys_clear(hdev);
 	hci_smp_ltks_clear(hdev);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 0b4dba0..6252307 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1442,6 +1442,84 @@ static void hci_cc_write_ssp_debug_mode(struct hci_dev *hdev, struct sk_buff *sk
 		hdev->ssp_debug_mode = *mode;
 }
 
+static void hci_cc_le_read_resolving_list_size(struct hci_dev *hdev,
+					       struct sk_buff *skb)
+{
+	struct hci_rp_le_read_resolving_list_size *rp = (void *)skb->data;
+
+	BT_DBG("%s status 0x%2.2x size %u", hdev->name, rp->status, rp->size);
+
+	if (rp->status)
+		return;
+
+	hdev->le_resolving_list_size = rp->size;
+}
+
+static void hci_cc_le_clear_resolving_list(struct hci_dev *hdev,
+					   struct sk_buff *skb)
+{
+	__u8 status = *((__u8 *)skb->data);
+
+	BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+	if (status)
+		return;
+
+	/* Clear all entries in the resolving list.*/
+	hci_clear_resolving_list(hdev);
+}
+
+static void hci_cc_le_add_to_resolving_list(struct hci_dev *hdev,
+					    struct sk_buff *skb)
+{
+	struct hci_cp_le_add_to_resolving_list *sent;
+	__u8 status = *((__u8 *)skb->data);
+
+	BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+	if (status)
+		return;
+
+	sent = hci_sent_cmd_data(hdev, HCI_OP_LE_ADD_TO_RESOLVING_LIST);
+	if (!sent)
+		return;
+
+	hci_update_resolving_list(hdev, sent->peer_bdaddr_type,
+				  &sent->peer_bdaddr, sent->peer_irk);
+}
+
+static void hci_cc_le_del_from_resolving_list(struct hci_dev *hdev,
+					      struct sk_buff *skb)
+{
+	struct hci_cp_le_del_from_resolving_list *sent;
+	__u8 status = *((__u8 *)skb->data);
+
+	BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+	if (status)
+		return;
+
+	sent = hci_sent_cmd_data(hdev, HCI_OP_LE_DEL_FROM_RESOLVING_LIST);
+	if (!sent)
+		return;
+
+	hci_delete_from_resolving_list(hdev, sent->peer_bdaddr_type,
+				       &sent->peer_bdaddr);
+}
+
+static void hci_cc_le_set_address_resolution_enable(struct hci_dev *hdev,
+						    struct sk_buff *skb)
+{
+	__u8 status = *((__u8 *)skb->data);
+
+	BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+	if (status)
+		return;
+
+	hdev->le_ll_addr_resolve_enabled = true;
+}
+
 static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
 {
 	BT_DBG("%s status 0x%2.2x", hdev->name, status);
@@ -3039,6 +3117,26 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb,
 		hci_cc_write_ssp_debug_mode(hdev, skb);
 		break;
 
+	case HCI_OP_LE_READ_RESOLVING_LIST_SIZE:
+		hci_cc_le_read_resolving_list_size(hdev, skb);
+		break;
+
+	case HCI_OP_LE_CLEAR_RESOLVING_LIST:
+		hci_cc_le_clear_resolving_list(hdev, skb);
+		break;
+
+	case HCI_OP_LE_ADD_TO_RESOLVING_LIST:
+		hci_cc_le_add_to_resolving_list(hdev, skb);
+		break;
+
+	case HCI_OP_LE_DEL_FROM_RESOLVING_LIST:
+		hci_cc_le_del_from_resolving_list(hdev, skb);
+		break;
+
+	case HCI_OP_LE_SET_ADDR_RESOL_ENABLE:
+		hci_cc_le_set_address_resolution_enable(hdev, skb);
+		break;
+
 	default:
 		BT_DBG("%s opcode 0x%4.4x", hdev->name, *opcode);
 		break;
diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
index b73ac14..8bdc22b 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -773,6 +773,68 @@ static u8 update_white_list(struct hci_request *req)
 	return 0x01;
 }
 
+struct hci_irk *hci_resolving_list_lookup(struct hci_dev *hdev,
+					  bdaddr_t *bdaddr, u8 type)
+{
+	struct hci_irk *b;
+
+	list_for_each_entry(b, &hdev->resolvinglist, list) {
+		if (!bacmp(&b->bdaddr, bdaddr) && b->addr_type == type)
+			return b;
+	}
+
+	return NULL;
+}
+
+int hci_update_resolving_list(struct hci_dev *hdev, u8 addr_type,
+			      bdaddr_t *bdaddr, u8 irk_val[16])
+{
+	struct hci_irk *irk;
+
+	irk = hci_resolving_list_lookup(hdev, bdaddr, addr_type);
+	if (irk) {
+		/* If present, remove the entry from current position.*/
+		list_del(&irk->list);
+	} else {
+		irk = kzalloc(sizeof(*irk), GFP_KERNEL);
+		if (!irk)
+			return -ENOMEM;
+		bacpy(&irk->bdaddr, bdaddr);
+		irk->addr_type = addr_type;
+	}
+
+	memcpy(irk->val, irk_val, 16);
+
+	/* Add the entry to the end of the list.*/
+	list_add_tail(&irk->list, &hdev->resolvinglist);
+	return 0;
+}
+
+int hci_delete_from_resolving_list(struct hci_dev *hdev, u8 addr_type,
+				   bdaddr_t *bdaddr)
+{
+	struct hci_irk *irk;
+
+	irk = hci_resolving_list_lookup(hdev, bdaddr, addr_type);
+	if (!irk)
+		return -ENOENT;
+
+	/* If present, remove the entry from current position.*/
+	list_del(&irk->list);
+
+	return 0;
+}
+
+void hci_clear_resolving_list(struct hci_dev *hdev)
+{
+	struct hci_irk *irk;
+
+	list_for_each_entry(irk, &hdev->resolvinglist, list) {
+		list_del(&irk->list);
+		kfree(irk);
+	}
+}
+
 static bool scan_use_rpa(struct hci_dev *hdev)
 {
 	return hci_dev_test_flag(hdev, HCI_PRIVACY);
diff --git a/net/bluetooth/hci_request.h b/net/bluetooth/hci_request.h
index dde77bd..ab4aac6 100644
--- a/net/bluetooth/hci_request.h
+++ b/net/bluetooth/hci_request.h
@@ -66,6 +66,14 @@ struct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode, u32 plen,
 void hci_req_add_le_scan_disable(struct hci_request *req);
 void hci_req_add_le_passive_scan(struct hci_request *req);
 
+struct hci_irk *hci_resolving_list_lookup(struct hci_dev *hdev,
+					  bdaddr_t *bdaddr, u8 type);
+int hci_update_resolving_list(struct hci_dev *hdev, u8 addr_type,
+			      bdaddr_t *bdaddr, u8 irk_val[16]);
+int hci_delete_from_resolving_list(struct hci_dev *hdev, u8 addr_type,
+				   bdaddr_t *bdaddr);
+void hci_clear_resolving_list(struct hci_dev *hdev);
+
 void hci_req_reenable_advertising(struct hci_dev *hdev);
 void __hci_req_enable_advertising(struct hci_request *req);
 void __hci_req_disable_advertising(struct hci_request *req);
-- 
1.9.1

--
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