Bluetooth: Add LE connection parameter update procedure
authorSudha Bheemanna <b.sudha@samsung.com>
Thu, 25 Aug 2016 06:28:22 +0000 (11:58 +0530)
committerHoegeun Kwon <hoegeun.kwon@samsung.com>
Mon, 7 Feb 2022 07:09:31 +0000 (16:09 +0900)
Added new MGMT command to update LE connection parameters

Change-Id: I6ae16513437cd42d40e75958aa8415baa1cbedbb
Signed-off-by: Sudha Bheemanna <b.sudha@samsung.com>
Signed-off-by: Amit Purwar <amit.purwar@samsung.com>
include/net/bluetooth/hci_core.h
include/net/bluetooth/mgmt_tizen.h
net/bluetooth/hci_event.c
net/bluetooth/mgmt.c

index 308ef3b..e4928bc 100644 (file)
@@ -1873,6 +1873,11 @@ void mgmt_enable_rssi_cc(struct hci_dev *hdev, void *response, u8 status);
 int mgmt_device_name_update(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name,
                u8 name_len);
 void mgmt_le_discovering(struct hci_dev *hdev, u8 discovering);
+int mgmt_le_conn_updated(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
+               u8 dst_type, u16 conn_interval, u16 conn_latency,
+               u16 supervision_timeout);
+int mgmt_le_conn_update_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
+               u8 link_type, u8 addr_type, u8 status);
 #endif
 
 u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
index fab5beb..c912a69 100644 (file)
@@ -123,6 +123,18 @@ struct mgmt_cp_stop_le_discovery {
 #define MGMT_DISABLE_LE_AUTO_CONNECT_SIZE      0
 /* LE auto connection */
 
+/* For Add LE connection parameter update procedure */
+#define MGMT_LE_CONN_UPDATE_SIZE               14
+#define MGMT_OP_LE_CONN_UPDATE                 (TIZEN_OP_CODE_BASE + 0x0d)
+struct mgmt_cp_le_conn_update {
+       __le16  conn_interval_min;
+       __le16  conn_interval_max;
+       __le16  conn_latency;
+       __le16  supervision_timeout;
+       bdaddr_t        bdaddr;
+} __packed;
+/* Add LE connection parameter update procedure */
+
 /* EVENTS */
 
 /* For device name update changes */
@@ -156,4 +168,20 @@ struct mgmt_cc_rp_get_raw_rssi {
 #define MGMT_EV_RSSI_DISABLED                  (TIZEN_EV_BASE + 0x07)
 /* Handling of RSSI Events */
 
+/* For Add LE connection update Events */
+#define MGMT_EV_CONN_UPDATED                   (TIZEN_EV_BASE + 0x08)
+struct mgmt_ev_conn_updated {
+       struct  mgmt_addr_info addr;
+       __le16  conn_interval;
+       __le16  conn_latency;
+       __le16  supervision_timeout;
+} __packed;
+
+#define MGMT_EV_CONN_UPDATE_FAILED             (TIZEN_EV_BASE + 0x09)
+struct mgmt_ev_conn_update_failed {
+       struct  mgmt_addr_info addr;
+       __u8    status;
+} __packed;
+/* Add LE connection update Events */
+
 #endif /* __MGMT_TIZEN_H */
index c440440..ea0f8e4 100644 (file)
@@ -5395,12 +5395,26 @@ static void hci_le_conn_update_complete_evt(struct hci_dev *hdev,
 
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
        if (conn) {
+#ifdef TIZEN_BT
+               if (ev->status) {
+                       hci_dev_unlock(hdev);
+                       mgmt_le_conn_update_failed(hdev, &conn->dst,
+                               conn->type, conn->dst_type, ev->status);
+                       return;
+               }
+#endif
                conn->le_conn_interval = le16_to_cpu(ev->interval);
                conn->le_conn_latency = le16_to_cpu(ev->latency);
                conn->le_supv_timeout = le16_to_cpu(ev->supervision_timeout);
        }
 
        hci_dev_unlock(hdev);
+
+#ifdef TIZEN_BT
+       mgmt_le_conn_updated(hdev, &conn->dst, conn->type,
+                               conn->dst_type, conn->le_conn_interval,
+                               conn->le_conn_latency, conn->le_supv_timeout);
+#endif
 }
 
 /* This function requires the caller holds hdev->lock */
index a22cb29..c2c4c9e 100644 (file)
@@ -7363,6 +7363,74 @@ static int disable_le_auto_connect(struct sock *sk, struct hci_dev *hdev,
 
        return err;
 }
+
+static inline int check_le_conn_update_param(u16 min, u16 max, u16 latency,
+               u16 to_multiplier)
+{
+       u16 max_latency;
+
+       if (min > max || min < 6 || max > 3200)
+               return -EINVAL;
+
+       if (to_multiplier < 10 || to_multiplier > 3200)
+               return -EINVAL;
+
+       if (max >= to_multiplier * 8)
+               return -EINVAL;
+
+       max_latency = (to_multiplier * 8 / max) - 1;
+
+       if (latency > 499 || latency > max_latency)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int le_conn_update(struct sock *sk, struct hci_dev *hdev, void *data,
+               u16 len)
+{
+       struct mgmt_cp_le_conn_update *cp = data;
+
+       struct hci_conn *conn;
+       u16 min, max, latency, supervision_timeout;
+       int err = -1;
+
+       if (!hdev_is_powered(hdev))
+               return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LE_CONN_UPDATE,
+                               MGMT_STATUS_NOT_POWERED);
+
+       min = __le16_to_cpu(cp->conn_interval_min);
+       max = __le16_to_cpu(cp->conn_interval_max);
+       latency = __le16_to_cpu(cp->conn_latency);
+       supervision_timeout = __le16_to_cpu(cp->supervision_timeout);
+
+       BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x supervision_timeout: 0x%4.4x",
+                       min, max, latency, supervision_timeout);
+
+       err = check_le_conn_update_param(min, max, latency,
+                       supervision_timeout);
+
+       if (err < 0)
+               return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LE_CONN_UPDATE,
+                               MGMT_STATUS_INVALID_PARAMS);
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
+       if (!conn) {
+               err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_LE_CONN_UPDATE,
+                               MGMT_STATUS_NOT_CONNECTED);
+               hci_dev_unlock(hdev);
+               return err;
+       }
+
+       hci_dev_unlock(hdev);
+
+       hci_le_conn_update(conn, min, max, latency, supervision_timeout);
+
+       return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LE_CONN_UPDATE, 0,
+                                NULL, 0);
+}
 #endif /* TIZEN_BT */
 
 static bool ltk_is_valid(struct mgmt_ltk_info *key)
