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 = <v[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
bt_audio_get_chan_count(enum bt_audio_location chan_allocation)80 uint8_t bt_audio_get_chan_count(enum bt_audio_location chan_allocation)
81 {
82 if (chan_allocation == BT_AUDIO_LOCATION_MONO_AUDIO) {
83 return 1;
84 }
85
86 #ifdef POPCOUNT
87 return POPCOUNT(chan_allocation);
88 #else
89 uint8_t cnt = 0U;
90
91 while (chan_allocation != 0U) {
92 cnt += chan_allocation & 1U;
93 chan_allocation >>= 1U;
94 }
95
96 return cnt;
97 #endif
98 }
99
100 #if defined(CONFIG_BT_CONN)
101
bt_audio_security_check(const struct bt_conn * conn)102 static uint8_t bt_audio_security_check(const struct bt_conn *conn)
103 {
104 struct bt_conn_info info;
105 int err;
106
107 err = bt_conn_get_info(conn, &info);
108 if (err < 0) {
109 return BT_ATT_ERR_UNLIKELY;
110 }
111
112 /* Require an encryption key with at least 128 bits of entropy, derived from SC or OOB
113 * method.
114 */
115 if ((info.security.flags & (BT_SECURITY_FLAG_OOB | BT_SECURITY_FLAG_SC)) == 0) {
116 /* If the client has insufficient security to read/write the requested attribute
117 * then an ATT_ERROR_RSP PDU shall be sent with the Error Code parameter set to
118 * Insufficient Authentication (0x05).
119 */
120 return BT_ATT_ERR_AUTHENTICATION;
121 }
122
123 if (info.security.enc_key_size < BT_ENC_KEY_SIZE_MAX) {
124 return BT_ATT_ERR_ENCRYPTION_KEY_SIZE;
125 }
126
127 return BT_ATT_ERR_SUCCESS;
128 }
129
bt_audio_read_chrc(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)130 ssize_t bt_audio_read_chrc(struct bt_conn *conn, const struct bt_gatt_attr *attr,
131 void *buf, uint16_t len, uint16_t offset)
132 {
133 const struct bt_audio_attr_user_data *user_data = attr->user_data;
134
135 if (user_data->read == NULL) {
136 return BT_GATT_ERR(BT_ATT_ERR_READ_NOT_PERMITTED);
137 }
138
139 if (conn != NULL) {
140 uint8_t err;
141
142 err = bt_audio_security_check(conn);
143 if (err != 0) {
144 return BT_GATT_ERR(err);
145 }
146 }
147
148 return user_data->read(conn, attr, buf, len, offset);
149 }
150
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)151 ssize_t bt_audio_write_chrc(struct bt_conn *conn, const struct bt_gatt_attr *attr,
152 const void *buf, uint16_t len, uint16_t offset, uint8_t flags)
153 {
154 const struct bt_audio_attr_user_data *user_data = attr->user_data;
155
156 if (user_data->write == NULL) {
157 return BT_GATT_ERR(BT_ATT_ERR_WRITE_NOT_PERMITTED);
158 }
159
160 if (conn != NULL) {
161 uint8_t err;
162
163 err = bt_audio_security_check(conn);
164 if (err != 0) {
165 return BT_GATT_ERR(err);
166 }
167 }
168
169 return user_data->write(conn, attr, buf, len, offset, flags);
170 }
171
bt_audio_ccc_cfg_write(struct bt_conn * conn,const struct bt_gatt_attr * attr,uint16_t value)172 ssize_t bt_audio_ccc_cfg_write(struct bt_conn *conn, const struct bt_gatt_attr *attr,
173 uint16_t value)
174 {
175 if (conn != NULL) {
176 uint8_t err;
177
178 err = bt_audio_security_check(conn);
179 if (err != 0) {
180 return BT_GATT_ERR(err);
181 }
182 }
183
184 return sizeof(value);
185 }
186 #endif /* CONFIG_BT_CONN */
187