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 <errno.h>
10 #include <stdbool.h>
11 #include <stddef.h>
12 #include <stdint.h>
13 #include <sys/types.h>
14 
15 #include <zephyr/autoconf.h>
16 #include <zephyr/bluetooth/audio/audio.h>
17 #include <zephyr/bluetooth/audio/bap.h>
18 #include <zephyr/bluetooth/att.h>
19 #include <zephyr/bluetooth/bluetooth.h>
20 #include <zephyr/bluetooth/conn.h>
21 #include <zephyr/bluetooth/gatt.h>
22 #include <zephyr/bluetooth/hci.h>
23 #include <zephyr/bluetooth/hci_types.h>
24 #include <zephyr/logging/log.h>
25 #include <zephyr/sys/check.h>
26 #include <zephyr/toolchain.h>
27 
28 #include "audio_internal.h"
29 
30 LOG_MODULE_REGISTER(bt_audio, CONFIG_BT_AUDIO_LOG_LEVEL);
31 
bt_audio_data_parse(const uint8_t ltv[],size_t size,bool (* func)(struct bt_data * data,void * user_data),void * user_data)32 int bt_audio_data_parse(const uint8_t ltv[], size_t size,
33 			bool (*func)(struct bt_data *data, void *user_data), void *user_data)
34 {
35 	CHECKIF(ltv == NULL) {
36 		LOG_DBG("ltv is NULL");
37 
38 		return -EINVAL;
39 	}
40 
41 	CHECKIF(func == NULL) {
42 		LOG_DBG("func is NULL");
43 
44 		return -EINVAL;
45 	}
46 
47 	for (size_t i = 0; i < size;) {
48 		const uint8_t len = ltv[i];
49 		struct bt_data data;
50 
51 		if (i + len > size || len < sizeof(data.type)) {
52 			LOG_DBG("Invalid len %u at i = %zu", len, i);
53 
54 			return -EINVAL;
55 		}
56 
57 		i++; /* Increment as we have parsed the len field */
58 
59 		data.type = ltv[i++];
60 		data.data_len = len - sizeof(data.type);
61 
62 		if (data.data_len > 0) {
63 			data.data = &ltv[i];
64 		} else {
65 			data.data = NULL;
66 		}
67 
68 		if (!func(&data, user_data)) {
69 			return -ECANCELED;
70 		}
71 
72 		/* Since we are incrementing i by the value_len, we don't need to increment it
73 		 * further in the `for` statement
74 		 */
75 		i += data.data_len;
76 	}
77 
78 	return 0;
79 }
80 
81 struct search_type_param {
82 	bool found;
83 	uint8_t type;
84 	uint8_t data_len;
85 	const uint8_t **data;
86 };
87 
parse_cb(struct bt_data * data,void * user_data)88 static bool parse_cb(struct bt_data *data, void *user_data)
89 {
90 	struct search_type_param *param = (struct search_type_param *)user_data;
91 
92 	if (param->type == data->type) {
93 		param->found = true;
94 		param->data_len = data->data_len;
95 		*param->data = data->data;
96 
97 		return false;
98 	}
99 
100 	return true;
101 }
102 
bt_audio_data_get_val(const uint8_t ltv_data[],size_t size,uint8_t type,const uint8_t ** data)103 int bt_audio_data_get_val(const uint8_t ltv_data[], size_t size, uint8_t type, const uint8_t **data)
104 {
105 	struct search_type_param param = {
106 		.found = false,
107 		.type = type,
108 		.data_len = 0U,
109 		.data = data,
110 	};
111 	int err;
112 
113 	CHECKIF(ltv_data == NULL) {
114 		LOG_DBG("ltv_data is NULL");
115 		return -EINVAL;
116 	}
117 
118 	CHECKIF(data == NULL) {
119 		LOG_DBG("data is NULL");
120 		return -EINVAL;
121 	}
122 
123 	*data = NULL;
124 
125 	/* If the size is 0 we can terminate early */
126 	if (size == 0U) {
127 		return -ENODATA;
128 	}
129 
130 	err = bt_audio_data_parse(ltv_data, size, parse_cb, &param);
131 	if (err != 0 && err != -ECANCELED) {
132 		LOG_DBG("Could not parse the data: %d", err);
133 		return err;
134 	}
135 
136 	if (!param.found) {
137 		return -ENODATA;
138 	}
139 
140 	return param.data_len;
141 }
142 
bt_audio_get_chan_count(enum bt_audio_location chan_allocation)143 uint8_t bt_audio_get_chan_count(enum bt_audio_location chan_allocation)
144 {
145 	if (chan_allocation == BT_AUDIO_LOCATION_MONO_AUDIO) {
146 		return 1;
147 	}
148 
149 #ifdef POPCOUNT
150 	return POPCOUNT(chan_allocation);
151 #else
152 	uint8_t cnt = 0U;
153 
154 	while (chan_allocation != 0U) {
155 		cnt += chan_allocation & 1U;
156 		chan_allocation >>= 1U;
157 	}
158 
159 	return cnt;
160 #endif
161 }
162 
valid_ltv_cb(struct bt_data * data,void * user_data)163 static bool valid_ltv_cb(struct bt_data *data, void *user_data)
164 {
165 	/* just return true to continue parsing as bt_data_parse will validate for us */
166 	return true;
167 }
168 
bt_audio_valid_ltv(const uint8_t * data,uint8_t data_len)169 bool bt_audio_valid_ltv(const uint8_t *data, uint8_t data_len)
170 {
171 	return bt_audio_data_parse(data, data_len, valid_ltv_cb, NULL) == 0;
172 }
173 
174 #if defined(CONFIG_BT_CONN)
175 
bt_audio_security_check(const struct bt_conn * conn)176 static uint8_t bt_audio_security_check(const struct bt_conn *conn)
177 {
178 	struct bt_conn_info info;
179 	int err;
180 
181 	err = bt_conn_get_info(conn, &info);
182 	if (err < 0) {
183 		return BT_ATT_ERR_UNLIKELY;
184 	}
185 
186 	/* Require an encryption key with at least 128 bits of entropy, derived from SC or OOB
187 	 * method.
188 	 */
189 	if ((info.security.flags & (BT_SECURITY_FLAG_OOB | BT_SECURITY_FLAG_SC)) == 0) {
190 		/* If the client has insufficient security to read/write the requested attribute
191 		 * then an ATT_ERROR_RSP PDU shall be sent with the Error Code parameter set to
192 		 * Insufficient Authentication (0x05).
193 		 */
194 		return BT_ATT_ERR_AUTHENTICATION;
195 	}
196 
197 	if (info.security.enc_key_size < BT_ENC_KEY_SIZE_MAX) {
198 		return BT_ATT_ERR_ENCRYPTION_KEY_SIZE;
199 	}
200 
201 	return BT_ATT_ERR_SUCCESS;
202 }
203 
bt_audio_read_chrc(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)204 ssize_t bt_audio_read_chrc(struct bt_conn *conn, const struct bt_gatt_attr *attr,
205 			   void *buf, uint16_t len, uint16_t offset)
206 {
207 	const struct bt_audio_attr_user_data *user_data = attr->user_data;
208 
209 	if (user_data->read == NULL) {
210 		return BT_GATT_ERR(BT_ATT_ERR_READ_NOT_PERMITTED);
211 	}
212 
213 	if (conn != NULL) {
214 		uint8_t err;
215 
216 		err = bt_audio_security_check(conn);
217 		if (err != 0) {
218 			return BT_GATT_ERR(err);
219 		}
220 	}
221 
222 	return user_data->read(conn, attr, buf, len, offset);
223 }
224 
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)225 ssize_t bt_audio_write_chrc(struct bt_conn *conn, const struct bt_gatt_attr *attr,
226 			    const void *buf, uint16_t len, uint16_t offset, uint8_t flags)
227 {
228 	const struct bt_audio_attr_user_data *user_data = attr->user_data;
229 
230 	if (user_data->write == NULL) {
231 		return BT_GATT_ERR(BT_ATT_ERR_WRITE_NOT_PERMITTED);
232 	}
233 
234 	if (conn != NULL) {
235 		uint8_t err;
236 
237 		err = bt_audio_security_check(conn);
238 		if (err != 0) {
239 			return BT_GATT_ERR(err);
240 		}
241 	}
242 
243 	return user_data->write(conn, attr, buf, len, offset, flags);
244 }
245 
bt_audio_ccc_cfg_write(struct bt_conn * conn,const struct bt_gatt_attr * attr,uint16_t value)246 ssize_t bt_audio_ccc_cfg_write(struct bt_conn *conn, const struct bt_gatt_attr *attr,
247 			       uint16_t value)
248 {
249 	if (conn != NULL) {
250 		uint8_t err;
251 
252 		err = bt_audio_security_check(conn);
253 		if (err != 0) {
254 			return BT_GATT_ERR(err);
255 		}
256 	}
257 
258 	return sizeof(value);
259 }
260 
bt_audio_get_max_ntf_size(struct bt_conn * conn)261 uint16_t bt_audio_get_max_ntf_size(struct bt_conn *conn)
262 {
263 	const uint8_t att_ntf_header_size = 3; /* opcode (1) + handle (2) */
264 	const uint16_t mtu = conn == NULL ? 0 : bt_gatt_get_mtu(conn);
265 
266 	if (mtu > att_ntf_header_size) {
267 		return mtu - att_ntf_header_size;
268 	}
269 
270 	return 0U;
271 }
272 #endif /* CONFIG_BT_CONN */
273