1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
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 
13 #include <zephyr/autoconf.h>
14 #include <zephyr/bluetooth/att.h>
15 #include <zephyr/bluetooth/audio/gmap.h>
16 #include <zephyr/bluetooth/conn.h>
17 #include <zephyr/bluetooth/gatt.h>
18 #include <zephyr/bluetooth/uuid.h>
19 #include <zephyr/logging/log.h>
20 #include <zephyr/net_buf.h>
21 #include <zephyr/sys/__assert.h>
22 #include <zephyr/sys/atomic.h>
23 #include <zephyr/sys/check.h>
24 
25 #include "audio_internal.h"
26 
27 LOG_MODULE_REGISTER(bt_gmap_client, CONFIG_BT_GMAP_LOG_LEVEL);
28 
29 static const struct bt_uuid *gmas_uuid = BT_UUID_GMAS;
30 static const struct bt_uuid *gmap_role_uuid = BT_UUID_GMAP_ROLE;
31 static const struct bt_uuid *gmap_ugg_feat_uuid = BT_UUID_GMAP_UGG_FEAT;
32 static const struct bt_uuid *gmap_ugt_feat_uuid = BT_UUID_GMAP_UGT_FEAT;
33 static const struct bt_uuid *gmap_bgs_feat_uuid = BT_UUID_GMAP_BGS_FEAT;
34 static const struct bt_uuid *gmap_bgr_feat_uuid = BT_UUID_GMAP_BGR_FEAT;
35 
36 static const struct bt_gmap_cb *gmap_cb;
37 
38 enum gmap_client_flag {
39 	GMAP_CLIENT_FLAG_BUSY,
40 
41 	GMAP_CLIENT_FLAG_NUM_FLAGS, /* keep as last */
42 };
43 
44 static struct bt_gmap_client {
45 	/** Profile connection reference */
46 	struct bt_conn *conn;
47 
48 	/* Remote role and features */
49 	enum bt_gmap_role role;
50 	struct bt_gmap_feat feat;
51 
52 	uint16_t svc_start_handle;
53 	uint16_t svc_end_handle;
54 
55 	/* GATT procedure parameters */
56 	union {
57 		struct bt_gatt_read_params read;
58 		struct bt_gatt_discover_params discover;
59 	} params;
60 
61 	ATOMIC_DEFINE(flags, GMAP_CLIENT_FLAG_NUM_FLAGS);
62 } gmap_insts[CONFIG_BT_MAX_CONN];
63 
gmap_reset(struct bt_gmap_client * gmap_cli)64 static void gmap_reset(struct bt_gmap_client *gmap_cli)
65 {
66 	if (gmap_cli->conn != NULL) {
67 		bt_conn_unref(gmap_cli->conn);
68 	}
69 
70 	memset(gmap_cli, 0, sizeof(*gmap_cli));
71 }
72 
client_by_conn(struct bt_conn * conn)73 static struct bt_gmap_client *client_by_conn(struct bt_conn *conn)
74 {
75 	struct bt_gmap_client *gmap_cli = &gmap_insts[bt_conn_index(conn)];
76 
77 	if (gmap_cli->conn == conn) {
78 		return gmap_cli;
79 	}
80 
81 	return NULL;
82 }
83 
disconnected(struct bt_conn * conn,uint8_t reason)84 static void disconnected(struct bt_conn *conn, uint8_t reason)
85 {
86 	struct bt_gmap_client *gmap_cli = client_by_conn(conn);
87 
88 	if (gmap_cli != NULL) {
89 		bt_conn_unref(gmap_cli->conn);
90 		gmap_cli->conn = NULL;
91 	}
92 }
93 
94 BT_CONN_CB_DEFINE(conn_callbacks) = {
95 	.disconnected = disconnected,
96 };
97 
discover_complete(struct bt_gmap_client * gmap_cli)98 static void discover_complete(struct bt_gmap_client *gmap_cli)
99 {
100 	LOG_DBG("conn %p", (void *)gmap_cli->conn);
101 
102 	atomic_clear_bit(gmap_cli->flags, GMAP_CLIENT_FLAG_BUSY);
103 
104 	if (gmap_cb->discover != NULL) {
105 		gmap_cb->discover(gmap_cli->conn, 0, gmap_cli->role, gmap_cli->feat);
106 	}
107 }
108 
discover_failed(struct bt_gmap_client * gmap_cli,int err)109 static void discover_failed(struct bt_gmap_client *gmap_cli, int err)
110 {
111 	struct bt_conn *conn = gmap_cli->conn;
112 
113 	gmap_reset(gmap_cli);
114 
115 	LOG_DBG("conn %p err %d", (void *)conn, err);
116 
117 	gmap_cb->discover(conn, err, 0, (struct bt_gmap_feat){0});
118 }
119 
bgr_feat_read_cb(struct bt_conn * conn,uint8_t att_err,struct bt_gatt_read_params * params,const void * data,uint16_t len)120 static uint8_t bgr_feat_read_cb(struct bt_conn *conn, uint8_t att_err,
121 				struct bt_gatt_read_params *params, const void *data, uint16_t len)
122 {
123 	struct bt_gmap_client *gmap_cli = client_by_conn(conn);
124 	struct net_buf_simple buf;
125 	int err = att_err;
126 
127 	__ASSERT(gmap_cli, "no instance for conn %p", (void *)conn);
128 
129 	LOG_DBG("conn %p att_err 0x%02x params %p data %p len %u", (void *)conn, att_err, params,
130 		data, len);
131 
132 	if (data == NULL || att_err != BT_ATT_ERR_SUCCESS || len != sizeof(uint8_t)) {
133 		if (att_err == BT_ATT_ERR_SUCCESS) {
134 			att_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
135 		}
136 
137 		discover_failed(gmap_cli, err);
138 
139 		return BT_GATT_ITER_STOP;
140 	}
141 
142 	net_buf_simple_init_with_data(&buf, (void *)data, len);
143 
144 	gmap_cli->feat.bgr_feat = net_buf_simple_pull_u8(&buf);
145 	LOG_DBG("bgr_feat 0x%02x", gmap_cli->feat.bgr_feat);
146 
147 	discover_complete(gmap_cli);
148 
149 	return BT_GATT_ITER_STOP;
150 }
151 
gmap_read_bgr_feat(struct bt_gmap_client * gmap_cli,uint16_t handle)152 static int gmap_read_bgr_feat(struct bt_gmap_client *gmap_cli, uint16_t handle)
153 {
154 	LOG_DBG("conn %p handle 0x%04x", (void *)gmap_cli->conn, handle);
155 
156 	memset(&gmap_cli->params.read, 0, sizeof(gmap_cli->params.read));
157 
158 	gmap_cli->params.read.func = bgr_feat_read_cb;
159 	gmap_cli->params.read.handle_count = 1u;
160 	gmap_cli->params.read.single.handle = handle;
161 	gmap_cli->params.read.single.offset = 0u;
162 
163 	return bt_gatt_read(gmap_cli->conn, &gmap_cli->params.read);
164 }
165 
bgr_feat_discover_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)166 static uint8_t bgr_feat_discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr,
167 				      struct bt_gatt_discover_params *params)
168 {
169 	struct bt_gmap_client *gmap_cli = client_by_conn(conn);
170 	const struct bt_gatt_chrc *chrc;
171 	int err;
172 
173 	__ASSERT(gmap_cli != NULL, "no instance for conn %p", (void *)conn);
174 
175 	LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params);
176 
177 	if (attr == NULL) {
178 		discover_failed(gmap_cli, -ENOENT);
179 
180 		return BT_GATT_ITER_STOP;
181 	}
182 
183 	chrc = attr->user_data;
184 
185 	/* Read features */
186 	err = gmap_read_bgr_feat(gmap_cli, chrc->value_handle);
187 	if (err != 0) {
188 		discover_failed(gmap_cli, err);
189 	}
190 
191 	return BT_GATT_ITER_STOP;
192 }
193 
gmap_discover_bgr_feat(struct bt_gmap_client * gmap_cli)194 static int gmap_discover_bgr_feat(struct bt_gmap_client *gmap_cli)
195 {
196 	LOG_DBG("conn %p", (void *)gmap_cli->conn);
197 
198 	memset(&gmap_cli->params.discover, 0, sizeof(gmap_cli->params.discover));
199 
200 	gmap_cli->params.discover.func = bgr_feat_discover_func;
201 	gmap_cli->params.discover.uuid = gmap_bgr_feat_uuid;
202 	gmap_cli->params.discover.type = BT_GATT_DISCOVER_CHARACTERISTIC;
203 	gmap_cli->params.discover.start_handle = gmap_cli->svc_start_handle;
204 	gmap_cli->params.discover.end_handle = gmap_cli->svc_end_handle;
205 
206 	return bt_gatt_discover(gmap_cli->conn, &gmap_cli->params.discover);
207 }
208 
bgs_feat_read_cb(struct bt_conn * conn,uint8_t att_err,struct bt_gatt_read_params * params,const void * data,uint16_t len)209 static uint8_t bgs_feat_read_cb(struct bt_conn *conn, uint8_t att_err,
210 				struct bt_gatt_read_params *params, const void *data, uint16_t len)
211 {
212 	struct bt_gmap_client *gmap_cli = client_by_conn(conn);
213 	struct net_buf_simple buf;
214 	int err = att_err;
215 
216 	__ASSERT(gmap_cli, "no instance for conn %p", (void *)conn);
217 
218 	LOG_DBG("conn %p att_err 0x%02x params %p data %p len %u", (void *)conn, att_err, params,
219 		data, len);
220 
221 	if (data == NULL || att_err != BT_ATT_ERR_SUCCESS || len != sizeof(uint8_t)) {
222 		if (att_err == BT_ATT_ERR_SUCCESS) {
223 			att_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
224 		}
225 
226 		discover_failed(gmap_cli, err);
227 
228 		return BT_GATT_ITER_STOP;
229 	}
230 
231 	net_buf_simple_init_with_data(&buf, (void *)data, len);
232 
233 	gmap_cli->feat.bgs_feat = net_buf_simple_pull_u8(&buf);
234 	LOG_DBG("bgs_feat 0x%02x", gmap_cli->feat.bgs_feat);
235 
236 	if ((gmap_cli->role & BT_GMAP_ROLE_BGR) != 0) {
237 		err = gmap_discover_bgr_feat(gmap_cli);
238 	} else {
239 		discover_complete(gmap_cli);
240 
241 		return BT_GATT_ITER_STOP;
242 	}
243 
244 	if (err) {
245 		discover_failed(gmap_cli, err);
246 	}
247 
248 	return BT_GATT_ITER_STOP;
249 }
250 
gmap_read_bgs_feat(struct bt_gmap_client * gmap_cli,uint16_t handle)251 static int gmap_read_bgs_feat(struct bt_gmap_client *gmap_cli, uint16_t handle)
252 {
253 	LOG_DBG("conn %p handle 0x%04x", (void *)gmap_cli->conn, handle);
254 
255 	memset(&gmap_cli->params.read, 0, sizeof(gmap_cli->params.read));
256 
257 	gmap_cli->params.read.func = bgs_feat_read_cb;
258 	gmap_cli->params.read.handle_count = 1u;
259 	gmap_cli->params.read.single.handle = handle;
260 	gmap_cli->params.read.single.offset = 0u;
261 
262 	return bt_gatt_read(gmap_cli->conn, &gmap_cli->params.read);
263 }
264 
bgs_feat_discover_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)265 static uint8_t bgs_feat_discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr,
266 				      struct bt_gatt_discover_params *params)
267 {
268 	struct bt_gmap_client *gmap_cli = client_by_conn(conn);
269 	const struct bt_gatt_chrc *chrc;
270 	int err;
271 
272 	__ASSERT(gmap_cli != NULL, "no instance for conn %p", (void *)conn);
273 
274 	LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params);
275 
276 	if (attr == NULL) {
277 		discover_failed(gmap_cli, -ENOENT);
278 
279 		return BT_GATT_ITER_STOP;
280 	}
281 
282 	chrc = attr->user_data;
283 
284 	/* Read features */
285 	err = gmap_read_bgs_feat(gmap_cli, chrc->value_handle);
286 	if (err != 0) {
287 		discover_failed(gmap_cli, err);
288 	}
289 
290 	return BT_GATT_ITER_STOP;
291 }
292 
gmap_discover_bgs_feat(struct bt_gmap_client * gmap_cli)293 static int gmap_discover_bgs_feat(struct bt_gmap_client *gmap_cli)
294 {
295 	LOG_DBG("conn %p", (void *)gmap_cli->conn);
296 
297 	memset(&gmap_cli->params.discover, 0, sizeof(gmap_cli->params.discover));
298 
299 	gmap_cli->params.discover.func = bgs_feat_discover_func;
300 	gmap_cli->params.discover.uuid = gmap_bgs_feat_uuid;
301 	gmap_cli->params.discover.type = BT_GATT_DISCOVER_CHARACTERISTIC;
302 	gmap_cli->params.discover.start_handle = gmap_cli->svc_start_handle;
303 	gmap_cli->params.discover.end_handle = gmap_cli->svc_end_handle;
304 
305 	return bt_gatt_discover(gmap_cli->conn, &gmap_cli->params.discover);
306 }
307 
ugt_feat_read_cb(struct bt_conn * conn,uint8_t att_err,struct bt_gatt_read_params * params,const void * data,uint16_t len)308 static uint8_t ugt_feat_read_cb(struct bt_conn *conn, uint8_t att_err,
309 				struct bt_gatt_read_params *params, const void *data, uint16_t len)
310 {
311 	struct bt_gmap_client *gmap_cli = client_by_conn(conn);
312 	struct net_buf_simple buf;
313 	int err = att_err;
314 
315 	__ASSERT(gmap_cli, "no instance for conn %p", (void *)conn);
316 
317 	LOG_DBG("conn %p att_err 0x%02x params %p data %p len %u", (void *)conn, att_err, params,
318 		data, len);
319 
320 	if (data == NULL || att_err != BT_ATT_ERR_SUCCESS || len != sizeof(uint8_t)) {
321 		if (att_err == BT_ATT_ERR_SUCCESS) {
322 			att_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
323 		}
324 
325 		discover_failed(gmap_cli, err);
326 
327 		return BT_GATT_ITER_STOP;
328 	}
329 
330 	net_buf_simple_init_with_data(&buf, (void *)data, len);
331 
332 	gmap_cli->feat.ugt_feat = net_buf_simple_pull_u8(&buf);
333 	LOG_DBG("ugt_feat 0x%02x", gmap_cli->feat.ugt_feat);
334 
335 	if ((gmap_cli->role & BT_GMAP_ROLE_BGS) != 0) {
336 		err = gmap_discover_bgs_feat(gmap_cli);
337 	} else if ((gmap_cli->role & BT_GMAP_ROLE_BGR) != 0) {
338 		err = gmap_discover_bgr_feat(gmap_cli);
339 	} else {
340 		discover_complete(gmap_cli);
341 
342 		return BT_GATT_ITER_STOP;
343 	}
344 
345 	if (err) {
346 		discover_failed(gmap_cli, err);
347 	}
348 
349 	return BT_GATT_ITER_STOP;
350 }
351 
gmap_read_ugt_feat(struct bt_gmap_client * gmap_cli,uint16_t handle)352 static int gmap_read_ugt_feat(struct bt_gmap_client *gmap_cli, uint16_t handle)
353 {
354 	LOG_DBG("conn %p handle 0x%04x", (void *)gmap_cli->conn, handle);
355 
356 	memset(&gmap_cli->params.read, 0, sizeof(gmap_cli->params.read));
357 
358 	gmap_cli->params.read.func = ugt_feat_read_cb;
359 	gmap_cli->params.read.handle_count = 1u;
360 	gmap_cli->params.read.single.handle = handle;
361 	gmap_cli->params.read.single.offset = 0u;
362 
363 	return bt_gatt_read(gmap_cli->conn, &gmap_cli->params.read);
364 }
365 
ugt_feat_discover_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)366 static uint8_t ugt_feat_discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr,
367 				      struct bt_gatt_discover_params *params)
368 {
369 	struct bt_gmap_client *gmap_cli = client_by_conn(conn);
370 	const struct bt_gatt_chrc *chrc;
371 	int err;
372 
373 	__ASSERT(gmap_cli != NULL, "no instance for conn %p", (void *)conn);
374 
375 	LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params);
376 
377 	if (attr == NULL) {
378 		discover_failed(gmap_cli, -ENOENT);
379 
380 		return BT_GATT_ITER_STOP;
381 	}
382 
383 	chrc = attr->user_data;
384 
385 	/* Read features */
386 	err = gmap_read_ugt_feat(gmap_cli, chrc->value_handle);
387 	if (err != 0) {
388 		discover_failed(gmap_cli, err);
389 	}
390 
391 	return BT_GATT_ITER_STOP;
392 }
393 
gmap_discover_ugt_feat(struct bt_gmap_client * gmap_cli)394 static int gmap_discover_ugt_feat(struct bt_gmap_client *gmap_cli)
395 {
396 	LOG_DBG("conn %p", (void *)gmap_cli->conn);
397 
398 	memset(&gmap_cli->params.discover, 0, sizeof(gmap_cli->params.discover));
399 
400 	gmap_cli->params.discover.func = ugt_feat_discover_func;
401 	gmap_cli->params.discover.uuid = gmap_ugt_feat_uuid;
402 	gmap_cli->params.discover.type = BT_GATT_DISCOVER_CHARACTERISTIC;
403 	gmap_cli->params.discover.start_handle = gmap_cli->svc_start_handle;
404 	gmap_cli->params.discover.end_handle = gmap_cli->svc_end_handle;
405 
406 	return bt_gatt_discover(gmap_cli->conn, &gmap_cli->params.discover);
407 }
408 
ugg_feat_read_cb(struct bt_conn * conn,uint8_t att_err,struct bt_gatt_read_params * params,const void * data,uint16_t len)409 static uint8_t ugg_feat_read_cb(struct bt_conn *conn, uint8_t att_err,
410 				struct bt_gatt_read_params *params, const void *data, uint16_t len)
411 {
412 	struct bt_gmap_client *gmap_cli = client_by_conn(conn);
413 	struct net_buf_simple buf;
414 	int err = att_err;
415 
416 	__ASSERT(gmap_cli, "no instance for conn %p", (void *)conn);
417 
418 	LOG_DBG("conn %p att_err 0x%02x params %p data %p len %u", (void *)conn, att_err, params,
419 		data, len);
420 
421 	if (data == NULL || att_err != BT_ATT_ERR_SUCCESS || len != sizeof(uint8_t)) {
422 		if (att_err == BT_ATT_ERR_SUCCESS) {
423 			att_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
424 		}
425 
426 		discover_failed(gmap_cli, err);
427 
428 		return BT_GATT_ITER_STOP;
429 	}
430 
431 	net_buf_simple_init_with_data(&buf, (void *)data, len);
432 
433 	gmap_cli->feat.ugg_feat = net_buf_simple_pull_u8(&buf);
434 	LOG_DBG("ugg_feat 0x%02x", gmap_cli->feat.ugg_feat);
435 
436 	if ((gmap_cli->role & BT_GMAP_ROLE_UGT) != 0) {
437 		err = gmap_discover_ugt_feat(gmap_cli);
438 	} else if ((gmap_cli->role & BT_GMAP_ROLE_BGS) != 0) {
439 		err = gmap_discover_bgs_feat(gmap_cli);
440 	} else if ((gmap_cli->role & BT_GMAP_ROLE_BGR) != 0) {
441 		err = gmap_discover_bgr_feat(gmap_cli);
442 	} else {
443 		discover_complete(gmap_cli);
444 
445 		return BT_GATT_ITER_STOP;
446 	}
447 
448 	if (err) {
449 		discover_failed(gmap_cli, err);
450 	}
451 
452 	return BT_GATT_ITER_STOP;
453 }
454 
gmap_read_ugg_feat(struct bt_gmap_client * gmap_cli,uint16_t handle)455 static int gmap_read_ugg_feat(struct bt_gmap_client *gmap_cli, uint16_t handle)
456 {
457 	LOG_DBG("conn %p handle 0x%04x", (void *)gmap_cli->conn, handle);
458 
459 	memset(&gmap_cli->params.read, 0, sizeof(gmap_cli->params.read));
460 
461 	gmap_cli->params.read.func = ugg_feat_read_cb;
462 	gmap_cli->params.read.handle_count = 1u;
463 	gmap_cli->params.read.single.handle = handle;
464 	gmap_cli->params.read.single.offset = 0u;
465 
466 	return bt_gatt_read(gmap_cli->conn, &gmap_cli->params.read);
467 }
468 
ugg_feat_discover_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)469 static uint8_t ugg_feat_discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr,
470 				      struct bt_gatt_discover_params *params)
471 {
472 	struct bt_gmap_client *gmap_cli = client_by_conn(conn);
473 	const struct bt_gatt_chrc *chrc;
474 	int err;
475 
476 	__ASSERT(gmap_cli != NULL, "no instance for conn %p", (void *)conn);
477 
478 	LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params);
479 
480 	if (attr == NULL) {
481 		discover_failed(gmap_cli, -ENOENT);
482 
483 		return BT_GATT_ITER_STOP;
484 	}
485 
486 	chrc = attr->user_data;
487 
488 	/* Read features */
489 	err = gmap_read_ugg_feat(gmap_cli, chrc->value_handle);
490 	if (err != 0) {
491 		discover_failed(gmap_cli, err);
492 	}
493 
494 	return BT_GATT_ITER_STOP;
495 }
496 
gmap_discover_ugg_feat(struct bt_gmap_client * gmap_cli)497 static int gmap_discover_ugg_feat(struct bt_gmap_client *gmap_cli)
498 {
499 	LOG_DBG("conn %p", (void *)gmap_cli->conn);
500 
501 	memset(&gmap_cli->params.discover, 0, sizeof(gmap_cli->params.discover));
502 
503 	gmap_cli->params.discover.func = ugg_feat_discover_func;
504 	gmap_cli->params.discover.uuid = gmap_ugg_feat_uuid;
505 	gmap_cli->params.discover.type = BT_GATT_DISCOVER_CHARACTERISTIC;
506 	gmap_cli->params.discover.start_handle = gmap_cli->svc_start_handle;
507 	gmap_cli->params.discover.end_handle = gmap_cli->svc_end_handle;
508 
509 	return bt_gatt_discover(gmap_cli->conn, &gmap_cli->params.discover);
510 }
511 
role_read_cb(struct bt_conn * conn,uint8_t att_err,struct bt_gatt_read_params * params,const void * data,uint16_t len)512 static uint8_t role_read_cb(struct bt_conn *conn, uint8_t att_err,
513 			    struct bt_gatt_read_params *params, const void *data, uint16_t len)
514 {
515 	struct bt_gmap_client *gmap_cli = client_by_conn(conn);
516 	struct net_buf_simple buf;
517 	int err = att_err;
518 
519 	__ASSERT(gmap_cli, "no instance for conn %p", (void *)conn);
520 
521 	LOG_DBG("conn %p att_err 0x%02x params %p data %p len %u", (void *)conn, att_err, params,
522 		data, len);
523 
524 	if (data == NULL || att_err != BT_ATT_ERR_SUCCESS || len != sizeof(uint8_t)) {
525 		if (att_err == BT_ATT_ERR_SUCCESS) {
526 			att_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
527 		}
528 
529 		discover_failed(gmap_cli, err);
530 
531 		return BT_GATT_ITER_STOP;
532 	}
533 
534 	net_buf_simple_init_with_data(&buf, (void *)data, len);
535 
536 	gmap_cli->role = net_buf_simple_pull_u8(&buf);
537 	LOG_DBG("role 0x%02x", gmap_cli->role);
538 
539 	if ((gmap_cli->role & BT_GMAP_ROLE_UGG) != 0) {
540 		err = gmap_discover_ugg_feat(gmap_cli);
541 	} else if ((gmap_cli->role & BT_GMAP_ROLE_UGT) != 0) {
542 		err = gmap_discover_ugt_feat(gmap_cli);
543 	} else if ((gmap_cli->role & BT_GMAP_ROLE_BGS) != 0) {
544 		err = gmap_discover_bgs_feat(gmap_cli);
545 	} else if ((gmap_cli->role & BT_GMAP_ROLE_BGR) != 0) {
546 		err = gmap_discover_bgr_feat(gmap_cli);
547 	} else {
548 		LOG_DBG("Remote device does not support any known roles");
549 		err = -ECANCELED;
550 	}
551 
552 	if (err) {
553 		discover_failed(gmap_cli, err);
554 	}
555 
556 	return BT_GATT_ITER_STOP;
557 }
558 
gmap_read_role(struct bt_gmap_client * gmap_cli,uint16_t handle)559 static int gmap_read_role(struct bt_gmap_client *gmap_cli, uint16_t handle)
560 {
561 	LOG_DBG("conn %p handle 0x%04x", (void *)gmap_cli->conn, handle);
562 
563 	memset(&gmap_cli->params.read, 0, sizeof(gmap_cli->params.read));
564 
565 	gmap_cli->params.read.func = role_read_cb;
566 	gmap_cli->params.read.handle_count = 1u;
567 	gmap_cli->params.read.single.handle = handle;
568 	gmap_cli->params.read.single.offset = 0u;
569 
570 	return bt_gatt_read(gmap_cli->conn, &gmap_cli->params.read);
571 }
572 
role_discover_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)573 static uint8_t role_discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr,
574 				  struct bt_gatt_discover_params *params)
575 {
576 	struct bt_gmap_client *gmap_cli = client_by_conn(conn);
577 	const struct bt_gatt_chrc *chrc;
578 	int err;
579 
580 	__ASSERT(gmap_cli != NULL, "no instance for conn %p", (void *)conn);
581 
582 	LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params);
583 
584 	if (attr == NULL) {
585 		discover_failed(gmap_cli, -ENOENT);
586 
587 		return BT_GATT_ITER_STOP;
588 	}
589 
590 	chrc = attr->user_data;
591 
592 	/* Read features */
593 	err = gmap_read_role(gmap_cli, chrc->value_handle);
594 	if (err != 0) {
595 		discover_failed(gmap_cli, err);
596 	}
597 
598 	return BT_GATT_ITER_STOP;
599 }
600 
gmap_discover_role(struct bt_gmap_client * gmap_cli)601 static int gmap_discover_role(struct bt_gmap_client *gmap_cli)
602 {
603 	LOG_DBG("conn %p", (void *)gmap_cli->conn);
604 
605 	memset(&gmap_cli->params.discover, 0, sizeof(gmap_cli->params.discover));
606 
607 	gmap_cli->params.discover.func = role_discover_func;
608 	gmap_cli->params.discover.uuid = gmap_role_uuid;
609 	gmap_cli->params.discover.type = BT_GATT_DISCOVER_CHARACTERISTIC;
610 	gmap_cli->params.discover.start_handle = gmap_cli->svc_start_handle;
611 	gmap_cli->params.discover.end_handle = gmap_cli->svc_end_handle;
612 
613 	return bt_gatt_discover(gmap_cli->conn, &gmap_cli->params.discover);
614 }
615 
gmas_discover_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)616 static uint8_t gmas_discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr,
617 				  struct bt_gatt_discover_params *params)
618 {
619 	struct bt_gmap_client *gmap_cli = client_by_conn(conn);
620 	const struct bt_gatt_service_val *svc;
621 	int err;
622 
623 	__ASSERT(gmap_cli != NULL, "no instance for conn %p", (void *)conn);
624 
625 	LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params);
626 
627 	if (attr == NULL) {
628 		discover_failed(gmap_cli, -ENOENT);
629 
630 		return BT_GATT_ITER_STOP;
631 	}
632 
633 	svc = (struct bt_gatt_service_val *)attr->user_data;
634 	gmap_cli->svc_start_handle = attr->handle;
635 	gmap_cli->svc_end_handle = svc->end_handle;
636 
637 	err = gmap_discover_role(gmap_cli);
638 	if (err != 0) {
639 		discover_failed(gmap_cli, err);
640 	}
641 
642 	return BT_GATT_ITER_STOP;
643 }
644 
bt_gmap_discover(struct bt_conn * conn)645 int bt_gmap_discover(struct bt_conn *conn)
646 {
647 	struct bt_gmap_client *gmap_cli;
648 	int err;
649 
650 	CHECKIF(conn == NULL) {
651 		LOG_DBG("NULL conn");
652 
653 		return -EINVAL;
654 	}
655 
656 	gmap_cli = &gmap_insts[bt_conn_index(conn)];
657 
658 	if (atomic_test_and_set_bit(gmap_cli->flags, GMAP_CLIENT_FLAG_BUSY)) {
659 		LOG_DBG("Busy");
660 
661 		return -EBUSY;
662 	}
663 
664 	gmap_reset(gmap_cli);
665 
666 	gmap_cli->params.discover.func = gmas_discover_func;
667 	gmap_cli->params.discover.uuid = gmas_uuid;
668 	gmap_cli->params.discover.type = BT_GATT_DISCOVER_PRIMARY;
669 	gmap_cli->params.discover.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
670 	gmap_cli->params.discover.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
671 
672 	err = bt_gatt_discover(conn, &gmap_cli->params.discover);
673 	if (err != 0) {
674 		LOG_DBG("Failed to initiate discovery: %d", err);
675 
676 		atomic_clear_bit(gmap_cli->flags, GMAP_CLIENT_FLAG_BUSY);
677 
678 		return -ENOEXEC;
679 	}
680 
681 	gmap_cli->conn = bt_conn_ref(conn);
682 
683 	return 0;
684 }
685 
bt_gmap_cb_register(const struct bt_gmap_cb * cb)686 int bt_gmap_cb_register(const struct bt_gmap_cb *cb)
687 {
688 	CHECKIF(cb == NULL) {
689 		LOG_DBG("cb is NULL");
690 
691 		return -EINVAL;
692 	}
693 
694 	if (gmap_cb != NULL) {
695 		LOG_DBG("GMAP callbacks already registered");
696 
697 		return -EALREADY;
698 	}
699 
700 	gmap_cb = cb;
701 
702 	return 0;
703 }
704