1 /*
2  * Copyright (c) 2023 Codecoup
3  * Copyright (c) 2024-2025 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <errno.h>
9 #include <stdint.h>
10 #include <stdlib.h>
11 
12 #include <zephyr/bluetooth/bluetooth.h>
13 #include <zephyr/bluetooth/hci_types.h>
14 #include <zephyr/bluetooth/iso.h>
15 #include <zephyr/fff.h>
16 #include <zephyr/net_buf.h>
17 #include <zephyr/ztest_assert.h>
18 
19 #include "conn.h"
20 #include "iso.h"
21 
22 /* List of fakes used by this unit tester */
23 #define FFF_FAKES_LIST(FAKE) FAKE(bt_iso_chan_get_tx_sync)
24 
25 static struct bt_iso_server *iso_server;
26 
27 DEFINE_FAKE_VALUE_FUNC(int, bt_iso_chan_get_tx_sync, const struct bt_iso_chan *,
28 		       struct bt_iso_tx_info *);
29 
bt_iso_chan_send(struct bt_iso_chan * chan,struct net_buf * buf,uint16_t seq_num)30 int bt_iso_chan_send(struct bt_iso_chan *chan, struct net_buf *buf, uint16_t seq_num)
31 {
32 	if (chan->ops != NULL && chan->ops->sent != NULL) {
33 		chan->ops->sent(chan);
34 	}
35 
36 	return 0;
37 }
38 
bt_iso_chan_send_ts(struct bt_iso_chan * chan,struct net_buf * buf,uint16_t seq_num,uint32_t ts)39 int bt_iso_chan_send_ts(struct bt_iso_chan *chan, struct net_buf *buf, uint16_t seq_num,
40 			uint32_t ts)
41 {
42 	if (chan->ops != NULL && chan->ops->sent != NULL) {
43 		chan->ops->sent(chan);
44 	}
45 
46 	return 0;
47 }
48 
bt_iso_server_register(struct bt_iso_server * server)49 int bt_iso_server_register(struct bt_iso_server *server)
50 {
51 	zassert_not_null(server, "server is NULL");
52 	zassert_not_null(server->accept, "server->accept is NULL");
53 	zassert_is_null(iso_server, "iso_server is NULL");
54 
55 	iso_server = server;
56 
57 	return 0;
58 }
59 
bt_iso_server_unregister(struct bt_iso_server * server)60 int bt_iso_server_unregister(struct bt_iso_server *server)
61 {
62 	zassert_not_null(server, "server is NULL");
63 	zassert_equal_ptr(iso_server, server, "not registered");
64 
65 	iso_server = NULL;
66 
67 	return 0;
68 }
69 
bt_iso_chan_disconnect(struct bt_iso_chan * chan)70 int bt_iso_chan_disconnect(struct bt_iso_chan *chan)
71 {
72 	return mock_bt_iso_disconnected(chan, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
73 }
74 
mock_bt_iso_init(void)75 void mock_bt_iso_init(void)
76 {
77 	FFF_FAKES_LIST(RESET_FAKE);
78 }
79 
mock_bt_iso_cleanup(void)80 void mock_bt_iso_cleanup(void)
81 {
82 
83 }
84 
bt_iso_setup_data_path(const struct bt_iso_chan * chan,uint8_t dir,const struct bt_iso_chan_path * path)85 int bt_iso_setup_data_path(const struct bt_iso_chan *chan, uint8_t dir,
86 			   const struct bt_iso_chan_path *path)
87 {
88 	return 0;
89 }
90 
bt_iso_remove_data_path(const struct bt_iso_chan * chan,uint8_t dir)91 int bt_iso_remove_data_path(const struct bt_iso_chan *chan, uint8_t dir)
92 {
93 	return 0;
94 }
95 
mock_bt_iso_connected(struct bt_conn * iso)96 void mock_bt_iso_connected(struct bt_conn *iso)
97 {
98 	struct bt_iso_chan *chan = iso->chan;
99 
100 	chan->state = BT_ISO_STATE_CONNECTED;
101 	chan->iso = iso;
102 
103 	chan->ops->connected(chan);
104 }
105 
mock_bt_iso_accept(struct bt_conn * conn,uint8_t cig_id,uint8_t cis_id,struct bt_iso_chan ** chan)106 int mock_bt_iso_accept(struct bt_conn *conn, uint8_t cig_id, uint8_t cis_id,
107 		       struct bt_iso_chan **chan)
108 {
109 	struct bt_iso_accept_info info = {
110 		.acl = conn,
111 		.cig_id = cig_id,
112 		.cis_id = cis_id,
113 	};
114 	struct bt_conn *iso;
115 	int err;
116 
117 	zassert_not_null(iso_server, "iso_server is NULL");
118 
119 	err = iso_server->accept(&info, chan);
120 	if (err != 0) {
121 		return err;
122 	}
123 
124 	zassert_not_null(*chan, "chan is NULL");
125 
126 	iso = malloc(sizeof(struct bt_conn));
127 	zassert_not_null(iso);
128 
129 	iso->chan = (*chan);
130 	mock_bt_iso_connected(iso);
131 
132 	return 0;
133 }
134 
mock_bt_iso_disconnected(struct bt_iso_chan * chan,uint8_t err)135 int mock_bt_iso_disconnected(struct bt_iso_chan *chan, uint8_t err)
136 {
137 	chan->state = BT_ISO_STATE_DISCONNECTED;
138 	chan->ops->disconnected(chan, err);
139 	free(chan->iso);
140 	chan->iso = NULL;
141 
142 	return 0;
143 }
144 
145 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
146 static struct bt_iso_big_cb *iso_cb;
147 
bt_iso_big_register_cb(struct bt_iso_big_cb * cb)148 int bt_iso_big_register_cb(struct bt_iso_big_cb *cb)
149 {
150 	if (cb == NULL) {
151 		return -EINVAL;
152 	}
153 
154 	iso_cb = cb;
155 
156 	return 0;
157 }
158 
bt_iso_big_create(struct bt_le_ext_adv * padv,struct bt_iso_big_create_param * param,struct bt_iso_big ** out_big)159 int bt_iso_big_create(struct bt_le_ext_adv *padv, struct bt_iso_big_create_param *param,
160 		      struct bt_iso_big **out_big)
161 {
162 	struct bt_iso_big *big;
163 
164 	zassert_not_null(out_big);
165 	zassert_not_null(param);
166 	zassert_not_equal(param->num_bis, 0);
167 
168 	big = malloc(sizeof(struct bt_iso_big));
169 	zassert_not_null(big);
170 	big->num_bis = 0U;
171 
172 	for (uint8_t i = 0U; i < param->num_bis; i++) {
173 		struct bt_iso_chan *bis = param->bis_channels[i];
174 		struct bt_conn *iso;
175 
176 		zassert_not_null(bis);
177 
178 		iso = malloc(sizeof(struct bt_conn));
179 		zassert_not_null(iso);
180 		big->bis[i] = bis;
181 		big->num_bis++;
182 
183 		iso->chan = bis;
184 		mock_bt_iso_connected(iso);
185 	}
186 
187 	*out_big = big;
188 
189 	if (iso_cb != NULL && iso_cb->started != NULL) {
190 		iso_cb->started(big);
191 	}
192 
193 	return 0;
194 }
195 
bt_iso_big_terminate(struct bt_iso_big * big)196 int bt_iso_big_terminate(struct bt_iso_big *big)
197 {
198 	/* TODO: Call chan->ops->disconnected(*chan); for each BIS */
199 	zassert_not_equal(big->num_bis, 0);
200 
201 	for (uint8_t i = 0U; i < big->num_bis; i++) {
202 		struct bt_iso_chan *bis = big->bis[i];
203 
204 		zassert_not_null(bis, "big %p", big);
205 
206 		mock_bt_iso_disconnected(bis, BT_HCI_ERR_LOCALHOST_TERM_CONN);
207 	}
208 
209 	if (iso_cb != NULL && iso_cb->stopped != NULL) {
210 		iso_cb->stopped(big, BT_HCI_ERR_LOCALHOST_TERM_CONN);
211 	}
212 
213 	free(big);
214 
215 	return 0;
216 }
217 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
218