1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/bluetooth/bluetooth.h>
9 #include <zephyr/bluetooth/conn.h>
10 #include <zephyr/bluetooth/att.h>
11 #include <zephyr/bluetooth/l2cap.h>
12 #include <zephyr/logging/log.h>
13
14 #include "testlib/scan.h"
15 #include "testlib/conn.h"
16
17 #include "babblekit/flags.h"
18 #include "babblekit/sync.h"
19 #include "babblekit/testcase.h"
20
21 /* local includes */
22 #include "data.h"
23
24 LOG_MODULE_REGISTER(central, CONFIG_APP_LOG_LEVEL);
25
26 static struct bt_l2cap_le_chan le_chan;
27
sent_cb(struct bt_l2cap_chan * chan)28 static void sent_cb(struct bt_l2cap_chan *chan)
29 {
30 TEST_FAIL("Tester should not send data");
31 }
32
recv_cb(struct bt_l2cap_chan * chan,struct net_buf * buf)33 static int recv_cb(struct bt_l2cap_chan *chan, struct net_buf *buf)
34 {
35 LOG_DBG("received %d bytes", buf->len);
36
37 return 0;
38 }
39
l2cap_chan_connected_cb(struct bt_l2cap_chan * chan)40 static void l2cap_chan_connected_cb(struct bt_l2cap_chan *chan)
41 {
42 LOG_DBG("%p", chan);
43 }
44
l2cap_chan_disconnected_cb(struct bt_l2cap_chan * chan)45 static void l2cap_chan_disconnected_cb(struct bt_l2cap_chan *chan)
46 {
47 LOG_DBG("%p", chan);
48 }
49
server_accept_cb(struct bt_conn * conn,struct bt_l2cap_server * server,struct bt_l2cap_chan ** chan)50 static int server_accept_cb(struct bt_conn *conn, struct bt_l2cap_server *server,
51 struct bt_l2cap_chan **chan)
52 {
53 static struct bt_l2cap_chan_ops ops = {
54 .connected = l2cap_chan_connected_cb,
55 .disconnected = l2cap_chan_disconnected_cb,
56 .recv = recv_cb,
57 .sent = sent_cb,
58 };
59
60 memset(&le_chan, 0, sizeof(le_chan));
61 le_chan.chan.ops = &ops;
62 *chan = &le_chan.chan;
63
64 return 0;
65 }
66
l2cap_server_register(bt_security_t sec_level)67 static int l2cap_server_register(bt_security_t sec_level)
68 {
69 static struct bt_l2cap_server test_l2cap_server = {.accept = server_accept_cb};
70
71 test_l2cap_server.psm = 0;
72 test_l2cap_server.sec_level = sec_level;
73
74 int err = bt_l2cap_server_register(&test_l2cap_server);
75
76 TEST_ASSERT(err == 0, "Failed to register l2cap server (err %d)", err);
77
78 return test_l2cap_server.psm;
79 }
80
acl_connected(struct bt_conn * conn,uint8_t err)81 static void acl_connected(struct bt_conn *conn, uint8_t err)
82 {
83 char addr[BT_ADDR_LE_STR_LEN];
84
85 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
86
87 if (err) {
88 LOG_ERR("Failed to connect to %s (0x%02x)", addr, err);
89 return;
90 }
91
92 LOG_DBG("Connected to %s", addr);
93 }
94
acl_disconnected(struct bt_conn * conn,uint8_t reason)95 static void acl_disconnected(struct bt_conn *conn, uint8_t reason)
96 {
97 char addr[BT_ADDR_LE_STR_LEN];
98
99 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
100
101 LOG_DBG("Disconnected from %s (reason 0x%02x)", addr, reason);
102 }
103
104 /* Read the comments on `entrypoint_dut()` first. */
entrypoint_central(void)105 void entrypoint_central(void)
106 {
107 int err;
108 struct bt_conn *conn = NULL;
109 bt_addr_le_t dut;
110 static struct bt_conn_cb central_cb = {
111 .connected = acl_connected,
112 .disconnected = acl_disconnected,
113 };
114
115 /* Mark test as in progress. */
116 TEST_START("central");
117
118 /* Initialize Bluetooth */
119 err = bt_conn_cb_register(¢ral_cb);
120 TEST_ASSERT(err == 0, "Can't register callbacks (err %d)", err);
121
122 err = bt_enable(NULL);
123 TEST_ASSERT(err == 0, "Can't enable Bluetooth (err %d)", err);
124
125 LOG_DBG("Bluetooth initialized");
126
127 int psm = l2cap_server_register(BT_SECURITY_L1);
128
129 LOG_DBG("Registered server PSM %x", psm);
130
131 /* The device address will not change. Scan only once in order to reduce
132 * test time.
133 */
134 err = bt_testlib_scan_find_name(&dut, DUT_NAME);
135 TEST_ASSERT(!err, "Failed to start scan (err %d)", err);
136
137 /* DUT will terminate all devices when it's done. Mark the device as
138 * "passed" so bsim doesn't return a nonzero err code when the
139 * termination happens.
140 */
141 TEST_PASS("central");
142
143 while (true) {
144 /* Create a connection using that address */
145 err = bt_testlib_connect(&dut, &conn);
146 TEST_ASSERT(!err, "Failed to initiate connection (err %d)", err);
147
148 LOG_DBG("Connected");
149
150 /* Receive in the background */
151 k_sleep(K_MSEC(1000));
152
153 /* Disconnect and destroy connection object */
154 err = bt_testlib_disconnect(&conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
155 TEST_ASSERT(!err, "Failed to disconnect (err %d)", err);
156
157 LOG_DBG("Disconnected");
158
159 /* Simulate the central going in and out of range. In the real world, it is unlikely
160 * to drop a connection and re-establish it after only a few milliseconds.
161 */
162 k_sleep(K_MSEC(200));
163 }
164 }
165