1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdbool.h>
8 
9 #include <zephyr/kernel.h>
10 #include <zephyr/bluetooth/bluetooth.h>
11 #include <zephyr/logging/log.h>
12 #include <sys/types.h>
13 
14 #include "ad.h"
15 #include "babblekit/testcase.h"
16 
17 LOG_MODULE_REGISTER(advertiser, LOG_LEVEL_INF);
18 
create_adv(struct bt_le_ext_adv ** adv)19 static void create_adv(struct bt_le_ext_adv **adv)
20 {
21 	int err;
22 	struct bt_le_adv_param params;
23 
24 	memset(&params, 0, sizeof(struct bt_le_adv_param));
25 
26 	params.options |= BT_LE_ADV_OPT_EXT_ADV;
27 
28 	params.id = BT_ID_DEFAULT;
29 	params.sid = 0;
30 	params.interval_min = BT_GAP_ADV_SLOW_INT_MIN;
31 	params.interval_max = BT_GAP_ADV_SLOW_INT_MAX;
32 
33 	err = bt_le_ext_adv_create(&params, NULL, adv);
34 	if (err) {
35 		TEST_FAIL("Failed to create advertiser (%d)\n", err);
36 	}
37 }
38 
start_adv(struct bt_le_ext_adv * adv)39 static void start_adv(struct bt_le_ext_adv *adv)
40 {
41 	int err;
42 	int32_t timeout = 0;
43 	uint8_t num_events = 0;
44 
45 	struct bt_le_ext_adv_start_param start_params;
46 
47 	start_params.timeout = timeout;
48 	start_params.num_events = num_events;
49 
50 	err = bt_le_ext_adv_start(adv, &start_params);
51 	if (err) {
52 		TEST_FAIL("Failed to start advertiser (%d)\n", err);
53 	}
54 }
55 
ad_deserialize(const uint8_t * input,size_t input_size,struct bt_data output[])56 static size_t ad_deserialize(const uint8_t *input, size_t input_size, struct bt_data output[])
57 {
58 	uint8_t type;
59 	uint8_t data_len;
60 	const uint8_t *data;
61 
62 	size_t idx = 0;
63 	size_t ad_len = 0;
64 
65 	while (idx < input_size) {
66 		data_len = input[idx] - 1;
67 		type = input[idx + 1];
68 		data = &input[idx + 2];
69 
70 		if (data_len + 2 > input_size - idx) {
71 			TEST_FAIL("malformed advertising data, expected %d bytes of data but got "
72 				  "only %d "
73 				  "bytes",
74 				  data_len + 1, input_size - idx);
75 			return -1;
76 		}
77 
78 		output[ad_len].data = data;
79 		output[ad_len].type = type;
80 		output[ad_len].data_len = data_len;
81 
82 		ad_len += 1;
83 		idx += data_len + 2;
84 	}
85 
86 	return ad_len;
87 }
88 
set_ad_data(struct bt_le_ext_adv * adv,const uint8_t * serialized_ad,size_t serialized_ad_size)89 static int set_ad_data(struct bt_le_ext_adv *adv, const uint8_t *serialized_ad,
90 			size_t serialized_ad_size)
91 {
92 	int err;
93 	size_t ad_len = 0;
94 	uint8_t max_ad_len = 10;
95 
96 	struct bt_data ad[max_ad_len];
97 
98 	ad_len = ad_deserialize(serialized_ad, serialized_ad_size, ad);
99 
100 	err = bt_le_ext_adv_set_data(adv, ad, ad_len, NULL, 0);
101 	if (err != 0 && err != -EDOM) {
102 		TEST_FAIL("Failed to set advertising data (%d)\n", err);
103 	}
104 
105 	return err;
106 }
107 
entrypoint_advertiser(void)108 void entrypoint_advertiser(void)
109 {
110 	/* Test purpose:
111 	 *
112 	 * Verifies that we can send Advertising Data up to the size set in the
113 	 * Kconfig. And if we try to set data too large we get the correct
114 	 * error code.
115 	 *
116 	 * Two devices:
117 	 * - `advertiser`: tries to send the data
118 	 * - `scanner`: will receive the data and check that they match with the
119 	 *   data sent
120 	 *
121 	 * Procedure:
122 	 * - [advertiser] try to use `test_ad1` as advertising data
123 	 * - [advertiser] get the expected error (adv or scan resp too large)
124 	 * - [advertiser] try to use `test_ad2` as advertising data
125 	 * - [advertiser] get a success
126 	 * - [advertiser] start advertiser
127 	 * - [scanner] start scanner
128 	 * - [scanner] wait until receiving advertising data matching `test_ad2`
129 	 *
130 	 * [verdict]
131 	 * - advertiser receives the correct error code when trying to set
132 	 *   advertising data
133 	 * - scanner receives the correct data in advertising data
134 	 */
135 	int err;
136 	struct bt_le_ext_adv *adv = NULL;
137 
138 	TEST_START("advertiser");
139 
140 	err = bt_enable(NULL);
141 	TEST_ASSERT(err == 0, "Can't enable Bluetooth (err %d)", err);
142 
143 	LOG_DBG("Bluetooth initialized");
144 
145 	create_adv(&adv);
146 	LOG_DBG("Advertiser created");
147 
148 	err = set_ad_data(adv, test_ad1, ARRAY_SIZE(test_ad1));
149 	TEST_ASSERT(err == -EDOM,
150 		    "Tried to set Advertising Data larger than the controller can accept, "
151 		    "expected failure with error code %d but got %d",
152 		    -EDOM, err);
153 
154 	err = set_ad_data(adv, test_ad2, ARRAY_SIZE(test_ad2));
155 	TEST_ASSERT(err == 0,
156 		    "Tried to set Advertising Data as large as the maximum advertising data size "
157 		    "the controller can accept, expected success but got error code %d",
158 		    err);
159 	LOG_DBG("AD set");
160 
161 	start_adv(adv);
162 	LOG_DBG("Advertiser started");
163 
164 	TEST_PASS("advertiser");
165 }
166