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