From: Anuj Jain Date: Fri, 6 Jan 2023 09:59:24 +0000 (+0530) Subject: Bluetooth: Add LE connection parameter update X-Git-Tag: accepted/tizen/unified/20230118.172025^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F71%2F286471%2F3;p=platform%2Fkernel%2Flinux-rpi.git Bluetooth: Add LE connection parameter update Add support for BT_LE_CONN_PARAM in l2cap socket. Change-Id: I2ed693da26ba2d3464b9997bf1880c6c136055cd Signed-off-by: Anuj Jain --- diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 3335b15..fefafa2 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -40,6 +40,16 @@ /*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 diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 4229fe8..fb5f723 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -1007,6 +1007,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); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index fe584c0..9ca63d1 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -403,8 +403,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); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 7f9f38a..41de98d 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1736,6 +1736,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 @@ -1754,6 +1755,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) @@ -5585,6 +5615,25 @@ static inline int l2cap_move_channel_confirm_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) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index d2c6785..d31e3e4 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1133,6 +1133,41 @@ 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; + + len = min_t(unsigned int, sizeof(param), optlen); + if (copy_from_sockptr(¶m, optval, len)) { + 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;