1 /*
2  * Copyright (c) 2022 Codecoup
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <errno.h>
7 #include <stdbool.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 #include <string.h>
11 
12 #include <zephyr/autoconf.h>
13 #include <zephyr/bluetooth/att.h>
14 #include <zephyr/bluetooth/audio/has.h>
15 #include <zephyr/bluetooth/bluetooth.h>
16 #include <zephyr/bluetooth/conn.h>
17 #include <zephyr/bluetooth/gatt.h>
18 #include <zephyr/bluetooth/uuid.h>
19 #include <zephyr/kernel.h>
20 #include <zephyr/logging/log.h>
21 #include <zephyr/net/buf.h>
22 #include <zephyr/sys/atomic.h>
23 #include <zephyr/sys/check.h>
24 #include <zephyr/sys/util.h>
25 #include <zephyr/sys/util_macro.h>
26 
27 #include "has_internal.h"
28 
29 LOG_MODULE_REGISTER(bt_has_client, CONFIG_BT_HAS_CLIENT_LOG_LEVEL);
30 
31 #define HAS_INST(_has) CONTAINER_OF(_has, struct bt_has_client, has)
32 #define HANDLE_IS_VALID(handle) ((handle) != 0x0000)
33 static struct bt_has_client clients[CONFIG_BT_MAX_CONN];
34 static const struct bt_has_client_cb *client_cb;
35 
inst_by_conn(struct bt_conn * conn)36 static struct bt_has_client *inst_by_conn(struct bt_conn *conn)
37 {
38 	struct bt_has_client *inst = &clients[bt_conn_index(conn)];
39 
40 	if (inst->conn == conn) {
41 		return inst;
42 	}
43 
44 	return NULL;
45 }
46 
inst_cleanup(struct bt_has_client * inst)47 static void inst_cleanup(struct bt_has_client *inst)
48 {
49 	bt_conn_unref(inst->conn);
50 
51 	(void)memset(inst, 0, sizeof(*inst));
52 }
53 
get_capabilities(const struct bt_has_client * inst)54 static enum bt_has_capabilities get_capabilities(const struct bt_has_client *inst)
55 {
56 	enum bt_has_capabilities caps = 0;
57 
58 	/* The Control Point support is optional, as the server might have no presets support */
59 	if (HANDLE_IS_VALID(inst->control_point_subscription.value_handle)) {
60 		caps |= BT_HAS_PRESET_SUPPORT;
61 	}
62 
63 	return caps;
64 }
65 
handle_read_preset_rsp(struct bt_has_client * inst,struct net_buf_simple * buf)66 static void handle_read_preset_rsp(struct bt_has_client *inst, struct net_buf_simple *buf)
67 {
68 	const struct bt_has_cp_read_preset_rsp *pdu;
69 	struct bt_has_preset_record record;
70 	char name[BT_HAS_PRESET_NAME_MAX + 1]; /* + 1 byte for null-terminator */
71 	size_t name_len;
72 
73 	LOG_DBG("conn %p buf %p", (void *)inst->conn, buf);
74 
75 	if (buf->len < sizeof(*pdu)) {
76 		LOG_ERR("malformed PDU");
77 		return;
78 	}
79 
80 	pdu = net_buf_simple_pull_mem(buf, sizeof(*pdu));
81 
82 	if (pdu->is_last > BT_HAS_IS_LAST) {
83 		LOG_WRN("unexpected is_last value 0x%02x", pdu->is_last);
84 	}
85 
86 	record.index = pdu->index;
87 	record.properties = pdu->properties;
88 	record.name = name;
89 
90 	name_len = buf->len + 1; /* + 1 byte for NULL terminator */
91 	if (name_len > ARRAY_SIZE(name)) {
92 		LOG_WRN("name is too long (%zu > %u)", buf->len, BT_HAS_PRESET_NAME_MAX);
93 
94 		name_len = ARRAY_SIZE(name);
95 	}
96 
97 	utf8_lcpy(name, pdu->name, name_len);
98 
99 	client_cb->preset_read_rsp(&inst->has, 0, &record, !!pdu->is_last);
100 }
101 
handle_generic_update(struct bt_has_client * inst,struct net_buf_simple * buf,bool is_last)102 static void handle_generic_update(struct bt_has_client *inst, struct net_buf_simple *buf,
103 				  bool is_last)
104 {
105 	const struct bt_has_cp_generic_update *pdu;
106 	struct bt_has_preset_record record;
107 	char name[BT_HAS_PRESET_NAME_MAX + 1]; /* + 1 byte for null-terminator */
108 	size_t name_len;
109 
110 	if (buf->len < sizeof(*pdu)) {
111 		LOG_ERR("malformed PDU");
112 		return;
113 	}
114 
115 	pdu = net_buf_simple_pull_mem(buf, sizeof(*pdu));
116 
117 	record.index = pdu->index;
118 	record.properties = pdu->properties;
119 	record.name = name;
120 
121 	name_len = buf->len + 1; /* + 1 byte for NULL terminator */
122 	if (name_len > ARRAY_SIZE(name)) {
123 		LOG_WRN("name is too long (%zu > %u)", buf->len, BT_HAS_PRESET_NAME_MAX);
124 
125 		name_len = ARRAY_SIZE(name);
126 	}
127 
128 	utf8_lcpy(name, pdu->name, name_len);
129 
130 	client_cb->preset_update(&inst->has, pdu->prev_index, &record, is_last);
131 }
132 
handle_preset_deleted(struct bt_has_client * inst,struct net_buf_simple * buf,bool is_last)133 static void handle_preset_deleted(struct bt_has_client *inst, struct net_buf_simple *buf,
134 				  bool is_last)
135 {
136 	if (buf->len < sizeof(uint8_t)) {
137 		LOG_ERR("malformed PDU");
138 		return;
139 	}
140 
141 	client_cb->preset_deleted(&inst->has, net_buf_simple_pull_u8(buf), is_last);
142 }
143 
handle_preset_availability(struct bt_has_client * inst,struct net_buf_simple * buf,bool available,bool is_last)144 static void handle_preset_availability(struct bt_has_client *inst, struct net_buf_simple *buf,
145 				       bool available, bool is_last)
146 {
147 	if (buf->len < sizeof(uint8_t)) {
148 		LOG_ERR("malformed PDU");
149 		return;
150 	}
151 
152 	client_cb->preset_availability(&inst->has, net_buf_simple_pull_u8(buf), available,
153 				       is_last);
154 }
155 
handle_preset_changed(struct bt_has_client * inst,struct net_buf_simple * buf)156 static void handle_preset_changed(struct bt_has_client *inst, struct net_buf_simple *buf)
157 {
158 	const struct bt_has_cp_preset_changed *pdu;
159 
160 	LOG_DBG("conn %p buf %p", (void *)inst->conn, buf);
161 
162 	if (buf->len < sizeof(*pdu)) {
163 		LOG_ERR("malformed PDU");
164 		return;
165 	}
166 
167 	pdu = net_buf_simple_pull_mem(buf, sizeof(*pdu));
168 
169 	if (pdu->is_last > BT_HAS_IS_LAST) {
170 		LOG_WRN("unexpected is_last 0x%02x", pdu->is_last);
171 	}
172 
173 	switch (pdu->change_id) {
174 	case BT_HAS_CHANGE_ID_GENERIC_UPDATE:
175 		if (client_cb->preset_update) {
176 			handle_generic_update(inst, buf, !!pdu->is_last);
177 		}
178 		break;
179 	case BT_HAS_CHANGE_ID_PRESET_DELETED:
180 		if (client_cb->preset_deleted) {
181 			handle_preset_deleted(inst, buf, !!pdu->is_last);
182 		}
183 		break;
184 	case BT_HAS_CHANGE_ID_PRESET_AVAILABLE:
185 		if (client_cb->preset_availability) {
186 			handle_preset_availability(inst, buf, !!pdu->is_last, true);
187 		}
188 		return;
189 	case BT_HAS_CHANGE_ID_PRESET_UNAVAILABLE:
190 		if (client_cb->preset_availability) {
191 			handle_preset_availability(inst, buf, !!pdu->is_last, false);
192 		}
193 		return;
194 	default:
195 		LOG_WRN("unknown change_id 0x%02x", pdu->change_id);
196 	}
197 }
198 
control_point_notify_cb(struct bt_conn * conn,struct bt_gatt_subscribe_params * params,const void * data,uint16_t len)199 static uint8_t control_point_notify_cb(struct bt_conn *conn,
200 				       struct bt_gatt_subscribe_params *params, const void *data,
201 				       uint16_t len)
202 {
203 	struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client,
204 						  control_point_subscription);
205 	const struct bt_has_cp_hdr *hdr;
206 	struct net_buf_simple buf;
207 
208 	LOG_DBG("conn %p params %p data %p len %u", (void *)conn, params, data, len);
209 
210 	if (!conn) { /* Unpaired, continue receiving notifications */
211 		return BT_GATT_ITER_CONTINUE;
212 	}
213 
214 	if (!data) { /* Unsubscribed */
215 		params->value_handle = 0u;
216 
217 		return BT_GATT_ITER_STOP;
218 	}
219 
220 	if (len < sizeof(*hdr)) { /* Ignore malformed notification */
221 		return BT_GATT_ITER_CONTINUE;
222 	}
223 
224 	net_buf_simple_init_with_data(&buf, (void *)data, len);
225 
226 	hdr = net_buf_simple_pull_mem(&buf, sizeof(*hdr));
227 
228 	switch (hdr->opcode) {
229 	case BT_HAS_OP_READ_PRESET_RSP:
230 		handle_read_preset_rsp(inst, &buf);
231 		break;
232 	case BT_HAS_OP_PRESET_CHANGED:
233 		handle_preset_changed(inst, &buf);
234 		break;
235 	};
236 
237 	return BT_GATT_ITER_CONTINUE;
238 }
239 
discover_complete(struct bt_has_client * inst)240 static void discover_complete(struct bt_has_client *inst)
241 {
242 	LOG_DBG("conn %p", (void *)inst->conn);
243 
244 	atomic_clear_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS);
245 
246 	client_cb->discover(inst->conn, 0, &inst->has,
247 			    inst->has.features & BT_HAS_FEAT_HEARING_AID_TYPE_MASK,
248 			    get_capabilities(inst));
249 
250 	/* If Active Preset Index supported, notify it's value */
251 	if (client_cb->preset_switch &&
252 	    HANDLE_IS_VALID(inst->active_index_subscription.value_handle)) {
253 		client_cb->preset_switch(&inst->has, 0, inst->has.active_index);
254 	}
255 }
256 
discover_failed(struct bt_conn * conn,int err)257 static void discover_failed(struct bt_conn *conn, int err)
258 {
259 	LOG_DBG("conn %p", (void *)conn);
260 
261 	client_cb->discover(conn, err, NULL, 0, 0);
262 }
263 
cp_write(struct bt_has_client * inst,struct net_buf_simple * buf,bt_gatt_write_func_t func)264 static int cp_write(struct bt_has_client *inst, struct net_buf_simple *buf,
265 		    bt_gatt_write_func_t func)
266 {
267 	const uint16_t value_handle = inst->control_point_subscription.value_handle;
268 
269 	if (!HANDLE_IS_VALID(value_handle)) {
270 		return -ENOTSUP;
271 	}
272 
273 	inst->params.write.func = func;
274 	inst->params.write.handle = value_handle;
275 	inst->params.write.offset = 0U;
276 	inst->params.write.data = buf->data;
277 	inst->params.write.length = buf->len;
278 
279 	return bt_gatt_write(inst->conn, &inst->params.write);
280 }
281 
read_presets_req_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)282 static void read_presets_req_cb(struct bt_conn *conn, uint8_t err,
283 				struct bt_gatt_write_params *params)
284 {
285 	struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, params.write);
286 
287 	LOG_DBG("conn %p err 0x%02x param %p", (void *)conn, err, params);
288 
289 	atomic_clear_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS);
290 
291 	if (err) {
292 		client_cb->preset_read_rsp(&inst->has, err, NULL, true);
293 	}
294 }
295 
read_presets_req(struct bt_has_client * inst,uint8_t start_index,uint8_t num_presets)296 static int read_presets_req(struct bt_has_client *inst, uint8_t start_index, uint8_t num_presets)
297 {
298 	struct bt_has_cp_hdr *hdr;
299 	struct bt_has_cp_read_presets_req *req;
300 
301 	NET_BUF_SIMPLE_DEFINE(buf, sizeof(*hdr) + sizeof(*req));
302 
303 	LOG_DBG("conn %p start_index 0x%02x num_presets %d", (void *)inst->conn, start_index,
304 		num_presets);
305 
306 	hdr = net_buf_simple_add(&buf, sizeof(*hdr));
307 	hdr->opcode = BT_HAS_OP_READ_PRESET_REQ;
308 	req = net_buf_simple_add(&buf, sizeof(*req));
309 	req->start_index = start_index;
310 	req->num_presets = num_presets;
311 
312 	return cp_write(inst, &buf, read_presets_req_cb);
313 }
314 
set_active_preset_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)315 static void set_active_preset_cb(struct bt_conn *conn, uint8_t err,
316 				 struct bt_gatt_write_params *params)
317 {
318 	struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, params.write);
319 
320 	LOG_DBG("conn %p err 0x%02x param %p", (void *)conn, err, params);
321 
322 	atomic_clear_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS);
323 
324 	if (err) {
325 		client_cb->preset_switch(&inst->has, err, inst->has.active_index);
326 	}
327 }
328 
preset_set(struct bt_has_client * inst,uint8_t opcode,uint8_t index)329 static int preset_set(struct bt_has_client *inst, uint8_t opcode, uint8_t index)
330 {
331 	struct bt_has_cp_hdr *hdr;
332 	struct bt_has_cp_set_active_preset *req;
333 
334 	NET_BUF_SIMPLE_DEFINE(buf, sizeof(*hdr) + sizeof(*req));
335 
336 	LOG_DBG("conn %p opcode 0x%02x index 0x%02x", (void *)inst->conn, opcode, index);
337 
338 	hdr = net_buf_simple_add(&buf, sizeof(*hdr));
339 	hdr->opcode = opcode;
340 	req = net_buf_simple_add(&buf, sizeof(*req));
341 	req->index = index;
342 
343 	return cp_write(inst, &buf, set_active_preset_cb);
344 }
345 
preset_set_next_or_prev(struct bt_has_client * inst,uint8_t opcode)346 static int preset_set_next_or_prev(struct bt_has_client *inst, uint8_t opcode)
347 {
348 	struct bt_has_cp_hdr *hdr;
349 
350 	NET_BUF_SIMPLE_DEFINE(buf, sizeof(*hdr));
351 
352 	LOG_DBG("conn %p opcode 0x%02x", (void *)inst->conn, opcode);
353 
354 	hdr = net_buf_simple_add(&buf, sizeof(*hdr));
355 	hdr->opcode = opcode;
356 
357 	return cp_write(inst, &buf, set_active_preset_cb);
358 }
359 
active_index_update(struct bt_has_client * inst,const void * data,uint16_t len)360 static uint8_t active_index_update(struct bt_has_client *inst, const void *data, uint16_t len)
361 {
362 	struct net_buf_simple buf;
363 	const uint8_t prev = inst->has.active_index;
364 
365 	net_buf_simple_init_with_data(&buf, (void *)data, len);
366 
367 	inst->has.active_index = net_buf_simple_pull_u8(&buf);
368 
369 	LOG_DBG("conn %p index 0x%02x", (void *)inst->conn, inst->has.active_index);
370 
371 	return prev;
372 }
373 
active_preset_notify_cb(struct bt_conn * conn,struct bt_gatt_subscribe_params * params,const void * data,uint16_t len)374 static uint8_t active_preset_notify_cb(struct bt_conn *conn,
375 				       struct bt_gatt_subscribe_params *params, const void *data,
376 				       uint16_t len)
377 {
378 	struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client,
379 						  active_index_subscription);
380 	uint8_t prev;
381 
382 	LOG_DBG("conn %p params %p data %p len %u", (void *)conn, params, data, len);
383 
384 	if (!conn) {
385 		/* Unpaired, stop receiving notifications from device */
386 		return BT_GATT_ITER_STOP;
387 	}
388 
389 	if (!data) {
390 		/* Unsubscribed */
391 		params->value_handle = 0u;
392 
393 		return BT_GATT_ITER_STOP;
394 	}
395 
396 	if (len == 0) {
397 		/* Ignore empty notification */
398 		return BT_GATT_ITER_CONTINUE;
399 	}
400 
401 	prev = active_index_update(inst, data, len);
402 
403 	if (atomic_test_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS)) {
404 		/* Got notification during discovery process, postpone the active_index callback
405 		 * until discovery is complete.
406 		 */
407 		return BT_GATT_ITER_CONTINUE;
408 	}
409 
410 	if (client_cb && client_cb->preset_switch && inst->has.active_index != prev) {
411 		client_cb->preset_switch(&inst->has, 0, inst->has.active_index);
412 	}
413 
414 	return BT_GATT_ITER_CONTINUE;
415 }
416 
active_index_subscribe_cb(struct bt_conn * conn,uint8_t att_err,struct bt_gatt_subscribe_params * params)417 static void active_index_subscribe_cb(struct bt_conn *conn, uint8_t att_err,
418 				      struct bt_gatt_subscribe_params *params)
419 {
420 	struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client,
421 						  active_index_subscription);
422 
423 	LOG_DBG("conn %p att_err 0x%02x params %p", (void *)inst->conn, att_err, params);
424 
425 	if (att_err != BT_ATT_ERR_SUCCESS) {
426 		/* Cleanup instance so that it can be reused */
427 		inst_cleanup(inst);
428 
429 		discover_failed(conn, att_err);
430 	} else {
431 		discover_complete(inst);
432 	}
433 }
434 
active_index_subscribe(struct bt_has_client * inst,uint16_t value_handle)435 static int active_index_subscribe(struct bt_has_client *inst, uint16_t value_handle)
436 {
437 	int err;
438 
439 	LOG_DBG("conn %p handle 0x%04x", (void *)inst->conn, value_handle);
440 
441 	inst->active_index_subscription.notify = active_preset_notify_cb;
442 	inst->active_index_subscription.subscribe = active_index_subscribe_cb;
443 	inst->active_index_subscription.value_handle = value_handle;
444 	inst->active_index_subscription.ccc_handle = 0x0000;
445 	inst->active_index_subscription.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
446 	inst->active_index_subscription.disc_params = &inst->params.discover;
447 	inst->active_index_subscription.value = BT_GATT_CCC_NOTIFY;
448 	atomic_set_bit(inst->active_index_subscription.flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE);
449 
450 	err = bt_gatt_subscribe(inst->conn, &inst->active_index_subscription);
451 	if (err != 0 && err != -EALREADY) {
452 		return err;
453 	}
454 
455 	return 0;
456 }
457 
active_index_read_cb(struct bt_conn * conn,uint8_t att_err,struct bt_gatt_read_params * params,const void * data,uint16_t len)458 static uint8_t active_index_read_cb(struct bt_conn *conn, uint8_t att_err,
459 				    struct bt_gatt_read_params *params, const void *data,
460 				    uint16_t len)
461 {
462 	struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, params.read);
463 	int err = att_err;
464 
465 	LOG_DBG("conn %p att_err 0x%02x params %p data %p len %u", (void *)conn, att_err, params,
466 		data, len);
467 
468 	if (att_err != BT_ATT_ERR_SUCCESS || len == 0) {
469 		goto fail;
470 	}
471 
472 	active_index_update(inst, data, len);
473 
474 	err = active_index_subscribe(inst, params->by_uuid.start_handle);
475 	if (err) {
476 		LOG_ERR("Subscribe failed (err %d)", err);
477 		goto fail;
478 	}
479 
480 	return BT_GATT_ITER_STOP;
481 
482 fail:
483 	/* Cleanup instance so that it can be reused */
484 	inst_cleanup(inst);
485 
486 	discover_failed(conn, err);
487 
488 	return BT_GATT_ITER_STOP;
489 }
490 
active_index_read(struct bt_has_client * inst)491 static int active_index_read(struct bt_has_client *inst)
492 {
493 	LOG_DBG("conn %p", (void *)inst->conn);
494 
495 	(void)memset(&inst->params.read, 0, sizeof(inst->params.read));
496 
497 	(void)memcpy(&inst->params.uuid, BT_UUID_HAS_ACTIVE_PRESET_INDEX,
498 		     sizeof(inst->params.uuid));
499 	inst->params.read.func = active_index_read_cb;
500 	inst->params.read.handle_count = 0u;
501 	inst->params.read.by_uuid.uuid = &inst->params.uuid.uuid;
502 	inst->params.read.by_uuid.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
503 	inst->params.read.by_uuid.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
504 
505 	return bt_gatt_read(inst->conn, &inst->params.read);
506 }
507 
control_point_subscribe_cb(struct bt_conn * conn,uint8_t att_err,struct bt_gatt_subscribe_params * params)508 static void control_point_subscribe_cb(struct bt_conn *conn, uint8_t att_err,
509 				       struct bt_gatt_subscribe_params *params)
510 {
511 	struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client,
512 						  control_point_subscription);
513 	int err = att_err;
514 
515 	LOG_DBG("conn %p att_err 0x%02x", (void *)inst->conn, att_err);
516 
517 	if (att_err != BT_ATT_ERR_SUCCESS) {
518 		goto fail;
519 	}
520 
521 	err = active_index_read(inst);
522 	if (err) {
523 		LOG_ERR("Active Preset Index read failed (err %d)", err);
524 		goto fail;
525 	}
526 
527 	return;
528 
529 fail:
530 	/* Cleanup instance so that it can be reused */
531 	inst_cleanup(inst);
532 
533 	discover_failed(conn, err);
534 }
535 
control_point_subscribe(struct bt_has_client * inst,uint16_t value_handle,uint8_t properties)536 static int control_point_subscribe(struct bt_has_client *inst, uint16_t value_handle,
537 				   uint8_t properties)
538 {
539 	int err;
540 
541 	LOG_DBG("conn %p handle 0x%04x", (void *)inst->conn, value_handle);
542 
543 	inst->control_point_subscription.notify = control_point_notify_cb;
544 	inst->control_point_subscription.subscribe = control_point_subscribe_cb;
545 	inst->control_point_subscription.value_handle = value_handle;
546 	inst->control_point_subscription.ccc_handle = 0x0000;
547 	inst->control_point_subscription.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
548 	inst->control_point_subscription.disc_params = &inst->params.discover;
549 	atomic_set_bit(inst->control_point_subscription.flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE);
550 
551 	if (IS_ENABLED(CONFIG_BT_EATT) && properties & BT_GATT_CHRC_NOTIFY) {
552 		inst->control_point_subscription.value = BT_GATT_CCC_INDICATE | BT_GATT_CCC_NOTIFY;
553 	} else {
554 		inst->control_point_subscription.value = BT_GATT_CCC_INDICATE;
555 	}
556 
557 	err = bt_gatt_subscribe(inst->conn, &inst->control_point_subscription);
558 	if (err != 0 && err != -EALREADY) {
559 		return err;
560 	}
561 
562 	return 0;
563 }
564 
control_point_discover_cb(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)565 static uint8_t control_point_discover_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr,
566 					 struct bt_gatt_discover_params *params)
567 {
568 	struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, params.discover);
569 	const struct bt_gatt_chrc *chrc;
570 	int err;
571 
572 	LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params);
573 
574 	if (!attr) {
575 		LOG_INF("Control Point not found");
576 		discover_complete(inst);
577 		return BT_GATT_ITER_STOP;
578 	}
579 
580 	chrc = attr->user_data;
581 
582 	err = control_point_subscribe(inst, chrc->value_handle, chrc->properties);
583 	if (err) {
584 		LOG_ERR("Subscribe failed (err %d)", err);
585 
586 		/* Cleanup instance so that it can be reused */
587 		inst_cleanup(inst);
588 
589 		discover_failed(conn, err);
590 	}
591 
592 	return BT_GATT_ITER_STOP;
593 }
594 
control_point_discover(struct bt_has_client * inst)595 static int control_point_discover(struct bt_has_client *inst)
596 {
597 	LOG_DBG("conn %p", (void *)inst->conn);
598 
599 	(void)memset(&inst->params.discover, 0, sizeof(inst->params.discover));
600 
601 	(void)memcpy(&inst->params.uuid, BT_UUID_HAS_PRESET_CONTROL_POINT,
602 		     sizeof(inst->params.uuid));
603 	inst->params.discover.uuid = &inst->params.uuid.uuid;
604 	inst->params.discover.func = control_point_discover_cb;
605 	inst->params.discover.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
606 	inst->params.discover.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
607 	inst->params.discover.type = BT_GATT_DISCOVER_CHARACTERISTIC;
608 
609 	return bt_gatt_discover(inst->conn, &inst->params.discover);
610 }
611 
features_update(struct bt_has_client * inst,const void * data,uint16_t len)612 static void features_update(struct bt_has_client *inst, const void *data, uint16_t len)
613 {
614 	struct net_buf_simple buf;
615 
616 	net_buf_simple_init_with_data(&buf, (void *)data, len);
617 
618 	inst->has.features = net_buf_simple_pull_u8(&buf);
619 
620 	LOG_DBG("conn %p features 0x%02x", (void *)inst->conn, inst->has.features);
621 }
622 
features_read_cb(struct bt_conn * conn,uint8_t att_err,struct bt_gatt_read_params * params,const void * data,uint16_t len)623 static uint8_t features_read_cb(struct bt_conn *conn, uint8_t att_err,
624 				struct bt_gatt_read_params *params, const void *data, uint16_t len)
625 {
626 	struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, params.read);
627 	int err = att_err;
628 
629 	LOG_DBG("conn %p att_err 0x%02x params %p data %p len %u", (void *)conn, att_err, params,
630 		data, len);
631 
632 	if (att_err != BT_ATT_ERR_SUCCESS || len == 0) {
633 		goto fail;
634 	}
635 
636 	features_update(inst, data, len);
637 
638 	if (!client_cb->preset_switch) {
639 		/* Complete the discovery if client is not interested in active preset changes */
640 		discover_complete(inst);
641 		return BT_GATT_ITER_STOP;
642 	}
643 
644 	err = control_point_discover(inst);
645 	if (err) {
646 		LOG_ERR("Control Point discover failed (err %d)", err);
647 		goto fail;
648 	}
649 
650 	return BT_GATT_ITER_STOP;
651 
652 fail:
653 	/* Cleanup instance so that it can be reused */
654 	inst_cleanup(inst);
655 
656 	discover_failed(conn, err);
657 
658 	return BT_GATT_ITER_STOP;
659 }
660 
features_read(struct bt_has_client * inst,uint16_t value_handle)661 static int features_read(struct bt_has_client *inst, uint16_t value_handle)
662 {
663 	LOG_DBG("conn %p handle 0x%04x", (void *)inst->conn, value_handle);
664 
665 	(void)memset(&inst->params.read, 0, sizeof(inst->params.read));
666 
667 	inst->params.read.func = features_read_cb;
668 	inst->params.read.handle_count = 1u;
669 	inst->params.read.single.handle = value_handle;
670 	inst->params.read.single.offset = 0u;
671 
672 	return bt_gatt_read(inst->conn, &inst->params.read);
673 }
674 
features_subscribe_cb(struct bt_conn * conn,uint8_t att_err,struct bt_gatt_subscribe_params * params)675 static void features_subscribe_cb(struct bt_conn *conn, uint8_t att_err,
676 				  struct bt_gatt_subscribe_params *params)
677 {
678 	struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client,
679 						  features_subscription);
680 	int err = att_err;
681 
682 	LOG_DBG("conn %p att_err 0x%02x params %p", (void *)conn, att_err, params);
683 
684 	if (att_err != BT_ATT_ERR_SUCCESS) {
685 		goto fail;
686 	}
687 
688 	err = features_read(inst, inst->features_subscription.value_handle);
689 	if (err) {
690 		LOG_ERR("Read failed (err %d)", err);
691 		goto fail;
692 	}
693 
694 	return;
695 
696 fail:
697 	/* Cleanup instance so that it can be reused */
698 	inst_cleanup(inst);
699 
700 	discover_failed(conn, err);
701 }
702 
features_notify_cb(struct bt_conn * conn,struct bt_gatt_subscribe_params * params,const void * data,uint16_t len)703 static uint8_t features_notify_cb(struct bt_conn *conn, struct bt_gatt_subscribe_params *params,
704 				  const void *data, uint16_t len)
705 {
706 	struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client,
707 						  features_subscription);
708 
709 	LOG_DBG("conn %p params %p data %p len %u", (void *)conn, params, data, len);
710 
711 	if (!conn) {
712 		/* Unpaired, stop receiving notifications from device */
713 		return BT_GATT_ITER_STOP;
714 	}
715 
716 	if (!data) {
717 		/* Unsubscribed */
718 		params->value_handle = 0u;
719 
720 		return BT_GATT_ITER_STOP;
721 	}
722 
723 	if (len == 0) {
724 		/* Ignore empty notification */
725 		return BT_GATT_ITER_CONTINUE;
726 	}
727 
728 	features_update(inst, data, len);
729 
730 	return BT_GATT_ITER_CONTINUE;
731 }
732 
features_subscribe(struct bt_has_client * inst,uint16_t value_handle)733 static int features_subscribe(struct bt_has_client *inst, uint16_t value_handle)
734 {
735 	int err;
736 
737 	LOG_DBG("conn %p handle 0x%04x", (void *)inst->conn, value_handle);
738 
739 	inst->features_subscription.notify = features_notify_cb;
740 	inst->features_subscription.subscribe = features_subscribe_cb;
741 	inst->features_subscription.value_handle = value_handle;
742 	inst->features_subscription.ccc_handle = 0x0000;
743 	inst->features_subscription.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
744 	inst->features_subscription.disc_params = &inst->params.discover;
745 	inst->features_subscription.value = BT_GATT_CCC_NOTIFY;
746 	atomic_set_bit(inst->features_subscription.flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE);
747 
748 	err = bt_gatt_subscribe(inst->conn, &inst->features_subscription);
749 	if (err != 0 && err != -EALREADY) {
750 		return err;
751 	}
752 
753 	return 0;
754 }
755 
features_discover_cb(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)756 static uint8_t features_discover_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr,
757 				    struct bt_gatt_discover_params *params)
758 {
759 	struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, params.discover);
760 	const struct bt_gatt_chrc *chrc;
761 	int err;
762 
763 	LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params);
764 
765 	if (!attr) {
766 		err = -ENOENT;
767 		goto fail;
768 	}
769 
770 	chrc = attr->user_data;
771 
772 	/* Subscribe first if notifications are supported, otherwise read the features */
773 	if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
774 		err = features_subscribe(inst, chrc->value_handle);
775 		if (err) {
776 			LOG_ERR("Subscribe failed (err %d)", err);
777 			goto fail;
778 		}
779 	} else {
780 		err = features_read(inst, chrc->value_handle);
781 		if (err) {
782 			LOG_ERR("Read failed (err %d)", err);
783 			goto fail;
784 		}
785 	}
786 
787 	return BT_GATT_ITER_STOP;
788 
789 fail:
790 	/* Cleanup instance so that it can be reused */
791 	inst_cleanup(inst);
792 
793 	discover_failed(conn, err);
794 
795 	return BT_GATT_ITER_STOP;
796 }
797 
features_discover(struct bt_has_client * inst)798 static int features_discover(struct bt_has_client *inst)
799 {
800 	LOG_DBG("conn %p", (void *)inst->conn);
801 
802 	(void)memset(&inst->params.discover, 0, sizeof(inst->params.discover));
803 
804 	(void)memcpy(&inst->params.uuid, BT_UUID_HAS_HEARING_AID_FEATURES,
805 		     sizeof(inst->params.uuid));
806 	inst->params.discover.uuid = &inst->params.uuid.uuid;
807 	inst->params.discover.func = features_discover_cb;
808 	inst->params.discover.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
809 	inst->params.discover.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
810 	inst->params.discover.type = BT_GATT_DISCOVER_CHARACTERISTIC;
811 
812 	return bt_gatt_discover(inst->conn, &inst->params.discover);
813 }
814 
bt_has_client_cb_register(const struct bt_has_client_cb * cb)815 int bt_has_client_cb_register(const struct bt_has_client_cb *cb)
816 {
817 	CHECKIF(!cb) {
818 		return -EINVAL;
819 	}
820 
821 	CHECKIF(client_cb) {
822 		return -EALREADY;
823 	}
824 
825 	client_cb = cb;
826 
827 	return 0;
828 }
829 
830 /* Hearing Access Service discovery
831  *
832  * This will initiate a discover procedure. The procedure will do the following sequence:
833  * 1) HAS related characteristic discovery
834  * 2) CCC subscription
835  * 3) Hearing Aid Features and Active Preset Index characteristic read
836  * 5) When everything above have been completed, the callback is called
837  */
bt_has_client_discover(struct bt_conn * conn)838 int bt_has_client_discover(struct bt_conn *conn)
839 {
840 	struct bt_has_client *inst;
841 	int err;
842 
843 	LOG_DBG("conn %p", (void *)conn);
844 
845 	CHECKIF(!conn || !client_cb || !client_cb->discover) {
846 		return -EINVAL;
847 	}
848 
849 	inst = &clients[bt_conn_index(conn)];
850 
851 	if (atomic_test_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS) ||
852 	    atomic_test_and_set_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS)) {
853 		return -EBUSY;
854 	}
855 
856 	if (inst->conn) {
857 		return -EALREADY;
858 	}
859 
860 	inst->conn = bt_conn_ref(conn);
861 
862 	err = features_discover(inst);
863 	if (err) {
864 		atomic_clear_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS);
865 	}
866 
867 	return err;
868 }
869 
bt_has_client_conn_get(const struct bt_has * has,struct bt_conn ** conn)870 int bt_has_client_conn_get(const struct bt_has *has, struct bt_conn **conn)
871 {
872 	struct bt_has_client *inst = HAS_INST(has);
873 
874 	*conn = bt_conn_ref(inst->conn);
875 
876 	return 0;
877 }
878 
bt_has_client_presets_read(struct bt_has * has,uint8_t start_index,uint8_t count)879 int bt_has_client_presets_read(struct bt_has *has, uint8_t start_index, uint8_t count)
880 {
881 	struct bt_has_client *inst = HAS_INST(has);
882 	int err;
883 
884 	LOG_DBG("conn %p start_index 0x%02x count %d", (void *)inst->conn, start_index, count);
885 
886 	if (!inst->conn) {
887 		return -ENOTCONN;
888 	}
889 
890 	if (atomic_test_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS) ||
891 	    atomic_test_and_set_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS)) {
892 		return -EBUSY;
893 	}
894 
895 	CHECKIF(start_index == BT_HAS_PRESET_INDEX_NONE) {
896 		return -EINVAL;
897 	}
898 
899 	CHECKIF(count == 0u) {
900 		return -EINVAL;
901 	}
902 
903 	err = read_presets_req(inst, start_index, count);
904 	if (err) {
905 		atomic_clear_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS);
906 	}
907 
908 	return err;
909 }
910 
bt_has_client_preset_set(struct bt_has * has,uint8_t index,bool sync)911 int bt_has_client_preset_set(struct bt_has *has, uint8_t index, bool sync)
912 {
913 	struct bt_has_client *inst = HAS_INST(has);
914 	uint8_t opcode;
915 
916 	LOG_DBG("conn %p index 0x%02x", (void *)inst->conn, index);
917 
918 	if (!inst->conn) {
919 		return -ENOTCONN;
920 	}
921 
922 	CHECKIF(index == BT_HAS_PRESET_INDEX_NONE) {
923 		return -EINVAL;
924 	}
925 
926 	if (sync && (inst->has.features & BT_HAS_FEAT_PRESET_SYNC_SUPP) == 0) {
927 		return -EOPNOTSUPP;
928 	}
929 
930 	if (atomic_test_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS) ||
931 	    atomic_test_and_set_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS)) {
932 		return -EBUSY;
933 	}
934 
935 	opcode = sync ? BT_HAS_OP_SET_ACTIVE_PRESET_SYNC : BT_HAS_OP_SET_ACTIVE_PRESET;
936 
937 	return preset_set(inst, opcode, index);
938 }
939 
bt_has_client_preset_next(struct bt_has * has,bool sync)940 int bt_has_client_preset_next(struct bt_has *has, bool sync)
941 {
942 	struct bt_has_client *inst = HAS_INST(has);
943 	uint8_t opcode;
944 
945 	LOG_DBG("conn %p sync %d", (void *)inst->conn, sync);
946 
947 	if (!inst->conn) {
948 		return -ENOTCONN;
949 	}
950 
951 	if (sync && (inst->has.features & BT_HAS_FEAT_PRESET_SYNC_SUPP) == 0) {
952 		return -EOPNOTSUPP;
953 	}
954 
955 	if (atomic_test_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS) ||
956 	    atomic_test_and_set_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS)) {
957 		return -EBUSY;
958 	}
959 
960 	opcode = sync ? BT_HAS_OP_SET_NEXT_PRESET_SYNC : BT_HAS_OP_SET_NEXT_PRESET;
961 
962 	return preset_set_next_or_prev(inst, opcode);
963 }
964 
bt_has_client_preset_prev(struct bt_has * has,bool sync)965 int bt_has_client_preset_prev(struct bt_has *has, bool sync)
966 {
967 	struct bt_has_client *inst = HAS_INST(has);
968 	uint8_t opcode;
969 
970 	LOG_DBG("conn %p sync %d", (void *)inst->conn, sync);
971 
972 	if (!inst->conn) {
973 		return -ENOTCONN;
974 	}
975 
976 	if (sync && (inst->has.features & BT_HAS_FEAT_PRESET_SYNC_SUPP) == 0) {
977 		return -EOPNOTSUPP;
978 	}
979 
980 	if (atomic_test_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS) ||
981 	    atomic_test_and_set_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS)) {
982 		return -EBUSY;
983 	}
984 
985 	opcode = sync ? BT_HAS_OP_SET_PREV_PRESET_SYNC : BT_HAS_OP_SET_PREV_PRESET;
986 
987 	return preset_set_next_or_prev(inst, opcode);
988 }
989 
disconnected(struct bt_conn * conn,uint8_t reason)990 static void disconnected(struct bt_conn *conn, uint8_t reason)
991 {
992 	struct bt_has_client *inst = inst_by_conn(conn);
993 
994 	if (!inst) {
995 		return;
996 	}
997 
998 	if (atomic_test_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS)) {
999 		discover_failed(conn, -ECONNABORTED);
1000 	}
1001 
1002 	inst_cleanup(inst);
1003 }
1004 
1005 BT_CONN_CB_DEFINE(conn_cb) = {
1006 	.disconnected = disconnected,
1007 };
1008