@@ -8353,6 +8421,35 @@ int mgmt_device_name_update(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name,
        return mgmt_event(MGMT_EV_DEVICE_NAME_UPDATE, hdev, buf,
                          sizeof(*ev) + eir_len, NULL);
 }
+
+int mgmt_le_conn_update_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                              u8 link_type, u8 addr_type, u8 status)
+{
+       struct mgmt_ev_conn_update_failed ev;
+
+       bacpy(&ev.addr.bdaddr, bdaddr);
+       ev.addr.type = link_to_bdaddr(link_type, addr_type);
+       ev.status = status;
+
+       return mgmt_event(MGMT_EV_CONN_UPDATE_FAILED, hdev,
+                               &ev, sizeof(ev), NULL);
+}
+
+int mgmt_le_conn_updated(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                        u8 link_type, u8 addr_type, u16 conn_interval,
+                        u16 conn_latency, u16 supervision_timeout)
+{
+       struct mgmt_ev_conn_updated ev;
+
+       bacpy(&ev.addr.bdaddr, bdaddr);
+       ev.addr.type = link_to_bdaddr(link_type, addr_type);
+       ev.conn_interval = cpu_to_le16(conn_interval);
+       ev.conn_latency = cpu_to_le16(conn_latency);
+       ev.supervision_timeout = cpu_to_le16(supervision_timeout);
+
+       return mgmt_event(MGMT_EV_CONN_UPDATED, hdev,
+                               &ev, sizeof(ev), NULL);
+}
 #endif
 
 static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
@@ -9335,6 +9432,7 @@ static const struct hci_mgmt_handler tizen_mgmt_handlers[] = {
        { start_le_discovery,      MGMT_START_LE_DISCOVERY_SIZE },
        { stop_le_discovery,       MGMT_STOP_LE_DISCOVERY_SIZE },
        { disable_le_auto_connect, MGMT_DISABLE_LE_AUTO_CONNECT_SIZE },
+       { le_conn_update,          MGMT_LE_CONN_UPDATE_SIZE },
 };
 #endif