1 /* Common functions for LE Audio services */
2
3 /*
4 * Copyright (c) 2022 Codecoup
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <zephyr/bluetooth/att.h>
10 #include <zephyr/bluetooth/conn.h>
11 #include <zephyr/bluetooth/hci.h>
12 #include <zephyr/bluetooth/audio/audio.h>
13 #include <zephyr/bluetooth/audio/bap.h>
14 #include <zephyr/logging/log.h>
15 #include <zephyr/sys/check.h>
16
17 #include "audio_internal.h"
18
19 LOG_MODULE_REGISTER(bt_audio, CONFIG_BT_AUDIO_LOG_LEVEL);
20
bt_audio_data_parse(const uint8_t ltv[],size_t size,bool (* func)(struct bt_data * data,void * user_data),void * user_data)21 int bt_audio_data_parse(const uint8_t ltv[], size_t size,
22 bool (*func)(struct bt_data *data, void *user_data), void *user_data)
23 {
24 CHECKIF(ltv == NULL) {
25 LOG_DBG("ltv is NULL");
26
27 return -EINVAL;
28 }
29
30 CHECKIF(func == NULL) {
31 LOG_DBG("func is NULL");
32
33 return -EINVAL;
34 }
35
36 for (size_t i = 0; i < size;) {
37 const uint8_t len = ltv[i];
38 struct bt_data data;
39
40 if (i + len > size || len < sizeof(data.type)) {
41 LOG_DBG("Invalid len %u at i = %zu", len, i);
42
43 return -EINVAL;
44 }
45
46 i++; /* Increment as we have parsed the len field */
47
48 data.type = ltv[i++];
49 data.data_len = len - sizeof(data.type);
50
51 if (data.data_len > 0) {
52 data.data = <v[i];
53 } else {
54 data.data = NULL;
55 }
56
57 if (!func(&data, user_data)) {
58 return -ECANCELED;
59 }
60
61 /* Since we are incrementing i by the value_len, we don't need to increment it
62 * further in the `for` statement
63 */
64 i += data.data_len;
65 }
66
67 return 0;
68 }
69
70 #if defined(CONFIG_BT_CONN)
71
bt_audio_security_check(const struct bt_conn * conn)72 static uint8_t bt_audio_security_check(const struct bt_conn *conn)
73 {
74 struct bt_conn_info info;
75 int err;
76
77 err = bt_conn_get_info(conn, &info);
78 if (err < 0) {
79 return BT_ATT_ERR_UNLIKELY;
80 }
81
82 /* Require an encryption key with at least 128 bits of entropy, derived from SC or OOB
83 * method.
84 */
85 if ((info.security.flags & (BT_SECURITY_FLAG_OOB | BT_SECURITY_FLAG_SC)) == 0) {
86 /* If the client has insufficient security to read/write the requested attribute
87 * then an ATT_ERROR_RSP PDU shall be sent with the Error Code parameter set to
88 * Insufficient Authentication (0x05).
89 */
90 return BT_ATT_ERR_AUTHENTICATION;
91 }
92
93 if (info.security.enc_key_size < BT_ENC_KEY_SIZE_MAX) {
94 return BT_ATT_ERR_ENCRYPTION_KEY_SIZE;
95 }
96
97 return BT_ATT_ERR_SUCCESS;
98 }
99
bt_audio_read_chrc(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)100 ssize_t bt_audio_read_chrc(struct bt_conn *conn, const struct bt_gatt_attr *attr,
101 void *buf, uint16_t len, uint16_t offset)
102 {
103 const struct bt_audio_attr_user_data *user_data = attr->user_data;
104
105 if (user_data->read == NULL) {
106 return BT_GATT_ERR(BT_ATT_ERR_READ_NOT_PERMITTED);
107 }
108
109 if (conn != NULL) {
110 uint8_t err;
111
112 err = bt_audio_security_check(conn);
113 if (err != 0) {
114 return BT_GATT_ERR(err);
115 }
116 }
117
118 return user_data->read(conn, attr, buf, len, offset);
119 }
120
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)121 ssize_t bt_audio_write_chrc(struct bt_conn *conn, const struct bt_gatt_attr *attr,
122 const void *buf, uint16_t len, uint16_t offset, uint8_t flags)
123 {
124 const struct bt_audio_attr_user_data *user_data = attr->user_data;
125
126 if (user_data->write == NULL) {
127 return BT_GATT_ERR(BT_ATT_ERR_WRITE_NOT_PERMITTED);
128 }
129
130 if (conn != NULL) {
131 uint8_t err;
132
133 err = bt_audio_security_check(conn);
134 if (err != 0) {
135 return BT_GATT_ERR(err);
136 }
137 }
138
139 return user_data->write(conn, attr, buf, len, offset, flags);
140 }
141
bt_audio_ccc_cfg_write(struct bt_conn * conn,const struct bt_gatt_attr * attr,uint16_t value)142 ssize_t bt_audio_ccc_cfg_write(struct bt_conn *conn, const struct bt_gatt_attr *attr,
143 uint16_t value)
144 {
145 if (conn != NULL) {
146 uint8_t err;
147
148 err = bt_audio_security_check(conn);
149 if (err != 0) {
150 return BT_GATT_ERR(err);
151 }
152 }
153
154 return sizeof(value);
155 }
156 #endif /* CONFIG_BT_CONN */
157