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/l2cap.h>
11 #include <zephyr/logging/log.h>
12 
13 #include "testlib/conn.h"
14 #include "testlib/scan.h"
15 
16 #include "babblekit/flags.h"
17 #include "babblekit/testcase.h"
18 
19 LOG_MODULE_REGISTER(dut, CONFIG_APP_LOG_LEVEL);
20 
21 static atomic_t disconnected_channels;
22 
23 static struct bt_l2cap_le_chan chans[4];
24 
sent_cb(struct bt_l2cap_chan * chan)25 void sent_cb(struct bt_l2cap_chan *chan)
26 {
27 	LOG_DBG("%p", chan);
28 }
29 
recv_cb(struct bt_l2cap_chan * chan,struct net_buf * buf)30 int recv_cb(struct bt_l2cap_chan *chan, struct net_buf *buf)
31 {
32 	LOG_DBG("%p", chan);
33 
34 	return 0;
35 }
36 
l2cap_chan_connected_cb(struct bt_l2cap_chan * l2cap_chan)37 void l2cap_chan_connected_cb(struct bt_l2cap_chan *l2cap_chan)
38 {
39 	TEST_ASSERT("This shouldn't happen");
40 }
41 
l2cap_chan_disconnected_cb(struct bt_l2cap_chan * chan)42 void l2cap_chan_disconnected_cb(struct bt_l2cap_chan *chan)
43 {
44 	atomic_inc(&disconnected_channels);
45 }
46 
47 static struct bt_l2cap_chan_ops ops = {
48 	.connected = l2cap_chan_connected_cb,
49 	.disconnected = l2cap_chan_disconnected_cb,
50 	.recv = recv_cb,
51 	.sent = sent_cb,
52 };
53 
entrypoint_dut(void)54 void entrypoint_dut(void)
55 {
56 	/* Test purpose:
57 	 *
58 	 * Verify that a peer that doesn't support ECRED channels doesn't result
59 	 * in us keeping half-open channels.
60 	 *
61 	 * Two devices:
62 	 * - `dut`: tries to establish 4 ecred chans
63 	 * - `peer`: rejects the request
64 	 *
65 	 * Initial conditions:
66 	 * - Both devices are connected
67 	 *
68 	 * Procedure:
69 	 * - [dut] request to establish 4 ecred channels
70 	 * - [peer] reject command as unknown
71 	 * - [dut] get `disconnected` called on all 4 channels
72 	 *
73 	 * [verdict]
74 	 * - each channel gets the `disconnected` callback called
75 	 */
76 	int err;
77 	bt_addr_le_t peer = {};
78 	struct bt_conn *conn = NULL;
79 
80 	TEST_START("dut");
81 
82 	/* Initialize Bluetooth */
83 	err = bt_enable(NULL);
84 	TEST_ASSERT(err == 0, "Can't enable Bluetooth (err %d)", err);
85 	LOG_DBG("Bluetooth initialized");
86 
87 	err = bt_testlib_scan_find_name(&peer, "ecred_peer");
88 	TEST_ASSERT(!err, "Failed to start scan (err %d)", err);
89 
90 	/* Create a connection using that address */
91 	err = bt_testlib_connect(&peer, &conn);
92 	TEST_ASSERT(!err, "Failed to initiate connection (err %d)", err);
93 
94 	LOG_DBG("Connected");
95 
96 	LOG_INF("Send ECRED connection request");
97 	struct bt_l2cap_chan *chan_list[5] = {0};
98 
99 	for (int i = 0; i < 4; i++) {
100 		/* Register the callbacks */
101 		chans[i].chan.ops = &ops;
102 
103 		/* Add the channel to the connection request list */
104 		chan_list[i] = &chans[i].chan;
105 	}
106 
107 	/* The PSM doesn't matter, as the peer doesn't support the command */
108 	err = bt_l2cap_ecred_chan_connect(conn, chan_list, 0x0080);
109 	TEST_ASSERT(!err, "Error connecting l2cap channels (err %d)\n", err);
110 
111 	LOG_INF("Wait until peer rejects the channel establishment request");
112 	while (atomic_get(&disconnected_channels) < 4) {
113 		k_sleep(K_MSEC(10));
114 	}
115 
116 	TEST_PASS_AND_EXIT("dut");
117 }
118