[RFC 1/2] 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 |   3 ++
 net/bluetooth/hci_core.c         |  18 +++++++
 net/bluetooth/hci_event.c        | 107 +++++++++++++++++++++++++++++++++++++++
 net/bluetooth/hci_request.c      |  64 +++++++++++++++++++++++
 net/bluetooth/hci_request.h      |   4 ++
 6 files changed, 221 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..82c9589 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -137,6 +137,7 @@ struct smp_irk {
 	bdaddr_t bdaddr;
 	u8 addr_type;
 	u8 val[16];
+	bool in_ll_resolving_list;
 };
 
 struct link_key {
@@ -221,6 +222,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 +261,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;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 6bc679c..ab16e71 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);
 	}
 
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 0b4dba0..3e7bbbe 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1442,6 +1442,93 @@ 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);
+	struct smp_irk *irk;
+
+	BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+	if (status)
+		return;
+
+	/* Clear in_ll_resolving_list flag for all entries in the
+	 * identity_resolving_keys list.
+	 */
+	rcu_read_lock();
+	list_for_each_entry_rcu(irk, &hdev->identity_resolving_keys, list) {
+		irk->in_ll_resolving_list = false;
+	}
+	rcu_read_unlock();
+}
+
+static void hci_cc_le_add_to_resolving_list(struct hci_dev *hdev,
+					    struct sk_buff *skb)
+{
+	struct hci_cp_le_add_to_white_list *sent;
+	__u8 status = *((__u8 *)skb->data);
+	struct smp_irk *irk;
+
+	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;
+
+	if (hci_find_irk_by_addr(hdev, &sent->bdaddr, sent->bdaddr_type))
+		irk->in_ll_resolving_list = true;
+}
+
+static void hci_cc_le_del_from_resolving_list(struct hci_dev *hdev,
+					      struct sk_buff *skb)
+{
+	struct hci_cp_le_del_from_white_list *sent;
+	__u8 status = *((__u8 *)skb->data);
+	struct smp_irk *irk;
+
+	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;
+
+	if (hci_find_irk_by_addr(hdev, &sent->bdaddr, sent->bdaddr_type))
+		irk->in_ll_resolving_list = false;
+}
+
+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 +3126,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..6dcc827 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -773,6 +773,70 @@ static u8 update_white_list(struct hci_request *req)
 	return 0x01;
 }
 
+static void add_to_resolving_list(struct hci_request *req, u8 addr_type,
+				  bdaddr_t *bdaddr, u8 irk[16])
+{
+	struct hci_dev *hdev = req->hdev;
+	struct hci_cp_le_add_to_resolving_list cp;
+
+	cp.peer_bdaddr_type = addr_type;
+	bacpy(&cp.peer_bdaddr, bdaddr);
+	memcpy(cp.peer_irk, irk, 16);
+	memcpy(cp.local_irk, hdev->irk, 16);
+
+	hci_req_add(req, HCI_OP_LE_ADD_TO_RESOLVING_LIST, sizeof(cp), &cp);
+}
+
+void hci_req_del_from_resolving_list(struct hci_dev *hdev, u8 addr_type,
+				     bdaddr_t *bdaddr)
+{
+	struct hci_cp_le_del_from_resolving_list cp;
+	struct hci_request req;
+
+	/* Nothing to be done if LL privacy is not supported. */
+	if (hdev->le_features[0] & HCI_LE_LL_PRIVACY)
+		return;
+
+	/* Resolving List cannot be updated if address resolution
+	 * in the controller is enabled and advertisement or scanning
+	 * or create connection command is ongoing.
+	 */
+	if ((hdev->le_ll_addr_resolve_enabled) &&
+	    ((hci_dev_test_flag(hdev, HCI_LE_ADV)) ||
+	    (hci_dev_test_flag(hdev, HCI_LE_SCAN)) ||
+	    (hci_lookup_le_connect(hdev))))
+		return;
+
+	hci_req_init(&req, hdev);
+	cp.peer_bdaddr_type = addr_type;
+	bacpy(&cp.peer_bdaddr, bdaddr);
+
+	hci_req_add(&req, HCI_OP_LE_DEL_FROM_RESOLVING_LIST, sizeof(cp), &cp);
+	hci_req_run(&req, NULL);
+}
+
+void hci_req_clear_resolving_list(struct hci_dev *hdev)
+{
+	struct hci_request req;
+
+	/* Nothing to be done if LL privacy is not supported. */
+	if (hdev->le_features[0] & HCI_LE_LL_PRIVACY)
+		return;
+
+	/* Resolving List cannot be updated if address resolution
+	 * in the controller is enabled and advertisement or scanning
+	 * or create connection command is ongoing.
+	 */
+	if ((hdev->le_ll_addr_resolve_enabled) &&
+	    ((hci_dev_test_flag(hdev, HCI_LE_ADV)) ||
+	    (hci_dev_test_flag(hdev, HCI_LE_SCAN)) ||
+	    (hci_lookup_le_connect(hdev))))
+		return;
+
+	hci_req_add(&req, HCI_OP_LE_CLEAR_RESOLVING_LIST, 0, NULL);
+	hci_req_run(&req, NULL);
+}
+
 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..bf12dbf 100644
--- a/net/bluetooth/hci_request.h
+++ b/net/bluetooth/hci_request.h
@@ -66,6 +66,10 @@ 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);
 
+void hci_req_del_from_resolving_list(struct hci_dev *hdev, u8 addr_type,
+				     bdaddr_t *bdaddr);
+void hci_req_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