diff --git a/drivers/nble/conn.c b/drivers/nble/conn.c index 2bdd80afbc2..ac16548f2c7 100644 --- a/drivers/nble/conn.c +++ b/drivers/nble/conn.c @@ -43,6 +43,12 @@ int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info) return -ENOSYS; } +int bt_conn_le_param_update(struct bt_conn *conn, + const struct bt_le_conn_param *param) +{ + return -ENOSYS; +} + int bt_conn_disconnect(struct bt_conn *conn, uint8_t reason) { return -ENOSYS; diff --git a/include/bluetooth/conn.h b/include/bluetooth/conn.h index 928c2928888..42498c2113a 100644 --- a/include/bluetooth/conn.h +++ b/include/bluetooth/conn.h @@ -149,6 +149,16 @@ struct bt_conn_info { */ int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info); +/** @brief Update the connection parameters. + * + * @param conn Connection object. + * @param param Updated connection parameters. + * + * @return Zero on success or (negative) error code on failure. + */ +int bt_conn_le_param_update(struct bt_conn *conn, + const struct bt_le_conn_param *param); + /** @brief Disconnect from a remote device or cancel pending connection. * * Disconnect an active connection with the specified reason code or cancel @@ -265,6 +275,8 @@ uint8_t bt_conn_enc_key_size(struct bt_conn *conn); struct bt_conn_cb { void (*connected)(struct bt_conn *conn, uint8_t err); void (*disconnected)(struct bt_conn *conn, uint8_t reason); + void (*le_param_updated)(struct bt_conn *conn, uint16_t interval, + uint16_t latency, uint16_t timeout); #if defined(CONFIG_BLUETOOTH_SMP) void (*identity_resolved)(struct bt_conn *conn, const bt_addr_le_t *rpa, diff --git a/net/bluetooth/conn.c b/net/bluetooth/conn.c index 49e14a97097..681418ef66c 100644 --- a/net/bluetooth/conn.c +++ b/net/bluetooth/conn.c @@ -104,6 +104,19 @@ static void notify_disconnected(struct bt_conn *conn) } } +void notify_le_param_updated(struct bt_conn *conn) +{ + struct bt_conn_cb *cb; + + for (cb = callback_list; cb; cb = cb->_next) { + if (cb->le_param_updated) { + cb->le_param_updated(conn, conn->le.interval, + conn->le.latency, + conn->le.timeout); + } + } +} + #if defined(CONFIG_BLUETOOTH_SMP) uint8_t bt_conn_enc_key_size(struct bt_conn *conn) { @@ -858,6 +871,12 @@ static int bt_hci_connect_le_cancel(struct bt_conn *conn) return 0; } +int bt_conn_le_param_update(struct bt_conn *conn, + const struct bt_le_conn_param *param) +{ + return bt_conn_update_param_le(conn, param); +} + int bt_conn_disconnect(struct bt_conn *conn, uint8_t reason) { #if defined(CONFIG_BLUETOOTH_CENTRAL) @@ -991,8 +1010,8 @@ struct bt_conn *bt_conn_create_slave_le(const bt_addr_le_t *peer, } #endif /* CONFIG_BLUETOOTH_PERIPHERAL */ -int bt_conn_le_conn_update(struct bt_conn *conn, uint16_t min, uint16_t max, - uint16_t latency, uint16_t timeout) +int bt_conn_le_conn_update(struct bt_conn *conn, + const struct bt_le_conn_param *param) { struct hci_cp_le_conn_update *conn_update; struct net_buf *buf; @@ -1006,10 +1025,10 @@ int bt_conn_le_conn_update(struct bt_conn *conn, uint16_t min, uint16_t max, conn_update = net_buf_add(buf, sizeof(*conn_update)); memset(conn_update, 0, sizeof(*conn_update)); conn_update->handle = sys_cpu_to_le16(conn->handle); - conn_update->conn_interval_min = sys_cpu_to_le16(min); - conn_update->conn_interval_max = sys_cpu_to_le16(max); - conn_update->conn_latency = sys_cpu_to_le16(latency); - conn_update->supervision_timeout = sys_cpu_to_le16(timeout); + conn_update->conn_interval_min = sys_cpu_to_le16(param->interval_min); + conn_update->conn_interval_max = sys_cpu_to_le16(param->interval_max); + conn_update->conn_latency = sys_cpu_to_le16(param->latency); + conn_update->supervision_timeout = sys_cpu_to_le16(param->timeout); return bt_hci_cmd_send(BT_HCI_OP_LE_CONN_UPDATE, buf); } diff --git a/net/bluetooth/conn_internal.h b/net/bluetooth/conn_internal.h index 1401f684139..06bb285bc5f 100644 --- a/net/bluetooth/conn_internal.h +++ b/net/bluetooth/conn_internal.h @@ -137,8 +137,13 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state); void bt_conn_set_param_le(struct bt_conn *conn, const struct bt_le_conn_param *param); -int bt_conn_le_conn_update(struct bt_conn *conn, uint16_t min, uint16_t max, - uint16_t latency, uint16_t timeout); +int bt_conn_update_param_le(struct bt_conn *conn, + const struct bt_le_conn_param *param); + +int bt_conn_le_conn_update(struct bt_conn *conn, + const struct bt_le_conn_param *param); + +void notify_le_param_updated(struct bt_conn *conn); #if defined(CONFIG_BLUETOOTH_SMP) /* rand and ediv should be in BT order */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f1ee29f53b1..2b4a069f44e 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -493,30 +493,15 @@ static int hci_le_read_remote_features(struct bt_conn *conn) return 0; } -static int update_conn_params(struct bt_conn *conn) +static int update_conn_param(struct bt_conn *conn) { - BT_DBG("conn %p features 0x%x", conn, conn->le.features[0]); + const struct bt_le_conn_param *param; - /* Check if there's a need to update conn params */ - if (conn->le.interval >= conn->le.interval_min && - conn->le.interval <= conn->le.interval_max) { - return -EALREADY; - } - - if ((conn->role == BT_HCI_ROLE_SLAVE) && - !(bt_dev.le.features[0] & BT_HCI_LE_CONN_PARAM_REQ_PROC)) { - return bt_l2cap_update_conn_param(conn); - } - - if ((conn->le.features[0] & BT_HCI_LE_CONN_PARAM_REQ_PROC) && - (bt_dev.le.features[0] & BT_HCI_LE_CONN_PARAM_REQ_PROC)) { - return bt_conn_le_conn_update(conn, conn->le.interval_min, - conn->le.interval_max, - conn->le.latency, - conn->le.timeout); - } - - return -EBUSY; + param = BT_LE_CONN_PARAM(conn->le.interval_min, + conn->le.interval_max, + conn->le.latency, + conn->le.timeout); + return bt_conn_update_param_le(conn, param); } static void le_conn_complete(struct net_buf *buf) @@ -605,7 +590,7 @@ static void le_conn_complete(struct net_buf *buf) } } - update_conn_params(conn); + update_conn_param(conn); done: bt_conn_unref(conn); @@ -629,7 +614,7 @@ static void le_remote_feat_complete(struct net_buf *buf) sizeof(conn->le.features)); } - update_conn_params(conn); + update_conn_param(conn); bt_conn_unref(conn); } @@ -708,10 +693,9 @@ static void le_conn_update_complete(struct net_buf *buf) { struct bt_hci_evt_le_conn_update_complete *evt = (void *)buf->data; struct bt_conn *conn; - uint16_t handle, interval; + uint16_t handle; handle = sys_le16_to_cpu(evt->handle); - interval = sys_le16_to_cpu(evt->interval); BT_DBG("status %u, handle %u", evt->status, handle); @@ -722,11 +706,12 @@ static void le_conn_update_complete(struct net_buf *buf) } if (!evt->status) { - conn->le.interval = interval; + conn->le.interval = sys_le16_to_cpu(evt->interval); + conn->le.latency = sys_le16_to_cpu(evt->latency); + conn->le.timeout = sys_le16_to_cpu(evt->supv_timeout); + notify_le_param_updated(conn); } - /* TODO Notify about connection */ - bt_conn_unref(conn); } @@ -808,6 +793,33 @@ void bt_conn_set_param_le(struct bt_conn *conn, conn->le.latency = param->latency; conn->le.timeout = param->timeout; } + +int bt_conn_update_param_le(struct bt_conn *conn, + const struct bt_le_conn_param *param) +{ + BT_DBG("conn %p features 0x%x params (%d-%d %d %d)", conn, + conn->le.features[0], param->interval_min, param->interval_max, + param->latency, param->timeout); + + /* Check if there's a need to update conn params */ + if (conn->le.interval >= param->interval_min && + conn->le.interval <= param->interval_max) { + return -EALREADY; + } + + if ((conn->role == BT_HCI_ROLE_SLAVE) && + !(bt_dev.le.features[0] & BT_HCI_LE_CONN_PARAM_REQ_PROC)) { + return bt_l2cap_update_conn_param(conn, param); + } + + if ((conn->le.features[0] & BT_HCI_LE_CONN_PARAM_REQ_PROC) && + (bt_dev.le.features[0] & BT_HCI_LE_CONN_PARAM_REQ_PROC)) { + return bt_conn_le_conn_update(conn, param); + } + + return -EBUSY; +} + #endif /* CONFIG_BLUETOOTH_CONN */ #if defined(CONFIG_BLUETOOTH_SMP) || defined(CONFIG_BLUETOOTH_BREDR) diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 7f1bd793add..759169c9a9d 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -283,6 +283,7 @@ static void le_conn_param_update_req(struct bt_l2cap *l2cap, uint8_t ident, struct net_buf *buf) { struct bt_conn *conn = l2cap->chan.conn; + const struct bt_le_conn_param *param; uint16_t min, max, latency, timeout; bool params_valid; struct bt_l2cap_sig_hdr *hdr; @@ -303,6 +304,7 @@ static void le_conn_param_update_req(struct bt_l2cap *l2cap, uint8_t ident, max = sys_le16_to_cpu(req->max_interval); latency = sys_le16_to_cpu(req->latency); timeout = sys_le16_to_cpu(req->timeout); + param = BT_LE_CONN_PARAM(min, max, latency, timeout); BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x timeout: 0x%4.4x", min, max, latency, timeout); @@ -329,7 +331,7 @@ static void le_conn_param_update_req(struct bt_l2cap *l2cap, uint8_t ident, bt_l2cap_send(l2cap->chan.conn, BT_L2CAP_CID_LE_SIG, buf); if (params_valid) { - bt_conn_le_conn_update(conn, min, max, latency, timeout); + bt_conn_le_conn_update(conn, param); } } #endif /* CONFIG_BLUETOOTH_CENTRAL */ @@ -963,7 +965,8 @@ void bt_l2cap_recv(struct bt_conn *conn, struct net_buf *buf) net_buf_unref(buf); } -int bt_l2cap_update_conn_param(struct bt_conn *conn) +int bt_l2cap_update_conn_param(struct bt_conn *conn, + const struct bt_le_conn_param *param) { struct bt_l2cap_sig_hdr *hdr; struct bt_l2cap_conn_param_req *req; @@ -980,10 +983,10 @@ int bt_l2cap_update_conn_param(struct bt_conn *conn) hdr->len = sys_cpu_to_le16(sizeof(*req)); req = net_buf_add(buf, sizeof(*req)); - req->min_interval = sys_cpu_to_le16(conn->le.interval_min); - req->max_interval = sys_cpu_to_le16(conn->le.interval_max); - req->latency = sys_cpu_to_le16(conn->le.latency); - req->timeout = sys_cpu_to_le16(conn->le.timeout); + req->min_interval = sys_cpu_to_le16(param->interval_min); + req->max_interval = sys_cpu_to_le16(param->interval_max); + req->latency = sys_cpu_to_le16(param->latency); + req->timeout = sys_cpu_to_le16(param->timeout); bt_l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf); diff --git a/net/bluetooth/l2cap_internal.h b/net/bluetooth/l2cap_internal.h index 7fbf243f9b6..c40a8fff077 100644 --- a/net/bluetooth/l2cap_internal.h +++ b/net/bluetooth/l2cap_internal.h @@ -144,7 +144,8 @@ void bt_l2cap_send(struct bt_conn *conn, uint16_t cid, struct net_buf *buf); void bt_l2cap_recv(struct bt_conn *conn, struct net_buf *buf); /* Perform connection parameter update request */ -int bt_l2cap_update_conn_param(struct bt_conn *conn); +int bt_l2cap_update_conn_param(struct bt_conn *conn, + const struct bt_le_conn_param *param); /* Initialize L2CAP and supported channels */ void bt_l2cap_init(void);