diff --git a/doc/releases/migration-guide-4.0.rst b/doc/releases/migration-guide-4.0.rst index b6866438735399..5e45b2d2c302e0 100644 --- a/doc/releases/migration-guide-4.0.rst +++ b/doc/releases/migration-guide-4.0.rst @@ -404,6 +404,10 @@ Bluetooth Audio Bluetooth Host ============== +* :c:func:`bt_gatt_subscribe` behavior has changed to if a different user/application has already + subscribed to the same handle, then the callback will contain the values aggregated of all the + users/applications. + Automatic advertiser resumption is deprecated --------------------------------------------- diff --git a/include/zephyr/bluetooth/gatt.h b/include/zephyr/bluetooth/gatt.h index c72cb821a726ad..4ad8b655888af6 100644 --- a/include/zephyr/bluetooth/gatt.h +++ b/include/zephyr/bluetooth/gatt.h @@ -2076,6 +2076,9 @@ struct bt_gatt_subscribe_params { * notified value. One may then decide whether to unsubscribe directly from * this callback. Notification callback with NULL data will not be called if * subscription was removed by this method. + * If a different user/application has already subscribed to the same handle, + * then the callback will contain the values aggregated of all the + * users/applications. * * The Response comes in callback @p params->subscribe. The callback is run from * the context specified by 'config BT_RECV_CONTEXT'. @@ -2095,6 +2098,8 @@ struct bt_gatt_subscribe_params { * @retval 0 Successfully queued request. Will call @p params->write on * resolution. * + * @retval -EINVAL if the @p params->value is out of range + * * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function * outside the BT RX thread to get blocking behavior. Queue size is controlled diff --git a/subsys/bluetooth/host/gatt.c b/subsys/bluetooth/host/gatt.c index 5503bb6b8b9992..de7e00069420bf 100644 --- a/subsys/bluetooth/host/gatt.c +++ b/subsys/bluetooth/host/gatt.c @@ -5429,7 +5429,7 @@ int bt_gatt_subscribe(struct bt_conn *conn, { struct gatt_sub *sub; struct bt_gatt_subscribe_params *tmp; - bool has_subscription = false; + int err; __ASSERT(conn, "invalid parameters\n"); __ASSERT(params && params->notify, "invalid parameters\n"); @@ -5446,6 +5446,11 @@ int bt_gatt_subscribe(struct bt_conn *conn, return -ENOTCONN; } + if (!IN_RANGE(params->value, BT_GATT_CCC_NOTIFY, + BT_GATT_CCC_NOTIFY | BT_GATT_CCC_INDICATE)) { + return -EINVAL; + } + sub = gatt_sub_add(conn); if (!sub) { return -ENOMEM; @@ -5467,26 +5472,20 @@ int bt_gatt_subscribe(struct bt_conn *conn, } /* Check if another subscription exists */ - if (tmp->value_handle == params->value_handle && - tmp->value >= params->value) { - has_subscription = true; + if (tmp->value_handle == params->value_handle) { + params->value |= tmp->value; } } - /* Skip write if already subscribed */ - if (!has_subscription) { - int err; - #if defined(CONFIG_BT_GATT_AUTO_DISCOVER_CCC) - if (params->ccc_handle == BT_GATT_AUTO_DISCOVER_CCC_HANDLE) { - return gatt_ccc_discover(conn, params); - } + if (params->ccc_handle == BT_GATT_AUTO_DISCOVER_CCC_HANDLE) { + return gatt_ccc_discover(conn, params); + } #endif - err = gatt_write_ccc(conn, params, gatt_write_ccc_rsp); - if (err) { - gatt_sub_remove(conn, sub, NULL, NULL); - return err; - } + err = gatt_write_ccc(conn, params, gatt_write_ccc_rsp); + if (err) { + gatt_sub_remove(conn, sub, NULL, NULL); + return err; } /*