1 /* main.c - HCI prop event test */
2
3 /*
4 * Copyright (c) 2019 Oticon A/S
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <zephyr/kernel.h>
10
11 #include <errno.h>
12 #include <zephyr/tc_util.h>
13 #include <zephyr/ztest.h>
14
15 #include <zephyr/bluetooth/hci.h>
16 #include <zephyr/bluetooth/buf.h>
17 #include <zephyr/bluetooth/bluetooth.h>
18 #include <zephyr/drivers/bluetooth.h>
19 #include <zephyr/sys/byteorder.h>
20
21 #define DT_DRV_COMPAT zephyr_bt_hci_test
22
23 struct driver_data {
24 bt_hci_recv_t recv;
25 };
26
27 /* HCI Proprietary vendor event */
28 const uint8_t hci_prop_evt_prefix[2] = { 0xAB, 0xBA };
29
30 struct hci_evt_prop {
31 uint8_t prefix[2];
32 } __packed;
33
34 struct hci_evt_prop_report {
35 uint8_t data_len;
36 uint8_t data[0];
37 } __packed;
38
39 /* Command handler structure for cmd_handle(). */
40 struct cmd_handler {
41 uint16_t opcode; /* HCI command opcode */
42 uint8_t len; /* HCI command response length */
43 void (*handler)(struct net_buf *buf, struct net_buf **evt,
44 uint8_t len, uint16_t opcode);
45 };
46
47 /* Add event to net_buf. */
evt_create(struct net_buf * buf,uint8_t evt,uint8_t len)48 static void evt_create(struct net_buf *buf, uint8_t evt, uint8_t len)
49 {
50 struct bt_hci_evt_hdr *hdr;
51
52 hdr = net_buf_add(buf, sizeof(*hdr));
53 hdr->evt = evt;
54 hdr->len = len;
55 }
56
57 /* Create a command complete event. */
cmd_complete(struct net_buf ** buf,uint8_t plen,uint16_t opcode)58 static void *cmd_complete(struct net_buf **buf, uint8_t plen, uint16_t opcode)
59 {
60 struct bt_hci_evt_cmd_complete *cc;
61
62 *buf = bt_buf_get_evt(BT_HCI_EVT_CMD_COMPLETE, false, K_FOREVER);
63 evt_create(*buf, BT_HCI_EVT_CMD_COMPLETE, sizeof(*cc) + plen);
64 cc = net_buf_add(*buf, sizeof(*cc));
65 cc->ncmd = 1U;
66 cc->opcode = sys_cpu_to_le16(opcode);
67 return net_buf_add(*buf, plen);
68 }
69
70 /* Loop over handlers to try to handle the command given by opcode. */
cmd_handle_helper(uint16_t opcode,struct net_buf * cmd,struct net_buf ** evt,const struct cmd_handler * handlers,size_t num_handlers)71 static int cmd_handle_helper(uint16_t opcode, struct net_buf *cmd,
72 struct net_buf **evt,
73 const struct cmd_handler *handlers,
74 size_t num_handlers)
75 {
76 for (size_t i = 0; i < num_handlers; i++) {
77 const struct cmd_handler *handler = &handlers[i];
78
79 if (handler->opcode != opcode) {
80 continue;
81 }
82
83 if (handler->handler) {
84 handler->handler(cmd, evt, handler->len, opcode);
85 return 0;
86 }
87 }
88
89 return -EINVAL;
90 }
91
92 /* Lookup the command opcode and invoke handler. */
cmd_handle(const struct device * dev,struct net_buf * cmd,const struct cmd_handler * handlers,size_t num_handlers)93 static int cmd_handle(const struct device *dev,
94 struct net_buf *cmd,
95 const struct cmd_handler *handlers,
96 size_t num_handlers)
97 {
98 struct driver_data *drv = dev->data;
99 struct net_buf *evt = NULL;
100 struct bt_hci_evt_cc_status *ccst;
101 struct bt_hci_cmd_hdr *chdr;
102 uint16_t opcode;
103 int err;
104
105 chdr = net_buf_pull_mem(cmd, sizeof(*chdr));
106 opcode = sys_le16_to_cpu(chdr->opcode);
107
108 err = cmd_handle_helper(opcode, cmd, &evt, handlers, num_handlers);
109
110 if (err == -EINVAL) {
111 ccst = cmd_complete(&evt, sizeof(*ccst), opcode);
112 ccst->status = BT_HCI_ERR_UNKNOWN_CMD;
113 }
114
115 if (evt) {
116 drv->recv(dev, evt);
117 }
118
119 return err;
120 }
121
122 /* Generic command complete with success status. */
generic_success(struct net_buf * buf,struct net_buf ** evt,uint8_t len,uint16_t opcode)123 static void generic_success(struct net_buf *buf, struct net_buf **evt,
124 uint8_t len, uint16_t opcode)
125 {
126 struct bt_hci_evt_cc_status *ccst;
127
128 ccst = cmd_complete(evt, len, opcode);
129
130 /* Fill any event parameters with zero */
131 (void)memset(ccst, 0, len);
132
133 ccst->status = BT_HCI_ERR_SUCCESS;
134 }
135
136 /* Bogus handler for BT_HCI_OP_READ_LOCAL_FEATURES. */
read_local_features(struct net_buf * buf,struct net_buf ** evt,uint8_t len,uint16_t opcode)137 static void read_local_features(struct net_buf *buf, struct net_buf **evt,
138 uint8_t len, uint16_t opcode)
139 {
140 struct bt_hci_rp_read_local_features *rp;
141
142 rp = cmd_complete(evt, sizeof(*rp), opcode);
143 rp->status = 0x00;
144 (void)memset(&rp->features[0], 0xFF, sizeof(rp->features));
145 }
146
147 /* Bogus handler for BT_HCI_OP_READ_SUPPORTED_COMMANDS. */
read_supported_commands(struct net_buf * buf,struct net_buf ** evt,uint8_t len,uint16_t opcode)148 static void read_supported_commands(struct net_buf *buf, struct net_buf **evt,
149 uint8_t len, uint16_t opcode)
150 {
151 struct bt_hci_rp_read_supported_commands *rp;
152
153 rp = cmd_complete(evt, sizeof(*rp), opcode);
154 (void)memset(&rp->commands[0], 0xFF, sizeof(rp->commands));
155 rp->status = 0x00;
156 }
157
158 /* Bogus handler for BT_HCI_OP_LE_READ_LOCAL_FEATURES. */
le_read_local_features(struct net_buf * buf,struct net_buf ** evt,uint8_t len,uint16_t opcode)159 static void le_read_local_features(struct net_buf *buf, struct net_buf **evt,
160 uint8_t len, uint16_t opcode)
161 {
162 struct bt_hci_rp_le_read_local_features *rp;
163
164 rp = cmd_complete(evt, sizeof(*rp), opcode);
165 rp->status = 0x00;
166 (void)memset(&rp->features[0], 0xFF, sizeof(rp->features));
167 }
168
169 /* Bogus handler for BT_HCI_OP_LE_READ_SUPP_STATES. */
le_read_supp_states(struct net_buf * buf,struct net_buf ** evt,uint8_t len,uint16_t opcode)170 static void le_read_supp_states(struct net_buf *buf, struct net_buf **evt,
171 uint8_t len, uint16_t opcode)
172 {
173 struct bt_hci_rp_le_read_supp_states *rp;
174
175 rp = cmd_complete(evt, sizeof(*rp), opcode);
176 rp->status = 0x00;
177 (void)memset(&rp->le_states, 0xFF, sizeof(rp->le_states));
178 }
179
180 /* Setup handlers needed for bt_enable to function. */
181 static const struct cmd_handler cmds[] = {
182 { BT_HCI_OP_READ_LOCAL_VERSION_INFO,
183 sizeof(struct bt_hci_rp_read_local_version_info),
184 generic_success },
185 { BT_HCI_OP_READ_SUPPORTED_COMMANDS,
186 sizeof(struct bt_hci_rp_read_supported_commands),
187 read_supported_commands },
188 { BT_HCI_OP_READ_LOCAL_FEATURES,
189 sizeof(struct bt_hci_rp_read_local_features),
190 read_local_features },
191 { BT_HCI_OP_READ_BD_ADDR,
192 sizeof(struct bt_hci_rp_read_bd_addr),
193 generic_success },
194 { BT_HCI_OP_SET_EVENT_MASK,
195 sizeof(struct bt_hci_evt_cc_status),
196 generic_success },
197 { BT_HCI_OP_LE_SET_EVENT_MASK,
198 sizeof(struct bt_hci_evt_cc_status),
199 generic_success },
200 { BT_HCI_OP_LE_READ_LOCAL_FEATURES,
201 sizeof(struct bt_hci_rp_le_read_local_features),
202 le_read_local_features },
203 { BT_HCI_OP_LE_READ_SUPP_STATES,
204 sizeof(struct bt_hci_rp_le_read_supp_states),
205 le_read_supp_states },
206 { BT_HCI_OP_LE_RAND,
207 sizeof(struct bt_hci_rp_le_rand),
208 generic_success },
209 { BT_HCI_OP_LE_SET_RANDOM_ADDRESS,
210 sizeof(struct bt_hci_cp_le_set_random_address),
211 generic_success },
212 { BT_HCI_OP_LE_READ_MAX_ADV_DATA_LEN,
213 sizeof(struct bt_hci_rp_le_read_max_adv_data_len),
214 generic_success },
215 };
216
217 /* HCI driver open. */
driver_open(const struct device * dev,bt_hci_recv_t recv)218 static int driver_open(const struct device *dev, bt_hci_recv_t recv)
219 {
220 struct driver_data *drv = dev->data;
221
222 drv->recv = recv;
223
224 return 0;
225 }
226
227 /* HCI driver send. */
driver_send(const struct device * dev,struct net_buf * buf)228 static int driver_send(const struct device *dev, struct net_buf *buf)
229 {
230 zassert_true(cmd_handle(dev, buf, cmds, ARRAY_SIZE(cmds)) == 0,
231 "Unknown HCI command");
232
233 net_buf_unref(buf);
234
235 return 0;
236 }
237
238 static DEVICE_API(bt_hci, driver_api) = {
239 .open = driver_open,
240 .send = driver_send,
241 };
242
243 #define TEST_DEVICE_INIT(inst) \
244 static struct driver_data driver_data_##inst = { \
245 }; \
246 DEVICE_DT_INST_DEFINE(inst, NULL, NULL, &driver_data_##inst, NULL, \
247 POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &driver_api)
248
249 DT_INST_FOREACH_STATUS_OKAY(TEST_DEVICE_INIT)
250
251 struct bt_recv_job_data {
252 struct k_work work; /* Work item */
253 struct k_sem *sync; /* Semaphore to synchronize with */
254 struct net_buf *buf; /* Net buffer to be passed to bt_recv() */
255 } job_data[CONFIG_BT_BUF_EVT_RX_COUNT];
256
257 #define job(buf) (&job_data[net_buf_id(buf)])
258
259 /* Work item handler for bt_recv() jobs. */
bt_recv_job_cb(struct k_work * item)260 static void bt_recv_job_cb(struct k_work *item)
261 {
262 const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0));
263 struct driver_data *drv = dev->data;
264 struct bt_recv_job_data *data =
265 CONTAINER_OF(item, struct bt_recv_job_data, work);
266 struct k_sem *sync = job(data->buf)->sync;
267
268 /* Send net buffer to host */
269 drv->recv(dev, data->buf);
270 data->buf = NULL;
271
272 /* Wake up bt_recv_job_submit */
273 k_sem_give(sync);
274 }
275
276 /* Prepare a job to call bt_recv() to be submitted to the system workqueue. */
bt_recv_job_submit(struct net_buf * buf)277 static void bt_recv_job_submit(struct net_buf *buf)
278 {
279 struct k_sem sync_sem;
280
281 /* Store the net buffer to be passed to bt_recv */
282 job(buf)->buf = net_buf_ref(buf);
283
284 /* Initialize job work item/semaphore */
285 k_work_init(&job(buf)->work, bt_recv_job_cb);
286 k_sem_init(&sync_sem, 0, 1);
287 job(buf)->sync = &sync_sem;
288
289 /* Submit the work item */
290 k_work_submit(&job(buf)->work);
291
292 /* Wait for bt_recv_job_cb to be done */
293 k_sem_take(&sync_sem, K_FOREVER);
294
295 net_buf_unref(buf);
296 }
297
298 /* Semaphore to test if the prop callback was called. */
299 static K_SEM_DEFINE(prop_cb_sem, 0, 1);
300
301 /* Used to verify prop event data. */
302 static uint8_t *prop_cb_data;
303 static uint8_t prop_cb_data_len;
304
305 /* Prop callback. */
prop_cb(struct net_buf_simple * buf)306 static bool prop_cb(struct net_buf_simple *buf)
307 {
308 struct hci_evt_prop *pe;
309
310 pe = net_buf_simple_pull_mem(buf, sizeof(*pe));
311
312 if (memcmp(&pe->prefix[0], &hci_prop_evt_prefix[0],
313 ARRAY_SIZE(hci_prop_evt_prefix)) == 0) {
314 struct hci_evt_prop_report *per;
315
316 per = net_buf_simple_pull_mem(buf, sizeof(*per));
317
318 uint8_t data_len = per->data_len;
319 uint8_t *data = &per->data[0];
320
321 /* Allocate memory for storing the data */
322 prop_cb_data = k_malloc(data_len);
323 zassert_not_null(prop_cb_data, "Cannot allocate memory");
324
325 /* Copy data so it can be verified later */
326 memcpy(prop_cb_data, data, data_len);
327 prop_cb_data_len = data_len;
328
329 /* Give control back to test */
330 k_sem_give(&prop_cb_sem);
331
332 return true;
333 }
334
335 return false;
336 }
337
338 /* Create a HCI Vendor Specific event to carry the prop event report. */
prop_evt(struct net_buf * buf,uint8_t pelen)339 static void *prop_evt(struct net_buf *buf, uint8_t pelen)
340 {
341 struct hci_evt_prop *pe;
342
343 evt_create(buf, BT_HCI_EVT_VENDOR, sizeof(*pe) + pelen);
344 pe = net_buf_add(buf, sizeof(*pe));
345 memcpy(&pe->prefix[0], &hci_prop_evt_prefix[0],
346 ARRAY_SIZE(hci_prop_evt_prefix));
347
348 return net_buf_add(buf, pelen);
349 }
350
351 /* Send a prop event report wit the given data. */
send_prop_report(uint8_t * data,uint8_t data_len)352 static void send_prop_report(uint8_t *data, uint8_t data_len)
353 {
354 struct net_buf *buf;
355 struct hci_evt_prop_report *per;
356
357 buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER);
358 per = prop_evt(buf, sizeof(*per) + data_len);
359 per->data_len = data_len;
360 memcpy(&per->data[0], data, data_len);
361
362 /* Submit job */
363 bt_recv_job_submit(buf);
364 }
365
366 ZTEST_SUITE(test_hci_prop_evt, NULL, NULL, NULL, NULL, NULL);
367
368 /* Test. */
ZTEST(test_hci_prop_evt,test_hci_prop_evt_entry)369 ZTEST(test_hci_prop_evt, test_hci_prop_evt_entry)
370 {
371 /* Go! Wait until Bluetooth initialization is done */
372 zassert_true((bt_enable(NULL) == 0),
373 "bt_enable failed");
374
375 /* Register the prop callback */
376 bt_hci_register_vnd_evt_cb(prop_cb);
377
378 /* Generate some data */
379 uint8_t data_len = 10;
380 uint8_t data[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
381
382 /* Send the prop event report */
383 send_prop_report(&data[0], data_len);
384
385 /* Wait for the prop callback to be called */
386 zassert_true(k_sem_take(&prop_cb_sem, K_MSEC(100)) == 0,
387 "prop_cb was not called within timeout");
388
389 /* Verify the data length */
390 zassert_true(prop_cb_data_len == data_len,
391 "prop_cb_data_len invalid");
392
393 /* Verify the data itself */
394 zassert_true(memcmp(prop_cb_data, data, data_len) == 0,
395 "prop_cb_data invalid");
396
397 /* Free the data memory */
398 k_free(prop_cb_data);
399 }
400