1 /*
2  * The goal of this test is to verify the bt_conn_cb_unregister() API works as expected
3  *
4  * Copyright (c) 2024 NXP
5  * Copyright (c) 2022 Nordic Semiconductor ASA
6  *
7  * SPDX-License-Identifier: Apache-2.0
8  */
9 
10 #include "bstests.h"
11 #include <zephyr/bluetooth/bluetooth.h>
12 
13 #include <testlib/conn.h>
14 
15 #include "common.h"
16 
17 CREATE_FLAG(flag_is_connected);
18 
19 static struct bt_conn *g_conn;
20 
connected(struct bt_conn * conn,uint8_t err)21 static void connected(struct bt_conn *conn, uint8_t err)
22 {
23 	char addr[BT_ADDR_LE_STR_LEN];
24 
25 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
26 
27 	if (err != 0) {
28 		FAIL("Failed to connect to %s (%u)\n", addr, err);
29 		return;
30 	}
31 
32 	printk("conn_callback:Connected to %s\n", addr);
33 
34 	__ASSERT_NO_MSG(g_conn == NULL);
35 	g_conn = bt_conn_ref(conn);
36 	SET_FLAG(flag_is_connected);
37 }
38 
disconnected(struct bt_conn * conn,uint8_t reason)39 static void disconnected(struct bt_conn *conn, uint8_t reason)
40 {
41 	char addr[BT_ADDR_LE_STR_LEN];
42 
43 	if (conn != g_conn) {
44 		return;
45 	}
46 
47 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
48 
49 	printk("conn_callback:Disconnected: %s (reason 0x%02x)\n", addr, reason);
50 
51 	bt_conn_unref(g_conn);
52 	g_conn = NULL;
53 
54 	UNSET_FLAG(flag_is_connected);
55 }
56 
57 static struct bt_conn_cb conn_callbacks = {
58 	.connected = connected,
59 	.disconnected = disconnected,
60 };
61 
device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)62 void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, struct net_buf_simple *ad)
63 {
64 	char addr_str[BT_ADDR_LE_STR_LEN];
65 	int err;
66 	struct bt_conn *conn;
67 
68 	if (g_conn != NULL) {
69 		printk("g_conn != NULL\n");
70 		return;
71 	}
72 
73 	/* We're only interested in connectable events */
74 	if (type != BT_HCI_ADV_IND && type != BT_HCI_ADV_DIRECT_IND) {
75 		printk("type not connectable\n");
76 		return;
77 	}
78 
79 	bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
80 	printk("Device found: %s (RSSI %d)\n", addr_str, rssi);
81 
82 	printk("Stopping scan\n");
83 	err = bt_le_scan_stop();
84 	if (err != 0) {
85 		FAIL("Could not stop scan: %d");
86 		return;
87 	}
88 
89 	err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, &conn);
90 	if (err != 0) {
91 		FAIL("Could not connect to peer: %d", err);
92 	}
93 	printk("%s: connected to found device\n", __func__);
94 
95 	bt_conn_unref(conn);
96 }
97 
connection_info(struct bt_conn * conn,void * user_data)98 static void connection_info(struct bt_conn *conn, void *user_data)
99 {
100 	char addr[BT_ADDR_LE_STR_LEN];
101 	int *conn_count = user_data;
102 	struct bt_conn_info info;
103 
104 	if (bt_conn_get_info(conn, &info) < 0) {
105 		printk("Unable to get info: conn %p", conn);
106 		return;
107 	}
108 
109 	switch (info.type) {
110 	case BT_CONN_TYPE_LE:
111 		(*conn_count)++;
112 		bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
113 		printk("%s: Connected to %s\n", __func__, addr);
114 		break;
115 	default:
116 		break;
117 	}
118 }
119 
start_adv(void)120 static void start_adv(void)
121 {
122 	int err;
123 	const struct bt_data ad[] = {
124 		BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR))};
125 
126 	err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, ad, ARRAY_SIZE(ad), NULL, 0);
127 	if (err != 0) {
128 		FAIL("Advertising failed to start (err %d)\n", err);
129 		return;
130 	}
131 
132 	printk("Advertising successfully started\n");
133 }
134 
test_peripheral_main(void)135 static void test_peripheral_main(void)
136 {
137 	int err;
138 
139 	err = bt_enable(NULL);
140 	if (err != 0) {
141 		FAIL("Bluetooth init failed (err %d)\n", err);
142 		return;
143 	}
144 
145 	printk("Bluetooth initialized\n");
146 
147 	bt_conn_cb_register(&conn_callbacks);
148 
149 	start_adv();
150 
151 	WAIT_FOR_FLAG(flag_is_connected);
152 
153 	WAIT_FOR_FLAG_UNSET(flag_is_connected);
154 
155 	bt_conn_cb_unregister(&conn_callbacks);
156 
157 	bt_testlib_conn_wait_free();
158 	start_adv();
159 
160 	k_sleep(K_SECONDS(1));
161 
162 	err = bt_disable();
163 	if (err != 0) {
164 		FAIL("Bluetooth disable failed (err %d)\n", err);
165 		return;
166 	}
167 
168 	printk("Bluetooth successfully disabled\n");
169 
170 	PASS("Peripheral device passed\n");
171 }
172 
test_central_main(void)173 static void test_central_main(void)
174 {
175 	int err;
176 	int conn_count = 0;
177 
178 	err = bt_enable(NULL);
179 	if (err != 0) {
180 		FAIL("Bluetooth discover failed (err %d)\n", err);
181 	}
182 	printk("Bluetooth initialized\n");
183 	bt_conn_cb_register(&conn_callbacks);
184 	/* Connect to peer device after conn_callbacks registered*/
185 	err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
186 	if (err != 0) {
187 		FAIL("Scanning failed to start (err %d)\n", err);
188 	}
189 
190 	printk("Scanning successfully started\n");
191 
192 	WAIT_FOR_FLAG(flag_is_connected);
193 
194 	err = bt_conn_disconnect(g_conn, 0x13);
195 
196 	if (err != 0) {
197 		FAIL("Disconnect failed (err %d)\n", err);
198 		return;
199 	}
200 
201 	WAIT_FOR_FLAG_UNSET(flag_is_connected);
202 	bt_conn_cb_unregister(&conn_callbacks);
203 	/* Reconnect to the device after conn_callbacks unregistered */
204 	err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
205 	if (err != 0) {
206 		FAIL("Scanning failed to start (err %d)\n", err);
207 	}
208 	printk("Scanning successfully started\n");
209 
210 	k_sleep(K_SECONDS(1));
211 	bt_conn_foreach(BT_CONN_TYPE_LE, connection_info, &conn_count);
212 	if (!conn_count) {
213 		FAIL("Reconnect to peer device failed!");
214 	}
215 
216 	/* flag_is_connected not set means no conn_callbacks being called */
217 	if (flag_is_connected) {
218 		FAIL("Unregister conn_callback didn't work");
219 	}
220 	printk("Unregister connection callbacks succeed!\n");
221 
222 	err = bt_disable();
223 	if (err != 0) {
224 		FAIL("Bluetooth disable failed (err %d)\n", err);
225 	}
226 	printk("Bluetooth successfully disabled\n");
227 
228 	PASS("Central device passed\n");
229 }
230 
231 static const struct bst_test_instance test_def[] = {{.test_id = "peripheral",
232 						     .test_descr = "Peripheral device",
233 						     .test_pre_init_f = test_init,
234 						     .test_tick_f = test_tick,
235 						     .test_main_f = test_peripheral_main},
236 						    {.test_id = "central",
237 						     .test_descr = "Central device",
238 						     .test_pre_init_f = test_init,
239 						     .test_tick_f = test_tick,
240 						     .test_main_f = test_central_main},
241 						    BSTEST_END_MARKER};
242 
test_unregister_conn_cb_install(struct bst_test_list * tests)243 struct bst_test_list *test_unregister_conn_cb_install(struct bst_test_list *tests)
244 {
245 	return bst_add_tests(tests, test_def);
246 }
247 
248 extern struct bst_test_list *test_unregister_conn_cb_install(struct bst_test_list *tests);
249 
250 bst_test_install_t test_installers[] = {test_unregister_conn_cb_install, NULL};
251 
main(void)252 int main(void)
253 {
254 	bst_main();
255 	return 0;
256 }
257