bluetooth: Add support for LE conn param
Added support to let the userspace know about the updated
LE connection parameters. On receiving successful connection
complete and connection parameters update event from the BT
Controller, send a mgmt event to the userspace bluetoothd.
CRs-fixed: 380271
Change-Id: If8c3d785188e0d4f38c7431d01c016f399137408
Signed-off-by: Sunny Kapdi <sunnyk@codeaurora.org>
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index eb89f4b..3526e29 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1334,6 +1334,15 @@
__u8 data[0];
} __packed;
+#define HCI_EV_LE_CONN_UPDATE_COMPLETE 0x03
+struct hci_ev_le_conn_update_complete {
+ __u8 status;
+ __le16 handle;
+ __le16 interval;
+ __le16 latency;
+ __le16 supervision_timeout;
+} __packed;
+
#define HCI_EV_LE_LTK_REQ 0x05
struct hci_ev_le_ltk_req {
__le16 handle;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 47b856c..22428c1 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1033,6 +1033,8 @@
int mgmt_connectable(u16 index, u8 connectable);
int mgmt_new_key(u16 index, struct link_key *key, u8 bonded);
int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le);
+int mgmt_le_conn_params(u16 index, bdaddr_t *bdaddr, u16 interval,
+ u16 latency, u16 timeout);
int mgmt_disconnected(u16 index, bdaddr_t *bdaddr);
int mgmt_disconnect_failed(u16 index);
int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status);
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index e34c425..3048339 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -379,3 +379,11 @@
bdaddr_t bdaddr;
__s8 rssi;
} __packed;
+
+#define MGMT_EV_LE_CONN_PARAMS 0xF000
+struct mgmt_ev_le_conn_params {
+ bdaddr_t bdaddr;
+ __u16 interval;
+ __u16 latency;
+ __u16 timeout;
+} __packed;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index eb5a0cc..f83c108 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3191,6 +3191,10 @@
conn->state = BT_CONNECTED;
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
mgmt_connected(hdev->id, &ev->bdaddr, 1);
+ mgmt_le_conn_params(hdev->id, &ev->bdaddr,
+ __le16_to_cpu(ev->interval),
+ __le16_to_cpu(ev->latency),
+ __le16_to_cpu(ev->supervision_timeout));
hci_conn_hold(conn);
hci_conn_hold_device(conn);
@@ -3202,6 +3206,37 @@
hci_dev_unlock(hdev);
}
+static inline void hci_le_conn_update_complete_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_ev_le_conn_update_complete *ev = (void *) skb->data;
+ struct hci_conn *conn;
+
+ BT_DBG("%s status %d", hdev->name, ev->status);
+
+ hci_dev_lock(hdev);
+
+ conn = hci_conn_hash_lookup_handle(hdev,
+ __le16_to_cpu(ev->handle));
+ if (conn == NULL) {
+ BT_ERR("Unknown connection update");
+ goto unlock;
+ }
+
+ if (ev->status) {
+ BT_ERR("Connection update unsuccessful");
+ goto unlock;
+ }
+
+ mgmt_le_conn_params(hdev->id, &conn->dst,
+ __le16_to_cpu(ev->interval),
+ __le16_to_cpu(ev->latency),
+ __le16_to_cpu(ev->supervision_timeout));
+
+unlock:
+ hci_dev_unlock(hdev);
+}
+
static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
@@ -3271,6 +3306,10 @@
hci_le_conn_complete_evt(hdev, skb);
break;
+ case HCI_EV_LE_CONN_UPDATE_COMPLETE:
+ hci_le_conn_update_complete_evt(hdev, skb);
+ break;
+
case HCI_EV_LE_LTK_REQ:
hci_le_ltk_request_evt(hdev, skb);
break;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index dce8491..72234c1 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2633,6 +2633,20 @@
return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
}
+int mgmt_le_conn_params(u16 index, bdaddr_t *bdaddr, u16 interval,
+ u16 latency, u16 timeout)
+{
+ struct mgmt_ev_le_conn_params ev;
+
+ bacpy(&ev.bdaddr, bdaddr);
+ ev.interval = interval;
+ ev.latency = latency;
+ ev.timeout = timeout;
+
+ return mgmt_event(MGMT_EV_LE_CONN_PARAMS, index, &ev, sizeof(ev),
+ NULL);
+}
+
static void disconnect_rsp(struct pending_cmd *cmd, void *data)
{
struct mgmt_cp_disconnect *cp = cmd->param;