Bluetooth: audio: Add security requirements check

The LE Audio related profiles define specific security requirements that
client have to met to gain access to related characteristics. This
introduces internal wrapper API for GATT characteristics and CCC
descriptors to ensure the security.

Signed-off-by: Mariusz Skamra <mariusz.skamra@codecoup.pl>
This commit is contained in:
Mariusz Skamra 2022-07-25 09:56:23 +02:00 committed by Carles Cufí
commit e0d36beb72
21 changed files with 646 additions and 573 deletions

View file

@ -1,6 +1,7 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
zephyr_library() zephyr_library()
zephyr_library_sources(audio.c)
if (CONFIG_BT_VOCS OR CONFIG_BT_VOCS_CLIENT) if (CONFIG_BT_VOCS OR CONFIG_BT_VOCS_CLIENT)
zephyr_library_sources(vocs.c) zephyr_library_sources(vocs.c)

View file

@ -8,7 +8,6 @@
config BT_ASCS config BT_ASCS
bool "Audio Stream Control Service Support" bool "Audio Stream Control Service Support"
select BT_SMP_SC_PAIR_ONLY
help help
This option enables support for Audio Stream Control Service. This option enables support for Audio Stream Control Service.

View file

@ -15,7 +15,6 @@ config BT_BASS
select BT_OBSERVER select BT_OBSERVER
select BT_EXT_ADV select BT_EXT_ADV
select BT_PER_ADV_SYNC select BT_PER_ADV_SYNC
select BT_SMP_SC_PAIR_ONLY
select BT_ISO_SYNC_RECEIVER select BT_ISO_SYNC_RECEIVER
help help
This option enables support for the Broadcast Audio Scan Service. This option enables support for the Broadcast Audio Scan Service.

View file

@ -31,7 +31,6 @@ config BT_CSIS_TEST_SAMPLE_DATA
config BT_CSIS_ENC_SIRK_SUPPORT config BT_CSIS_ENC_SIRK_SUPPORT
bool "Support for encrypted SIRK" bool "Support for encrypted SIRK"
default y default y
select BT_SMP_SC_PAIR_ONLY
help help
Enables support encrypting the SIRK. Enables support encrypting the SIRK.
@ -92,7 +91,6 @@ config BT_CSIS_CLIENT_MAX_CSIS_INSTANCES
config BT_CSIS_CLIENT_ENC_SIRK_SUPPORT config BT_CSIS_CLIENT_ENC_SIRK_SUPPORT
bool "Support for encrypted SIRK" bool "Support for encrypted SIRK"
default y default y
select BT_SMP_SC_PAIR_ONLY
help help
Enables support encrypting the SIRK. Enables support encrypting the SIRK.

View file

@ -8,8 +8,6 @@ menuconfig BT_HAS
bool "Hearing Access Service support [EXPERIMENTAL]" bool "Hearing Access Service support [EXPERIMENTAL]"
select EXPERIMENTAL select EXPERIMENTAL
select UTF8 select UTF8
depends on BT_SMP_SC_PAIR_ONLY
depends on BT_SMP_MIN_ENC_KEY_SIZE = 16
depends on BT_AUDIO_UNICAST_SERVER depends on BT_AUDIO_UNICAST_SERVER
help help
This option enables support for Hearing Access Service. This option enables support for Hearing Access Service.

View file

@ -87,7 +87,6 @@ endif # BT_PAC_SRC
config BT_PACS config BT_PACS
def_bool BT_PAC_SNK || BT_PAC_SRC def_bool BT_PAC_SNK || BT_PAC_SRC
select BT_SMP_SC_PAIR_ONLY
config BT_DEBUG_PACS config BT_DEBUG_PACS
bool "Published Audio Capabilities Service debug" bool "Published Audio Capabilities Service debug"

View file

@ -18,6 +18,7 @@
#include <zephyr/bluetooth/audio/aics.h> #include <zephyr/bluetooth/audio/aics.h>
#include "aics_internal.h" #include "aics_internal.h"
#include "audio_internal.h"
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_AICS) #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_AICS)
#define LOG_MODULE_NAME bt_aics #define LOG_MODULE_NAME bt_aics
@ -65,36 +66,33 @@ static ssize_t read_description(struct bt_conn *conn,
#define BT_AICS_SERVICE_DEFINITION(_aics) { \ #define BT_AICS_SERVICE_DEFINITION(_aics) { \
BT_GATT_SECONDARY_SERVICE(BT_UUID_AICS), \ BT_GATT_SECONDARY_SERVICE(BT_UUID_AICS), \
BT_GATT_CHARACTERISTIC(BT_UUID_AICS_STATE, \ BT_AUDIO_CHRC(BT_UUID_AICS_STATE, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ_LESC, \ BT_GATT_PERM_READ_ENCRYPT, \
read_aics_state, NULL, &_aics), \ read_aics_state, NULL, &_aics), \
BT_GATT_CCC(aics_state_cfg_changed, \ BT_AUDIO_CCC(aics_state_cfg_changed), \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_LESC), \ BT_AUDIO_CHRC(BT_UUID_AICS_GAIN_SETTINGS, \
BT_GATT_CHARACTERISTIC(BT_UUID_AICS_GAIN_SETTINGS, \ BT_GATT_CHRC_READ, \
BT_GATT_CHRC_READ, \ BT_GATT_PERM_READ_ENCRYPT, \
BT_GATT_PERM_READ_LESC, \ read_aics_gain_settings, NULL, &_aics), \
read_aics_gain_settings, NULL, &_aics), \ BT_AUDIO_CHRC(BT_UUID_AICS_INPUT_TYPE, \
BT_GATT_CHARACTERISTIC(BT_UUID_AICS_INPUT_TYPE, \ BT_GATT_CHRC_READ, \
BT_GATT_CHRC_READ, \ BT_GATT_PERM_READ_ENCRYPT, \
BT_GATT_PERM_READ_LESC, \ read_type, NULL, &_aics), \
read_type, NULL, &_aics), \ BT_AUDIO_CHRC(BT_UUID_AICS_INPUT_STATUS, \
BT_GATT_CHARACTERISTIC(BT_UUID_AICS_INPUT_STATUS, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ BT_GATT_PERM_READ_ENCRYPT, \
BT_GATT_PERM_READ_LESC, \ read_input_status, NULL, &_aics), \
read_input_status, NULL, &_aics), \ BT_AUDIO_CCC(aics_input_status_cfg_changed), \
BT_GATT_CCC(aics_input_status_cfg_changed, \ BT_AUDIO_CHRC(BT_UUID_AICS_CONTROL, \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_LESC), \ BT_GATT_CHRC_WRITE, \
BT_GATT_CHARACTERISTIC(BT_UUID_AICS_CONTROL, \ BT_GATT_PERM_WRITE_ENCRYPT, \
BT_GATT_CHRC_WRITE, \ NULL, write_aics_control, &_aics), \
BT_GATT_PERM_WRITE_LESC, \ BT_AUDIO_CHRC(BT_UUID_AICS_DESCRIPTION, \
NULL, write_aics_control, &_aics), \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_CHARACTERISTIC(BT_UUID_AICS_DESCRIPTION, \ BT_GATT_PERM_READ_ENCRYPT, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ read_description, write_description, &_aics), \
BT_GATT_PERM_READ_LESC, \ BT_AUDIO_CCC(aics_description_cfg_changed) \
read_description, NULL, &_aics), \
BT_GATT_CCC(aics_description_cfg_changed, \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_LESC) \
} }
@ -114,7 +112,7 @@ static ssize_t read_aics_state(struct bt_conn *conn,
const struct bt_gatt_attr *attr, void *buf, const struct bt_gatt_attr *attr, void *buf,
uint16_t len, uint16_t offset) uint16_t len, uint16_t offset)
{ {
struct bt_aics *inst = attr->user_data; struct bt_aics *inst = BT_AUDIO_CHRC_USER_DATA(attr);
BT_DBG("gain %d, mute %u, gain_mode %u, counter %u", BT_DBG("gain %d, mute %u, gain_mode %u, counter %u",
inst->srv.state.gain, inst->srv.state.mute, inst->srv.state.gain, inst->srv.state.mute,
@ -128,7 +126,7 @@ static ssize_t read_aics_gain_settings(struct bt_conn *conn,
const struct bt_gatt_attr *attr, const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset) void *buf, uint16_t len, uint16_t offset)
{ {
struct bt_aics *inst = attr->user_data; struct bt_aics *inst = BT_AUDIO_CHRC_USER_DATA(attr);
BT_DBG("units %u, min %d, max %d", BT_DBG("units %u, min %d, max %d",
inst->srv.gain_settings.units, inst->srv.gain_settings.minimum, inst->srv.gain_settings.units, inst->srv.gain_settings.minimum,
@ -142,7 +140,7 @@ static ssize_t read_aics_gain_settings(struct bt_conn *conn,
static ssize_t read_type(struct bt_conn *conn, const struct bt_gatt_attr *attr, static ssize_t read_type(struct bt_conn *conn, const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset) void *buf, uint16_t len, uint16_t offset)
{ {
struct bt_aics *inst = attr->user_data; struct bt_aics *inst = BT_AUDIO_CHRC_USER_DATA(attr);
BT_DBG("%u", inst->srv.type); BT_DBG("%u", inst->srv.type);
@ -160,7 +158,7 @@ static ssize_t read_input_status(struct bt_conn *conn,
const struct bt_gatt_attr *attr, void *buf, const struct bt_gatt_attr *attr, void *buf,
uint16_t len, uint16_t offset) uint16_t len, uint16_t offset)
{ {
struct bt_aics *inst = attr->user_data; struct bt_aics *inst = BT_AUDIO_CHRC_USER_DATA(attr);
BT_DBG("%u", inst->srv.status); BT_DBG("%u", inst->srv.status);
@ -175,7 +173,7 @@ static ssize_t write_aics_control(struct bt_conn *conn,
const void *buf, uint16_t len, const void *buf, uint16_t len,
uint16_t offset, uint8_t flags) uint16_t offset, uint8_t flags)
{ {
struct bt_aics *inst = attr->user_data; struct bt_aics *inst = BT_AUDIO_CHRC_USER_DATA(attr);
const struct bt_aics_gain_control *cp = buf; const struct bt_aics_gain_control *cp = buf;
bool notify = false; bool notify = false;
@ -297,7 +295,7 @@ static ssize_t write_description(struct bt_conn *conn,
const void *buf, uint16_t len, uint16_t offset, const void *buf, uint16_t len, uint16_t offset,
uint8_t flags) uint8_t flags)
{ {
struct bt_aics *inst = attr->user_data; struct bt_aics *inst = BT_AUDIO_CHRC_USER_DATA(attr);
if (len >= sizeof(inst->srv.description)) { if (len >= sizeof(inst->srv.description)) {
BT_DBG("Output desc was clipped from length %u to %zu", BT_DBG("Output desc was clipped from length %u to %zu",
@ -327,12 +325,35 @@ static ssize_t write_description(struct bt_conn *conn,
return len; return len;
} }
static int aics_write(struct bt_aics *inst,
ssize_t (*write)(struct bt_conn *conn,
const struct bt_gatt_attr *attr,
const void *buf, uint16_t len,
uint16_t offset, uint8_t flags),
const void *buf, uint16_t len)
{
struct bt_audio_attr_user_data user_data = {
.user_data = inst,
};
struct bt_gatt_attr attr = {
.user_data = &user_data,
};
int err;
err = write(NULL, &attr, buf, len, 0, 0);
if (err < 0) {
return err;
}
return 0;
}
#if defined(CONFIG_BT_AICS) #if defined(CONFIG_BT_AICS)
static ssize_t read_description(struct bt_conn *conn, static ssize_t read_description(struct bt_conn *conn,
const struct bt_gatt_attr *attr, void *buf, const struct bt_gatt_attr *attr, void *buf,
uint16_t len, uint16_t offset) uint16_t len, uint16_t offset)
{ {
struct bt_aics *inst = attr->user_data; struct bt_aics *inst = BT_AUDIO_CHRC_USER_DATA(attr);
BT_DBG("%s", inst->srv.description); BT_DBG("%s", inst->srv.description);
@ -455,8 +476,7 @@ int bt_aics_register(struct bt_aics *aics, struct bt_aics_register_param *param)
struct bt_gatt_chrc *chrc; struct bt_gatt_chrc *chrc;
chrc = aics->srv.service_p->attrs[i - 1].user_data; chrc = aics->srv.service_p->attrs[i - 1].user_data;
attr->write = write_description; attr->perm |= BT_GATT_PERM_WRITE_ENCRYPT;
attr->perm |= BT_GATT_PERM_WRITE_LESC;
chrc->properties |= BT_GATT_CHRC_WRITE_WITHOUT_RESP; chrc->properties |= BT_GATT_CHRC_WRITE_WITHOUT_RESP;
break; break;
@ -638,18 +658,12 @@ int bt_aics_unmute(struct bt_aics *inst)
if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) { if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
return bt_aics_client_unmute(inst); return bt_aics_client_unmute(inst);
} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) { } else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
struct bt_gatt_attr attr;
struct bt_aics_control cp; struct bt_aics_control cp;
int err;
cp.opcode = BT_AICS_OPCODE_UNMUTE; cp.opcode = BT_AICS_OPCODE_UNMUTE;
cp.counter = inst->srv.state.change_counter; cp.counter = inst->srv.state.change_counter;
attr.user_data = inst; return aics_write(inst, write_aics_control, &cp, sizeof(cp));
err = write_aics_control(NULL, &attr, &cp, sizeof(cp), 0, 0);
return err > 0 ? 0 : err;
} }
return -ENOTSUP; return -ENOTSUP;
@ -665,18 +679,12 @@ int bt_aics_mute(struct bt_aics *inst)
if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) { if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
return bt_aics_client_mute(inst); return bt_aics_client_mute(inst);
} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) { } else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
struct bt_gatt_attr attr;
struct bt_aics_control cp; struct bt_aics_control cp;
int err;
cp.opcode = BT_AICS_OPCODE_MUTE; cp.opcode = BT_AICS_OPCODE_MUTE;
cp.counter = inst->srv.state.change_counter; cp.counter = inst->srv.state.change_counter;
attr.user_data = inst; return aics_write(inst, write_aics_control, &cp, sizeof(cp));
err = write_aics_control(NULL, &attr, &cp, sizeof(cp), 0, 0);
return err > 0 ? 0 : err;
} }
return -ENOTSUP; return -ENOTSUP;
@ -692,18 +700,12 @@ int bt_aics_manual_gain_set(struct bt_aics *inst)
if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) { if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
return bt_aics_client_manual_gain_set(inst); return bt_aics_client_manual_gain_set(inst);
} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) { } else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
struct bt_gatt_attr attr;
struct bt_aics_control cp; struct bt_aics_control cp;
int err;
cp.opcode = BT_AICS_OPCODE_SET_MANUAL; cp.opcode = BT_AICS_OPCODE_SET_MANUAL;
cp.counter = inst->srv.state.change_counter; cp.counter = inst->srv.state.change_counter;
attr.user_data = inst; return aics_write(inst, write_aics_control, &cp, sizeof(cp));
err = write_aics_control(NULL, &attr, &cp, sizeof(cp), 0, 0);
return err > 0 ? 0 : err;
} }
return -ENOTSUP; return -ENOTSUP;
@ -719,18 +721,12 @@ int bt_aics_automatic_gain_set(struct bt_aics *inst)
if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) { if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
return bt_aics_client_automatic_gain_set(inst); return bt_aics_client_automatic_gain_set(inst);
} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) { } else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
struct bt_gatt_attr attr;
struct bt_aics_control cp; struct bt_aics_control cp;
int err;
cp.opcode = BT_AICS_OPCODE_SET_AUTO; cp.opcode = BT_AICS_OPCODE_SET_AUTO;
cp.counter = inst->srv.state.change_counter; cp.counter = inst->srv.state.change_counter;
attr.user_data = inst; return aics_write(inst, write_aics_control, &cp, sizeof(cp));
err = write_aics_control(NULL, &attr, &cp, sizeof(cp), 0, 0);
return err > 0 ? 0 : err;
} }
return -ENOTSUP; return -ENOTSUP;
@ -746,19 +742,13 @@ int bt_aics_gain_set(struct bt_aics *inst, int8_t gain)
if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) { if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
return bt_aics_client_gain_set(inst, gain); return bt_aics_client_gain_set(inst, gain);
} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) { } else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
struct bt_gatt_attr attr;
struct bt_aics_gain_control cp; struct bt_aics_gain_control cp;
int err;
cp.cp.opcode = BT_AICS_OPCODE_SET_GAIN; cp.cp.opcode = BT_AICS_OPCODE_SET_GAIN;
cp.cp.counter = inst->srv.state.change_counter; cp.cp.counter = inst->srv.state.change_counter;
cp.gain_setting = gain; cp.gain_setting = gain;
attr.user_data = inst; return aics_write(inst, write_aics_control, &cp, sizeof(cp));
err = write_aics_control(NULL, &attr, &cp, sizeof(cp), 0, 0);
return err > 0 ? 0 : err;
} }
return -ENOTSUP; return -ENOTSUP;
@ -801,15 +791,7 @@ int bt_aics_description_set(struct bt_aics *inst, const char *description)
if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) { if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && inst->client_instance) {
return bt_aics_client_description_set(inst, description); return bt_aics_client_description_set(inst, description);
} else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) { } else if (IS_ENABLED(CONFIG_BT_AICS) && !inst->client_instance) {
struct bt_gatt_attr attr; return aics_write(inst, write_description, description, strlen(description));
int err;
attr.user_data = inst;
err = write_description(NULL, &attr, description,
strlen(description), 0, 0);
return err > 0 ? 0 : err;
} }
return -ENOTSUP; return -ENOTSUP;

