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