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