1 /*
2 * Copyright (c) 2022 Codecoup
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <errno.h>
8 #include <stdbool.h>
9 #include <stddef.h>
10 #include <stdint.h>
11 #include <string.h>
12 #include <sys/types.h>
13
14 #include <zephyr/autoconf.h>
15 #include <zephyr/bluetooth/audio/audio.h>
16 #include <zephyr/bluetooth/audio/pacs.h>
17 #include <zephyr/bluetooth/audio/has.h>
18 #include <zephyr/bluetooth/addr.h>
19 #include <zephyr/bluetooth/att.h>
20 #include <zephyr/bluetooth/bluetooth.h>
21 #include <zephyr/bluetooth/conn.h>
22 #include <zephyr/bluetooth/gatt.h>
23 #include <zephyr/bluetooth/uuid.h>
24 #include <zephyr/kernel.h>
25 #include <zephyr/logging/log.h>
26 #include <zephyr/net_buf.h>
27 #include <zephyr/settings/settings.h>
28 #include <zephyr/sys/__assert.h>
29 #include <zephyr/sys/atomic.h>
30 #include <zephyr/sys/check.h>
31 #include <zephyr/sys/slist.h>
32 #include <zephyr/sys/util.h>
33 #include <zephyr/sys/util_macro.h>
34 #include <zephyr/sys_clock.h>
35 #include <zephyr/toolchain.h>
36
37 #include "../bluetooth/host/settings.h"
38
39 #include "audio_internal.h"
40 #include "common/bt_str.h"
41 #include "has_internal.h"
42
43 LOG_MODULE_REGISTER(bt_has, CONFIG_BT_HAS_LOG_LEVEL);
44
45 /* The service allows operations with paired devices only.
46 * The number of clients is set to maximum number of simultaneous connections to paired devices.
47 */
48 #define MAX_INSTS MIN(CONFIG_BT_MAX_CONN, CONFIG_BT_MAX_PAIRED)
49
50 #define BITS_CHANGED(_new_value, _old_value) ((_new_value) ^ (_old_value))
51 #define FEATURE_DEVICE_TYPE_UNCHANGED(_new_value) \
52 !BITS_CHANGED(_new_value, (has.features & BT_HAS_FEAT_HEARING_AID_TYPE_MASK))
53 #define FEATURE_SYNC_SUPPORT_UNCHANGED(_new_value) \
54 !BITS_CHANGED(_new_value, ((has.features & BT_HAS_FEAT_PRESET_SYNC_SUPP) != 0 ? 1 : 0))
55 #define FEATURE_IND_PRESETS_UNCHANGED(_new_value) \
56 !BITS_CHANGED(_new_value, ((has.features & BT_HAS_FEAT_INDEPENDENT_PRESETS) != 0 ? 1 : 0))
57 #define BONDED_CLIENT_INIT_FLAGS \
58 (BIT(FLAG_ACTIVE_INDEX_CHANGED) | BIT(FLAG_NOTIFY_PRESET_LIST) | BIT(FLAG_FEATURES_CHANGED))
59
60 static struct bt_has has;
61
62 #if defined(CONFIG_BT_HAS_ACTIVE_PRESET_INDEX)
active_preset_index_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)63 static void active_preset_index_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
64 {
65 LOG_DBG("attr %p value 0x%04x", attr, value);
66 }
67 #endif /* CONFIG_BT_HAS_ACTIVE_PRESET_INDEX */
68
69 #if defined(CONFIG_BT_HAS_PRESET_SUPPORT)
70 struct has_client;
71
72 static int read_preset_response(struct has_client *client);
73 static int preset_list_changed(struct has_client *client);
74 static int preset_list_changed_generic_update_tail(struct has_client *client);
75 static int preset_list_changed_record_deleted_last(struct has_client *client);
76 static ssize_t write_control_point(struct bt_conn *conn, const struct bt_gatt_attr *attr,
77 const void *data, uint16_t len, uint16_t offset, uint8_t flags);
78
preset_cp_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)79 static void preset_cp_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
80 {
81 LOG_DBG("attr %p value 0x%04x", attr, value);
82 }
83
read_active_preset_index(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)84 static ssize_t read_active_preset_index(struct bt_conn *conn, const struct bt_gatt_attr *attr,
85 void *buf, uint16_t len, uint16_t offset)
86 {
87 uint8_t active_index;
88
89 LOG_DBG("conn %p attr %p offset %d", (void *)conn, attr, offset);
90
91 if (offset > sizeof(active_index)) {
92 return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
93 }
94
95 active_index = bt_has_preset_active_get();
96
97 return bt_gatt_attr_read(conn, attr, buf, len, offset, &active_index, sizeof(active_index));
98 }
99 #endif /* CONFIG_BT_HAS_PRESET_SUPPORT */
100
101 #if defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE)
features_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)102 static void features_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
103 {
104 LOG_DBG("attr %p value 0x%04x", attr, value);
105 }
106 #endif /* CONFIG_BT_HAS_FEATURES_NOTIFIABLE */
107
read_features(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)108 static ssize_t read_features(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
109 uint16_t len, uint16_t offset)
110 {
111 LOG_DBG("conn %p attr %p offset %d", (void *)conn, attr, offset);
112
113 if (offset > sizeof(has.features)) {
114 return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
115 }
116
117 return bt_gatt_attr_read(conn, attr, buf, len, offset, &has.features,
118 sizeof(has.features));
119 }
120
121 #if defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE)
122 #define BT_HAS_CHR_FEATURES \
123 BT_AUDIO_CHRC(BT_UUID_HAS_HEARING_AID_FEATURES, \
124 BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
125 BT_GATT_PERM_READ_ENCRYPT, \
126 read_features, NULL, NULL), \
127 BT_AUDIO_CCC(features_cfg_changed),
128 #else
129 #define BT_HAS_CHR_FEATURES \
130 BT_AUDIO_CHRC(BT_UUID_HAS_HEARING_AID_FEATURES, \
131 BT_GATT_CHRC_READ, \
132 BT_GATT_PERM_READ_ENCRYPT, \
133 read_features, NULL, NULL),
134 #endif /* CONFIG_BT_HAS_FEATURES_NOTIFIABLE */
135
136 #if defined(CONFIG_BT_HAS_PRESET_SUPPORT)
137 #if defined(CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE)
138 #define BT_HAS_CHR_PRESET_CONTROL_POINT \
139 BT_AUDIO_CHRC(BT_UUID_HAS_PRESET_CONTROL_POINT, \
140 BT_GATT_CHRC_WRITE | BT_GATT_CHRC_INDICATE | BT_GATT_CHRC_NOTIFY, \
141 BT_GATT_PERM_WRITE_ENCRYPT, \
142 NULL, write_control_point, NULL), \
143 BT_AUDIO_CCC(preset_cp_cfg_changed),
144 #else
145 #define BT_HAS_CHR_PRESET_CONTROL_POINT \
146 BT_AUDIO_CHRC(BT_UUID_HAS_PRESET_CONTROL_POINT, \
147 BT_GATT_CHRC_WRITE | BT_GATT_CHRC_INDICATE, \
148 BT_GATT_PERM_WRITE_ENCRYPT, \
149 NULL, write_control_point, NULL), \
150 BT_AUDIO_CCC(preset_cp_cfg_changed),
151 #endif /* CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE */
152 #else
153 #define BT_HAS_CHR_PRESET_CONTROL_POINT
154 #endif /* CONFIG_BT_HAS_PRESET_SUPPORT */
155
156 #if defined(CONFIG_BT_HAS_ACTIVE_PRESET_INDEX)
157 #define BT_HAS_CHR_ACTIVE_PRESET_INDEX \
158 BT_AUDIO_CHRC(BT_UUID_HAS_ACTIVE_PRESET_INDEX, \
159 BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \
160 BT_GATT_PERM_READ_ENCRYPT, \
161 read_active_preset_index, NULL, NULL), \
162 BT_AUDIO_CCC(active_preset_index_cfg_changed)
163 #else
164 #define BT_HAS_CHR_ACTIVE_PRESET_INDEX
165 #endif /* CONFIG_BT_HAS_ACTIVE_PRESET_INDEX */
166
167 /* Hearing Access Service GATT Attributes */
168 static struct bt_gatt_attr has_attrs[] = {
169 BT_GATT_PRIMARY_SERVICE(BT_UUID_HAS),
170 BT_HAS_CHR_FEATURES
171 BT_HAS_CHR_PRESET_CONTROL_POINT
172 BT_HAS_CHR_ACTIVE_PRESET_INDEX
173 };
174
175 static struct bt_gatt_service has_svc;
176 static struct bt_gatt_attr *hearing_aid_features_attr;
177 static struct bt_gatt_attr *preset_control_point_attr;
178 static struct bt_gatt_attr *active_preset_index_attr;
179
180 #if defined(CONFIG_BT_HAS_PRESET_SUPPORT) || defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE)
181 static void notify_work_handler(struct k_work *work);
182
183 enum flag_internal {
184 FLAG_ACTIVE_INDEX_CHANGED,
185 FLAG_PENDING_READ_PRESET_RESPONSE,
186 FLAG_NOTIFY_PRESET_LIST,
187 FLAG_NOTIFY_PRESET_LIST_GENERIC_UPDATE_TAIL,
188 FLAG_NOTIFY_PRESET_LIST_RECORD_DELETED_LAST,
189 FLAG_FEATURES_CHANGED,
190 FLAG_NUM,
191 };
192
193 /* Stored client context */
194 static struct client_context {
195 bt_addr_le_t addr;
196
197 /* Pending notification flags */
198 ATOMIC_DEFINE(flags, FLAG_NUM);
199
200 /* Last notified preset index */
201 uint8_t last_preset_index_known;
202 } contexts[CONFIG_BT_MAX_PAIRED];
203
204 /* Connected client instance */
205 static struct has_client {
206 struct bt_conn *conn;
207 #if defined(CONFIG_BT_HAS_PRESET_SUPPORT)
208 union {
209 struct bt_gatt_indicate_params ind;
210 #if defined(CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE)
211 struct bt_gatt_notify_params ntf;
212 #endif /* CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE */
213 } params;
214
215 uint8_t preset_changed_index_next;
216 struct bt_has_cp_read_presets_req read_presets_req;
217 #endif /* CONFIG_BT_HAS_PRESET_SUPPORT */
218 struct k_work_delayable notify_work;
219 struct client_context *context;
220 } has_client_list[MAX_INSTS];
221
222
context_find(const bt_addr_le_t * addr)223 static struct client_context *context_find(const bt_addr_le_t *addr)
224 {
225 __ASSERT_NO_MSG(addr != NULL);
226
227 for (size_t i = 0; i < ARRAY_SIZE(contexts); i++) {
228 if (bt_addr_le_eq(&contexts[i].addr, addr)) {
229 return &contexts[i];
230 }
231 }
232
233 return NULL;
234 }
235
context_alloc(const bt_addr_le_t * addr)236 static struct client_context *context_alloc(const bt_addr_le_t *addr)
237 {
238 struct client_context *context;
239
240 __ASSERT_NO_MSG(addr != NULL);
241
242 /* Free contexts has BT_ADDR_LE_ANY as the address */
243 context = context_find(BT_ADDR_LE_ANY);
244 if (context == NULL) {
245 return NULL;
246 }
247
248 memset(context, 0, sizeof(*context));
249
250 bt_addr_le_copy(&context->addr, addr);
251
252 return context;
253 }
254
context_free(struct client_context * context)255 static void context_free(struct client_context *context)
256 {
257 bt_addr_le_copy(&context->addr, BT_ADDR_LE_ANY);
258 }
259
client_free(struct has_client * client)260 static void client_free(struct has_client *client)
261 {
262 struct bt_conn_info info = { 0 };
263 int err;
264
265 #if defined(CONFIG_BT_HAS_PRESET_SUPPORT) || defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE)
266 (void)k_work_cancel_delayable(&client->notify_work);
267 #endif /* CONFIG_BT_HAS_PRESET_SUPPORT || CONFIG_BT_HAS_FEATURES_NOTIFIABLE */
268
269 err = bt_conn_get_info(client->conn, &info);
270 __ASSERT_NO_MSG(err == 0);
271
272 if (client->context != NULL && !bt_le_bond_exists(info.id, info.le.dst)) {
273 /* Free stored context of non-bonded client */
274 context_free(client->context);
275 client->context = NULL;
276 }
277
278 bt_conn_unref(client->conn);
279 client->conn = NULL;
280 }
281
client_alloc(struct bt_conn * conn)282 static struct has_client *client_alloc(struct bt_conn *conn)
283 {
284 struct bt_conn_info info = { 0 };
285 struct has_client *client = NULL;
286 int err;
287
288 for (size_t i = 0; i < ARRAY_SIZE(has_client_list); i++) {
289 if (conn == has_client_list[i].conn) {
290 return &has_client_list[i];
291 }
292
293 /* first free slot */
294 if (!client && has_client_list[i].conn == NULL) {
295 client = &has_client_list[i];
296 }
297 }
298
299 __ASSERT(client, "failed to get client for conn %p", (void *)conn);
300
301 memset(client, 0, sizeof(*client));
302
303 client->conn = bt_conn_ref(conn);
304
305 #if defined(CONFIG_BT_HAS_PRESET_SUPPORT) || defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE)
306 k_work_init_delayable(&client->notify_work, notify_work_handler);
307 #endif /* CONFIG_BT_HAS_PRESET_SUPPORT || CONFIG_BT_HAS_FEATURES_NOTIFIABLE */
308
309 err = bt_conn_get_info(conn, &info);
310 if (err != 0) {
311 LOG_DBG("Could not get conn info: %d", err);
312
313 return NULL;
314 }
315
316 client->context = context_find(info.le.dst);
317 if (client->context == NULL) {
318 client->context = context_alloc(info.le.dst);
319 if (client->context == NULL) {
320 LOG_ERR("Failed to allocate client_context for %s",
321 bt_addr_le_str(info.le.dst));
322
323 client_free(client);
324
325 return NULL;
326 }
327
328 LOG_DBG("New client_context for %s", bt_addr_le_str(info.le.dst));
329 }
330
331 return client;
332 }
333
client_find_by_conn(struct bt_conn * conn)334 static struct has_client *client_find_by_conn(struct bt_conn *conn)
335 {
336 for (size_t i = 0; i < ARRAY_SIZE(has_client_list); i++) {
337 if (conn == has_client_list[i].conn) {
338 return &has_client_list[i];
339 }
340 }
341
342 return NULL;
343 }
344
notify_work_reschedule(struct has_client * client,k_timeout_t delay)345 static void notify_work_reschedule(struct has_client *client, k_timeout_t delay)
346 {
347 int err;
348
349 __ASSERT(client->conn, "Not connected");
350
351 if (k_work_delayable_remaining_get(&client->notify_work) > 0) {
352 return;
353 }
354
355 err = k_work_reschedule(&client->notify_work, delay);
356 if (err < 0) {
357 LOG_ERR("Failed to reschedule notification work err %d", err);
358 }
359 }
360
security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)361 static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err)
362 {
363 struct has_client *client;
364 struct bt_conn_info info;
365 int ret;
366
367 LOG_DBG("conn %p level %d err %d", (void *)conn, level, err);
368
369 if (err != BT_SECURITY_ERR_SUCCESS) {
370 return;
371 }
372
373 client = client_alloc(conn);
374 if (unlikely(!client)) {
375 LOG_ERR("Failed to allocate client");
376 return;
377 }
378
379 ret = bt_conn_get_info(client->conn, &info);
380 if (ret < 0) {
381 LOG_ERR("bt_conn_get_info err %d", ret);
382 return;
383 }
384
385 if (!bt_le_bond_exists(info.id, info.le.dst)) {
386 return;
387 }
388
389 if (atomic_get(client->context->flags) != 0) {
390 notify_work_reschedule(client, K_NO_WAIT);
391 }
392 }
393
disconnected(struct bt_conn * conn,uint8_t reason)394 static void disconnected(struct bt_conn *conn, uint8_t reason)
395 {
396 struct has_client *client;
397
398 LOG_DBG("conn %p reason %d", (void *)conn, reason);
399
400 client = client_find_by_conn(conn);
401 if (client) {
402 client_free(client);
403 }
404 }
405
identity_resolved(struct bt_conn * conn,const bt_addr_le_t * rpa,const bt_addr_le_t * identity)406 static void identity_resolved(struct bt_conn *conn, const bt_addr_le_t *rpa,
407 const bt_addr_le_t *identity)
408 {
409 struct has_client *client;
410
411 LOG_DBG("conn %p %s -> %s", (void *)conn, bt_addr_le_str(rpa), bt_addr_le_str(identity));
412
413 client = client_find_by_conn(conn);
414 if (client == NULL) {
415 return;
416 }
417
418 bt_addr_le_copy(&client->context->addr, identity);
419 }
420
421 BT_CONN_CB_DEFINE(conn_cb) = {
422 .disconnected = disconnected,
423 .security_changed = security_changed,
424 .identity_resolved = identity_resolved,
425 };
426
notify_work_handler(struct k_work * work)427 static void notify_work_handler(struct k_work *work)
428 {
429 struct k_work_delayable *dwork = k_work_delayable_from_work(work);
430 struct has_client *client = CONTAINER_OF(dwork, struct has_client, notify_work);
431 int err;
432
433 if (IS_ENABLED(CONFIG_BT_HAS_FEATURES_NOTIFIABLE) &&
434 atomic_test_and_clear_bit(client->context->flags, FLAG_FEATURES_CHANGED) &&
435 bt_gatt_is_subscribed(client->conn, hearing_aid_features_attr, BT_GATT_CCC_NOTIFY)) {
436 err = bt_gatt_notify(client->conn, hearing_aid_features_attr, &has.features,
437 sizeof(has.features));
438 if (err == -ENOMEM) {
439 atomic_set_bit(client->context->flags, FLAG_FEATURES_CHANGED);
440 notify_work_reschedule(client, K_USEC(BT_AUDIO_NOTIFY_RETRY_DELAY_US));
441 } else if (err < 0) {
442 LOG_ERR("Notify features err %d", err);
443 }
444 }
445
446 #if defined(CONFIG_BT_HAS_PRESET_SUPPORT)
447 if (atomic_test_and_clear_bit(client->context->flags, FLAG_PENDING_READ_PRESET_RESPONSE)) {
448 err = read_preset_response(client);
449 if (err == -ENOMEM) {
450 atomic_set_bit(client->context->flags, FLAG_PENDING_READ_PRESET_RESPONSE);
451 notify_work_reschedule(client, K_USEC(BT_AUDIO_NOTIFY_RETRY_DELAY_US));
452 } else if (err < 0) {
453 LOG_ERR("Notify read preset response err %d", err);
454 }
455 } else if (atomic_test_and_clear_bit(client->context->flags, FLAG_NOTIFY_PRESET_LIST)) {
456 err = preset_list_changed(client);
457 if (err == -ENOMEM) {
458 atomic_set_bit(client->context->flags, FLAG_NOTIFY_PRESET_LIST);
459 notify_work_reschedule(client, K_USEC(BT_AUDIO_NOTIFY_RETRY_DELAY_US));
460 } else if (err < 0) {
461 LOG_ERR("Notify preset list changed err %d", err);
462 }
463 } else if (atomic_test_and_clear_bit(client->context->flags,
464 FLAG_NOTIFY_PRESET_LIST_GENERIC_UPDATE_TAIL)) {
465 err = preset_list_changed_generic_update_tail(client);
466 if (err == -ENOMEM) {
467 atomic_set_bit(client->context->flags,
468 FLAG_NOTIFY_PRESET_LIST_GENERIC_UPDATE_TAIL);
469 notify_work_reschedule(client, K_USEC(BT_AUDIO_NOTIFY_RETRY_DELAY_US));
470 } else if (err < 0) {
471 LOG_ERR("Notify preset list changed generic update tail err %d", err);
472 }
473 } else if (atomic_test_and_clear_bit(client->context->flags,
474 FLAG_NOTIFY_PRESET_LIST_RECORD_DELETED_LAST)) {
475 err = preset_list_changed_record_deleted_last(client);
476 if (err == -ENOMEM) {
477 atomic_set_bit(client->context->flags,
478 FLAG_NOTIFY_PRESET_LIST_RECORD_DELETED_LAST);
479 notify_work_reschedule(client, K_USEC(BT_AUDIO_NOTIFY_RETRY_DELAY_US));
480 } else if (err < 0) {
481 LOG_ERR("Notify preset list changed recoed deleted last err %d", err);
482 }
483 }
484
485 #endif /* CONFIG_BT_HAS_PRESET_SUPPORT */
486
487 if (IS_ENABLED(CONFIG_BT_HAS_PRESET_SUPPORT) &&
488 atomic_test_and_clear_bit(client->context->flags, FLAG_ACTIVE_INDEX_CHANGED) &&
489 bt_gatt_is_subscribed(client->conn, active_preset_index_attr, BT_GATT_CCC_NOTIFY)) {
490 uint8_t active_index;
491
492 active_index = bt_has_preset_active_get();
493
494 err = bt_gatt_notify(client->conn, active_preset_index_attr,
495 &active_index, sizeof(active_index));
496 if (err == -ENOMEM) {
497 atomic_set_bit(client->context->flags, FLAG_ACTIVE_INDEX_CHANGED);
498 notify_work_reschedule(client, K_USEC(BT_AUDIO_NOTIFY_RETRY_DELAY_US));
499 } else if (err < 0) {
500 LOG_ERR("Notify active index err %d", err);
501 }
502 }
503 }
504
notify(struct has_client * client,enum flag_internal flag)505 static void notify(struct has_client *client, enum flag_internal flag)
506 {
507 if (client != NULL) {
508 atomic_set_bit(client->context->flags, flag);
509 notify_work_reschedule(client, K_NO_WAIT);
510 return;
511 }
512
513 /* Mark notification to be sent to all clients */
514 for (size_t i = 0U; i < ARRAY_SIZE(contexts); i++) {
515 atomic_set_bit(contexts[i].flags, flag);
516 }
517
518 for (size_t i = 0U; i < ARRAY_SIZE(has_client_list); i++) {
519 client = &has_client_list[i];
520
521 if (client->conn == NULL) {
522 continue;
523 }
524
525 notify_work_reschedule(client, K_NO_WAIT);
526 }
527 }
528
bond_deleted_cb(uint8_t id,const bt_addr_le_t * addr)529 static void bond_deleted_cb(uint8_t id, const bt_addr_le_t *addr)
530 {
531 struct client_context *context;
532
533 context = context_find(addr);
534 if (context != NULL) {
535 context_free(context);
536 }
537
538 if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
539 bt_settings_delete("has", 0, addr);
540 }
541 }
542
543 static struct bt_conn_auth_info_cb auth_info_cb = {
544 .bond_deleted = bond_deleted_cb,
545 };
546 #endif /* CONFIG_BT_HAS_PRESET_SUPPORT || CONFIG_BT_HAS_FEATURES_NOTIFIABLE */
547
548 #if defined(CONFIG_BT_HAS_PRESET_SUPPORT)
549 static struct has_preset *active_preset;
550
551 /* HAS internal preset representation */
552 static struct has_preset {
553 uint8_t index;
554 enum bt_has_properties properties;
555 #if defined(CONFIG_BT_HAS_PRESET_NAME_DYNAMIC)
556 char name[BT_HAS_PRESET_NAME_MAX + 1]; /* +1 byte for NULL-terminator */
557 #else
558 const char *name;
559 #endif /* CONFIG_BT_HAS_PRESET_NAME_DYNAMIC */
560 const struct bt_has_preset_ops *ops;
561 sys_snode_t node;
562 } preset_pool[CONFIG_BT_HAS_PRESET_COUNT];
563
564 static sys_slist_t preset_list = SYS_SLIST_STATIC_INIT(&preset_list);
565 static sys_slist_t preset_free_list = SYS_SLIST_STATIC_INIT(&preset_free_list);
566
567 typedef uint8_t (*preset_func_t)(const struct has_preset *preset, void *user_data);
568
preset_foreach(uint8_t start_index,uint8_t end_index,preset_func_t func,void * user_data)569 static void preset_foreach(uint8_t start_index, uint8_t end_index, preset_func_t func,
570 void *user_data)
571 {
572 struct has_preset *preset, *tmp;
573
574 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&preset_list, preset, tmp, node) {
575 if (preset->index < start_index) {
576 continue;
577 }
578
579 if (preset->index > end_index) {
580 return;
581 }
582
583 if (func(preset, user_data) == BT_HAS_PRESET_ITER_STOP) {
584 return;
585 }
586 }
587 }
588
preset_found(const struct has_preset * preset,void * user_data)589 static uint8_t preset_found(const struct has_preset *preset, void *user_data)
590 {
591 const struct has_preset **found = user_data;
592
593 *found = preset;
594
595 return BT_HAS_PRESET_ITER_STOP;
596 }
597
preset_insert(struct has_preset * preset)598 static void preset_insert(struct has_preset *preset)
599 {
600 struct has_preset *tmp, *prev = NULL;
601
602 SYS_SLIST_FOR_EACH_CONTAINER(&preset_list, tmp, node) {
603 if (tmp->index > preset->index) {
604 if (prev) {
605 sys_slist_insert(&preset_list, &prev->node, &preset->node);
606 } else {
607 sys_slist_prepend(&preset_list, &preset->node);
608 }
609 return;
610 }
611
612 prev = tmp;
613 }
614
615 sys_slist_append(&preset_list, &preset->node);
616 }
617
preset_alloc(uint8_t index,enum bt_has_properties properties,const char * name,const struct bt_has_preset_ops * ops)618 static struct has_preset *preset_alloc(uint8_t index, enum bt_has_properties properties,
619 const char *name, const struct bt_has_preset_ops *ops)
620 {
621 struct has_preset *preset;
622 sys_snode_t *node;
623
624 node = sys_slist_get(&preset_free_list);
625 if (node == NULL) {
626 return NULL;
627 }
628
629 preset = CONTAINER_OF(node, struct has_preset, node);
630 preset->index = index;
631 preset->properties = properties;
632 #if defined(CONFIG_BT_HAS_PRESET_NAME_DYNAMIC)
633 utf8_lcpy(preset->name, name, ARRAY_SIZE(preset->name));
634 #else
635 preset->name = name;
636 #endif /* CONFIG_BT_HAS_PRESET_NAME_DYNAMIC */
637 preset->ops = ops;
638
639 preset_insert(preset);
640
641 return preset;
642 }
643
preset_free(struct has_preset * preset)644 static void preset_free(struct has_preset *preset)
645 {
646 bool removed;
647
648 removed = sys_slist_find_and_remove(&preset_list, &preset->node);
649 if (removed) {
650 sys_slist_append(&preset_free_list, &preset->node);
651 }
652 }
653
preset_get_head(void)654 static struct has_preset *preset_get_head(void)
655 {
656 struct has_preset *next;
657
658 return SYS_SLIST_PEEK_HEAD_CONTAINER(&preset_list, next, node);
659 }
660
preset_get_tail(void)661 static struct has_preset *preset_get_tail(void)
662 {
663 struct has_preset *prev;
664
665 return SYS_SLIST_PEEK_TAIL_CONTAINER(&preset_list, prev, node);
666 }
667
preset_get_prev(const struct has_preset * preset)668 static struct has_preset *preset_get_prev(const struct has_preset *preset)
669 {
670 struct has_preset *prev;
671
672 SYS_SLIST_FOR_EACH_CONTAINER(&preset_list, prev, node) {
673 if (SYS_SLIST_PEEK_NEXT_CONTAINER(prev, node) == preset) {
674 return prev;
675 }
676 }
677
678 prev = preset_get_tail();
679 if (prev == preset) {
680 return NULL;
681 }
682
683 return prev;
684 }
685
preset_lookup_index(uint8_t index)686 static struct has_preset *preset_lookup_index(uint8_t index)
687 {
688 struct has_preset *preset;
689
690 SYS_SLIST_FOR_EACH_CONTAINER(&preset_list, preset, node) {
691 if (preset->index == index) {
692 return preset;
693 }
694 }
695
696 return NULL;
697 }
698
preset_get_next(struct has_preset * preset)699 static struct has_preset *preset_get_next(struct has_preset *preset)
700 {
701 struct has_preset *next;
702
703 next = SYS_SLIST_PEEK_NEXT_CONTAINER(preset, node);
704 if (next == NULL) {
705 next = preset_get_head();
706 if (next == preset) {
707 return NULL;
708 }
709 }
710
711 return next;
712 }
713
preset_get_prev_index(const struct has_preset * preset)714 static uint8_t preset_get_prev_index(const struct has_preset *preset)
715 {
716 const struct has_preset *prev;
717
718 prev = preset_get_prev(preset);
719 if (prev == NULL || prev->index >= preset->index) {
720 return BT_HAS_PRESET_INDEX_NONE;
721 }
722
723 return prev->index;
724 }
725
control_point_ntf_complete(struct bt_conn * conn,void * user_data)726 static void control_point_ntf_complete(struct bt_conn *conn, void *user_data)
727 {
728 struct has_client *client = client_find_by_conn(conn);
729
730 LOG_DBG("conn %p", (void *)conn);
731
732 /* Resubmit if needed */
733 if (client != NULL && atomic_get(client->context->flags) != 0) {
734 notify_work_reschedule(client, K_NO_WAIT);
735 }
736 }
737
control_point_ind_complete(struct bt_conn * conn,struct bt_gatt_indicate_params * params,uint8_t err)738 static void control_point_ind_complete(struct bt_conn *conn,
739 struct bt_gatt_indicate_params *params,
740 uint8_t err)
741 {
742 if (err) {
743 /* TODO: Handle error somehow */
744 LOG_ERR("conn %p err 0x%02x", (void *)conn, err);
745 }
746
747 control_point_ntf_complete(conn, NULL);
748 }
749
control_point_send(struct has_client * client,struct net_buf_simple * buf)750 static int control_point_send(struct has_client *client, struct net_buf_simple *buf)
751 {
752 const uint16_t max_ntf_size = bt_audio_get_max_ntf_size(client->conn);
753
754 if (max_ntf_size < buf->len) {
755 LOG_WRN("Sending truncated control point PDU %u < %u", max_ntf_size, buf->len);
756 buf->len = max_ntf_size;
757 }
758
759 #if defined(CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE)
760 if (bt_eatt_count(client->conn) > 0 &&
761 bt_gatt_is_subscribed(client->conn, preset_control_point_attr, BT_GATT_CCC_NOTIFY)) {
762 memset(&client->params.ntf, 0, sizeof(client->params.ntf));
763 client->params.ntf.attr = preset_control_point_attr;
764 client->params.ntf.func = control_point_ntf_complete;
765 client->params.ntf.data = buf->data;
766 client->params.ntf.len = buf->len;
767
768 return bt_gatt_notify_cb(client->conn, &client->params.ntf);
769 }
770 #endif /* CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE */
771
772 if (bt_gatt_is_subscribed(client->conn, preset_control_point_attr, BT_GATT_CCC_INDICATE)) {
773 memset(&client->params.ind, 0, sizeof(client->params.ind));
774 client->params.ind.attr = preset_control_point_attr;
775 client->params.ind.func = control_point_ind_complete;
776 client->params.ind.destroy = NULL;
777 client->params.ind.data = buf->data;
778 /* indications have same size as notifications */
779 client->params.ind.len = buf->len;
780
781 return bt_gatt_indicate(client->conn, &client->params.ind);
782 }
783
784 return -ECANCELED;
785 }
786
control_point_send_all(struct net_buf_simple * buf)787 static int control_point_send_all(struct net_buf_simple *buf)
788 {
789 int result = 0;
790
791 for (size_t i = 0U; i < ARRAY_SIZE(contexts); i++) {
792 struct client_context *context = &contexts[i];
793 struct has_client *client = NULL;
794 int err;
795
796 for (size_t j = 0U; j < ARRAY_SIZE(has_client_list); j++) {
797 if (has_client_list[j].context == context) {
798 client = &has_client_list[j];
799 break;
800 }
801 }
802
803 if (client == NULL || client->conn == NULL) {
804 /* Mark preset changed operation as pending */
805 atomic_set_bit(context->flags, FLAG_NOTIFY_PRESET_LIST);
806 continue;
807 }
808
809 if (!bt_gatt_is_subscribed(client->conn, preset_control_point_attr,
810 BT_GATT_CCC_NOTIFY | BT_GATT_CCC_INDICATE)) {
811 continue;
812 }
813
814 err = control_point_send(client, buf);
815 if (err) {
816 result = err;
817 /* continue anyway */
818 }
819 }
820
821 return result;
822 }
823
bt_has_cp_read_preset_rsp(struct has_client * client,const struct has_preset * preset,bool is_last)824 static int bt_has_cp_read_preset_rsp(struct has_client *client, const struct has_preset *preset,
825 bool is_last)
826 {
827 struct bt_has_cp_hdr *hdr;
828 struct bt_has_cp_read_preset_rsp *rsp;
829
830 NET_BUF_SIMPLE_DEFINE(buf, sizeof(*hdr) + sizeof(*rsp) + BT_HAS_PRESET_NAME_MAX);
831
832 LOG_DBG("conn %p index 0x%02x prop 0x%02x %s is_last 0x%02x", (void *)client->conn,
833 preset->index, preset->properties, preset->name, is_last);
834
835 hdr = net_buf_simple_add(&buf, sizeof(*hdr));
836 hdr->opcode = BT_HAS_OP_READ_PRESET_RSP;
837 rsp = net_buf_simple_add(&buf, sizeof(*rsp));
838 rsp->is_last = is_last ? 0x01 : 0x00;
839 rsp->index = preset->index;
840 rsp->properties = preset->properties;
841 net_buf_simple_add_mem(&buf, preset->name, strlen(preset->name));
842
843 return control_point_send(client, &buf);
844 }
845
preset_changed_prepare(struct net_buf_simple * buf,uint8_t change_id,uint8_t is_last)846 static void preset_changed_prepare(struct net_buf_simple *buf, uint8_t change_id, uint8_t is_last)
847 {
848 struct bt_has_cp_hdr *hdr;
849 struct bt_has_cp_preset_changed *preset_changed;
850
851 hdr = net_buf_simple_add(buf, sizeof(*hdr));
852 hdr->opcode = BT_HAS_OP_PRESET_CHANGED;
853 preset_changed = net_buf_simple_add(buf, sizeof(*preset_changed));
854 preset_changed->change_id = change_id;
855 preset_changed->is_last = is_last;
856 }
857
bt_has_cp_generic_update(struct has_client * client,uint8_t prev_index,uint8_t index,uint8_t properties,const char * name,uint8_t is_last)858 static int bt_has_cp_generic_update(struct has_client *client, uint8_t prev_index, uint8_t index,
859 uint8_t properties, const char *name, uint8_t is_last)
860 {
861 struct bt_has_cp_generic_update *generic_update;
862
863 NET_BUF_SIMPLE_DEFINE(buf, sizeof(struct bt_has_cp_hdr) +
864 sizeof(struct bt_has_cp_preset_changed) +
865 sizeof(struct bt_has_cp_generic_update) + BT_HAS_PRESET_NAME_MAX);
866
867 LOG_DBG("client %p prev_index 0x%02x index 0x%02x prop 0x%02x %s is_last %d",
868 client, prev_index, index, properties, name, is_last);
869
870 preset_changed_prepare(&buf, BT_HAS_CHANGE_ID_GENERIC_UPDATE, is_last);
871
872 generic_update = net_buf_simple_add(&buf, sizeof(*generic_update));
873 generic_update->prev_index = prev_index;
874 generic_update->index = index;
875 generic_update->properties = properties;
876 net_buf_simple_add_mem(&buf, name, strlen(name));
877
878 if (client) {
879 return control_point_send(client, &buf);
880 } else {
881 return control_point_send_all(&buf);
882 }
883 }
884
885 #if defined(CONFIG_BT_SETTINGS)
886 struct client_context_store {
887 /* Last notified preset index */
888 uint8_t last_preset_index_known;
889 } __packed;
890
settings_set_cb(const char * name,size_t len_rd,settings_read_cb read_cb,void * cb_arg)891 static int settings_set_cb(const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg)
892 {
893 struct client_context_store store;
894 struct client_context *context;
895 bt_addr_le_t addr;
896 ssize_t len;
897 int err;
898
899 if (!name) {
900 LOG_ERR("Insufficient number of arguments");
901 return -EINVAL;
902 }
903
904 err = bt_settings_decode_key(name, &addr);
905 if (err) {
906 LOG_ERR("Unable to decode address %s", name);
907 return -EINVAL;
908 }
909
910 context = context_find(&addr);
911 if (context == NULL) {
912 /* Find and initialize a free entry */
913 context = context_alloc(&addr);
914 if (context == NULL) {
915 LOG_ERR("Failed to allocate client_context for %s", bt_addr_le_str(&addr));
916 return -ENOMEM;
917 }
918 }
919
920 if (len_rd) {
921 len = read_cb(cb_arg, &store, sizeof(store));
922 if (len < 0) {
923 LOG_ERR("Failed to decode value (err %zd)", len);
924 return len;
925 }
926
927 context->last_preset_index_known = store.last_preset_index_known;
928 } else {
929 context->last_preset_index_known = 0x00;
930 }
931
932 /* Notify all the characteristics values after reboot */
933 atomic_set(context->flags, BONDED_CLIENT_INIT_FLAGS);
934
935 return 0;
936 }
937
938 static BT_SETTINGS_DEFINE(has, "has", settings_set_cb, NULL);
939
store_client_context(struct client_context * context)940 static void store_client_context(struct client_context *context)
941 {
942 struct client_context_store store = {
943 .last_preset_index_known = context->last_preset_index_known,
944 };
945 int err;
946
947 LOG_DBG("%s last_preset_index_known 0x%02x",
948 bt_addr_le_str(&context->addr), store.last_preset_index_known);
949
950 err = bt_settings_store("has", 0, &context->addr, &store, sizeof(store));
951 if (err != 0) {
952 LOG_ERR("Failed to store err %d", err);
953 }
954 }
955 #else
956 #define store_client_context(...)
957 #endif /* CONFIG_BT_SETTINGS */
958
update_last_preset_index_known(struct has_client * client,uint8_t index)959 static void update_last_preset_index_known(struct has_client *client, uint8_t index)
960 {
961 if (client != NULL && client->context != NULL &&
962 client->context->last_preset_index_known != index) {
963 client->context->last_preset_index_known = index;
964 store_client_context(client->context);
965 return;
966 }
967
968 for (size_t i = 0; i < ARRAY_SIZE(has_client_list); i++) {
969 client = &has_client_list[i];
970
971 /* For each connected client */
972 if (client->conn != NULL && client->context != NULL &&
973 client->context->last_preset_index_known != index) {
974 client->context->last_preset_index_known = index;
975 store_client_context(client->context);
976 }
977 }
978 }
979
read_preset_response(struct has_client * client)980 static int read_preset_response(struct has_client *client)
981 {
982 const struct has_preset *preset = NULL;
983 bool is_last = true;
984 int err;
985
986 __ASSERT_NO_MSG(client != NULL);
987
988 preset_foreach(client->read_presets_req.start_index, BT_HAS_PRESET_INDEX_LAST,
989 preset_found, &preset);
990
991 if (unlikely(preset == NULL)) {
992 return bt_has_cp_read_preset_rsp(client, NULL, BT_HAS_IS_LAST);
993 }
994
995 if (client->read_presets_req.num_presets > 1) {
996 const struct has_preset *next = NULL;
997
998 preset_foreach(preset->index + 1, BT_HAS_PRESET_INDEX_LAST, preset_found, &next);
999
1000 is_last = next == NULL;
1001 }
1002
1003 err = bt_has_cp_read_preset_rsp(client, preset, is_last);
1004 if (err != 0) {
1005 return err;
1006 }
1007
1008 if (preset->index > client->context->last_preset_index_known) {
1009 update_last_preset_index_known(client, preset->index);
1010 }
1011
1012 if (!is_last) {
1013 client->read_presets_req.start_index = preset->index + 1;
1014 client->read_presets_req.num_presets--;
1015
1016 atomic_set_bit(client->context->flags, FLAG_PENDING_READ_PRESET_RESPONSE);
1017 notify_work_reschedule(client, K_USEC(BT_AUDIO_NOTIFY_RETRY_DELAY_US));
1018 }
1019
1020 return 0;
1021 }
1022
bt_has_cp_preset_record_deleted(struct has_client * client,uint8_t index)1023 static int bt_has_cp_preset_record_deleted(struct has_client *client, uint8_t index)
1024 {
1025 NET_BUF_SIMPLE_DEFINE(buf, sizeof(struct bt_has_cp_hdr) +
1026 sizeof(struct bt_has_cp_preset_changed) + sizeof(uint8_t));
1027
1028 LOG_DBG("client %p index 0x%02x", client, index);
1029
1030 preset_changed_prepare(&buf, BT_HAS_CHANGE_ID_PRESET_DELETED, BT_HAS_IS_LAST);
1031 net_buf_simple_add_u8(&buf, index);
1032
1033 if (client != NULL) {
1034 return control_point_send(client, &buf);
1035 } else {
1036 return control_point_send_all(&buf);
1037 }
1038 }
1039
1040 /* Generic Update the last (already deleted) preset */
preset_list_changed_generic_update_tail(struct has_client * client)1041 static int preset_list_changed_generic_update_tail(struct has_client *client)
1042 {
1043 const struct has_preset *prev;
1044 struct has_preset last = {
1045 /* The index value of the last preset the client knew about. */
1046 .index = client->context->last_preset_index_known,
1047
1048 /* As the properties of deleted preset is not available anymore, we set this value
1049 * to 0x00 meaning the preset is unavailable and non-writable which is actually true
1050 */
1051 .properties = BT_HAS_PROP_NONE,
1052
1053 /* As the name of deleted preset are not available anymore, we set this value
1054 * to the value what is compliant with specification.
1055 * As per HAS_v1.0 the Name is 1-40 octet value.
1056 */
1057 .name = "N/A",
1058 };
1059 int err;
1060
1061 prev = preset_get_tail();
1062
1063 err = bt_has_cp_generic_update(client, prev ? prev->index : BT_HAS_PRESET_INDEX_NONE,
1064 last.index, last.properties, last.name, false);
1065 if (err != 0) {
1066 return err;
1067 }
1068
1069 return 0;
1070 }
1071
preset_list_changed_record_deleted_last(struct has_client * client)1072 static int preset_list_changed_record_deleted_last(struct has_client *client)
1073 {
1074 const struct has_preset *last;
1075 int err;
1076
1077 err = bt_has_cp_preset_record_deleted(client, client->context->last_preset_index_known);
1078 if (err != 0) {
1079 return err;
1080 }
1081
1082 last = preset_get_tail();
1083
1084 update_last_preset_index_known(client, last ? last->index : BT_HAS_PRESET_INDEX_NONE);
1085
1086 return 0;
1087 }
1088
preset_list_changed(struct has_client * client)1089 static int preset_list_changed(struct has_client *client)
1090 {
1091 const struct has_preset *preset = NULL;
1092 const struct has_preset *next = NULL;
1093 bool is_last = true;
1094 int err;
1095
1096 if (sys_slist_is_empty(&preset_list)) {
1097 /* The preset list is empty. We need to indicate deletion of all presets */
1098 atomic_set_bit(client->context->flags,
1099 FLAG_NOTIFY_PRESET_LIST_GENERIC_UPDATE_TAIL);
1100 atomic_set_bit(client->context->flags,
1101 FLAG_NOTIFY_PRESET_LIST_RECORD_DELETED_LAST);
1102 notify_work_reschedule(client, K_USEC(BT_AUDIO_NOTIFY_RETRY_DELAY_US));
1103
1104 return 0;
1105 }
1106
1107 preset_foreach(client->preset_changed_index_next, BT_HAS_PRESET_INDEX_LAST,
1108 preset_found, &preset);
1109
1110 if (preset == NULL) {
1111 return 0;
1112 }
1113
1114 preset_foreach(preset->index + 1, BT_HAS_PRESET_INDEX_LAST, preset_found, &next);
1115
1116 /* It is last Preset Changed notification if there are no presets left to notify and the
1117 * currently notified preset have the highest index known to the client.
1118 */
1119 is_last = next == NULL && preset->index >= client->context->last_preset_index_known;
1120
1121 err = bt_has_cp_generic_update(client, preset_get_prev_index(preset), preset->index,
1122 preset->properties, preset->name, is_last);
1123 if (err != 0) {
1124 return err;
1125 }
1126
1127 if (is_last) {
1128 client->preset_changed_index_next = 0;
1129
1130 /* It's the last preset notified, so update the highest index known to the client */
1131 update_last_preset_index_known(client, preset->index);
1132
1133 return 0;
1134 }
1135
1136 if (next == NULL) {
1137 /* If we end up here, the last preset known to the client has been removed.
1138 * As we do not hold the information about the deleted presets, we need to use
1139 * Generic Update procedure to:
1140 * 1. Notify the presets that have been removed in range
1141 * (PrevIndex = current_preset_last, Index=previous_preset_last)
1142 * 2. Notify deletion of preset Index=previous_preset_last.
1143 */
1144 atomic_set_bit(client->context->flags,
1145 FLAG_NOTIFY_PRESET_LIST_GENERIC_UPDATE_TAIL);
1146 atomic_set_bit(client->context->flags,
1147 FLAG_NOTIFY_PRESET_LIST_RECORD_DELETED_LAST);
1148 } else {
1149 client->preset_changed_index_next = preset->index + 1;
1150
1151 atomic_set_bit(client->context->flags, FLAG_NOTIFY_PRESET_LIST);
1152 }
1153
1154 notify_work_reschedule(client, K_USEC(BT_AUDIO_NOTIFY_RETRY_DELAY_US));
1155
1156 return 0;
1157 }
1158
handle_read_preset_req(struct bt_conn * conn,struct net_buf_simple * buf)1159 static uint8_t handle_read_preset_req(struct bt_conn *conn, struct net_buf_simple *buf)
1160 {
1161 const struct bt_has_cp_read_presets_req *req;
1162 const struct has_preset *preset = NULL;
1163 struct has_client *client;
1164
1165 if (buf->len < sizeof(*req)) {
1166 return BT_HAS_ERR_INVALID_PARAM_LEN;
1167 }
1168
1169 /* As per HAS_d1.0r00 Client Characteristic Configuration Descriptor Improperly Configured
1170 * shall be returned if client writes Read Presets Request but is not registered for
1171 * indications.
1172 */
1173 if (!bt_gatt_is_subscribed(conn, preset_control_point_attr, BT_GATT_CCC_INDICATE)) {
1174 return BT_ATT_ERR_CCC_IMPROPER_CONF;
1175 }
1176
1177 client = client_find_by_conn(conn);
1178 if (client == NULL) {
1179 return BT_ATT_ERR_UNLIKELY;
1180 }
1181
1182 req = net_buf_simple_pull_mem(buf, sizeof(*req));
1183
1184 LOG_DBG("start_index %d num_presets %d", req->start_index, req->num_presets);
1185
1186 /* Abort if there is no preset in requested index range */
1187 preset_foreach(req->start_index, BT_HAS_PRESET_INDEX_LAST, preset_found, &preset);
1188
1189 if (preset == NULL) {
1190 return BT_ATT_ERR_OUT_OF_RANGE;
1191 }
1192
1193 /* Reject if already in progress */
1194 if (atomic_test_bit(client->context->flags, FLAG_PENDING_READ_PRESET_RESPONSE)) {
1195 return BT_HAS_ERR_OPERATION_NOT_POSSIBLE;
1196 }
1197
1198 /* Store the request */
1199 client->read_presets_req.start_index = req->start_index;
1200 client->read_presets_req.num_presets = req->num_presets;
1201
1202 notify(client, FLAG_PENDING_READ_PRESET_RESPONSE);
1203
1204 return 0;
1205 }
1206
set_preset_name(uint8_t index,const char * name,size_t len)1207 static int set_preset_name(uint8_t index, const char *name, size_t len)
1208 {
1209 struct has_preset *preset = NULL;
1210
1211 LOG_DBG("index %d name_len %zu", index, len);
1212
1213 if (len < BT_HAS_PRESET_NAME_MIN || len > BT_HAS_PRESET_NAME_MAX) {
1214 return -EINVAL;
1215 }
1216
1217 /* Abort if there is no preset in requested index range */
1218 preset_foreach(index, BT_HAS_PRESET_INDEX_LAST, preset_found, &preset);
1219
1220 if (preset == NULL) {
1221 return -ENOENT;
1222 }
1223
1224 if (!(preset->properties & BT_HAS_PROP_WRITABLE)) {
1225 return -EPERM;
1226 }
1227
1228 IF_ENABLED(CONFIG_BT_HAS_PRESET_NAME_DYNAMIC, (
1229 __ASSERT(len < ARRAY_SIZE(preset->name), "No space for name");
1230
1231 (void)memcpy(preset->name, name, len);
1232
1233 /* NULL-terminate string */
1234 preset->name[len] = '\0';
1235
1236 /* Properly truncate a NULL-terminated UTF-8 string */
1237 utf8_trunc(preset->name);
1238 ));
1239
1240 if (preset->ops->name_changed) {
1241 preset->ops->name_changed(index, preset->name);
1242 }
1243
1244 return bt_has_cp_generic_update(NULL, preset_get_prev_index(preset), preset->index,
1245 preset->properties, preset->name, BT_HAS_IS_LAST);
1246 }
1247
handle_write_preset_name(struct bt_conn * conn,struct net_buf_simple * buf)1248 static uint8_t handle_write_preset_name(struct bt_conn *conn, struct net_buf_simple *buf)
1249 {
1250 const struct bt_has_cp_write_preset_name *req;
1251 struct has_client *client;
1252 int err;
1253
1254 if (buf->len < sizeof(*req)) {
1255 return BT_HAS_ERR_INVALID_PARAM_LEN;
1256 }
1257
1258 /* As per HAS_v1.0 Client Characteristic Configuration Descriptor Improperly Configured
1259 * shall be returned if client writes Write Preset Name opcode but is not registered for
1260 * indications.
1261 */
1262 if (!bt_gatt_is_subscribed(conn, preset_control_point_attr, BT_GATT_CCC_INDICATE)) {
1263 return BT_ATT_ERR_CCC_IMPROPER_CONF;
1264 }
1265
1266 client = client_find_by_conn(conn);
1267 if (!client) {
1268 return BT_ATT_ERR_UNLIKELY;
1269 }
1270
1271 req = net_buf_simple_pull_mem(buf, sizeof(*req));
1272
1273 err = set_preset_name(req->index, req->name, buf->len);
1274 if (err == -EINVAL) {
1275 return BT_HAS_ERR_INVALID_PARAM_LEN;
1276 } else if (err == -ENOENT) {
1277 return BT_ATT_ERR_OUT_OF_RANGE;
1278 } else if (err == -EPERM) {
1279 return BT_HAS_ERR_WRITE_NAME_NOT_ALLOWED;
1280 } else if (err) {
1281 return BT_ATT_ERR_UNLIKELY;
1282 }
1283
1284 return BT_ATT_ERR_SUCCESS;
1285 }
1286
preset_set_active(struct has_preset * preset)1287 static void preset_set_active(struct has_preset *preset)
1288 {
1289 if (active_preset != preset) {
1290 active_preset = preset;
1291
1292 notify(NULL, FLAG_ACTIVE_INDEX_CHANGED);
1293 }
1294 }
1295
preset_select(struct has_preset * preset,bool sync)1296 static uint8_t preset_select(struct has_preset *preset, bool sync)
1297 {
1298 const int err = preset->ops->select(preset->index, sync);
1299
1300 if (err == -EINPROGRESS) {
1301 /* User has to confirm once the requested preset becomes active by
1302 * calling bt_has_preset_active_set.
1303 */
1304 return 0;
1305 }
1306
1307 if (err == -EBUSY) {
1308 return BT_HAS_ERR_OPERATION_NOT_POSSIBLE;
1309 }
1310
1311 if (err) {
1312 return BT_ATT_ERR_UNLIKELY;
1313 }
1314
1315 preset_set_active(preset);
1316
1317 return 0;
1318 }
1319
is_preset_available(const struct has_preset * preset)1320 static bool is_preset_available(const struct has_preset *preset)
1321 {
1322 return (preset->properties & BT_HAS_PROP_AVAILABLE) != 0;
1323 }
1324
handle_set_active_preset(struct net_buf_simple * buf,bool sync)1325 static uint8_t handle_set_active_preset(struct net_buf_simple *buf, bool sync)
1326 {
1327 const struct bt_has_cp_set_active_preset *pdu;
1328 struct has_preset *preset;
1329
1330 if (buf->len < sizeof(*pdu)) {
1331 return BT_HAS_ERR_INVALID_PARAM_LEN;
1332 }
1333
1334 pdu = net_buf_simple_pull_mem(buf, sizeof(*pdu));
1335
1336 preset = preset_lookup_index(pdu->index);
1337 if (preset == NULL) {
1338 return BT_ATT_ERR_OUT_OF_RANGE;
1339 }
1340
1341 if (!is_preset_available(preset)) {
1342 return BT_HAS_ERR_OPERATION_NOT_POSSIBLE;
1343 }
1344
1345 return preset_select(preset, sync);
1346 }
1347
handle_set_next_preset(bool sync)1348 static uint8_t handle_set_next_preset(bool sync)
1349 {
1350 struct has_preset *next, *tmp;
1351
1352 if (active_preset == NULL) {
1353 next = preset_get_head();
1354 } else {
1355 next = preset_get_next(active_preset);
1356 }
1357
1358 tmp = next;
1359 do {
1360 if (next == NULL) {
1361 break;
1362 }
1363
1364 if (is_preset_available(next)) {
1365 return preset_select(next, sync);
1366 }
1367
1368 next = preset_get_next(next);
1369 } while (tmp != next);
1370
1371 return BT_HAS_ERR_OPERATION_NOT_POSSIBLE;
1372 }
1373
handle_set_prev_preset(bool sync)1374 static uint8_t handle_set_prev_preset(bool sync)
1375 {
1376 struct has_preset *prev, *tmp;
1377
1378 if (active_preset == NULL) {
1379 prev = preset_get_tail();
1380 } else {
1381 prev = preset_get_prev(active_preset);
1382 }
1383
1384 tmp = prev;
1385 do {
1386 if (prev == NULL) {
1387 break;
1388 }
1389
1390 if (is_preset_available(prev)) {
1391 return preset_select(prev, sync);
1392 }
1393
1394 prev = preset_get_prev(prev);
1395 } while (tmp != prev);
1396
1397 return BT_HAS_ERR_OPERATION_NOT_POSSIBLE;
1398 }
1399
handle_control_point_op(struct bt_conn * conn,struct net_buf_simple * buf)1400 static uint8_t handle_control_point_op(struct bt_conn *conn, struct net_buf_simple *buf)
1401 {
1402 const struct bt_has_cp_hdr *hdr;
1403
1404 hdr = net_buf_simple_pull_mem(buf, sizeof(*hdr));
1405
1406 LOG_DBG("conn %p opcode %s (0x%02x)", (void *)conn, bt_has_op_str(hdr->opcode),
1407 hdr->opcode);
1408
1409 switch (hdr->opcode) {
1410 case BT_HAS_OP_READ_PRESET_REQ:
1411 return handle_read_preset_req(conn, buf);
1412 case BT_HAS_OP_WRITE_PRESET_NAME:
1413 if (IS_ENABLED(CONFIG_BT_HAS_PRESET_NAME_DYNAMIC)) {
1414 return handle_write_preset_name(conn, buf);
1415 } else {
1416 return BT_HAS_ERR_WRITE_NAME_NOT_ALLOWED;
1417 }
1418 break;
1419 case BT_HAS_OP_SET_ACTIVE_PRESET:
1420 return handle_set_active_preset(buf, false);
1421 case BT_HAS_OP_SET_NEXT_PRESET:
1422 return handle_set_next_preset(false);
1423 case BT_HAS_OP_SET_PREV_PRESET:
1424 return handle_set_prev_preset(false);
1425 case BT_HAS_OP_SET_ACTIVE_PRESET_SYNC:
1426 if ((has.features & BT_HAS_FEAT_PRESET_SYNC_SUPP) != 0) {
1427 return handle_set_active_preset(buf, true);
1428 } else {
1429 return BT_HAS_ERR_PRESET_SYNC_NOT_SUPP;
1430 }
1431 case BT_HAS_OP_SET_NEXT_PRESET_SYNC:
1432 if ((has.features & BT_HAS_FEAT_PRESET_SYNC_SUPP) != 0) {
1433 return handle_set_next_preset(true);
1434 } else {
1435 return BT_HAS_ERR_PRESET_SYNC_NOT_SUPP;
1436 }
1437 case BT_HAS_OP_SET_PREV_PRESET_SYNC:
1438 if ((has.features & BT_HAS_FEAT_PRESET_SYNC_SUPP) != 0) {
1439 return handle_set_prev_preset(true);
1440 } else {
1441 return BT_HAS_ERR_PRESET_SYNC_NOT_SUPP;
1442 }
1443 };
1444
1445 return BT_HAS_ERR_INVALID_OPCODE;
1446 }
1447
write_control_point(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * data,uint16_t len,uint16_t offset,uint8_t flags)1448 static ssize_t write_control_point(struct bt_conn *conn, const struct bt_gatt_attr *attr,
1449 const void *data, uint16_t len, uint16_t offset, uint8_t flags)
1450 {
1451 struct net_buf_simple buf;
1452 uint8_t err;
1453
1454 LOG_DBG("conn %p attr %p data %p len %d offset %d flags 0x%02x", (void *)conn, attr, data,
1455 len, offset, flags);
1456
1457 if (offset > 0) {
1458 return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
1459 }
1460
1461 if (len == 0) {
1462 return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
1463 }
1464
1465 net_buf_simple_init_with_data(&buf, (void *)data, len);
1466
1467 err = handle_control_point_op(conn, &buf);
1468 if (err) {
1469 LOG_WRN("handle_control_point_op err 0x%02x", err);
1470 return BT_GATT_ERR(err);
1471 }
1472
1473 return len;
1474 }
1475
bt_has_preset_register(const struct bt_has_preset_register_param * param)1476 int bt_has_preset_register(const struct bt_has_preset_register_param *param)
1477 {
1478 struct has_preset *preset;
1479 size_t name_len;
1480
1481 CHECKIF(param == NULL) {
1482 LOG_ERR("param is NULL");
1483 return -EINVAL;
1484 }
1485
1486 CHECKIF(param->index == BT_HAS_PRESET_INDEX_NONE) {
1487 LOG_ERR("param->index is invalid");
1488 return -EINVAL;
1489 }
1490
1491 CHECKIF(param->name == NULL) {
1492 LOG_ERR("param->name is NULL");
1493 return -EINVAL;
1494 }
1495
1496 name_len = strlen(param->name);
1497
1498 CHECKIF(name_len < BT_HAS_PRESET_NAME_MIN) {
1499 LOG_ERR("param->name is too short (%zu < %u)", name_len, BT_HAS_PRESET_NAME_MIN);
1500 return -EINVAL;
1501 }
1502
1503 CHECKIF(name_len > BT_HAS_PRESET_NAME_MAX) {
1504 LOG_WRN("param->name is too long (%zu > %u)", name_len, BT_HAS_PRESET_NAME_MAX);
1505 }
1506
1507 CHECKIF(param->ops == NULL) {
1508 LOG_ERR("param->ops is NULL");
1509 return -EINVAL;
1510 }
1511
1512 CHECKIF(param->ops->select == NULL) {
1513 LOG_ERR("param->ops->select is NULL");
1514 return -EINVAL;
1515 }
1516
1517 preset = preset_lookup_index(param->index);
1518 if (preset != NULL) {
1519 return -EALREADY;
1520 }
1521
1522 CHECKIF(!IS_ENABLED(CONFIG_BT_HAS_PRESET_NAME_DYNAMIC) &&
1523 (param->properties & BT_HAS_PROP_WRITABLE) > 0) {
1524 LOG_ERR("Writable presets are not supported");
1525 return -ENOTSUP;
1526 }
1527
1528 preset = preset_alloc(param->index, param->properties, param->name, param->ops);
1529 if (preset == NULL) {
1530 return -ENOMEM;
1531 }
1532
1533 if (preset == preset_get_tail()) {
1534 update_last_preset_index_known(NULL, preset->index);
1535 }
1536
1537 return bt_has_cp_generic_update(NULL, preset_get_prev_index(preset), preset->index,
1538 preset->properties, preset->name, BT_HAS_IS_LAST);
1539 }
1540
bt_has_preset_unregister(uint8_t index)1541 int bt_has_preset_unregister(uint8_t index)
1542 {
1543 struct has_preset *preset;
1544 int err;
1545
1546 CHECKIF(index == BT_HAS_PRESET_INDEX_NONE) {
1547 LOG_ERR("index is invalid");
1548 return -EINVAL;
1549 }
1550
1551 preset = preset_lookup_index(index);
1552 if (preset == NULL) {
1553 return -ENOENT;
1554 }
1555
1556 if (preset == active_preset) {
1557 return -EADDRINUSE;
1558 }
1559
1560 err = bt_has_cp_preset_record_deleted(NULL, preset->index);
1561 if (err != 0) {
1562 return err;
1563 }
1564
1565 if (preset == preset_get_tail()) {
1566 update_last_preset_index_known(NULL, preset_get_prev_index(preset));
1567 }
1568
1569 preset_free(preset);
1570
1571 return 0;
1572 }
1573
set_preset_availability(uint8_t index,bool available)1574 static int set_preset_availability(uint8_t index, bool available)
1575 {
1576 NET_BUF_SIMPLE_DEFINE(buf, sizeof(struct bt_has_cp_hdr) +
1577 sizeof(struct bt_has_cp_preset_changed) + sizeof(uint8_t));
1578 struct has_preset *preset;
1579 uint8_t change_id;
1580
1581 CHECKIF(index == BT_HAS_PRESET_INDEX_NONE) {
1582 LOG_ERR("index is invalid");
1583 return -EINVAL;
1584 }
1585
1586 preset = preset_lookup_index(index);
1587 if (preset == NULL) {
1588 return -ENOENT;
1589 }
1590
1591 if (is_preset_available(preset) == available) {
1592 /* availability not changed */
1593 return 0;
1594 }
1595
1596 preset->properties ^= BT_HAS_PROP_AVAILABLE;
1597
1598 if (is_preset_available(preset)) {
1599 change_id = BT_HAS_CHANGE_ID_PRESET_AVAILABLE;
1600 } else {
1601 change_id = BT_HAS_CHANGE_ID_PRESET_UNAVAILABLE;
1602 }
1603
1604 preset_changed_prepare(&buf, change_id, BT_HAS_IS_LAST);
1605 net_buf_simple_add_u8(&buf, preset->index);
1606
1607 return control_point_send_all(&buf);
1608 }
1609
bt_has_preset_available(uint8_t index)1610 int bt_has_preset_available(uint8_t index)
1611 {
1612 return set_preset_availability(index, true);
1613 }
1614
bt_has_preset_unavailable(uint8_t index)1615 int bt_has_preset_unavailable(uint8_t index)
1616 {
1617 return set_preset_availability(index, false);
1618 }
1619
1620 struct bt_has_preset_foreach_data {
1621 bt_has_preset_func_t func;
1622 void *user_data;
1623 };
1624
bt_has_preset_foreach_func(const struct has_preset * preset,void * user_data)1625 static uint8_t bt_has_preset_foreach_func(const struct has_preset *preset, void *user_data)
1626 {
1627 const struct bt_has_preset_foreach_data *data = user_data;
1628
1629 return data->func(preset->index, preset->properties, preset->name, data->user_data);
1630 }
1631
bt_has_preset_foreach(uint8_t index,bt_has_preset_func_t func,void * user_data)1632 void bt_has_preset_foreach(uint8_t index, bt_has_preset_func_t func, void *user_data)
1633 {
1634 uint8_t start_index, end_index;
1635 struct bt_has_preset_foreach_data data = {
1636 .func = func,
1637 .user_data = user_data,
1638 };
1639
1640 if (index == BT_HAS_PRESET_INDEX_NONE) {
1641 start_index = BT_HAS_PRESET_INDEX_FIRST;
1642 end_index = BT_HAS_PRESET_INDEX_LAST;
1643 } else {
1644 start_index = end_index = index;
1645 }
1646
1647 preset_foreach(start_index, end_index, bt_has_preset_foreach_func, &data);
1648 }
1649
bt_has_preset_active_set(uint8_t index)1650 int bt_has_preset_active_set(uint8_t index)
1651 {
1652 struct has_preset *preset;
1653
1654 if (index == BT_HAS_PRESET_INDEX_NONE) {
1655 preset_set_active(NULL);
1656 return 0;
1657 }
1658
1659 preset = preset_lookup_index(index);
1660 if (preset == NULL) {
1661 return -ENOENT;
1662 }
1663
1664 if (!is_preset_available(preset)) {
1665 return -EINVAL;
1666 }
1667
1668 preset_set_active(preset);
1669
1670 return 0;
1671 }
1672
bt_has_preset_active_get(void)1673 uint8_t bt_has_preset_active_get(void)
1674 {
1675 if (active_preset == NULL) {
1676 return BT_HAS_PRESET_INDEX_NONE;
1677 }
1678
1679 return active_preset->index;
1680 }
1681
bt_has_preset_name_change(uint8_t index,const char * name)1682 int bt_has_preset_name_change(uint8_t index, const char *name)
1683 {
1684 CHECKIF(name == NULL) {
1685 return -EINVAL;
1686 }
1687
1688 if (IS_ENABLED(CONFIG_BT_HAS_PRESET_NAME_DYNAMIC)) {
1689 return set_preset_name(index, name, strlen(name));
1690 } else {
1691 return -EOPNOTSUPP;
1692 }
1693 }
1694 #endif /* CONFIG_BT_HAS_PRESET_SUPPORT */
1695
has_features_register(const struct bt_has_features_param * features)1696 static int has_features_register(const struct bt_has_features_param *features)
1697 {
1698 /* Initialize the supported features characteristic value */
1699 has.features = features->type;
1700
1701 if (IS_ENABLED(CONFIG_BT_HAS_PRESET_SUPPORT)) {
1702 has.features |= BT_HAS_FEAT_DYNAMIC_PRESETS;
1703
1704 if (features->preset_sync_support) {
1705 if (features->type != BT_HAS_HEARING_AID_TYPE_BINAURAL) {
1706 LOG_DBG("Preset sync support only available "
1707 "for binaural hearing aid type");
1708 return -EINVAL;
1709 }
1710
1711 has.features |= BT_HAS_FEAT_PRESET_SYNC_SUPP;
1712 }
1713
1714 if (features->independent_presets) {
1715 if (features->type != BT_HAS_HEARING_AID_TYPE_BINAURAL) {
1716 LOG_DBG("Independent presets only available "
1717 "for binaural hearing aid type");
1718 return -EINVAL;
1719 }
1720
1721 has.features |= BT_HAS_FEAT_INDEPENDENT_PRESETS;
1722 }
1723 }
1724
1725 if (IS_ENABLED(CONFIG_BT_HAS_PRESET_NAME_DYNAMIC)) {
1726 has.features |= BT_HAS_FEAT_WRITABLE_PRESETS_SUPP;
1727 }
1728
1729 return 0;
1730 }
1731
1732 #if defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE)
bt_has_features_set(const struct bt_has_features_param * features)1733 int bt_has_features_set(const struct bt_has_features_param *features)
1734 {
1735 int err;
1736
1737 if (!has.registered) {
1738 return -ENOTSUP;
1739 }
1740
1741 /* Check whether any features will change, otherwise we don't want to notify clients */
1742 if (FEATURE_DEVICE_TYPE_UNCHANGED(features->type) &&
1743 FEATURE_SYNC_SUPPORT_UNCHANGED(features->preset_sync_support) &&
1744 FEATURE_IND_PRESETS_UNCHANGED(features->independent_presets)) {
1745 return 0;
1746 }
1747
1748 err = has_features_register(features);
1749 if (err != 0) {
1750 LOG_DBG("Failed to register features");
1751 return err;
1752 }
1753
1754 notify(NULL, FLAG_FEATURES_CHANGED);
1755
1756 return 0;
1757 }
1758 #endif /* CONFIG_BT_HAS_FEATURES_NOTIFIABLE */
1759
bt_has_register(const struct bt_has_features_param * features)1760 int bt_has_register(const struct bt_has_features_param *features)
1761 {
1762 int err;
1763
1764 LOG_DBG("features %p", features);
1765
1766 CHECKIF(!features) {
1767 LOG_DBG("NULL params pointer");
1768 return -EINVAL;
1769 }
1770
1771 if (has.registered) {
1772 return -EALREADY;
1773 }
1774
1775 err = has_features_register(features);
1776 if (err != 0) {
1777 LOG_DBG("HAS service failed to register features: %d", err);
1778 return err;
1779 }
1780
1781 has_svc = (struct bt_gatt_service)BT_GATT_SERVICE(has_attrs);
1782 err = bt_gatt_service_register(&has_svc);
1783 if (err != 0) {
1784 LOG_DBG("HAS service register failed: %d", err);
1785 return err;
1786 }
1787
1788 if (IS_ENABLED(CONFIG_BT_HAS_FEATURES_NOTIFIABLE)) {
1789 hearing_aid_features_attr = bt_gatt_find_by_uuid(has_svc.attrs, has_svc.attr_count,
1790 BT_UUID_HAS_HEARING_AID_FEATURES);
1791 __ASSERT_NO_MSG(hearing_aid_features_attr != NULL);
1792 }
1793
1794 if (IS_ENABLED(CONFIG_BT_HAS_PRESET_SUPPORT)) {
1795 preset_control_point_attr = bt_gatt_find_by_uuid(has_svc.attrs, has_svc.attr_count,
1796 BT_UUID_HAS_PRESET_CONTROL_POINT);
1797 __ASSERT_NO_MSG(preset_control_point_attr != NULL);
1798
1799 active_preset_index_attr = bt_gatt_find_by_uuid(has_svc.attrs, has_svc.attr_count,
1800 BT_UUID_HAS_ACTIVE_PRESET_INDEX);
1801 __ASSERT_NO_MSG(active_preset_index_attr != NULL);
1802 }
1803
1804 #if defined(CONFIG_BT_HAS_PRESET_SUPPORT)
1805 for (size_t i = 0; i < ARRAY_SIZE(preset_pool); i++) {
1806 struct has_preset *preset = &preset_pool[i];
1807
1808 sys_slist_append(&preset_free_list, &preset->node);
1809 }
1810 #endif /* CONFIG_BT_HAS_PRESET_SUPPORT */
1811
1812 #if defined(CONFIG_BT_HAS_PRESET_SUPPORT) || defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE)
1813 bt_conn_auth_info_cb_register(&auth_info_cb);
1814 #endif /* CONFIG_BT_HAS_PRESET_SUPPORT || CONFIG_BT_HAS_FEATURES_NOTIFIABLE */
1815
1816 has.registered = true;
1817
1818 return 0;
1819 }
1820