1 /*
2  * Copyright (c) 2025 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <string.h>
8 #include <stdbool.h>
9 
10 #include <zephyr/kernel.h>
11 
12 #include <zephyr/bluetooth/bluetooth.h>
13 #include <zephyr/bluetooth/conn.h>
14 #include <zephyr/bluetooth/gatt.h>
15 #include <zephyr/bluetooth/uuid.h>
16 
17 #include <zephyr/settings/settings.h>
18 
19 #include <zephyr/logging/log.h>
20 
21 #include <zephyr/sys/util.h>
22 
23 #include "testlib/conn.h"
24 #include "testlib/scan.h"
25 
26 #include "babblekit/flags.h"
27 #include "babblekit/sync.h"
28 #include "babblekit/testcase.h"
29 
30 #include "common.h"
31 
32 LOG_MODULE_REGISTER(server, LOG_LEVEL_DBG);
33 
34 DEFINE_FLAG_STATIC(security_changed_flag);
35 
36 static struct bt_conn_cb server_conn_cb;
37 
memeq(const void * m1,size_t len1,const void * m2,size_t len2)38 static inline bool memeq(const void *m1, size_t len1, const void *m2, size_t len2)
39 {
40 	int ret;
41 
42 	if (len1 != len2) {
43 		return false;
44 	}
45 
46 	ret = memcmp(m1, m2, len1);
47 
48 	return ret == 0;
49 }
50 
security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)51 static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err)
52 {
53 	char addr_str[BT_ADDR_LE_STR_LEN];
54 
55 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr_str, sizeof(addr_str));
56 
57 	TEST_ASSERT(err == 0, "Security update failed: %s level %u err %d", addr_str, level, err);
58 
59 	LOG_DBG("Security changed: %s level %u", addr_str, level);
60 	SET_FLAG(security_changed_flag);
61 }
62 
init_server_conn_callbacks(void)63 static void init_server_conn_callbacks(void)
64 {
65 	int err;
66 
67 	server_conn_cb.connected = NULL;
68 	server_conn_cb.disconnected = NULL;
69 	server_conn_cb.security_changed = security_changed;
70 	server_conn_cb.identity_resolved = NULL;
71 
72 	err = bt_conn_cb_register(&server_conn_cb);
73 	TEST_ASSERT(err == 0, "Failed to set server conn callbacks (err %d)", err);
74 }
75 
connect_and_set_security(struct bt_conn ** conn)76 static void connect_and_set_security(struct bt_conn **conn)
77 {
78 	int err;
79 	bt_addr_le_t client = {};
80 
81 	err = bt_testlib_scan_find_name(&client, ADVERTISER_NAME);
82 	TEST_ASSERT(err == 0, "Failed to start scan (err %d)", err);
83 
84 	err = bt_testlib_connect(&client, conn);
85 	TEST_ASSERT(err == 0, "Failed to initiate connection (err %d)", err);
86 
87 	err = bt_conn_set_security(*conn, BT_SECURITY_L2);
88 	TEST_ASSERT(err == 0, "Failed to set security (err %d)", err);
89 
90 	WAIT_FOR_FLAG(security_changed_flag);
91 }
92 
server_procedure(void)93 void server_procedure(void)
94 {
95 	/* Test purpose:
96 	 *
97 	 * Verifies that writing to the GAP Device Name characteristic correctly
98 	 * update the device name.
99 	 *
100 	 * Two devices:
101 	 * - `server`: GATT server, connect and elevate security
102 	 * - `client`: GATT client, when connected will look for the GAP Device
103 	 *   Name characteristic handle and then will send a GATT write with a
104 	 *   new name
105 	 *
106 	 * [verdict]
107 	 * - the server device name has been updated by the client
108 	 */
109 
110 	int err;
111 	struct bt_conn *conn = NULL;
112 
113 	bool names_are_matching;
114 
115 	uint8_t expected_name[CONFIG_BT_DEVICE_NAME_MAX];
116 
117 	/* add one for the null character */
118 	char original_name[CONFIG_BT_DEVICE_NAME_MAX + 1];
119 	char new_name[CONFIG_BT_DEVICE_NAME_MAX + 1];
120 
121 	const char *name;
122 
123 	generate_name(expected_name, CONFIG_BT_DEVICE_NAME_MAX);
124 
125 	TEST_START("server");
126 
127 	bk_sync_init();
128 
129 	err = bt_enable(NULL);
130 	TEST_ASSERT(err == 0, "Cannot enable Bluetooth (err %d)", err);
131 
132 	LOG_DBG("Bluetooth initialized");
133 
134 	err = bt_set_name("Server Super Name");
135 	TEST_ASSERT(err == 0, "Failed to set the name (err %d)", err);
136 
137 	name = bt_get_name();
138 	memcpy(original_name, name, strlen(name) + 1);
139 
140 	init_server_conn_callbacks();
141 
142 	connect_and_set_security(&conn);
143 
144 	/* wait for client to do gatt write */
145 	bk_sync_wait();
146 
147 	name = bt_get_name();
148 	memcpy(new_name, name, strlen(name) + 1);
149 
150 	LOG_DBG("Original Device Name: %s", original_name);
151 	LOG_DBG("New Device Name: %s", new_name);
152 
153 	names_are_matching =
154 		memeq(expected_name, sizeof(expected_name), new_name, strlen(new_name));
155 	TEST_ASSERT(names_are_matching,
156 		    "The name of the server doesn't match the one set by the client (server name: "
157 		    "`%s`, expected name: `%.*s`)",
158 		    new_name, sizeof(expected_name), expected_name);
159 
160 	TEST_PASS("server");
161 }
162