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