View file

@ -27,6 +27,7 @@
#include "../host/hci_core.h" #include "../host/hci_core.h"
#include "../host/conn_internal.h" #include "../host/conn_internal.h"
#include "audio_internal.h"
#include "endpoint.h" #include "endpoint.h"
#include "unicast_server.h" #include "unicast_server.h"
#include "pacs_internal.h" #include "pacs_internal.h"
@ -932,7 +933,7 @@ static uint8_t ase_attr_cb(const struct bt_gatt_attr *attr, uint16_t handle,
{ {
struct bt_ascs_ase *ase = user_data; struct bt_ascs_ase *ase = user_data;
if (ase->ep.status.id == POINTER_TO_UINT(attr->user_data)) { if (ase->ep.status.id == POINTER_TO_UINT(BT_AUDIO_CHRC_USER_DATA(attr))) {
ase->ep.server.attr = attr; ase->ep.server.attr = attr;
return BT_GATT_ITER_STOP; return BT_GATT_ITER_STOP;
@ -1067,7 +1068,7 @@ static ssize_t ascs_ase_read(struct bt_conn *conn,
return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY); return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
} }
ase = ase_get(ascs, POINTER_TO_UINT(attr->user_data)); ase = ase_get(ascs, POINTER_TO_UINT(BT_AUDIO_CHRC_USER_DATA(attr)));
if (!ase) { if (!ase) {
BT_ERR("Unable to get ASE"); BT_ERR("Unable to get ASE");
return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY); return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
@ -2298,47 +2299,38 @@ respond:
BT_GATT_SERVICE_DEFINE(ascs_svc, BT_GATT_SERVICE_DEFINE(ascs_svc,
BT_GATT_PRIMARY_SERVICE(BT_UUID_ASCS), BT_GATT_PRIMARY_SERVICE(BT_UUID_ASCS),
#if CONFIG_BT_ASCS_ASE_SNK_COUNT > 0 #if CONFIG_BT_ASCS_ASE_SNK_COUNT > 0
BT_GATT_CHARACTERISTIC(BT_UUID_ASCS_ASE_SNK, BT_AUDIO_CHRC(BT_UUID_ASCS_ASE_SNK,
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
BT_GATT_PERM_READ_ENCRYPT, BT_GATT_PERM_READ_ENCRYPT,
ascs_ase_read, NULL, UINT_TO_POINTER(1)), ascs_ase_read, NULL, UINT_TO_POINTER(1)),
BT_GATT_CCC(ascs_ase_cfg_changed, BT_AUDIO_CCC(ascs_ase_cfg_changed),
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT),
#endif #endif
#if CONFIG_BT_ASCS_ASE_SNK_COUNT > 1 #if CONFIG_BT_ASCS_ASE_SNK_COUNT > 1
BT_GATT_CHARACTERISTIC(BT_UUID_ASCS_ASE_SNK, BT_AUDIO_CHRC(BT_UUID_ASCS_ASE_SNK,
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
BT_GATT_PERM_READ_ENCRYPT, BT_GATT_PERM_READ_ENCRYPT,
ascs_ase_read, NULL, UINT_TO_POINTER(2)), ascs_ase_read, NULL, UINT_TO_POINTER(2)),
BT_GATT_CCC(ascs_ase_cfg_changed, BT_AUDIO_CCC(ascs_ase_cfg_changed),
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT),
#endif #endif
#if CONFIG_BT_ASCS_ASE_SRC_COUNT > 0 #if CONFIG_BT_ASCS_ASE_SRC_COUNT > 0
BT_GATT_CHARACTERISTIC(BT_UUID_ASCS_ASE_SRC, BT_AUDIO_CHRC(BT_UUID_ASCS_ASE_SRC,
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
BT_GATT_PERM_READ_ENCRYPT, BT_GATT_PERM_READ_ENCRYPT,
ascs_ase_read, NULL, ascs_ase_read, NULL, UINT_TO_POINTER(CONFIG_BT_ASCS_ASE_SNK_COUNT + 1)),
UINT_TO_POINTER(CONFIG_BT_ASCS_ASE_SNK_COUNT + 1)), BT_AUDIO_CCC(ascs_ase_cfg_changed),
BT_GATT_CCC(ascs_ase_cfg_changed,
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT),
#endif #endif
#if CONFIG_BT_ASCS_ASE_SRC_COUNT > 1 #if CONFIG_BT_ASCS_ASE_SRC_COUNT > 1
BT_GATT_CHARACTERISTIC(BT_UUID_ASCS_ASE_SRC, BT_AUDIO_CHRC(BT_UUID_ASCS_ASE_SRC,
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
BT_GATT_PERM_READ_ENCRYPT, BT_GATT_PERM_READ_ENCRYPT,
ascs_ase_read, NULL, ascs_ase_read, NULL, UINT_TO_POINTER(CONFIG_BT_ASCS_ASE_SNK_COUNT + 2)),
UINT_TO_POINTER(CONFIG_BT_ASCS_ASE_SNK_COUNT + 2)), BT_AUDIO_CCC(ascs_ase_cfg_changed),
BT_GATT_CCC(ascs_ase_cfg_changed,
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT),
#endif #endif
BT_GATT_CHARACTERISTIC(BT_UUID_ASCS_ASE_CP, BT_AUDIO_CHRC(BT_UUID_ASCS_ASE_CP,
BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP | BT_GATT_CHRC_NOTIFY,
BT_GATT_CHRC_WRITE_WITHOUT_RESP | BT_GATT_PERM_WRITE_ENCRYPT,
BT_GATT_CHRC_NOTIFY, NULL, ascs_cp_write, NULL),
BT_GATT_PERM_WRITE_ENCRYPT, BT_AUDIO_CCC(ascs_cp_cfg_changed),
NULL, ascs_cp_write, NULL),
BT_GATT_CCC(ascs_cp_cfg_changed,
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT)
); );
#endif /* BT_AUDIO_UNICAST_SERVER */ #endif /* BT_AUDIO_UNICAST_SERVER */

View file

@ -0,0 +1,99 @@
/* Common functions for LE Audio services */
/*
* Copyright (c) 2022 Codecoup
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/bluetooth/att.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/bluetooth/audio/audio.h>
#include "audio_internal.h"
static uint8_t bt_audio_security_check(const struct bt_conn *conn)
{
struct bt_conn_info info;
int err;
err = bt_conn_get_info(conn, &info);
if (err < 0) {
return BT_ATT_ERR_UNLIKELY;
}
/* Require an encryption key with at least 128 bits of entropy, derived from SC or OOB
* method.
*/
if ((info.security.flags & (BT_SECURITY_FLAG_OOB | BT_SECURITY_FLAG_SC)) == 0) {
/* If the client has insufficient security to read/write the requested attribute
* then an ATT_ERROR_RSP PDU shall be sent with the Error Code parameter set to
* Insufficient Authentication (0x05).
*/
return BT_ATT_ERR_AUTHENTICATION;
}
if (info.security.enc_key_size < BT_ENC_KEY_SIZE_MAX) {
return BT_ATT_ERR_ENCRYPTION_KEY_SIZE;
}
return BT_ATT_ERR_SUCCESS;
}
ssize_t bt_audio_read_chrc(struct bt_conn *conn, const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset)
{
const struct bt_audio_attr_user_data *user_data = attr->user_data;
if (user_data->read == NULL) {
return BT_GATT_ERR(BT_ATT_ERR_READ_NOT_PERMITTED);
}
if (conn != NULL) {
uint8_t err;
err = bt_audio_security_check(conn);
if (err != 0) {
return BT_GATT_ERR(err);
}
}
return user_data->read(conn, attr, buf, len, offset);
}
ssize_t bt_audio_write_chrc(struct bt_conn *conn, const struct bt_gatt_attr *attr,
const void *buf, uint16_t len, uint16_t offset, uint8_t flags)
{
const struct bt_audio_attr_user_data *user_data = attr->user_data;
if (user_data->write == NULL) {
return BT_GATT_ERR(BT_ATT_ERR_WRITE_NOT_PERMITTED);
}
if (conn != NULL) {
uint8_t err;
err = bt_audio_security_check(conn);
if (err != 0) {
return BT_GATT_ERR(err);
}
}
return user_data->write(conn, attr, buf, len, offset, flags);
}
ssize_t bt_audio_ccc_cfg_write(struct bt_conn *conn, const struct bt_gatt_attr *attr,
uint16_t value)
{
if (conn != NULL) {
uint8_t err;
err = bt_audio_security_check(conn);
if (err != 0) {
return BT_GATT_ERR(err);
}
}
return sizeof(value);
}

View file

@ -0,0 +1,60 @@
/* @file
* @brief Internal APIs for LE Audio
*
* Copyright (c) 2022 Codecoup
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/audio/audio.h>
/** @brief LE Audio Attribute User Data. */
struct bt_audio_attr_user_data {
/** Attribute read callback */
ssize_t (*read)(struct bt_conn *conn, const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset);
/** Attribute write callback */
ssize_t (*write)(struct bt_conn *conn, const struct bt_gatt_attr *attr,
const void *buf, uint16_t len, uint16_t offset,
uint8_t flags);
/** Attribute user data */
void *user_data;
};
/** LE Audio Read Characteristic value helper. */
ssize_t bt_audio_read_chrc(struct bt_conn *conn, const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset);
/** LE Audio Write Characteristic value helper. */
ssize_t bt_audio_write_chrc(struct bt_conn *conn, const struct bt_gatt_attr *attr,
const void *buf, uint16_t len, uint16_t offset, uint8_t flags);
#define BT_AUDIO_ATTR_USER_DATA_INIT(_read, _write, _user_data) \
{ \
.read = _read, \
.write = _write, \
.user_data = _user_data, \
}
/** Helper to define LE Audio characteristic. */
#define BT_AUDIO_CHRC(_uuid, _props, _perm, _read, _write, _user_data) \
BT_GATT_CHARACTERISTIC(_uuid, _props, _perm, bt_audio_read_chrc, bt_audio_write_chrc, \
((struct bt_audio_attr_user_data[]) { \
BT_AUDIO_ATTR_USER_DATA_INIT(_read, _write, _user_data), \
}))
#define BT_AUDIO_CHRC_USER_DATA(_attr) \
(((struct bt_audio_attr_user_data *)(_attr)->user_data)->user_data)
/** LE Audio Write CCCD value helper. */
ssize_t bt_audio_ccc_cfg_write(struct bt_conn *conn, const struct bt_gatt_attr *attr,
uint16_t value);
/** Helper to define LE Audio CCC descriptor. */
#define BT_AUDIO_CCC(_changed) \
BT_GATT_CCC_MANAGED(((struct _bt_gatt_ccc[]) \
{BT_GATT_CCC_INITIALIZER(_changed, bt_audio_ccc_cfg_write, NULL)}), \
(BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT))

View file

@ -9,6 +9,7 @@
#include <zephyr/zephyr.h> #include <zephyr/zephyr.h>
#include <zephyr/sys/byteorder.h> #include <zephyr/sys/byteorder.h>
#include <zephyr/sys/util.h>
#include <zephyr/device.h> #include <zephyr/device.h>
#include <zephyr/init.h> #include <zephyr/init.h>
@ -23,6 +24,7 @@
#define LOG_MODULE_NAME bt_bass #define LOG_MODULE_NAME bt_bass
#include "common/log.h" #include "common/log.h"
#include "audio_internal.h"
#include "bass_internal.h" #include "bass_internal.h"
#include "../host/conn_internal.h" #include "../host/conn_internal.h"
#include "../host/hci_core.h" #include "../host/hci_core.h"
@ -1223,7 +1225,7 @@ static ssize_t read_recv_state(struct bt_conn *conn,
const struct bt_gatt_attr *attr, void *buf, const struct bt_gatt_attr *attr, void *buf,
uint16_t len, uint16_t offset) uint16_t len, uint16_t offset)
{ {
uint8_t idx = (uint8_t)(uintptr_t)attr->user_data; uint8_t idx = POINTER_TO_UINT(BT_AUDIO_CHRC_USER_DATA(attr));
struct bass_recv_state_internal *recv_state = &bass_inst.recv_states[idx]; struct bass_recv_state_internal *recv_state = &bass_inst.recv_states[idx];
struct bt_bass_recv_state *state = &recv_state->state; struct bt_bass_recv_state *state = &recv_state->state;
@ -1244,19 +1246,18 @@ static ssize_t read_recv_state(struct bt_conn *conn,
} }
#define RECEIVE_STATE_CHARACTERISTIC(idx) \ #define RECEIVE_STATE_CHARACTERISTIC(idx) \
BT_GATT_CHARACTERISTIC(BT_UUID_BASS_RECV_STATE, \ BT_AUDIO_CHRC(BT_UUID_BASS_RECV_STATE, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,\ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,\
BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
read_recv_state, NULL, (void *)idx), \ read_recv_state, NULL, UINT_TO_POINTER(idx)), \
BT_GATT_CCC(recv_state_cfg_changed, \ BT_AUDIO_CCC(recv_state_cfg_changed)
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT)
BT_GATT_SERVICE_DEFINE(bass_svc, BT_GATT_SERVICE_DEFINE(bass_svc,
BT_GATT_PRIMARY_SERVICE(BT_UUID_BASS), BT_GATT_PRIMARY_SERVICE(BT_UUID_BASS),
BT_GATT_CHARACTERISTIC(BT_UUID_BASS_CONTROL_POINT, BT_AUDIO_CHRC(BT_UUID_BASS_CONTROL_POINT,
BT_GATT_CHRC_WRITE_WITHOUT_RESP | BT_GATT_CHRC_WRITE, BT_GATT_CHRC_WRITE_WITHOUT_RESP | BT_GATT_CHRC_WRITE,
BT_GATT_PERM_WRITE_ENCRYPT, BT_GATT_PERM_WRITE_ENCRYPT,
NULL, write_control_point, NULL), NULL, write_control_point, NULL),
RECEIVE_STATE_CHARACTERISTIC(0), RECEIVE_STATE_CHARACTERISTIC(0),
#if CONFIG_BT_BASS_RECV_STATE_COUNT > 1 #if CONFIG_BT_BASS_RECV_STATE_COUNT > 1
RECEIVE_STATE_CHARACTERISTIC(1), RECEIVE_STATE_CHARACTERISTIC(1),

View file

@ -20,6 +20,8 @@
#include <zephyr/bluetooth/buf.h> #include <zephyr/bluetooth/buf.h>
#include <zephyr/sys/byteorder.h> #include <zephyr/sys/byteorder.h>
#include <zephyr/sys/check.h> #include <zephyr/sys/check.h>
#include "audio_internal.h"
#include "csis_internal.h" #include "csis_internal.h"
#include "csis_crypto.h" #include "csis_crypto.h"
#include "../host/conn_internal.h" #include "../host/conn_internal.h"
@ -298,7 +300,7 @@ static ssize_t read_set_sirk(struct bt_conn *conn,
{ {
struct bt_csis_set_sirk enc_sirk; struct bt_csis_set_sirk enc_sirk;
struct bt_csis_set_sirk *sirk; struct bt_csis_set_sirk *sirk;
struct bt_csis *csis = attr->user_data; struct bt_csis *csis = BT_AUDIO_CHRC_USER_DATA(attr);
if (csis->srv.cb != NULL && csis->srv.cb->sirk_read_req != NULL) { if (csis->srv.cb != NULL && csis->srv.cb->sirk_read_req != NULL) {
uint8_t cb_rsp; uint8_t cb_rsp;
@ -354,7 +356,7 @@ static ssize_t read_set_size(struct bt_conn *conn,
const struct bt_gatt_attr *attr, const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset) void *buf, uint16_t len, uint16_t offset)
{ {
struct bt_csis *csis = attr->user_data; struct bt_csis *csis = BT_AUDIO_CHRC_USER_DATA(attr);
BT_DBG("%u", csis->srv.set_size); BT_DBG("%u", csis->srv.set_size);
@ -373,7 +375,7 @@ static ssize_t read_set_lock(struct bt_conn *conn,
const struct bt_gatt_attr *attr, const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset) void *buf, uint16_t len, uint16_t offset)
{ {
struct bt_csis *csis = attr->user_data; struct bt_csis *csis = BT_AUDIO_CHRC_USER_DATA(attr);
BT_DBG("%u", csis->srv.set_lock); BT_DBG("%u", csis->srv.set_lock);
@ -389,7 +391,7 @@ static ssize_t write_set_lock(struct bt_conn *conn,
{ {
uint8_t val; uint8_t val;
bool notify; bool notify;
struct bt_csis *csis = attr->user_data; struct bt_csis *csis = BT_AUDIO_CHRC_USER_DATA(attr);
if (offset != 0) { if (offset != 0) {
return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
@ -460,7 +462,7 @@ static void set_lock_cfg_changed(const struct bt_gatt_attr *attr,
static ssize_t read_rank(struct bt_conn *conn, const struct bt_gatt_attr *attr, static ssize_t read_rank(struct bt_conn *conn, const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset) void *buf, uint16_t len, uint16_t offset)
{ {
struct bt_csis *csis = attr->user_data; struct bt_csis *csis = BT_AUDIO_CHRC_USER_DATA(attr);
BT_DBG("%u", csis->srv.rank); BT_DBG("%u", csis->srv.rank);
@ -792,31 +794,25 @@ static void adv_connected(struct bt_le_ext_adv *adv,
#define BT_CSIS_SERVICE_DEFINITION(_csis) {\ #define BT_CSIS_SERVICE_DEFINITION(_csis) {\
BT_GATT_PRIMARY_SERVICE(BT_UUID_CSIS), \ BT_GATT_PRIMARY_SERVICE(BT_UUID_CSIS), \
BT_GATT_CHARACTERISTIC(BT_UUID_CSIS_SET_SIRK, \ BT_AUDIO_CHRC(BT_UUID_CSIS_SET_SIRK, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
read_set_sirk, NULL, &_csis), \ read_set_sirk, NULL, &_csis), \
BT_GATT_CCC(set_sirk_cfg_changed, \ BT_AUDIO_CCC(set_sirk_cfg_changed), \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), \ BT_AUDIO_CHRC(BT_UUID_CSIS_SET_SIZE, \
BT_GATT_CHARACTERISTIC(BT_UUID_CSIS_SET_SIZE, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ BT_GATT_PERM_READ_ENCRYPT, \
BT_GATT_PERM_READ_ENCRYPT, \ read_set_size, NULL, &_csis), \
read_set_size, NULL, &_csis), \ BT_AUDIO_CCC(set_size_cfg_changed), \
BT_GATT_CCC(set_size_cfg_changed, \ BT_AUDIO_CHRC(BT_UUID_CSIS_SET_LOCK, \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY | BT_GATT_CHRC_WRITE, \
BT_GATT_CHARACTERISTIC(BT_UUID_CSIS_SET_LOCK, \ BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT, \
BT_GATT_CHRC_READ | \ read_set_lock, write_set_lock, &_csis), \
BT_GATT_CHRC_NOTIFY | \ BT_AUDIO_CCC(set_lock_cfg_changed), \
BT_GATT_CHRC_WRITE, \ BT_AUDIO_CHRC(BT_UUID_CSIS_RANK, \
BT_GATT_PERM_READ_ENCRYPT | \ BT_GATT_CHRC_READ, \
BT_GATT_PERM_WRITE_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
read_set_lock, write_set_lock, &_csis), \ read_rank, NULL, &_csis) \
BT_GATT_CCC(set_lock_cfg_changed, \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), \
BT_GATT_CHARACTERISTIC(BT_UUID_CSIS_RANK, \
BT_GATT_CHRC_READ, \
BT_GATT_PERM_READ_ENCRYPT, \
read_rank, NULL, &_csis) \
} }
BT_GATT_SERVICE_INSTANCE_DEFINE(csis_service_list, csis_insts, BT_GATT_SERVICE_INSTANCE_DEFINE(csis_service_list, csis_insts,

View file

@ -18,6 +18,7 @@
#include "../bluetooth/host/conn_internal.h" #include "../bluetooth/host/conn_internal.h"
#include "../bluetooth/host/hci_core.h" #include "../bluetooth/host/hci_core.h"
#include "audio_internal.h"
#include "has_internal.h" #include "has_internal.h"
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HAS) #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HAS)
@ -71,21 +72,25 @@ static ssize_t read_features(struct bt_conn *conn, const struct bt_gatt_attr *at
/* Hearing Access Service GATT Attributes */ /* Hearing Access Service GATT Attributes */
BT_GATT_SERVICE_DEFINE(has_svc, BT_GATT_SERVICE_DEFINE(has_svc,
BT_GATT_PRIMARY_SERVICE(BT_UUID_HAS), BT_GATT_PRIMARY_SERVICE(BT_UUID_HAS),
BT_GATT_CHARACTERISTIC(BT_UUID_HAS_HEARING_AID_FEATURES, BT_GATT_CHRC_READ, BT_AUDIO_CHRC(BT_UUID_HAS_HEARING_AID_FEATURES,
BT_GATT_PERM_READ_ENCRYPT, read_features, NULL, NULL), BT_GATT_CHRC_READ,
BT_GATT_PERM_READ_ENCRYPT,
read_features, NULL, NULL),
#if defined(CONFIG_BT_HAS_PRESET_SUPPORT) #if defined(CONFIG_BT_HAS_PRESET_SUPPORT)
BT_GATT_CHARACTERISTIC(BT_UUID_HAS_PRESET_CONTROL_POINT, BT_AUDIO_CHRC(BT_UUID_HAS_PRESET_CONTROL_POINT,
#if defined(CONFIG_BT_EATT) #if defined(CONFIG_BT_EATT)
BT_GATT_CHRC_WRITE | BT_GATT_CHRC_INDICATE | BT_GATT_CHRC_NOTIFY, BT_GATT_CHRC_WRITE | BT_GATT_CHRC_INDICATE | BT_GATT_CHRC_NOTIFY,
#else #else
BT_GATT_CHRC_WRITE | BT_GATT_CHRC_INDICATE, BT_GATT_CHRC_WRITE | BT_GATT_CHRC_INDICATE,
#endif /* CONFIG_BT_EATT */ #endif /* CONFIG_BT_EATT */
BT_GATT_PERM_WRITE_ENCRYPT, NULL, write_control_point, NULL), BT_GATT_PERM_WRITE_ENCRYPT,
BT_GATT_CCC(ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), NULL, write_control_point, NULL),
BT_GATT_CHARACTERISTIC(BT_UUID_HAS_ACTIVE_PRESET_INDEX, BT_AUDIO_CCC(ccc_cfg_changed),
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ_ENCRYPT, BT_AUDIO_CHRC(BT_UUID_HAS_ACTIVE_PRESET_INDEX,
read_active_preset_index, NULL, NULL), BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
BT_GATT_CCC(ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), BT_GATT_PERM_READ_ENCRYPT,
read_active_preset_index, NULL, NULL),
BT_AUDIO_CCC(ccc_cfg_changed),
#endif /* CONFIG_BT_HAS_PRESET_SUPPORT */ #endif /* CONFIG_BT_HAS_PRESET_SUPPORT */
); );

View file

@ -23,6 +23,7 @@
#include <zephyr/bluetooth/services/ots.h> #include <zephyr/bluetooth/services/ots.h>
#include <zephyr/bluetooth/audio/media_proxy.h> #include <zephyr/bluetooth/audio/media_proxy.h>
#include "audio_internal.h"
#include "media_proxy_internal.h" #include "media_proxy_internal.h"
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_MCS) #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_MCS)
@ -620,62 +621,49 @@ static ssize_t read_content_ctrl_id(struct bt_conn *conn,
/* Defines for OTS-dependent characteristics - empty if no OTS */ /* Defines for OTS-dependent characteristics - empty if no OTS */
#ifdef CONFIG_BT_OTS #ifdef CONFIG_BT_OTS
#define ICON_OBJ_ID_CHARACTERISTIC_IF_OTS \ #define ICON_OBJ_ID_CHARACTERISTIC_IF_OTS \
BT_GATT_CHARACTERISTIC(BT_UUID_MCS_ICON_OBJ_ID, \ BT_AUDIO_CHRC(BT_UUID_MCS_ICON_OBJ_ID, \
BT_GATT_CHRC_READ, BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_CHRC_READ, \
read_icon_id, NULL, NULL), BT_GATT_PERM_READ_ENCRYPT, \
read_icon_id, NULL, NULL),
#define SEGMENTS_TRACK_GROUP_ID_CHARACTERISTICS_IF_OTS \ #define SEGMENTS_TRACK_GROUP_ID_CHARACTERISTICS_IF_OTS \
BT_GATT_CHARACTERISTIC(BT_UUID_MCS_TRACK_SEGMENTS_OBJ_ID, \ BT_AUDIO_CHRC(BT_UUID_MCS_TRACK_SEGMENTS_OBJ_ID, \
BT_GATT_CHRC_READ, BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_CHRC_READ, \
read_track_segments_id, NULL, NULL), \ BT_GATT_PERM_READ_ENCRYPT, \
BT_GATT_CHARACTERISTIC(BT_UUID_MCS_CURRENT_TRACK_OBJ_ID, \ read_track_segments_id, NULL, NULL), \
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | \ BT_AUDIO_CHRC(BT_UUID_MCS_CURRENT_TRACK_OBJ_ID, \
BT_GATT_CHRC_WRITE_WITHOUT_RESP | \ BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | \
BT_GATT_CHRC_NOTIFY, \ BT_GATT_CHRC_WRITE_WITHOUT_RESP | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ_ENCRYPT | \ BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT, \
BT_GATT_PERM_WRITE_ENCRYPT, \ read_current_track_id, write_current_track_id, NULL), \
read_current_track_id, write_current_track_id, \ BT_AUDIO_CCC(current_track_id_cfg_changed), \
NULL), \ BT_AUDIO_CHRC(BT_UUID_MCS_NEXT_TRACK_OBJ_ID, \
BT_GATT_CCC(current_track_id_cfg_changed, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), \ BT_GATT_CHRC_WRITE_WITHOUT_RESP | BT_GATT_CHRC_NOTIFY, \
BT_GATT_CHARACTERISTIC(BT_UUID_MCS_NEXT_TRACK_OBJ_ID, \ BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | \ read_next_track_id, write_next_track_id, NULL), \
BT_GATT_CHRC_WRITE_WITHOUT_RESP | \ BT_AUDIO_CCC(next_track_id_cfg_changed), \
BT_GATT_CHRC_NOTIFY, \ BT_AUDIO_CHRC(BT_UUID_MCS_PARENT_GROUP_OBJ_ID, \
BT_GATT_PERM_READ_ENCRYPT | \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_WRITE_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
read_next_track_id, write_next_track_id, NULL), \ read_parent_group_id, NULL, NULL), \
BT_GATT_CCC(next_track_id_cfg_changed, \ BT_AUDIO_CCC(parent_group_id_cfg_changed), \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), \ BT_AUDIO_CHRC(BT_UUID_MCS_CURRENT_GROUP_OBJ_ID, \
BT_GATT_CHARACTERISTIC(BT_UUID_MCS_PARENT_GROUP_OBJ_ID, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ BT_GATT_CHRC_WRITE_WITHOUT_RESP | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT, \
read_parent_group_id, NULL, NULL), \ read_current_group_id, write_current_group_id, NULL), \
BT_GATT_CCC(parent_group_id_cfg_changed, \ BT_AUDIO_CCC(current_group_id_cfg_changed),
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), \
BT_GATT_CHARACTERISTIC(BT_UUID_MCS_CURRENT_GROUP_OBJ_ID, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | \
BT_GATT_CHRC_WRITE_WITHOUT_RESP | \
BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ_ENCRYPT | \
BT_GATT_PERM_WRITE_ENCRYPT, \
read_current_group_id, write_current_group_id, NULL), \
BT_GATT_CCC(current_group_id_cfg_changed, \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT),
#define SEARCH_CHARACTERISTICS_IF_OTS \ #define SEARCH_CHARACTERISTICS_IF_OTS \
BT_GATT_CHARACTERISTIC(BT_UUID_MCS_SEARCH_CONTROL_POINT, \ BT_AUDIO_CHRC(BT_UUID_MCS_SEARCH_CONTROL_POINT, \
BT_GATT_CHRC_WRITE | \ BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP | BT_GATT_CHRC_NOTIFY, \
BT_GATT_CHRC_WRITE_WITHOUT_RESP | \ BT_GATT_PERM_WRITE_ENCRYPT, \
BT_GATT_CHRC_NOTIFY, \ NULL, write_search_control_point, NULL), \
BT_GATT_PERM_WRITE_ENCRYPT, \ BT_AUDIO_CCC(search_control_point_cfg_changed), \
NULL, write_search_control_point, NULL), \ BT_AUDIO_CHRC(BT_UUID_MCS_SEARCH_RESULTS_OBJ_ID, \
BT_GATT_CCC(search_control_point_cfg_changed, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), \ BT_GATT_PERM_READ_ENCRYPT, \
BT_GATT_CHARACTERISTIC(BT_UUID_MCS_SEARCH_RESULTS_OBJ_ID, \ read_search_results_id, NULL, NULL), \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ BT_AUDIO_CCC(search_results_id_cfg_changed),
BT_GATT_PERM_READ_ENCRYPT, \
read_search_results_id, NULL, NULL), \
BT_GATT_CCC(search_results_id_cfg_changed, \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT),
#else #else
#define ICON_OBJ_ID_CHARACTERISTIC_IF_OTS #define ICON_OBJ_ID_CHARACTERISTIC_IF_OTS
@ -687,97 +675,79 @@ static ssize_t read_content_ctrl_id(struct bt_conn *conn,
#define BT_MCS_SERVICE_DEFINITION \ #define BT_MCS_SERVICE_DEFINITION \
BT_GATT_PRIMARY_SERVICE(BT_UUID_GMCS), \ BT_GATT_PRIMARY_SERVICE(BT_UUID_GMCS), \
BT_GATT_INCLUDE_SERVICE(NULL), /* To be overwritten */ \ BT_GATT_INCLUDE_SERVICE(NULL), /* To be overwritten */ \
BT_GATT_CHARACTERISTIC(BT_UUID_MCS_PLAYER_NAME, \ BT_AUDIO_CHRC(BT_UUID_MCS_PLAYER_NAME, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
read_player_name, NULL, NULL), \ read_player_name, NULL, NULL), \
BT_GATT_CCC(player_name_cfg_changed, \ BT_AUDIO_CCC(player_name_cfg_changed), \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), \
ICON_OBJ_ID_CHARACTERISTIC_IF_OTS \ ICON_OBJ_ID_CHARACTERISTIC_IF_OTS \
BT_GATT_CHARACTERISTIC(BT_UUID_MCS_ICON_URL, \ BT_AUDIO_CHRC(BT_UUID_MCS_ICON_URL, \
BT_GATT_CHRC_READ, BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_CHRC_READ, \
read_icon_url, NULL, NULL), \ BT_GATT_PERM_READ_ENCRYPT, \
BT_GATT_CHARACTERISTIC(BT_UUID_MCS_TRACK_CHANGED, \ read_icon_url, NULL, NULL), \
BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_NONE, \ BT_AUDIO_CHRC(BT_UUID_MCS_TRACK_CHANGED, \
NULL, NULL, NULL), \ BT_GATT_CHRC_NOTIFY, \
BT_GATT_CCC(track_cfg_changed, \ BT_GATT_PERM_NONE, \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), \ NULL, NULL, NULL), \
BT_GATT_CHARACTERISTIC(BT_UUID_MCS_TRACK_TITLE, \ BT_AUDIO_CCC(track_cfg_changed), \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ BT_AUDIO_CHRC(BT_UUID_MCS_TRACK_TITLE, \
BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
read_track_title, NULL, NULL), \ BT_GATT_PERM_READ_ENCRYPT, \
BT_GATT_CCC(track_title_cfg_changed, \ read_track_title, NULL, NULL), \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), \ BT_AUDIO_CCC(track_title_cfg_changed), \
BT_GATT_CHARACTERISTIC(BT_UUID_MCS_TRACK_DURATION, \ BT_AUDIO_CHRC(BT_UUID_MCS_TRACK_DURATION, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
read_track_duration, NULL, NULL), \ read_track_duration, NULL, NULL), \
BT_GATT_CCC(track_duration_cfg_changed, \ BT_AUDIO_CCC(track_duration_cfg_changed), \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), \ BT_AUDIO_CHRC(BT_UUID_MCS_TRACK_POSITION, \
BT_GATT_CHARACTERISTIC(BT_UUID_MCS_TRACK_POSITION, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | \
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | \ BT_GATT_CHRC_WRITE_WITHOUT_RESP | BT_GATT_CHRC_NOTIFY, \
BT_GATT_CHRC_WRITE_WITHOUT_RESP | \ BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT, \
BT_GATT_CHRC_NOTIFY, \ read_track_position, write_track_position, NULL), \
BT_GATT_PERM_READ_ENCRYPT | \ BT_AUDIO_CCC(track_position_cfg_changed), \
BT_GATT_PERM_WRITE_ENCRYPT, \ BT_AUDIO_CHRC(BT_UUID_MCS_PLAYBACK_SPEED, \
read_track_position, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | \
write_track_position, NULL), \ BT_GATT_CHRC_WRITE_WITHOUT_RESP | BT_GATT_CHRC_NOTIFY, \
BT_GATT_CCC(track_position_cfg_changed, \ BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT, \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), \ read_playback_speed, write_playback_speed, NULL), \
BT_GATT_CHARACTERISTIC(BT_UUID_MCS_PLAYBACK_SPEED, \ BT_AUDIO_CCC(playback_speed_cfg_changed), \
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | \ BT_AUDIO_CHRC(BT_UUID_MCS_SEEKING_SPEED, \
BT_GATT_CHRC_WRITE_WITHOUT_RESP | \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_CHRC_NOTIFY, \ BT_GATT_PERM_READ_ENCRYPT, \
BT_GATT_PERM_READ_ENCRYPT | \ read_seeking_speed, NULL, NULL), \
BT_GATT_PERM_WRITE_ENCRYPT, \ BT_AUDIO_CCC(seeking_speed_cfg_changed), \
read_playback_speed, write_playback_speed, \
NULL), \
BT_GATT_CCC(playback_speed_cfg_changed, \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), \
BT_GATT_CHARACTERISTIC(BT_UUID_MCS_SEEKING_SPEED, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ_ENCRYPT, \
read_seeking_speed, NULL, NULL), \
BT_GATT_CCC(seeking_speed_cfg_changed, \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), \
SEGMENTS_TRACK_GROUP_ID_CHARACTERISTICS_IF_OTS \ SEGMENTS_TRACK_GROUP_ID_CHARACTERISTICS_IF_OTS \
BT_GATT_CHARACTERISTIC(BT_UUID_MCS_PLAYING_ORDER, \ BT_AUDIO_CHRC(BT_UUID_MCS_PLAYING_ORDER, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | \ BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | \
BT_GATT_CHRC_WRITE_WITHOUT_RESP | \ BT_GATT_CHRC_WRITE_WITHOUT_RESP | BT_GATT_CHRC_NOTIFY, \
BT_GATT_CHRC_NOTIFY, \ BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT, \
BT_GATT_PERM_READ_ENCRYPT | \ read_playing_order, write_playing_order, NULL), \
BT_GATT_PERM_WRITE_ENCRYPT, \ BT_AUDIO_CCC(playing_order_cfg_changed), \
read_playing_order, write_playing_order, NULL), \ BT_AUDIO_CHRC(BT_UUID_MCS_PLAYING_ORDERS, \
BT_GATT_CCC(playing_order_cfg_changed, \ BT_GATT_CHRC_READ, \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), \ BT_GATT_PERM_READ_ENCRYPT, \
BT_GATT_CHARACTERISTIC(BT_UUID_MCS_PLAYING_ORDERS, \ read_playing_orders_supported, NULL, NULL), \
BT_GATT_CHRC_READ, BT_GATT_PERM_READ_ENCRYPT, \ BT_AUDIO_CHRC(BT_UUID_MCS_MEDIA_STATE, \
read_playing_orders_supported, NULL, NULL), \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_CHARACTERISTIC(BT_UUID_MCS_MEDIA_STATE, \ BT_GATT_PERM_READ_ENCRYPT, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ read_media_state, NULL, NULL), \
BT_GATT_PERM_READ_ENCRYPT, \ BT_AUDIO_CCC(media_state_cfg_changed), \
read_media_state, NULL, NULL), \ BT_AUDIO_CHRC(BT_UUID_MCS_MEDIA_CONTROL_POINT, \
BT_GATT_CCC(media_state_cfg_changed, \ BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), \ BT_GATT_PERM_WRITE_ENCRYPT, \
BT_GATT_CHARACTERISTIC(BT_UUID_MCS_MEDIA_CONTROL_POINT, \ NULL, write_control_point, NULL), \
BT_GATT_CHRC_WRITE | \ BT_AUDIO_CCC(control_point_cfg_changed), \
BT_GATT_CHRC_WRITE_WITHOUT_RESP | \ BT_AUDIO_CHRC(BT_UUID_MCS_MEDIA_CONTROL_OPCODES, \
BT_GATT_CHRC_NOTIFY, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_WRITE_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
NULL, write_control_point, NULL), \ read_opcodes_supported, NULL, NULL), \
BT_GATT_CCC(control_point_cfg_changed, \ BT_AUDIO_CCC(opcodes_supported_cfg_changed), \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), \
BT_GATT_CHARACTERISTIC(BT_UUID_MCS_MEDIA_CONTROL_OPCODES, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ_ENCRYPT, \
read_opcodes_supported, NULL, NULL), \
BT_GATT_CCC(opcodes_supported_cfg_changed, \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), \
SEARCH_CHARACTERISTICS_IF_OTS \ SEARCH_CHARACTERISTICS_IF_OTS \
BT_GATT_CHARACTERISTIC(BT_UUID_CCID, \ BT_AUDIO_CHRC(BT_UUID_CCID, \
BT_GATT_CHRC_READ, \ BT_GATT_CHRC_READ, \
BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
read_content_ctrl_id, NULL, NULL) read_content_ctrl_id, NULL, NULL)
static struct bt_gatt_attr svc_attrs[] = { BT_MCS_SERVICE_DEFINITION }; static struct bt_gatt_attr svc_attrs[] = { BT_MCS_SERVICE_DEFINITION };
static struct bt_gatt_service mcs; static struct bt_gatt_service mcs;

View file

@ -19,6 +19,8 @@
#include <zephyr/bluetooth/audio/micp.h> #include <zephyr/bluetooth/audio/micp.h>
#include <zephyr/bluetooth/audio/aics.h> #include <zephyr/bluetooth/audio/aics.h>
#include "audio_internal.h"
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_MICP_MIC_DEV) #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_MICP_MIC_DEV)
#define LOG_MODULE_NAME bt_micp #define LOG_MODULE_NAME bt_micp
#include "common/log.h" #include "common/log.h"
@ -94,12 +96,11 @@ static ssize_t write_mute(struct bt_conn *conn, const struct bt_gatt_attr *attr,
#define BT_MICP_SERVICE_DEFINITION \ #define BT_MICP_SERVICE_DEFINITION \
BT_GATT_PRIMARY_SERVICE(BT_UUID_MICS), \ BT_GATT_PRIMARY_SERVICE(BT_UUID_MICS), \
AICS_INCLUDES(CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT) \ AICS_INCLUDES(CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT) \
BT_GATT_CHARACTERISTIC(BT_UUID_MICS_MUTE, \ BT_AUDIO_CHRC(BT_UUID_MICS_MUTE, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_NOTIFY, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT, \
read_mute, write_mute, NULL), \ read_mute, write_mute, NULL), \
BT_GATT_CCC(mute_cfg_changed, \ BT_AUDIO_CCC(mute_cfg_changed)
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT)
#define MICS_ATTR_COUNT \ #define MICS_ATTR_COUNT \
ARRAY_SIZE(((struct bt_gatt_attr []){ BT_MICP_SERVICE_DEFINITION })) ARRAY_SIZE(((struct bt_gatt_attr []){ BT_MICP_SERVICE_DEFINITION }))

View file

@ -27,6 +27,7 @@
#define LOG_MODULE_NAME bt_pacs #define LOG_MODULE_NAME bt_pacs
#include "common/log.h" #include "common/log.h"
#include "audio_internal.h"
#include "pacs_internal.h" #include "pacs_internal.h"
#include "unicast_server.h" #include "unicast_server.h"
@ -437,63 +438,53 @@ static void src_loc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
BT_GATT_SERVICE_DEFINE(pacs_svc, BT_GATT_SERVICE_DEFINE(pacs_svc,
BT_GATT_PRIMARY_SERVICE(BT_UUID_PACS), BT_GATT_PRIMARY_SERVICE(BT_UUID_PACS),
#if defined(CONFIG_BT_PAC_SNK) #if defined(CONFIG_BT_PAC_SNK)
BT_GATT_CHARACTERISTIC(BT_UUID_PACS_SNK, BT_AUDIO_CHRC(BT_UUID_PACS_SNK,
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
BT_GATT_PERM_READ_ENCRYPT, BT_GATT_PERM_READ_ENCRYPT,
snk_read, NULL, NULL), snk_read, NULL, NULL),
BT_GATT_CCC(snk_cfg_changed, BT_AUDIO_CCC(snk_cfg_changed),
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT),
#if defined(CONFIG_BT_PAC_SNK_LOC_WRITEABLE) #if defined(CONFIG_BT_PAC_SNK_LOC_WRITEABLE)
BT_GATT_CHARACTERISTIC(BT_UUID_PACS_SNK_LOC, BT_AUDIO_CHRC(BT_UUID_PACS_SNK_LOC,
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_NOTIFY,
BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT,
BT_GATT_PERM_READ_ENCRYPT | snk_loc_read, snk_loc_write, NULL),
BT_GATT_PERM_WRITE_ENCRYPT,
snk_loc_read, snk_loc_write, NULL),
#elif defined(CONFIG_BT_PAC_SNK_LOC) #elif defined(CONFIG_BT_PAC_SNK_LOC)
BT_GATT_CHARACTERISTIC(BT_UUID_PACS_SNK_LOC, BT_AUDIO_CHRC(BT_UUID_PACS_SNK_LOC,
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
BT_GATT_PERM_READ_ENCRYPT, BT_GATT_PERM_READ_ENCRYPT,
snk_loc_read, NULL, NULL), snk_loc_read, NULL, NULL),
#endif /* CONFIG_BT_PAC_SNK_LOC_WRITEABLE */ #endif /* CONFIG_BT_PAC_SNK_LOC_WRITEABLE */
BT_GATT_CCC(snk_loc_cfg_changed, BT_AUDIO_CCC(snk_loc_cfg_changed),
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT),
#endif /* CONFIG_BT_PAC_SNK */ #endif /* CONFIG_BT_PAC_SNK */
#if defined(CONFIG_BT_PAC_SRC) #if defined(CONFIG_BT_PAC_SRC)
BT_GATT_CHARACTERISTIC(BT_UUID_PACS_SRC, BT_AUDIO_CHRC(BT_UUID_PACS_SRC,
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
BT_GATT_PERM_READ_ENCRYPT, BT_GATT_PERM_READ_ENCRYPT,
src_read, NULL, NULL), src_read, NULL, NULL),
BT_GATT_CCC(src_cfg_changed, BT_AUDIO_CCC(src_cfg_changed),
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT),
#if defined(CONFIG_BT_PAC_SRC_LOC_WRITEABLE) #if defined(CONFIG_BT_PAC_SRC_LOC_WRITEABLE)
BT_GATT_CHARACTERISTIC(BT_UUID_PACS_SRC_LOC, BT_AUDIO_CHRC(BT_UUID_PACS_SRC_LOC,
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_NOTIFY,
BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ_ENCRYPT BT_GATT_PERM_WRITE_ENCRYPT,
BT_GATT_PERM_READ_ENCRYPT | src_loc_read, src_loc_write, NULL),
BT_GATT_PERM_WRITE_ENCRYPT,
src_loc_read, src_loc_write, NULL),
#elif defined(CONFIG_BT_PAC_SRC_LOC) #elif defined(CONFIG_BT_PAC_SRC_LOC)
BT_GATT_CHARACTERISTIC(BT_UUID_PACS_SRC_LOC, BT_AUDIO_CHRC(BT_UUID_PACS_SRC_LOC,
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
BT_GATT_PERM_READ_ENCRYPT, BT_GATT_PERM_READ_ENCRYPT,
src_loc_read, NULL, NULL), src_loc_read, NULL, NULL),
#endif /* CONFIG_BT_PAC_SRC_LOC_WRITEABLE */ #endif /* CONFIG_BT_PAC_SRC_LOC_WRITEABLE */
BT_GATT_CCC(src_loc_cfg_changed, BT_AUDIO_CCC(src_loc_cfg_changed),
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT),
#endif /* CONFIG_BT_PAC_SRC */ #endif /* CONFIG_BT_PAC_SRC */
BT_GATT_CHARACTERISTIC(BT_UUID_PACS_AVAILABLE_CONTEXT, BT_AUDIO_CHRC(BT_UUID_PACS_AVAILABLE_CONTEXT,
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
BT_GATT_PERM_READ_ENCRYPT, BT_GATT_PERM_READ_ENCRYPT,
available_contexts_read, NULL, NULL), available_contexts_read, NULL, NULL),
BT_GATT_CCC(available_context_cfg_changed, BT_AUDIO_CCC(available_context_cfg_changed),
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), BT_AUDIO_CHRC(BT_UUID_PACS_SUPPORTED_CONTEXT,
BT_GATT_CHARACTERISTIC(BT_UUID_PACS_SUPPORTED_CONTEXT, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ_ENCRYPT,
BT_GATT_PERM_READ_ENCRYPT, supported_context_read, NULL, NULL),
supported_context_read, NULL, NULL), BT_AUDIO_CCC(supported_context_cfg_changed)
BT_GATT_CCC(supported_context_cfg_changed,
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT)
); );
static struct k_work_delayable *bt_pacs_get_work(enum bt_audio_dir dir) static struct k_work_delayable *bt_pacs_get_work(enum bt_audio_dir dir)

View file

@ -17,6 +17,7 @@
#include <zephyr/bluetooth/conn.h> #include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/gatt.h> #include <zephyr/bluetooth/gatt.h>
#include "audio_internal.h"
#include "tbs_internal.h" #include "tbs_internal.h"
#include "ccid_internal.h" #include "ccid_internal.h"
@ -25,6 +26,8 @@
#include "common/log.h" #include "common/log.h"
#define BT_TBS_VALID_STATUS_FLAGS(val) ((val) <= (BIT(0) | BIT(1))) #define BT_TBS_VALID_STATUS_FLAGS(val) ((val) <= (BIT(0) | BIT(1)))
#define IS_GTBS_CHRC(_attr) \
IS_ENABLED(CONFIG_BT_GTBS) && BT_AUDIO_CHRC_USER_DATA(_attr) == &gtbs_inst
/* TODO: Have tbs_service_inst include gtbs_service_inst and use CONTAINER_OF /* TODO: Have tbs_service_inst include gtbs_service_inst and use CONTAINER_OF
* to get a specific TBS instance from a GTBS pointer. * to get a specific TBS instance from a GTBS pointer.
@ -500,11 +503,11 @@ static ssize_t read_provider_name(struct bt_conn *conn,
{ {
const char *provider_name; const char *provider_name;
if (IS_ENABLED(CONFIG_BT_GTBS) && attr->user_data == &gtbs_inst) { if (IS_GTBS_CHRC(attr)) {
provider_name = gtbs_inst.provider_name; provider_name = gtbs_inst.provider_name;
BT_DBG("GTBS: Provider name %s", provider_name); BT_DBG("GTBS: Provider name %s", provider_name);
} else { } else {
const struct tbs_service_inst *inst = (struct tbs_service_inst *)attr->user_data; const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr);
provider_name = inst->provider_name; provider_name = inst->provider_name;
BT_DBG("Index %u, Provider name %s", BT_DBG("Index %u, Provider name %s",
@ -533,11 +536,11 @@ static ssize_t read_uci(struct bt_conn *conn, const struct bt_gatt_attr *attr,
{ {
const char *uci; const char *uci;
if (IS_ENABLED(CONFIG_BT_GTBS) && attr->user_data == &gtbs_inst) { if (IS_GTBS_CHRC(attr)) {
uci = gtbs_inst.uci; uci = gtbs_inst.uci;
BT_DBG("GTBS: UCI %s", uci); BT_DBG("GTBS: UCI %s", uci);
} else { } else {
const struct tbs_service_inst *inst = (struct tbs_service_inst *)attr->user_data; const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr);
uci = inst->uci; uci = inst->uci;
BT_DBG("Index %u: UCI %s", inst->index, uci); BT_DBG("Index %u: UCI %s", inst->index, uci);
@ -553,11 +556,11 @@ static ssize_t read_technology(struct bt_conn *conn,
{ {
uint8_t technology; uint8_t technology;
if (IS_ENABLED(CONFIG_BT_GTBS) && attr->user_data == &gtbs_inst) { if (IS_GTBS_CHRC(attr)) {
technology = gtbs_inst.technology; technology = gtbs_inst.technology;
BT_DBG("GTBS: Technology 0x%02X", technology); BT_DBG("GTBS: Technology 0x%02X", technology);
} else { } else {
const struct tbs_service_inst *inst = (struct tbs_service_inst *)attr->user_data; const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr);
technology = inst->technology; technology = inst->technology;
BT_DBG("Index %u: Technology 0x%02X", inst->index, technology); BT_DBG("Index %u: Technology 0x%02X", inst->index, technology);
@ -585,7 +588,7 @@ static ssize_t read_uri_scheme_list(struct bt_conn *conn,
{ {
net_buf_simple_reset(&read_buf); net_buf_simple_reset(&read_buf);
if (IS_ENABLED(CONFIG_BT_GTBS) && attr->user_data == &gtbs_inst) { if (IS_GTBS_CHRC(attr)) {
/* TODO: Make uri schemes unique */ /* TODO: Make uri schemes unique */
for (size_t i = 0; i < ARRAY_SIZE(svc_insts); i++) { for (size_t i = 0; i < ARRAY_SIZE(svc_insts); i++) {
size_t uri_len = strlen(svc_insts[i].uri_scheme_list); size_t uri_len = strlen(svc_insts[i].uri_scheme_list);
@ -604,7 +607,7 @@ static ssize_t read_uri_scheme_list(struct bt_conn *conn,
read_buf.data[read_buf.len] = '\0'; read_buf.data[read_buf.len] = '\0';
BT_DBG("GTBS: URI scheme %s", read_buf.data); BT_DBG("GTBS: URI scheme %s", read_buf.data);
} else { } else {
const struct tbs_service_inst *inst = (struct tbs_service_inst *)attr->user_data; const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr);
net_buf_simple_add_mem(&read_buf, inst->uri_scheme_list, net_buf_simple_add_mem(&read_buf, inst->uri_scheme_list,
strlen(inst->uri_scheme_list)); strlen(inst->uri_scheme_list));
@ -636,11 +639,11 @@ static ssize_t read_signal_strength(struct bt_conn *conn,
{ {
uint8_t signal_strength; uint8_t signal_strength;
if (IS_ENABLED(CONFIG_BT_GTBS) && attr->user_data == &gtbs_inst) { if (IS_GTBS_CHRC(attr)) {
signal_strength = gtbs_inst.signal_strength; signal_strength = gtbs_inst.signal_strength;
BT_DBG("GTBS: Signal strength 0x%02x", signal_strength); BT_DBG("GTBS: Signal strength 0x%02x", signal_strength);
} else { } else {
const struct tbs_service_inst *inst = (struct tbs_service_inst *)attr->user_data; const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr);
signal_strength = inst->signal_strength; signal_strength = inst->signal_strength;
BT_DBG("Index %u: Signal strength 0x%02x", BT_DBG("Index %u: Signal strength 0x%02x",
@ -674,12 +677,12 @@ static ssize_t read_signal_strength_interval(struct bt_conn *conn,
return BT_GATT_ERR(BT_ATT_ERR_AUTHORIZATION); return BT_GATT_ERR(BT_ATT_ERR_AUTHORIZATION);
} }
if (IS_ENABLED(CONFIG_BT_GTBS) && attr->user_data == &gtbs_inst) { if (IS_GTBS_CHRC(attr)) {
signal_strength_interval = gtbs_inst.signal_strength_interval; signal_strength_interval = gtbs_inst.signal_strength_interval;
BT_DBG("GTBS: Signal strength interval 0x%02x", BT_DBG("GTBS: Signal strength interval 0x%02x",
signal_strength_interval); signal_strength_interval);
} else { } else {
const struct tbs_service_inst *inst = (struct tbs_service_inst *)attr->user_data; const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr);
signal_strength_interval = inst->signal_strength_interval; signal_strength_interval = inst->signal_strength_interval;
BT_DBG("Index %u: Signal strength interval 0x%02x", BT_DBG("Index %u: Signal strength interval 0x%02x",
@ -714,11 +717,11 @@ static ssize_t write_signal_strength_interval(struct bt_conn *conn,
net_buf_simple_init_with_data(&net_buf, (void *)buf, len); net_buf_simple_init_with_data(&net_buf, (void *)buf, len);
signal_strength_interval = net_buf_simple_pull_u8(&net_buf); signal_strength_interval = net_buf_simple_pull_u8(&net_buf);
if (IS_ENABLED(CONFIG_BT_GTBS) && attr->user_data == &gtbs_inst) { if (IS_GTBS_CHRC(attr)) {
gtbs_inst.signal_strength_interval = signal_strength_interval; gtbs_inst.signal_strength_interval = signal_strength_interval;
BT_DBG("GTBS: 0x%02x", signal_strength_interval); BT_DBG("GTBS: 0x%02x", signal_strength_interval);
} else { } else {
struct tbs_service_inst *inst = (struct tbs_service_inst *)attr->user_data; struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr);
inst->signal_strength_interval = signal_strength_interval; inst->signal_strength_interval = signal_strength_interval;
BT_DBG("Index %u: 0x%02x", BT_DBG("Index %u: 0x%02x",
@ -746,12 +749,12 @@ static ssize_t read_current_calls(struct bt_conn *conn,
const struct bt_gatt_attr *attr, const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset) void *buf, uint16_t len, uint16_t offset)
{ {
net_buf_put_current_calls(attr->user_data); net_buf_put_current_calls(BT_AUDIO_CHRC_USER_DATA(attr));
if (IS_ENABLED(CONFIG_BT_GTBS) && attr->user_data == &gtbs_inst) { if (IS_GTBS_CHRC(attr)) {
BT_DBG("GTBS"); BT_DBG("GTBS");
} else { } else {
const struct tbs_service_inst *inst = (struct tbs_service_inst *)attr->user_data; const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr);
BT_DBG("Index %u", inst->index); BT_DBG("Index %u", inst->index);
} }
@ -770,11 +773,11 @@ static ssize_t read_ccid(struct bt_conn *conn,
{ {
uint8_t ccid; uint8_t ccid;
if (IS_ENABLED(CONFIG_BT_GTBS) && attr->user_data == &gtbs_inst) { if (IS_GTBS_CHRC(attr)) {
ccid = gtbs_inst.ccid; ccid = gtbs_inst.ccid;
BT_DBG("GTBS: CCID 0x%02X", ccid); BT_DBG("GTBS: CCID 0x%02X", ccid);
} else { } else {
const struct tbs_service_inst *inst = (struct tbs_service_inst *)attr->user_data; const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr);
ccid = inst->ccid; ccid = inst->ccid;
BT_DBG("Index %u: CCID 0x%02X", inst->index, ccid); BT_DBG("Index %u: CCID 0x%02X", inst->index, ccid);
@ -790,11 +793,11 @@ static ssize_t read_status_flags(struct bt_conn *conn,
{ {
uint16_t status_flags; uint16_t status_flags;
if (IS_ENABLED(CONFIG_BT_GTBS) && attr->user_data == &gtbs_inst) { if (IS_GTBS_CHRC(attr)) {
status_flags = gtbs_inst.status_flags; status_flags = gtbs_inst.status_flags;
BT_DBG("GTBS: status_flags 0x%04X", status_flags); BT_DBG("GTBS: status_flags 0x%04X", status_flags);
} else { } else {
const struct tbs_service_inst *inst = (struct tbs_service_inst *)attr->user_data; const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr);
status_flags = inst->status_flags; status_flags = inst->status_flags;
BT_DBG("Index %u: status_flags 0x%04X", BT_DBG("Index %u: status_flags 0x%04X",
@ -825,13 +828,13 @@ static ssize_t read_incoming_uri(struct bt_conn *conn,
const struct bt_tbs_in_uri *inc_call_target; const struct bt_tbs_in_uri *inc_call_target;
size_t val_len; size_t val_len;
if (IS_ENABLED(CONFIG_BT_GTBS) && attr->user_data == &gtbs_inst) { if (IS_GTBS_CHRC(attr)) {
inc_call_target = &gtbs_inst.incoming_uri; inc_call_target = &gtbs_inst.incoming_uri;
BT_DBG("GTBS: call index 0x%02X, URI %s", BT_DBG("GTBS: call index 0x%02X, URI %s",
inc_call_target->call_index, inc_call_target->call_index,
inc_call_target->uri); inc_call_target->uri);
} else { } else {
const struct tbs_service_inst *inst = (struct tbs_service_inst *)attr->user_data; const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr);
inc_call_target = &inst->incoming_uri; inc_call_target = &inst->incoming_uri;
BT_DBG("Index %u: call index 0x%02X, URI %s", BT_DBG("Index %u: call index 0x%02X, URI %s",
@ -868,12 +871,12 @@ static ssize_t read_call_state(struct bt_conn *conn,
const struct bt_gatt_attr *attr, const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset) void *buf, uint16_t len, uint16_t offset)
{ {
net_buf_put_call_state(attr->user_data); net_buf_put_call_state(BT_AUDIO_CHRC_USER_DATA(attr));
if (IS_ENABLED(CONFIG_BT_GTBS) && attr->user_data == &gtbs_inst) { if (IS_GTBS_CHRC(attr)) {
BT_DBG("GTBS"); BT_DBG("GTBS");
} else { } else {
const struct tbs_service_inst *inst = (struct tbs_service_inst *)attr->user_data; const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr);
BT_DBG("Index %u", inst->index); BT_DBG("Index %u", inst->index);
} }
@ -1278,8 +1281,7 @@ static ssize_t write_call_cp(struct bt_conn *conn,
const union bt_tbs_call_cp_t *ccp = (union bt_tbs_call_cp_t *)buf; const union bt_tbs_call_cp_t *ccp = (union bt_tbs_call_cp_t *)buf;
uint8_t status; uint8_t status;
uint8_t call_index = 0; uint8_t call_index = 0;
const bool is_gtbs = IS_ENABLED(CONFIG_BT_GTBS) && const bool is_gtbs = IS_GTBS_CHRC(attr);
attr->user_data == &gtbs_inst;
if (!is_authorized(conn)) { if (!is_authorized(conn)) {
return BT_GATT_ERR(BT_ATT_ERR_AUTHORIZATION); return BT_GATT_ERR(BT_ATT_ERR_AUTHORIZATION);
@ -1297,7 +1299,8 @@ static ssize_t write_call_cp(struct bt_conn *conn,
BT_DBG("GTBS: Processing the %s opcode", BT_DBG("GTBS: Processing the %s opcode",
bt_tbs_opcode_str(ccp->opcode)); bt_tbs_opcode_str(ccp->opcode));
} else { } else {
inst = (struct tbs_service_inst *)attr->user_data; inst = BT_AUDIO_CHRC_USER_DATA(attr);
BT_DBG("Index %u: Processing the %s opcode", BT_DBG("Index %u: Processing the %s opcode",
inst->index, bt_tbs_opcode_str(ccp->opcode)); inst->index, bt_tbs_opcode_str(ccp->opcode));
} }
@ -1485,11 +1488,11 @@ static ssize_t read_optional_opcodes(struct bt_conn *conn,
{ {
uint16_t optional_opcodes; uint16_t optional_opcodes;
if (IS_ENABLED(CONFIG_BT_GTBS) && attr->user_data == &gtbs_inst) { if (IS_GTBS_CHRC(attr)) {
optional_opcodes = gtbs_inst.optional_opcodes; optional_opcodes = gtbs_inst.optional_opcodes;
BT_DBG("GTBS: Supported opcodes 0x%02x", optional_opcodes); BT_DBG("GTBS: Supported opcodes 0x%02x", optional_opcodes);
} else { } else {
const struct tbs_service_inst *inst = (struct tbs_service_inst *)attr->user_data; const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr);
optional_opcodes = inst->optional_opcodes; optional_opcodes = inst->optional_opcodes;
BT_DBG("Index %u: Supported opcodes 0x%02x", BT_DBG("Index %u: Supported opcodes 0x%02x",
@ -1519,13 +1522,13 @@ static ssize_t read_friendly_name(struct bt_conn *conn,
const struct bt_tbs_in_uri *friendly_name; const struct bt_tbs_in_uri *friendly_name;
size_t val_len; size_t val_len;
if (IS_ENABLED(CONFIG_BT_GTBS) && attr->user_data == &gtbs_inst) { if (IS_GTBS_CHRC(attr)) {
friendly_name = &gtbs_inst.friendly_name; friendly_name = &gtbs_inst.friendly_name;
BT_DBG("GTBS: call index 0x%02X, URI %s", BT_DBG("GTBS: call index 0x%02X, URI %s",
friendly_name->call_index, friendly_name->call_index,
friendly_name->uri); friendly_name->uri);
} else { } else {
const struct tbs_service_inst *inst = (struct tbs_service_inst *)attr->user_data; const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr);
friendly_name = &inst->friendly_name; friendly_name = &inst->friendly_name;
BT_DBG("Index %u: call index 0x%02X, URI %s", BT_DBG("Index %u: call index 0x%02X, URI %s",
@ -1564,12 +1567,12 @@ static ssize_t read_incoming_call(struct bt_conn *conn,
const struct bt_tbs_in_uri *remote_uri; const struct bt_tbs_in_uri *remote_uri;
size_t val_len; size_t val_len;
if (IS_ENABLED(CONFIG_BT_GTBS) && attr->user_data == &gtbs_inst) { if (IS_GTBS_CHRC(attr)) {
remote_uri = &gtbs_inst.in_call; remote_uri = &gtbs_inst.in_call;
BT_DBG("GTBS: call index 0x%02X, URI %s", BT_DBG("GTBS: call index 0x%02X, URI %s",
remote_uri->call_index, remote_uri->uri); remote_uri->call_index, remote_uri->uri);
} else { } else {
const struct tbs_service_inst *inst = (struct tbs_service_inst *)attr->user_data; const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr);
remote_uri = &inst->in_call; remote_uri = &inst->in_call;
BT_DBG("Index %u: call index 0x%02X, URI %s", BT_DBG("Index %u: call index 0x%02X, URI %s",
@ -1602,128 +1605,112 @@ static void in_call_cfg_changed(const struct bt_gatt_attr *attr,
} }
#define BT_TBS_CHR_PROVIDER_NAME(inst) \ #define BT_TBS_CHR_PROVIDER_NAME(inst) \
BT_GATT_CHARACTERISTIC(BT_UUID_TBS_PROVIDER_NAME, \ BT_AUDIO_CHRC(BT_UUID_TBS_PROVIDER_NAME, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
read_provider_name, NULL, inst), \ read_provider_name, NULL, inst), \
BT_GATT_CCC(provider_name_cfg_changed, \ BT_AUDIO_CCC(provider_name_cfg_changed)
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT)
#define BT_TBS_CHR_UCI(inst) \ #define BT_TBS_CHR_UCI(inst) \
BT_GATT_CHARACTERISTIC(BT_UUID_TBS_UCI, \ BT_AUDIO_CHRC(BT_UUID_TBS_UCI, \
BT_GATT_CHRC_READ, \ BT_GATT_CHRC_READ, \
BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
read_uci, NULL, inst) read_uci, NULL, inst)
#define BT_TBS_CHR_TECHNOLOGY(inst) \ #define BT_TBS_CHR_TECHNOLOGY(inst) \
BT_GATT_CHARACTERISTIC(BT_UUID_TBS_TECHNOLOGY, \ BT_AUDIO_CHRC(BT_UUID_TBS_TECHNOLOGY, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
read_technology, NULL, inst), \ read_technology, NULL, inst), \
BT_GATT_CCC(technology_cfg_changed, \ BT_AUDIO_CCC(technology_cfg_changed)
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT)
#define BT_TBS_CHR_URI_LIST(inst) \ #define BT_TBS_CHR_URI_LIST(inst) \
BT_GATT_CHARACTERISTIC(BT_UUID_TBS_URI_LIST, \ BT_AUDIO_CHRC(BT_UUID_TBS_URI_LIST, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
read_uri_scheme_list, NULL, inst), \ read_uri_scheme_list, NULL, inst), \
BT_GATT_CCC(uri_scheme_list_cfg_changed, \ BT_AUDIO_CCC(uri_scheme_list_cfg_changed)
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT)
#define BT_TBS_CHR_SIGNAL_STRENGTH(inst) \ #define BT_TBS_CHR_SIGNAL_STRENGTH(inst) \
BT_GATT_CHARACTERISTIC(BT_UUID_TBS_SIGNAL_STRENGTH, /* Optional */ \ BT_AUDIO_CHRC(BT_UUID_TBS_SIGNAL_STRENGTH, /* Optional */ \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
read_signal_strength, NULL, inst), \ read_signal_strength, NULL, inst), \
BT_GATT_CCC(signal_strength_cfg_changed, \ BT_AUDIO_CCC(signal_strength_cfg_changed)
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT)
#define BT_TBS_CHR_SIGNAL_INTERVAL(inst) \ #define BT_TBS_CHR_SIGNAL_INTERVAL(inst) \
BT_GATT_CHARACTERISTIC(BT_UUID_TBS_SIGNAL_INTERVAL, /* Conditional */ \ BT_AUDIO_CHRC(BT_UUID_TBS_SIGNAL_INTERVAL, /* Conditional */ \
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | \ BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP, \
BT_GATT_CHRC_WRITE_WITHOUT_RESP, \ BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT, \
BT_GATT_PERM_READ_ENCRYPT | \ read_signal_strength_interval, write_signal_strength_interval, inst)
BT_GATT_PERM_WRITE_ENCRYPT, \
read_signal_strength_interval, \
write_signal_strength_interval, inst)
#define BT_TBS_CHR_CURRENT_CALLS(inst) \ #define BT_TBS_CHR_CURRENT_CALLS(inst) \
BT_GATT_CHARACTERISTIC(BT_UUID_TBS_LIST_CURRENT_CALLS, \ BT_AUDIO_CHRC(BT_UUID_TBS_LIST_CURRENT_CALLS, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
read_current_calls, NULL, inst), \ read_current_calls, NULL, inst), \
BT_GATT_CCC(current_calls_cfg_changed, \ BT_AUDIO_CCC(current_calls_cfg_changed)
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT)
#define BT_TBS_CHR_CCID(inst) \ #define BT_TBS_CHR_CCID(inst) \
BT_GATT_CHARACTERISTIC(BT_UUID_CCID, \ BT_AUDIO_CHRC(BT_UUID_CCID, \
BT_GATT_CHRC_READ, \ BT_GATT_CHRC_READ, \
BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
read_ccid, NULL, inst) read_ccid, NULL, inst)
#define BT_TBS_CHR_STATUS_FLAGS(inst) \ #define BT_TBS_CHR_STATUS_FLAGS(inst) \
BT_GATT_CHARACTERISTIC(BT_UUID_TBS_STATUS_FLAGS, \ BT_AUDIO_CHRC(BT_UUID_TBS_STATUS_FLAGS, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
read_status_flags, NULL, inst), \ read_status_flags, NULL, inst), \
BT_GATT_CCC(status_flags_cfg_changed, \ BT_AUDIO_CCC(status_flags_cfg_changed)
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT)
#define BT_TBS_CHR_INCOMING_URI(inst) \ #define BT_TBS_CHR_INCOMING_URI(inst) \
BT_GATT_CHARACTERISTIC(BT_UUID_TBS_INCOMING_URI, /* Optional */ \ BT_AUDIO_CHRC(BT_UUID_TBS_INCOMING_URI, /* Optional */ \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
read_incoming_uri, NULL, inst), \ read_incoming_uri, NULL, inst), \
BT_GATT_CCC(incoming_uri_cfg_changed, \ BT_AUDIO_CCC(incoming_uri_cfg_changed)
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT)
#define BT_TBS_CHR_CALL_STATE(inst) \ #define BT_TBS_CHR_CALL_STATE(inst) \
BT_GATT_CHARACTERISTIC(BT_UUID_TBS_CALL_STATE, \ BT_AUDIO_CHRC(BT_UUID_TBS_CALL_STATE, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
read_call_state, NULL, inst), \ read_call_state, NULL, inst), \
BT_GATT_CCC(call_state_cfg_changed, \ BT_AUDIO_CCC(call_state_cfg_changed)
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT)
#define BT_TBS_CHR_CONTROL_POINT(inst) \ #define BT_TBS_CHR_CONTROL_POINT(inst) \
BT_GATT_CHARACTERISTIC(BT_UUID_TBS_CALL_CONTROL_POINT, \ BT_AUDIO_CHRC(BT_UUID_TBS_CALL_CONTROL_POINT, \
BT_GATT_CHRC_WRITE | BT_GATT_CHRC_NOTIFY | \ BT_GATT_CHRC_WRITE | BT_GATT_CHRC_NOTIFY | BT_GATT_CHRC_WRITE_WITHOUT_RESP, \
BT_GATT_CHRC_WRITE_WITHOUT_RESP, \ BT_GATT_PERM_WRITE_ENCRYPT, \
BT_GATT_PERM_WRITE_ENCRYPT, \ NULL, write_call_cp, inst), \
NULL, write_call_cp, inst), \ BT_AUDIO_CCC(call_cp_cfg_changed)
BT_GATT_CCC(call_cp_cfg_changed, \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT)
#define BT_TBS_CHR_OPTIONAL_OPCODES(inst) \ #define BT_TBS_CHR_OPTIONAL_OPCODES(inst) \
BT_GATT_CHARACTERISTIC(BT_UUID_TBS_OPTIONAL_OPCODES, \ BT_AUDIO_CHRC(BT_UUID_TBS_OPTIONAL_OPCODES, \
BT_GATT_CHRC_READ, \ BT_GATT_CHRC_READ, \
BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
read_optional_opcodes, NULL, inst) \ read_optional_opcodes, NULL, inst) \
#define BT_TBS_CHR_TERMINATE_REASON(inst) \ #define BT_TBS_CHR_TERMINATE_REASON(inst) \
BT_GATT_CHARACTERISTIC(BT_UUID_TBS_TERMINATE_REASON, \ BT_AUDIO_CHRC(BT_UUID_TBS_TERMINATE_REASON, \
BT_GATT_CHRC_NOTIFY, \ BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
NULL, NULL, inst), \ NULL, NULL, inst), \
BT_GATT_CCC(terminate_reason_cfg_changed, \ BT_AUDIO_CCC(terminate_reason_cfg_changed)
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT)
#define BT_TBS_CHR_INCOMING_CALL(inst) \ #define BT_TBS_CHR_INCOMING_CALL(inst) \
BT_GATT_CHARACTERISTIC(BT_UUID_TBS_INCOMING_CALL, \ BT_AUDIO_CHRC(BT_UUID_TBS_INCOMING_CALL, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
read_incoming_call, NULL, inst), \ read_incoming_call, NULL, inst), \
BT_GATT_CCC(in_call_cfg_changed, \ BT_AUDIO_CCC(in_call_cfg_changed)
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT)
#define BT_TBS_CHR_FRIENDLY_NAME(inst) \ #define BT_TBS_CHR_FRIENDLY_NAME(inst) \
BT_GATT_CHARACTERISTIC(BT_UUID_TBS_FRIENDLY_NAME, /* Optional */ \ BT_AUDIO_CHRC(BT_UUID_TBS_FRIENDLY_NAME, /* Optional */ \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
read_friendly_name, NULL, inst), \ read_friendly_name, NULL, inst), \
BT_GATT_CCC(friendly_name_cfg_changed, \ BT_AUDIO_CCC(friendly_name_cfg_changed)
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT)
#define BT_TBS_SERVICE_DEFINITION(inst) {\ #define BT_TBS_SERVICE_DEFINITION(inst) {\
BT_GATT_PRIMARY_SERVICE(BT_UUID_TBS), \ BT_GATT_PRIMARY_SERVICE(BT_UUID_TBS), \

View file

@ -20,6 +20,7 @@
#include <zephyr/bluetooth/gatt.h> #include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/audio/vcs.h> #include <zephyr/bluetooth/audio/vcs.h>
#include "audio_internal.h"
#include "vcs_internal.h" #include "vcs_internal.h"
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_VCS) #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_VCS)
@ -249,22 +250,20 @@ static ssize_t read_flags(struct bt_conn *conn, const struct bt_gatt_attr *attr,
BT_GATT_PRIMARY_SERVICE(BT_UUID_VCS), \ BT_GATT_PRIMARY_SERVICE(BT_UUID_VCS), \
VOCS_INCLUDES(CONFIG_BT_VCS_VOCS_INSTANCE_COUNT) \ VOCS_INCLUDES(CONFIG_BT_VCS_VOCS_INSTANCE_COUNT) \
AICS_INCLUDES(CONFIG_BT_VCS_AICS_INSTANCE_COUNT) \ AICS_INCLUDES(CONFIG_BT_VCS_AICS_INSTANCE_COUNT) \
BT_GATT_CHARACTERISTIC(BT_UUID_VCS_STATE, \ BT_AUDIO_CHRC(BT_UUID_VCS_STATE, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
read_vol_state, NULL, NULL), \ read_vol_state, NULL, NULL), \
BT_GATT_CCC(volume_state_cfg_changed, \ BT_AUDIO_CCC(volume_state_cfg_changed), \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), \ BT_AUDIO_CHRC(BT_UUID_VCS_CONTROL, \
BT_GATT_CHARACTERISTIC(BT_UUID_VCS_CONTROL, \ BT_GATT_CHRC_WRITE, \
BT_GATT_CHRC_WRITE, \ BT_GATT_PERM_WRITE_ENCRYPT, \
BT_GATT_PERM_WRITE_ENCRYPT, \ NULL, write_vcs_control, NULL), \
NULL, write_vcs_control, NULL), \ BT_AUDIO_CHRC(BT_UUID_VCS_FLAGS, \
BT_GATT_CHARACTERISTIC(BT_UUID_VCS_FLAGS, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ BT_GATT_PERM_READ_ENCRYPT, \
BT_GATT_PERM_READ_ENCRYPT, \ read_flags, NULL, NULL), \
read_flags, NULL, NULL), \ BT_AUDIO_CCC(flags_cfg_changed)
BT_GATT_CCC(flags_cfg_changed, \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT)
static struct bt_gatt_attr vcs_attrs[] = { BT_VCS_SERVICE_DEFINITION }; static struct bt_gatt_attr vcs_attrs[] = { BT_VCS_SERVICE_DEFINITION };
static struct bt_gatt_service vcs_svc; static struct bt_gatt_service vcs_svc;

View file

@ -17,6 +17,7 @@
#include <zephyr/bluetooth/gatt.h> #include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/audio/vocs.h> #include <zephyr/bluetooth/audio/vocs.h>
#include "audio_internal.h"
#include "vocs_internal.h" #include "vocs_internal.h"
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_VOCS) #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_VOCS)
@ -34,7 +35,7 @@ static void offset_state_cfg_changed(const struct bt_gatt_attr *attr, uint16_t v
static ssize_t read_offset_state(struct bt_conn *conn, const struct bt_gatt_attr *attr, static ssize_t read_offset_state(struct bt_conn *conn, const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset) void *buf, uint16_t len, uint16_t offset)
{ {
struct bt_vocs *inst = attr->user_data; struct bt_vocs *inst = BT_AUDIO_CHRC_USER_DATA(attr);
BT_DBG("offset %d, counter %u", inst->srv.state.offset, inst->srv.state.change_counter); BT_DBG("offset %d, counter %u", inst->srv.state.offset, inst->srv.state.change_counter);
return bt_gatt_attr_read(conn, attr, buf, len, offset, &inst->srv.state, return bt_gatt_attr_read(conn, attr, buf, len, offset, &inst->srv.state,
@ -51,7 +52,7 @@ static void location_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value
static ssize_t write_location(struct bt_conn *conn, const struct bt_gatt_attr *attr, static ssize_t write_location(struct bt_conn *conn, const struct bt_gatt_attr *attr,
const void *buf, uint16_t len, uint16_t offset, uint8_t flags) const void *buf, uint16_t len, uint16_t offset, uint8_t flags)
{ {
struct bt_vocs *inst = attr->user_data; struct bt_vocs *inst = BT_AUDIO_CHRC_USER_DATA(attr);
uint32_t old_location = inst->srv.location; uint32_t old_location = inst->srv.location;
if (offset) { if (offset) {
@ -83,7 +84,7 @@ static ssize_t write_location(struct bt_conn *conn, const struct bt_gatt_attr *a
static ssize_t read_location(struct bt_conn *conn, const struct bt_gatt_attr *attr, static ssize_t read_location(struct bt_conn *conn, const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset) void *buf, uint16_t len, uint16_t offset)
{ {
struct bt_vocs *inst = attr->user_data; struct bt_vocs *inst = BT_AUDIO_CHRC_USER_DATA(attr);
BT_DBG("0x%08x", inst->srv.location); BT_DBG("0x%08x", inst->srv.location);
return bt_gatt_attr_read(conn, attr, buf, len, offset, &inst->srv.location, return bt_gatt_attr_read(conn, attr, buf, len, offset, &inst->srv.location,
@ -94,7 +95,7 @@ static ssize_t read_location(struct bt_conn *conn, const struct bt_gatt_attr *at
static ssize_t write_vocs_control(struct bt_conn *conn, const struct bt_gatt_attr *attr, static ssize_t write_vocs_control(struct bt_conn *conn, const struct bt_gatt_attr *attr,
const void *buf, uint16_t len, uint16_t offset, uint8_t flags) const void *buf, uint16_t len, uint16_t offset, uint8_t flags)
{ {
struct bt_vocs *inst = attr->user_data; struct bt_vocs *inst = BT_AUDIO_CHRC_USER_DATA(attr);
const struct bt_vocs_control *cp = buf; const struct bt_vocs_control *cp = buf;
bool notify = false; bool notify = false;
@ -166,7 +167,7 @@ static void output_desc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t va
static ssize_t write_output_desc(struct bt_conn *conn, const struct bt_gatt_attr *attr, static ssize_t write_output_desc(struct bt_conn *conn, const struct bt_gatt_attr *attr,
const void *buf, uint16_t len, uint16_t offset, uint8_t flags) const void *buf, uint16_t len, uint16_t offset, uint8_t flags)
{ {
struct bt_vocs *inst = attr->user_data; struct bt_vocs *inst = BT_AUDIO_CHRC_USER_DATA(attr);
if (offset) { if (offset) {
return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
@ -198,11 +199,34 @@ static ssize_t write_output_desc(struct bt_conn *conn, const struct bt_gatt_attr
return len; return len;
} }
static int vocs_write(struct bt_vocs *inst,
ssize_t (*write)(struct bt_conn *conn,
const struct bt_gatt_attr *attr,
const void *buf, uint16_t len,
uint16_t offset, uint8_t flags),
const void *buf, uint16_t len)
{
struct bt_audio_attr_user_data user_data = {
.user_data = inst,
};
struct bt_gatt_attr attr = {
.user_data = &user_data,
};
int err;
err = write(NULL, &attr, buf, len, 0, 0);
if (err < 0) {
return err;
}
return 0;
}
#if defined(CONFIG_BT_VOCS) #if defined(CONFIG_BT_VOCS)
static ssize_t read_output_desc(struct bt_conn *conn, const struct bt_gatt_attr *attr, static ssize_t read_output_desc(struct bt_conn *conn, const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset) void *buf, uint16_t len, uint16_t offset)
{ {
struct bt_vocs *inst = attr->user_data; struct bt_vocs *inst = BT_AUDIO_CHRC_USER_DATA(attr);
BT_DBG("%s", inst->srv.output_desc); BT_DBG("%s", inst->srv.output_desc);
return bt_gatt_attr_read(conn, attr, buf, len, offset, &inst->srv.output_desc, return bt_gatt_attr_read(conn, attr, buf, len, offset, &inst->srv.output_desc,
@ -211,28 +235,25 @@ static ssize_t read_output_desc(struct bt_conn *conn, const struct bt_gatt_attr
#define BT_VOCS_SERVICE_DEFINITION(_vocs) { \ #define BT_VOCS_SERVICE_DEFINITION(_vocs) { \
BT_GATT_SECONDARY_SERVICE(BT_UUID_VOCS), \ BT_GATT_SECONDARY_SERVICE(BT_UUID_VOCS), \
BT_GATT_CHARACTERISTIC(BT_UUID_VOCS_STATE, \ BT_AUDIO_CHRC(BT_UUID_VOCS_STATE, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_PERM_READ_ENCRYPT, \ BT_GATT_PERM_READ_ENCRYPT, \
read_offset_state, NULL, &_vocs), \ read_offset_state, NULL, &_vocs), \
BT_GATT_CCC(offset_state_cfg_changed, \ BT_AUDIO_CCC(offset_state_cfg_changed), \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), \ BT_AUDIO_CHRC(BT_UUID_VOCS_LOCATION, \
BT_GATT_CHARACTERISTIC(BT_UUID_VOCS_LOCATION, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ BT_GATT_PERM_READ_ENCRYPT, \
BT_GATT_PERM_READ_ENCRYPT, \ read_location, write_location, &_vocs), \
read_location, NULL, &_vocs), \ BT_AUDIO_CCC(location_cfg_changed), \
BT_GATT_CCC(location_cfg_changed, \ BT_AUDIO_CHRC(BT_UUID_VOCS_CONTROL, \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT), \ BT_GATT_CHRC_WRITE, \
BT_GATT_CHARACTERISTIC(BT_UUID_VOCS_CONTROL, \ BT_GATT_PERM_WRITE_ENCRYPT, \
BT_GATT_CHRC_WRITE, \ NULL, write_vocs_control, &_vocs), \
BT_GATT_PERM_WRITE_ENCRYPT, \ BT_AUDIO_CHRC(BT_UUID_VOCS_DESCRIPTION, \
NULL, write_vocs_control, &_vocs), \ BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
BT_GATT_CHARACTERISTIC(BT_UUID_VOCS_DESCRIPTION, \ BT_GATT_PERM_READ_ENCRYPT, \
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ read_output_desc, write_output_desc, &_vocs), \
BT_GATT_PERM_READ_ENCRYPT, \ BT_AUDIO_CCC(output_desc_cfg_changed) \
read_output_desc, NULL, &_vocs), \
BT_GATT_CCC(output_desc_cfg_changed, \
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT) \
} }
static struct bt_vocs vocs_insts[CONFIG_BT_VOCS_MAX_INSTANCE_COUNT]; static struct bt_vocs vocs_insts[CONFIG_BT_VOCS_MAX_INSTANCE_COUNT];
@ -327,14 +348,12 @@ int bt_vocs_register(struct bt_vocs *vocs,
if (param->location_writable && !bt_uuid_cmp(attr->uuid, BT_UUID_VOCS_LOCATION)) { if (param->location_writable && !bt_uuid_cmp(attr->uuid, BT_UUID_VOCS_LOCATION)) {
/* Update attr and chrc to be writable */ /* Update attr and chrc to be writable */
chrc = vocs->srv.service_p->attrs[i - 1].user_data; chrc = vocs->srv.service_p->attrs[i - 1].user_data;
attr->write = write_location;
attr->perm |= BT_GATT_PERM_WRITE_ENCRYPT; attr->perm |= BT_GATT_PERM_WRITE_ENCRYPT;
chrc->properties |= BT_GATT_CHRC_WRITE_WITHOUT_RESP; chrc->properties |= BT_GATT_CHRC_WRITE_WITHOUT_RESP;
} else if (param->desc_writable && } else if (param->desc_writable &&
!bt_uuid_cmp(attr->uuid, BT_UUID_VOCS_DESCRIPTION)) { !bt_uuid_cmp(attr->uuid, BT_UUID_VOCS_DESCRIPTION)) {
/* Update attr and chrc to be writable */ /* Update attr and chrc to be writable */
chrc = vocs->srv.service_p->attrs[i - 1].user_data; chrc = vocs->srv.service_p->attrs[i - 1].user_data;
attr->write = write_output_desc;
attr->perm |= BT_GATT_PERM_WRITE_ENCRYPT; attr->perm |= BT_GATT_PERM_WRITE_ENCRYPT;
chrc->properties |= BT_GATT_CHRC_WRITE_WITHOUT_RESP; chrc->properties |= BT_GATT_CHRC_WRITE_WITHOUT_RESP;
} }
@ -399,14 +418,7 @@ int bt_vocs_location_set(struct bt_vocs *inst, uint32_t location)
if (IS_ENABLED(CONFIG_BT_VOCS_CLIENT) && inst->client_instance) { if (IS_ENABLED(CONFIG_BT_VOCS_CLIENT) && inst->client_instance) {
return bt_vocs_client_location_set(inst, location); return bt_vocs_client_location_set(inst, location);
} else if (IS_ENABLED(CONFIG_BT_VOCS) && !inst->client_instance) { } else if (IS_ENABLED(CONFIG_BT_VOCS) && !inst->client_instance) {
struct bt_gatt_attr attr; return vocs_write(inst, write_location, &location, sizeof(location));
int err;
attr.user_data = inst;
err = write_location(NULL, &attr, &location, sizeof(location), 0, 0);
return err > 0 ? 0 : err;
} }
return -ENOTSUP; return -ENOTSUP;
@ -422,19 +434,13 @@ int bt_vocs_state_set(struct bt_vocs *inst, int16_t offset)
if (IS_ENABLED(CONFIG_BT_VOCS_CLIENT) && inst->client_instance) { if (IS_ENABLED(CONFIG_BT_VOCS_CLIENT) && inst->client_instance) {
return bt_vocs_client_state_set(inst, offset); return bt_vocs_client_state_set(inst, offset);
} else if (IS_ENABLED(CONFIG_BT_VOCS) && !inst->client_instance) { } else if (IS_ENABLED(CONFIG_BT_VOCS) && !inst->client_instance) {
struct bt_gatt_attr attr;
struct bt_vocs_control cp; struct bt_vocs_control cp;
int err;
cp.opcode = BT_VOCS_OPCODE_SET_OFFSET; cp.opcode = BT_VOCS_OPCODE_SET_OFFSET;
cp.counter = inst->srv.state.change_counter; cp.counter = inst->srv.state.change_counter;
cp.offset = sys_cpu_to_le16(offset); cp.offset = sys_cpu_to_le16(offset);
attr.user_data = inst; return vocs_write(inst, write_vocs_control, &cp, sizeof(cp));
err = write_vocs_control(NULL, &attr, &cp, sizeof(cp), 0, 0);
return err > 0 ? 0 : err;
} }
return -ENOTSUP; return -ENOTSUP;
@ -474,13 +480,7 @@ int bt_vocs_description_set(struct bt_vocs *inst, const char *description)
if (IS_ENABLED(CONFIG_BT_VOCS_CLIENT) && inst->client_instance) { if (IS_ENABLED(CONFIG_BT_VOCS_CLIENT) && inst->client_instance) {
return bt_vocs_client_description_set(inst, description); return bt_vocs_client_description_set(inst, description);
} else if (IS_ENABLED(CONFIG_BT_VOCS) && !inst->client_instance) { } else if (IS_ENABLED(CONFIG_BT_VOCS) && !inst->client_instance) {
struct bt_gatt_attr attr; return vocs_write(inst, write_output_desc, description, strlen(description));
int err;
attr.user_data = inst;
err = write_output_desc(NULL, &attr, description, strlen(description), 0, 0);
return err > 0 ? 0 : err;
} }
return -ENOTSUP; return -ENOTSUP;

View file

@ -95,8 +95,6 @@ CONFIG_BT_BASS_CLIENT=y
CONFIG_BT_HAS=y CONFIG_BT_HAS=y
CONFIG_BT_HAS_CLIENT=y CONFIG_BT_HAS_CLIENT=y
CONFIG_BT_HAS_HEARING_AID_MONAURAL=y CONFIG_BT_HAS_HEARING_AID_MONAURAL=y
CONFIG_BT_SMP_SC_PAIR_ONLY=y
CONFIG_BT_SMP_MIN_ENC_KEY_SIZE=16
# Common Audio Profile # Common Audio Profile
CONFIG_BT_CAP_ACCEPTOR=y CONFIG_BT_CAP_ACCEPTOR=y

View file

@ -103,8 +103,6 @@ CONFIG_BT_HAS=y
CONFIG_BT_HAS_HEARING_AID_MONAURAL=y CONFIG_BT_HAS_HEARING_AID_MONAURAL=y
CONFIG_BT_HAS_PRESET_NAME_DYNAMIC=y CONFIG_BT_HAS_PRESET_NAME_DYNAMIC=y
CONFIG_BT_HAS_PRESET_COUNT=4 CONFIG_BT_HAS_PRESET_COUNT=4
CONFIG_BT_SMP_SC_PAIR_ONLY=y
CONFIG_BT_SMP_MIN_ENC_KEY_SIZE=16
CONFIG_BT_HAS_CLIENT=y CONFIG_BT_HAS_CLIENT=y
# Common Audio Profile # Common Audio Profile