1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <errno.h>
8 #include <stddef.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 
13 #include <zephyr/bluetooth/bluetooth.h>
14 #include <zephyr/bluetooth/conn.h>
15 #include <zephyr/bluetooth/gatt.h>
16 #include <zephyr/bluetooth/hci.h>
17 #include <zephyr/bluetooth/uuid.h>
18 #include <zephyr/kernel.h>
19 #include <zephyr/sys/byteorder.h>
20 #include <zephyr/sys/check.h>
21 #include <zephyr/sys/printk.h>
22 #include <zephyr/types.h>
23 
24 #include <zephyr/logging/log.h>
25 LOG_MODULE_REGISTER(central, LOG_LEVEL_INF);
26 
27 #include "bstests.h"
28 #include "bs_types.h"
29 #include "bs_tracing.h"
30 #include "bstests.h"
31 #include "bs_pc_backchannel.h"
32 
33 #define DEFAULT_CONN_INTERVAL	   20
34 #define PERIPHERAL_DEVICE_NAME	   "Zephyr Peripheral"
35 #define PERIPHERAL_DEVICE_NAME_LEN (sizeof(PERIPHERAL_DEVICE_NAME) - 1)
36 
37 #define NOTIFICATION_DATA_PREFIX     "Counter:"
38 #define NOTIFICATION_DATA_PREFIX_LEN (sizeof(NOTIFICATION_DATA_PREFIX) - 1)
39 
40 #define CHARACTERISTIC_DATA_MAX_LEN 260
41 #define NOTIFICATION_DATA_LEN	    MAX(200, (CONFIG_BT_L2CAP_TX_MTU - 4))
42 BUILD_ASSERT(NOTIFICATION_DATA_LEN <= CHARACTERISTIC_DATA_MAX_LEN);
43 
44 #define PERIPHERAL_SERVICE_UUID_VAL                                                                \
45 	BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0)
46 
47 #define PERIPHERAL_CHARACTERISTIC_UUID_VAL                                                         \
48 	BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef1)
49 
50 #define PERIPHERAL_SERVICE_UUID	       BT_UUID_DECLARE_128(PERIPHERAL_SERVICE_UUID_VAL)
51 #define PERIPHERAL_CHARACTERISTIC_UUID BT_UUID_DECLARE_128(PERIPHERAL_CHARACTERISTIC_UUID_VAL)
52 
53 static struct bt_uuid_128 vnd_uuid =
54 	BT_UUID_INIT_128(BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdea0));
55 
56 static struct bt_uuid_128 vnd_enc_uuid =
57 	BT_UUID_INIT_128(BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdea1));
58 
59 enum {
60 	DEVICE_IS_SCANNING,
61 	DEVICE_IS_CONNECTING,
62 
63 	/* Total number of flags - must be at the end of the enum */
64 	DEVICE_NUM_FLAGS,
65 };
66 
67 enum {
68 	CONN_INFO_SENT_MTU_EXCHANGE,
69 	CONN_INFO_MTU_EXCHANGED,
70 	CONN_INFO_DISCOVERING,
71 	CONN_INFO_DISCOVER_PAUSED,
72 	CONN_INFO_SUBSCRIBED,
73 
74 	/* Total number of flags - must be at the end of the enum */
75 	CONN_INFO_NUM_FLAGS,
76 };
77 
78 ATOMIC_DEFINE(status_flags, DEVICE_NUM_FLAGS);
79 static atomic_t conn_count;
80 static struct bt_conn *conn_connecting;
81 static struct bt_gatt_exchange_params mtu_exchange_params;
82 
83 struct conn_info {
84 	ATOMIC_DEFINE(flags, CONN_INFO_NUM_FLAGS);
85 	struct bt_conn *conn_ref;
86 	uint32_t notify_counter;
87 	uint32_t tx_notify_counter;
88 	struct bt_uuid_128 uuid;
89 	struct bt_gatt_discover_params discover_params;
90 	struct bt_gatt_subscribe_params subscribe_params;
91 	bt_addr_le_t addr;
92 };
93 
94 static struct conn_info conn_infos[CONFIG_BT_MAX_CONN] = {0};
95 
96 static uint32_t conn_interval_max, notification_size;
97 static uint8_t vnd_value[CHARACTERISTIC_DATA_MAX_LEN];
98 
99 static const struct bt_uuid_16 ccc_uuid = BT_UUID_INIT_16(BT_UUID_GATT_CCC_VAL);
100 
clear_info(struct conn_info * info)101 void clear_info(struct conn_info *info)
102 {
103 	/* clear everything except the address + sub params + uuid (lifetime > connection) */
104 	memset(&info->flags, 0, sizeof(info->flags));
105 	memset(&info->conn_ref, 0, sizeof(info->conn_ref));
106 	memset(&info->notify_counter, 0, sizeof(info->notify_counter));
107 	memset(&info->tx_notify_counter, 0, sizeof(info->tx_notify_counter));
108 }
109 
ccc_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)110 static void ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
111 {
112 	/* TODO: add peer subscription check? */
113 	LOG_INF("CCC changed: %u", value);
114 }
115 
116 /* Vendor Primary Service Declaration */
117 BT_GATT_SERVICE_DEFINE(
118 	vnd_svc, BT_GATT_PRIMARY_SERVICE(&vnd_uuid),
119 	BT_GATT_CHARACTERISTIC(&vnd_enc_uuid.uuid,
120 			       BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_NOTIFY,
121 			       BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, NULL, NULL,
122 			       NULL),
123 	BT_GATT_CCC(ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
124 );
125 
get_new_conn_info_ref(const bt_addr_le_t * addr)126 static struct conn_info *get_new_conn_info_ref(const bt_addr_le_t *addr)
127 {
128 	/* try to find per-addr first */
129 	for (size_t i = 0; i < ARRAY_SIZE(conn_infos); i++) {
130 		if (bt_addr_le_eq(&conn_infos[i].addr, addr)) {
131 			return &conn_infos[i];
132 		}
133 	}
134 
135 	/* try to allocate if addr not found */
136 	for (size_t i = 0; i < ARRAY_SIZE(conn_infos); i++) {
137 		if (conn_infos[i].conn_ref == NULL) {
138 			bt_addr_le_copy(&conn_infos[i].addr, addr);
139 
140 			return &conn_infos[i];
141 		}
142 	}
143 
144 	__ASSERT(0, "ran out of contexts");
145 }
146 
get_conn_info_ref(struct bt_conn * conn_ref)147 static struct conn_info *get_conn_info_ref(struct bt_conn *conn_ref)
148 {
149 	for (size_t i = 0; i < ARRAY_SIZE(conn_infos); i++) {
150 		if (conn_ref == conn_infos[i].conn_ref) {
151 			return &conn_infos[i];
152 		}
153 	}
154 
155 	return NULL;
156 }
157 
is_connected(struct bt_conn * conn)158 static bool is_connected(struct bt_conn *conn)
159 {
160 	struct bt_conn_info info;
161 	int err = bt_conn_get_info(conn, &info);
162 
163 	__ASSERT(!err, "Couldn't get conn info %d", err);
164 
165 	return info.state == BT_CONN_STATE_CONNECTED;
166 }
167 
get_connected_conn_info_ref(struct bt_conn * conn)168 static struct conn_info *get_connected_conn_info_ref(struct bt_conn *conn)
169 {
170 	if (is_connected(conn)) {
171 		return get_conn_info_ref(conn);
172 	}
173 
174 	return NULL;
175 }
176 
notify_func(struct bt_conn * conn,struct bt_gatt_subscribe_params * params,const void * data,uint16_t length)177 static uint8_t notify_func(struct bt_conn *conn, struct bt_gatt_subscribe_params *params,
178 			   const void *data, uint16_t length)
179 {
180 	const char *data_ptr = (const char *)data + NOTIFICATION_DATA_PREFIX_LEN;
181 	uint32_t received_counter;
182 	struct conn_info *conn_info_ref;
183 	char addr[BT_ADDR_LE_STR_LEN];
184 
185 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
186 
187 	if (!data) {
188 		LOG_INF("[UNSUBSCRIBED] addr %s", addr);
189 		params->value_handle = 0U;
190 		return BT_GATT_ITER_STOP;
191 	}
192 
193 	conn_info_ref = get_conn_info_ref(conn);
194 	__ASSERT_NO_MSG(conn_info_ref);
195 
196 	received_counter = strtoul(data_ptr, NULL, 0);
197 
198 	LOG_DBG("[NOTIFICATION] addr %s data %s length %u cnt %u",
199 		addr, data, length, received_counter);
200 
201 	LOG_HEXDUMP_DBG(data, length, "RX");
202 
203 	__ASSERT(conn_info_ref->notify_counter == received_counter,
204 		 "addr %s expected counter : %u , received counter : %u",
205 		 addr, conn_info_ref->notify_counter, received_counter);
206 	conn_info_ref->notify_counter++;
207 
208 	return BT_GATT_ITER_CONTINUE;
209 }
210 
discover_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)211 static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr,
212 			     struct bt_gatt_discover_params *params)
213 {
214 	int err;
215 	char uuid_str[BT_UUID_STR_LEN];
216 	struct conn_info *conn_info_ref;
217 
218 	if (!attr) {
219 		/* We might be called from the ATT disconnection callback if we
220 		 * have an ongoing procedure. That is ok.
221 		 */
222 		__ASSERT_NO_MSG(!is_connected(conn));
223 		return BT_GATT_ITER_STOP;
224 	}
225 	__ASSERT(attr, "Did not find requested UUID");
226 
227 	bt_uuid_to_str(params->uuid, uuid_str, sizeof(uuid_str));
228 	LOG_DBG("UUID found : %s", uuid_str);
229 
230 	LOG_INF("[ATTRIBUTE] handle %u", attr->handle);
231 
232 	conn_info_ref = get_connected_conn_info_ref(conn);
233 	__ASSERT_NO_MSG(conn_info_ref);
234 
235 	atomic_clear_bit(conn_info_ref->flags, CONN_INFO_DISCOVER_PAUSED);
236 
237 	if (conn_info_ref->discover_params.type == BT_GATT_DISCOVER_PRIMARY) {
238 		LOG_DBG("Primary Service Found");
239 		memcpy(&conn_info_ref->uuid,
240 		       PERIPHERAL_CHARACTERISTIC_UUID,
241 		       sizeof(conn_info_ref->uuid));
242 		conn_info_ref->discover_params.uuid = &conn_info_ref->uuid.uuid;
243 		conn_info_ref->discover_params.start_handle = attr->handle + 1;
244 		conn_info_ref->discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
245 
246 		err = bt_gatt_discover(conn, &conn_info_ref->discover_params);
247 		if (err == -ENOMEM || err == -ENOTCONN) {
248 			goto retry;
249 		}
250 
251 		__ASSERT(!err, "Discover failed (err %d)", err);
252 
253 	} else if (conn_info_ref->discover_params.type == BT_GATT_DISCOVER_CHARACTERISTIC) {
254 		LOG_DBG("Service Characteristic Found");
255 
256 		conn_info_ref->discover_params.uuid = &ccc_uuid.uuid;
257 		conn_info_ref->discover_params.start_handle = attr->handle + 2;
258 		conn_info_ref->discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
259 		conn_info_ref->subscribe_params.value_handle = bt_gatt_attr_value_handle(attr);
260 
261 		err = bt_gatt_discover(conn, &conn_info_ref->discover_params);
262 		if (err == -ENOMEM || err == -ENOTCONN) {
263 			goto retry;
264 		}
265 
266 		__ASSERT(!err, "Discover failed (err %d)", err);
267 
268 	} else {
269 		conn_info_ref->subscribe_params.notify = notify_func;
270 		conn_info_ref->subscribe_params.value = BT_GATT_CCC_NOTIFY;
271 		conn_info_ref->subscribe_params.ccc_handle = attr->handle;
272 
273 		err = bt_gatt_subscribe(conn, &conn_info_ref->subscribe_params);
274 		if (err == -ENOMEM || err == -ENOTCONN) {
275 			goto retry;
276 		}
277 
278 		if (err != -EALREADY) {
279 			__ASSERT(!err, "Subscribe failed (err %d)", err);
280 		}
281 
282 		__ASSERT_NO_MSG(atomic_test_bit(conn_info_ref->flags, CONN_INFO_DISCOVERING));
283 		__ASSERT_NO_MSG(!atomic_test_bit(conn_info_ref->flags, CONN_INFO_SUBSCRIBED));
284 		atomic_set_bit(conn_info_ref->flags, CONN_INFO_SUBSCRIBED);
285 
286 		char addr[BT_ADDR_LE_STR_LEN];
287 
288 		bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
289 		LOG_INF("[SUBSCRIBED] addr %s", addr);
290 	}
291 
292 	return BT_GATT_ITER_STOP;
293 
294 retry:
295 	/* if we're out of buffers or metadata contexts, continue discovery
296 	 * later.
297 	 */
298 	LOG_INF("out of memory/not connected, continuing sub later");
299 	atomic_set_bit(conn_info_ref->flags, CONN_INFO_DISCOVER_PAUSED);
300 
301 	return BT_GATT_ITER_STOP;
302 }
303 
stop_scan(void)304 static void stop_scan(void)
305 {
306 	int err;
307 
308 	__ASSERT(atomic_test_bit(status_flags, DEVICE_IS_SCANNING),
309 		 "No scanning procedure is ongoing");
310 	atomic_clear_bit(status_flags, DEVICE_IS_SCANNING);
311 
312 	err = bt_le_scan_stop();
313 	__ASSERT(!err, "Stop LE scan failed (err %d)", err);
314 
315 	LOG_INF("Stopped scanning");
316 }
317 
check_if_peer_connected(const bt_addr_le_t * addr)318 static bool check_if_peer_connected(const bt_addr_le_t *addr)
319 {
320 	for (size_t i = 0; i < ARRAY_SIZE(conn_infos); i++) {
321 		if (conn_infos[i].conn_ref != NULL) {
322 			if (!bt_addr_le_cmp(bt_conn_get_dst(conn_infos[i].conn_ref), addr)) {
323 				return true;
324 			}
325 		}
326 	}
327 
328 	return false;
329 }
330 
parse_ad(struct bt_data * data,void * user_data)331 static bool parse_ad(struct bt_data *data, void *user_data)
332 {
333 	bt_addr_le_t *addr = user_data;
334 
335 	LOG_DBG("[AD]: %u data_len %u", data->type, data->data_len);
336 
337 	switch (data->type) {
338 	case BT_DATA_NAME_SHORTENED:
339 	case BT_DATA_NAME_COMPLETE:
340 		LOG_INF("------------------------------------------------------");
341 		LOG_INF("Device name : %.*s", data->data_len, data->data);
342 
343 		if (check_if_peer_connected(addr)) {
344 			LOG_ERR("Peer is already connected or in disconnecting state");
345 			break;
346 		}
347 
348 		__ASSERT(!atomic_test_bit(status_flags, DEVICE_IS_CONNECTING),
349 			 "A connection procedure is ongoing");
350 		atomic_set_bit(status_flags, DEVICE_IS_CONNECTING);
351 
352 		stop_scan();
353 
354 		char addr_str[BT_ADDR_LE_STR_LEN];
355 
356 		bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
357 		LOG_INF("Connecting to %s", addr_str);
358 
359 		struct bt_le_conn_param *param = BT_LE_CONN_PARAM_DEFAULT;
360 		int err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param,
361 					    &conn_connecting);
362 
363 		__ASSERT(!err, "Create conn failed (err %d)", err);
364 
365 		return false;
366 
367 		break;
368 	}
369 
370 	return true;
371 }
372 
device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)373 static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
374 			 struct net_buf_simple *ad)
375 {
376 	bt_data_parse(ad, parse_ad, (void *)addr);
377 }
378 
start_scan(void)379 static void start_scan(void)
380 {
381 	int err;
382 	struct bt_le_scan_param scan_param = {
383 		.type = BT_LE_SCAN_TYPE_ACTIVE,
384 		.options = BT_LE_SCAN_OPT_NONE,
385 		.interval = BT_GAP_SCAN_FAST_INTERVAL,
386 		.window = BT_GAP_SCAN_FAST_WINDOW,
387 	};
388 
389 	atomic_set_bit(status_flags, DEVICE_IS_SCANNING);
390 
391 	err = bt_le_scan_start(&scan_param, device_found);
392 	__ASSERT(!err, "Scanning failed to start (err %d)", err);
393 
394 	LOG_INF("Started scanning");
395 }
396 
connected_cb(struct bt_conn * conn,uint8_t conn_err)397 static void connected_cb(struct bt_conn *conn, uint8_t conn_err)
398 {
399 	struct conn_info *conn_info_ref;
400 	char addr[BT_ADDR_LE_STR_LEN];
401 
402 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
403 
404 	__ASSERT(conn_err == BT_HCI_ERR_SUCCESS, "Failed to connect to %s (%u)", addr, conn_err);
405 
406 	LOG_INF("Connection %p established : %s", conn, addr);
407 
408 	atomic_inc(&conn_count);
409 	LOG_DBG("connected to %u devices", atomic_get(&conn_count));
410 
411 	conn_info_ref = get_new_conn_info_ref(bt_conn_get_dst(conn));
412 	__ASSERT_NO_MSG(conn_info_ref->conn_ref == NULL);
413 
414 	conn_info_ref->conn_ref = conn_connecting;
415 
416 #if defined(CONFIG_BT_SMP)
417 	int err = bt_conn_set_security(conn, BT_SECURITY_L2);
418 
419 	if (!err) {
420 		LOG_INF("Security level is set to : %u", BT_SECURITY_L2);
421 	} else {
422 		LOG_ERR("Failed to set security (%d).", err);
423 	}
424 #endif /* CONFIG_BT_SMP */
425 
426 	__ASSERT_NO_MSG(conn == conn_connecting);
427 	if (conn == conn_connecting) {
428 		conn_connecting = NULL;
429 		atomic_clear_bit(status_flags, DEVICE_IS_CONNECTING);
430 	}
431 }
432 
disconnected(struct bt_conn * conn,uint8_t reason)433 static void disconnected(struct bt_conn *conn, uint8_t reason)
434 {
435 	struct conn_info *conn_info_ref;
436 	char addr[BT_ADDR_LE_STR_LEN];
437 
438 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
439 
440 	LOG_INF("Disconnected: %s (reason 0x%02x)", addr, reason);
441 
442 	conn_info_ref = get_conn_info_ref(conn);
443 	__ASSERT_NO_MSG(conn_info_ref->conn_ref != NULL);
444 
445 	bool valid_reason =
446 		reason == BT_HCI_ERR_REMOTE_POWER_OFF ||
447 		reason == BT_HCI_ERR_LOCALHOST_TERM_CONN;
448 
449 	__ASSERT(valid_reason, "Disconnected (reason 0x%02x)", reason);
450 
451 	bt_conn_unref(conn);
452 	clear_info(conn_info_ref);
453 	atomic_dec(&conn_count);
454 }
455 
456 #if defined(CONFIG_BT_SMP)
security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)457 static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err)
458 {
459 	char addr[BT_ADDR_LE_STR_LEN];
460 
461 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
462 
463 	__ASSERT(!err, "Security for %s failed", addr);
464 	LOG_INF("Security for %s changed: level %u", addr, level);
465 
466 	if (err) {
467 		LOG_ERR("Security failed, disconnecting");
468 		bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_POWER_OFF);
469 	}
470 }
471 #endif /* CONFIG_BT_SMP */
472 
identity_resolved(struct bt_conn * conn,const bt_addr_le_t * rpa,const bt_addr_le_t * identity)473 static void identity_resolved(struct bt_conn *conn, const bt_addr_le_t *rpa,
474 			      const bt_addr_le_t *identity)
475 {
476 	char addr_identity[BT_ADDR_LE_STR_LEN];
477 	char addr_rpa[BT_ADDR_LE_STR_LEN];
478 	struct conn_info *conn_info_ref;
479 
480 	bt_addr_le_to_str(identity, addr_identity, sizeof(addr_identity));
481 	bt_addr_le_to_str(rpa, addr_rpa, sizeof(addr_rpa));
482 
483 	LOG_ERR("Identity resolved %s -> %s", addr_rpa, addr_identity);
484 
485 	/* overwrite RPA */
486 	conn_info_ref = get_conn_info_ref(conn);
487 	bt_addr_le_copy(&conn_info_ref->addr, identity);
488 }
489 
490 BT_CONN_CB_DEFINE(conn_callbacks) = {
491 	.connected = connected_cb,
492 	.disconnected = disconnected,
493 #if defined(CONFIG_BT_SMP)
494 	.security_changed = security_changed,
495 #endif /* CONFIG_BT_SMP */
496 	.identity_resolved = identity_resolved,
497 };
498 
mtu_updated(struct bt_conn * conn,uint16_t tx,uint16_t rx)499 void mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx)
500 {
501 	LOG_INF("Updated MTU: TX: %d RX: %d bytes", tx, rx);
502 }
503 
504 static struct bt_gatt_cb gatt_callbacks = {.att_mtu_updated = mtu_updated};
505 
mtu_exchange_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_exchange_params * params)506 static void mtu_exchange_cb(struct bt_conn *conn, uint8_t err,
507 			    struct bt_gatt_exchange_params *params)
508 {
509 	struct conn_info *conn_info_ref;
510 	char addr[BT_ADDR_LE_STR_LEN];
511 
512 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
513 
514 	conn_info_ref = get_conn_info_ref(conn);
515 	__ASSERT_NO_MSG(conn_info_ref);
516 
517 	LOG_DBG("MTU exchange addr %s conn %s", addr,
518 		   err == 0U ? "successful" : "failed");
519 
520 	atomic_set_bit(conn_info_ref->flags, CONN_INFO_MTU_EXCHANGED);
521 }
522 
exchange_mtu(struct bt_conn * conn,void * data)523 static void exchange_mtu(struct bt_conn *conn, void *data)
524 {
525 	struct conn_info *conn_info_ref;
526 	char addr[BT_ADDR_LE_STR_LEN];
527 	int err;
528 
529 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
530 
531 	conn_info_ref = get_connected_conn_info_ref(conn);
532 	if (conn_info_ref == NULL) {
533 		LOG_DBG("not connected: %s", addr);
534 		return;
535 	}
536 
537 	if (!atomic_test_bit(conn_info_ref->flags, CONN_INFO_MTU_EXCHANGED) &&
538 	    !atomic_test_and_set_bit(conn_info_ref->flags, CONN_INFO_SENT_MTU_EXCHANGE)) {
539 		LOG_DBG("Updating MTU for %s to %u", addr, bt_gatt_get_mtu(conn));
540 
541 		mtu_exchange_params.func = mtu_exchange_cb;
542 		err = bt_gatt_exchange_mtu(conn, &mtu_exchange_params);
543 		if (err) {
544 			LOG_ERR("MTU exchange failed (err %d)", err);
545 			atomic_clear_bit(conn_info_ref->flags, CONN_INFO_SENT_MTU_EXCHANGE);
546 		} else {
547 			LOG_INF("MTU Exchange pending...");
548 		}
549 	}
550 }
551 
subscribe_to_service(struct bt_conn * conn,void * data)552 static void subscribe_to_service(struct bt_conn *conn, void *data)
553 {
554 	struct conn_info *conn_info_ref;
555 	int err;
556 	int *p_err = (int *)data;
557 	char addr[BT_ADDR_LE_STR_LEN];
558 
559 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
560 
561 	conn_info_ref = get_connected_conn_info_ref(conn);
562 	if (conn_info_ref == NULL) {
563 		LOG_DBG("not connected: %s", addr);
564 		return;
565 	}
566 
567 	/* start subscription procedure if:
568 	 * - we haven't started it yet for this conn
569 	 * - it was suspended due to a lack of resources
570 	 */
571 	if (!atomic_test_bit(conn_info_ref->flags, CONN_INFO_SUBSCRIBED) &&
572 	    (!atomic_test_bit(conn_info_ref->flags, CONN_INFO_DISCOVERING) ||
573 	     atomic_test_bit(conn_info_ref->flags, CONN_INFO_DISCOVER_PAUSED))) {
574 		/* If discovery hasn't started yet, load params. If it was
575 		 * already started, then not touching the params will resume
576 		 * discovery at the attribute it was stopped at.
577 		 */
578 		if (!atomic_test_and_set_bit(conn_info_ref->flags, CONN_INFO_DISCOVERING)) {
579 			memcpy(&conn_info_ref->uuid, PERIPHERAL_SERVICE_UUID,
580 			       sizeof(conn_info_ref->uuid));
581 			memset(&conn_info_ref->discover_params, 0,
582 			       sizeof(conn_info_ref->discover_params));
583 
584 			conn_info_ref->discover_params.uuid = &conn_info_ref->uuid.uuid;
585 			conn_info_ref->discover_params.func = discover_func;
586 			conn_info_ref->discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
587 			conn_info_ref->discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
588 			conn_info_ref->discover_params.type = BT_GATT_DISCOVER_PRIMARY;
589 			LOG_INF("start discovery of %s", addr);
590 		} else {
591 			LOG_INF("resume discovery of %s", addr);
592 		}
593 
594 		err = bt_gatt_discover(conn, &conn_info_ref->discover_params);
595 		if (*p_err == 0) {
596 			/* Don't overwrite `err` if it was previously set. it is
597 			 * cleared by the caller.
598 			 */
599 			*p_err = err;
600 		}
601 
602 		if (err != -ENOMEM && err != -ENOTCONN) {
603 			__ASSERT(!err, "Subscribe failed (err %d)", err);
604 		}
605 	}
606 }
607 
notify_peers(struct bt_conn * conn,void * data)608 static void notify_peers(struct bt_conn *conn, void *data)
609 {
610 	int err;
611 	struct bt_gatt_attr *vnd_attr = (struct bt_gatt_attr *)data;
612 	struct conn_info *conn_info_ref;
613 	char addr[BT_ADDR_LE_STR_LEN];
614 
615 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
616 
617 	conn_info_ref = get_connected_conn_info_ref(conn);
618 	if (conn_info_ref == NULL) {
619 		LOG_DBG("not connected: %s", addr);
620 		return;
621 	}
622 
623 	if (!atomic_test_bit(conn_info_ref->flags, CONN_INFO_MTU_EXCHANGED)) {
624 		LOG_DBG("can't notify: MTU not yet exchanged");
625 		/* sleep a bit to allow the exchange to take place */
626 		k_msleep(100);
627 		return;
628 	}
629 
630 	memset(vnd_value, 0x00, sizeof(vnd_value));
631 	snprintk(vnd_value, notification_size, "%s%u", NOTIFICATION_DATA_PREFIX,
632 		 conn_info_ref->tx_notify_counter);
633 	LOG_INF("notify: %s", addr);
634 	err = bt_gatt_notify(conn, vnd_attr, vnd_value, notification_size);
635 	if (err) {
636 		LOG_ERR("Couldn't send GATT notification");
637 		return;
638 	}
639 
640 	LOG_DBG("central notified: %s %d", addr, conn_info_ref->tx_notify_counter);
641 
642 	conn_info_ref->tx_notify_counter++;
643 }
644 
test_central_main(void)645 void test_central_main(void)
646 {
647 	int err;
648 	struct bt_gatt_attr *vnd_attr;
649 	char str[BT_UUID_STR_LEN];
650 	char addr[BT_ADDR_LE_STR_LEN];
651 
652 	memset(&conn_infos, 0x00, sizeof(conn_infos));
653 
654 	err = bt_enable(NULL);
655 
656 	if (err) {
657 		LOG_ERR("Bluetooth init failed (err %d)", err);
658 		return;
659 	}
660 
661 	LOG_DBG("Bluetooth initialized");
662 
663 	bt_gatt_cb_register(&gatt_callbacks);
664 
665 	vnd_attr = bt_gatt_find_by_uuid(vnd_svc.attrs, vnd_svc.attr_count, &vnd_enc_uuid.uuid);
666 
667 	bt_uuid_to_str(&vnd_enc_uuid.uuid, str, sizeof(str));
668 	LOG_DBG("Indicate VND attr %p (UUID %s)", vnd_attr, str);
669 
670 	start_scan();
671 
672 	while (true) {
673 		/* reconnect peripherals when they drop out */
674 		if (atomic_get(&conn_count) < CONFIG_BT_MAX_CONN &&
675 		    !atomic_test_bit(status_flags, DEVICE_IS_SCANNING) &&
676 		    !atomic_test_bit(status_flags, DEVICE_IS_CONNECTING)) {
677 			start_scan();
678 		} else {
679 			if (atomic_test_bit(status_flags, DEVICE_IS_CONNECTING)) {
680 				bt_addr_le_to_str(bt_conn_get_dst(conn_connecting),
681 						  addr, sizeof(addr));
682 				LOG_INF("already connecting to: %s", addr);
683 			}
684 		}
685 
686 		bt_conn_foreach(BT_CONN_TYPE_LE, exchange_mtu, NULL);
687 
688 		err = 0;
689 		bt_conn_foreach(BT_CONN_TYPE_LE, subscribe_to_service, &err);
690 		if (!err) {
691 			bt_conn_foreach(BT_CONN_TYPE_LE, notify_peers, vnd_attr);
692 		} else {
693 			/* Allow the sub procedure to complete. Else the
694 			 * notifications use up all the buffers and it can never
695 			 * complete in time.
696 			 */
697 			LOG_ERR("subscription failed: %d, not notifying", err);
698 		}
699 		k_msleep(10);
700 	}
701 }
702 
test_init(void)703 void test_init(void)
704 {
705 	extern enum bst_result_t bst_result;
706 
707 	LOG_INF("Initializing Test");
708 	/* The peripherals determines whether the test passed. */
709 	bst_result = Passed;
710 }
711 
test_args(int argc,char ** argv)712 static void test_args(int argc, char **argv)
713 {
714 	conn_interval_max = DEFAULT_CONN_INTERVAL;
715 	notification_size = NOTIFICATION_DATA_LEN;
716 
717 	if (argc >= 1) {
718 		char const *ptr;
719 
720 		ptr = strstr(argv[0], "notify_size=");
721 		if (ptr != NULL) {
722 			ptr += strlen("notify_size=");
723 			notification_size = atol(ptr);
724 			notification_size = MIN(NOTIFICATION_DATA_LEN, notification_size);
725 		}
726 	}
727 
728 	if (argc == 2) {
729 		char const *ptr;
730 
731 		ptr = strstr(argv[1], "conn_interval=");
732 		if (ptr != NULL) {
733 			ptr += strlen("conn_interval=");
734 			conn_interval_max = atol(ptr);
735 		}
736 	}
737 
738 	bs_trace_raw(0, "Connection interval max : %d\n", conn_interval_max);
739 	bs_trace_raw(0, "Notification data size : %d\n", notification_size);
740 }
741 
742 static const struct bst_test_instance test_def[] = {
743 	{
744 		.test_id = "central",
745 		.test_descr = "Central Connection Stress",
746 		.test_args_f = test_args,
747 		.test_pre_init_f = test_init,
748 		.test_main_f = test_central_main
749 	},
750 	BSTEST_END_MARKER
751 };
752 
test_main_conn_stress_install(struct bst_test_list * tests)753 struct bst_test_list *test_main_conn_stress_install(struct bst_test_list *tests)
754 {
755 	return bst_add_tests(tests, test_def);
756 }
757 
758 extern struct bst_test_list *test_main_conn_stress_install(struct bst_test_list *tests);
759 
760 bst_test_install_t test_installers[] = {
761 	test_main_conn_stress_install,
762 	NULL
763 };
764 
main(void)765 int main(void)
766 {
767 	bst_main();
768 
769 	return 0;
770 }
771