Bluetooth: Poll for RSSI updates from the remote device
This feature is required for implementing Low energy
proximity client immediate alert service. The proximtiy
client registers with the kernel for receiving RSSI updates
of the remote device. The kernel starts polling for RSSI
value using READ_RSSI HCI command and When it reaches
a particular threshold set by the proximity client,
updates are sent to the client.
Change-Id: I723dd140ad3bf02978c57b3ab127bb6768f28cca
CRs-fixed: 344936
Signed-off-by: Archana Ramachandran <archanar@codeaurora.org>
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index bc68c9f..ddb650b 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1810,6 +1810,81 @@
return err;
}
+static int set_rssi_reporter(struct sock *sk, u16 index,
+ unsigned char *data, u16 len)
+{
+ struct mgmt_cp_set_rssi_reporter *cp = (void *) data;
+ struct hci_dev *hdev;
+ struct hci_conn *conn;
+ int err = 0;
+
+ if (len != sizeof(*cp))
+ return cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
+ EINVAL);
+
+ hdev = hci_dev_get(index);
+ if (!hdev)
+ return cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
+ ENODEV);
+
+ hci_dev_lock(hdev);
+
+ conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
+
+ if (!conn) {
+ err = cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
+ ENOTCONN);
+ goto failed;
+ }
+
+ BT_DBG("updateOnThreshExceed %d ", cp->updateOnThreshExceed);
+ hci_conn_set_rssi_reporter(conn, cp->rssi_threshold,
+ __le16_to_cpu(cp->interval), cp->updateOnThreshExceed);
+
+failed:
+ hci_dev_unlock(hdev);
+ hci_dev_put(hdev);
+
+ return err;
+}
+
+static int unset_rssi_reporter(struct sock *sk, u16 index,
+ unsigned char *data, u16 len)
+{
+ struct mgmt_cp_unset_rssi_reporter *cp = (void *) data;
+ struct hci_dev *hdev;
+ struct hci_conn *conn;
+ int err = 0;
+
+ if (len != sizeof(*cp))
+ return cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
+ EINVAL);
+
+ hdev = hci_dev_get(index);
+
+ if (!hdev)
+ return cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
+ ENODEV);
+
+ hci_dev_lock(hdev);
+
+ conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
+
+ if (!conn) {
+ err = cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
+ ENOTCONN);
+ goto failed;
+ }
+
+ hci_conn_unset_rssi_reporter(conn);
+
+failed:
+ hci_dev_unlock(hdev);
+ hci_dev_put(hdev);
+
+ return err;
+}
+
static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
u16 len)
{
@@ -2365,6 +2440,12 @@
case MGMT_OP_SET_CONNECTION_PARAMS:
err = set_connection_params(sk, index, buf + sizeof(*hdr), len);
break;
+ case MGMT_OP_SET_RSSI_REPORTER:
+ err = set_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
+ break;
+ case MGMT_OP_UNSET_RSSI_REPORTER:
+ err = unset_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
+ break;
case MGMT_OP_READ_LOCAL_OOB_DATA:
err = read_local_oob_data(sk, index);
break;
@@ -2817,6 +2898,57 @@
return err;
}
+void mgmt_read_rssi_complete(u16 index, s8 rssi, bdaddr_t *bdaddr,
+ u16 handle, u8 status)
+{
+ struct mgmt_ev_rssi_update ev;
+ struct hci_conn *conn;
+ struct hci_dev *hdev;
+
+ if (status)
+ return;
+
+ hdev = hci_dev_get(index);
+ conn = hci_conn_hash_lookup_handle(hdev, handle);
+
+ if (!conn)
+ return;
+
+ BT_DBG("rssi_update_thresh_exceed : %d ",
+ conn->rssi_update_thresh_exceed);
+ BT_DBG("RSSI Threshold : %d , recvd RSSI : %d ",
+ conn->rssi_threshold, rssi);
+
+ if (conn->rssi_update_thresh_exceed == 1) {
+ BT_DBG("rssi_update_thresh_exceed == 1");
+ if (rssi >= conn->rssi_threshold) {
+ memset(&ev, 0, sizeof(ev));
+ bacpy(&ev.bdaddr, bdaddr);
+ ev.rssi = rssi;
+ mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
+ sizeof(ev), NULL);
+ } else {
+ hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
+ conn->rssi_update_interval,
+ conn->rssi_update_thresh_exceed);
+ }
+ } else {
+ BT_DBG("rssi_update_thresh_exceed == 0");
+ if (rssi <= conn->rssi_threshold) {
+ memset(&ev, 0, sizeof(ev));
+ bacpy(&ev.bdaddr, bdaddr);
+ ev.rssi = rssi;
+ mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
+ sizeof(ev), NULL);
+ } else {
+ hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
+ conn->rssi_update_interval,
+ conn->rssi_update_thresh_exceed);
+ }
+ }
+}
+
+
int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
{