Bluetooth: Add LE connection parameter update
authorAnuj Jain <anuj01.jain@samsung.com>
Fri, 6 Jan 2023 09:59:24 +0000 (15:29 +0530)
committerJaehoon Chung <jh80.chung@samsung.com>
Tue, 12 Nov 2024 04:03:14 +0000 (13:03 +0900)
Add support for BT_LE_CONN_PARAM in l2cap socket.

Change-Id: I9a65b55790a9b2a7e43405890209aaac53002b81
Signed-off-by: Anuj Jain <anuj01.jain@samsung.com>
Signed-off-by: Wootak Jung <wootak.jung@samsung.com>
Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com>
include/net/bluetooth/bluetooth.h
include/net/bluetooth/l2cap.h
net/bluetooth/hci_conn.c
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_sock.c

index 90981941bc619d266ec6daeef5012750aa9c863a..52db9664d7f4f848de5a1356e67537dedae08d2c 100644 (file)
 /*To enable Tizen specific fixes */
 #define TIZEN_BT
 
+#ifdef TIZEN_BT
+#define BT_LE_CONN_PARAM        14
+struct le_conn_param {
+       __u16 min;
+       __u16 max;
+       __u16 latency;
+       __u16 to_multiplier;
+};
+#endif
+
 /* Bluetooth versions */
 #define BLUETOOTH_VER_1_1      1
 #define BLUETOOTH_VER_1_2      2
index ad199b52a1985180c591317081bcca5108b611cf..bb6d27a0b6556075a6ed555fdaf57f118c850b94 100644 (file)
@@ -974,6 +974,9 @@ int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user);
 void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user);
 
 #ifdef TIZEN_BT
+int l2cap_update_connection_param(struct l2cap_conn *conn, u16 min, u16 max,
+               u16 latency, u16 to_multiplier);
+
 #ifdef CONFIG_BT_6LOWPAN
 /* IPSP : initialize/deinitialize 6lowpan */
 void bt_6lowpan_enable(void);
index 27223cd2f685efb0b8ee5e75e0608341333a0639..4ed5c10928d6a5031f7882a7e0e06a7f4731a715 100644 (file)
@@ -525,8 +525,16 @@ u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
        cp.conn_interval_max    = cpu_to_le16(max);
        cp.conn_latency         = cpu_to_le16(latency);
        cp.supervision_timeout  = cpu_to_le16(to_multiplier);
-       cp.min_ce_len           = cpu_to_le16(0x0000);
-       cp.max_ce_len           = cpu_to_le16(0x0000);
+
+#ifdef TIZEN_BT
+       cp.min_ce_len           = cpu_to_le16(0x0009);
+       cp.max_ce_len           = cpu_to_le16(0x0009);
+
+       BT_INFO("[%s(%d)] Sent to Remote - Min Connection Interval: %u (in slots), Max Connection Interval: %u (in slots)", __FUNCTION__, __LINE__, min, max);
+#else
+       cp.min_ce_len           = cpu_to_le16(0x0000);
+       cp.max_ce_len           = cpu_to_le16(0x0000);
+#endif
 
        hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp);
 
index aadbb454cb568e6587192c6a416a796beef90e0d..0199a8ea2f16d0e99c2dfd810765a52e13343770 100644 (file)
@@ -1599,6 +1599,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
        if (hcon->out)
                smp_conn_security(hcon, hcon->pending_sec_level);
 
+#ifndef TIZEN_BT
        /* For LE peripheral connections, make sure the connection interval
         * is in the range of the minimum and maximum interval that has
         * been configured for this connection. If not, then trigger
@@ -1617,6 +1618,35 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
                l2cap_send_cmd(conn, l2cap_get_ident(conn),
                               L2CAP_CONN_PARAM_UPDATE_REQ, sizeof(req), &req);
        }
+#else
+/*
+* Too small supervision timeout causes sudden link loss,
+* when remote device has multiple links and it cannot manage those
+* properly.
+*
+* To protect such a case, it needs to widen supervision timeout
+*/
+       if (hcon->role == HCI_ROLE_SLAVE &&
+                       hcon->le_supv_timeout < hdev->le_supv_timeout) {
+               if (hdev->le_features[0] & HCI_LE_CONN_PARAM_REQ_PROC &&
+                               hcon->features[0][0] & HCI_LE_CONN_PARAM_REQ_PROC) {
+                       BT_DBG("use hci_le_conn_update");
+                       hci_le_conn_update(hcon,
+                                       hcon->le_conn_min_interval,
+                                       hcon->le_conn_max_interval,
+                                       hcon->le_conn_latency,
+                                       hdev->le_supv_timeout);
+               } else {
+                       BT_DBG("use l2cap conn_update");
+                       l2cap_update_connection_param(conn,
+                                       hcon->le_conn_min_interval,
+                                       hcon->le_conn_max_interval,
+                                       hcon->le_conn_latency,
+                                       hdev->le_supv_timeout);
+               }
+       }
+
+#endif
 }
 
 static void l2cap_conn_ready(struct l2cap_conn *conn)
@@ -4625,6 +4655,25 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn,
        return 0;
 }
 
+#ifdef TIZEN_BT
+int l2cap_update_connection_param(struct l2cap_conn *conn, u16 min, u16 max,
+                       u16 latency, u16 to_multiplier)
+{
+       struct l2cap_conn_param_update_req req;
+
+       req.min = cpu_to_le16(min);
+       req.max = cpu_to_le16(max);
+       req.latency = cpu_to_le16(latency);
+       req.to_multiplier = cpu_to_le16(to_multiplier);
+
+       BT_INFO("[%s(%d)] Sent to Remote - Min Connection Interval: %u (in slots), Max Connection Interval: %u (in slots)", __FUNCTION__, __LINE__, min, max);
+       l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONN_PARAM_UPDATE_REQ,
+               sizeof(req), &req);
+
+       return 0;
+}
+#endif
+
 static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
                                              struct l2cap_cmd_hdr *cmd,
                                              u16 cmd_len, u8 *data)
index f04ce84267988feff5e5ef7fedc6f49d6a3e77b5..cffa387c38156d98170b819af20da821cccfe678 100644 (file)
@@ -1089,6 +1089,40 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
 
                break;
 
+#ifdef TIZEN_BT
+       case BT_LE_CONN_PARAM: {
+               struct hci_dev *hdev;
+               struct le_conn_param param;
+               int err;
+
+               if (bt_copy_from_sockptr(&param, sizeof(param), optval, optlen)) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               err = hci_check_conn_params(param.min, param.max,
+                               param.latency, param.to_multiplier);
+               if (err < 0)
+                       break;
+
+               conn = chan->conn;
+               hdev = conn->hcon->hdev;
+               if (conn->hcon->out ||
+                       (hdev->le_features[0] & HCI_LE_CONN_PARAM_REQ_PROC &&
+                       conn->hcon->features[0][0] & HCI_LE_CONN_PARAM_REQ_PROC)) {
+                       BT_DBG("use hci_le_conn_update");
+                       err = hci_le_conn_update(conn->hcon, param.min,
+                                               param.max, param.latency,
+                                               param.to_multiplier);
+                       break;
+               }
+               BT_DBG("use l2cap conn_update");
+               err = l2cap_update_connection_param(conn, param.min,
+                       param.max, param.latency, param.to_multiplier);
+               break;
+       }
+#endif
+
        default:
                err = -ENOPROTOOPT;
                break;