1 /*
2  * Copyright (c) 2021 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <stddef.h>
9 #include <zephyr/ztest.h>
10 
11 #include <zephyr/bluetooth/bluetooth.h>
12 #include <zephyr/bluetooth/hci.h>
13 #include <zephyr/sys/byteorder.h>
14 #include <host/hci_core.h>
15 
16 #include "util/util.h"
17 #include "util/memq.h"
18 #include "util/mem.h"
19 #include "util/dbuf.h"
20 
21 #include "pdu_df.h"
22 #include "lll/pdu_vendor.h"
23 #include "pdu.h"
24 
25 #include "hal/ccm.h"
26 
27 #include "lll.h"
28 #include "lll/lll_adv_types.h"
29 #include "lll_adv.h"
30 #include "lll/lll_adv_pdu.h"
31 #include "lll_adv_sync.h"
32 #include "lll/lll_df_types.h"
33 
34 #include "ull_adv_types.h"
35 #include "ull_adv_internal.h"
36 
37 #include "ll.h"
38 #include "common.h"
39 
40 #define PDU_PAULOAD_BUFF_SIZE 100
41 #define TEST_CTE_LENGTH 20
42 
43 /* Controller code uses static function sync_acquire to get adv. sync.
44  * For test purposes it is used as global variable to avoid complete
45  * creation of advertising set.
46  */
47 static struct ll_adv_sync_set g_sync_set;
48 static struct lll_df_adv_cfg g_df_cfg;
49 
50 static void common_pdu_adv_data_set(struct pdu_adv *pdu, const uint8_t *data, uint8_t len);
51 
52 /*
53  * @brief Helper function to create advertising set.
54  *
55  * The function creates advertising set to an extent required to test adding CTE to periodic
56  * advertising chains. The function returns handle to advertising set that may be used
57  * in calls to ULL functions related with advertising.
58  *
59  * @param hci_handle equivalent of a handle received from HCI command.
60  *
61  * @return Handle to created advertising set.
62  */
common_create_adv_set(uint8_t hci_handle)63 struct ll_adv_set *common_create_adv_set(uint8_t hci_handle)
64 {
65 	struct lll_adv_sync *lll_sync;
66 	struct ll_adv_set *adv_set;
67 	uint8_t handle;
68 	uint8_t err;
69 
70 	zassert_true(hci_handle < BT_HCI_LE_ADV_HANDLE_MAX,
71 		     "Advertising set handle: %" PRIu8 " exceeds maximum handles value %" PRIu8,
72 		     hci_handle, BT_HCI_LE_ADV_HANDLE_MAX);
73 	err = ll_adv_set_by_hci_handle_get_or_new(hci_handle, &handle);
74 	zassert_equal(err, 0, "Unexpected error while create new advertising set, err: %" PRIu8,
75 		      err);
76 
77 	adv_set = ull_adv_set_get(handle);
78 	zassert_not_null(adv_set, 0, "Unexpectedly advertising set is NULL");
79 	/* Note: there is single lll_adv_sync instance. If created more than one advertising set
80 	 * all will have reference to the same lll_adv_sync instance.
81 	 */
82 	lll_sync = &g_sync_set.lll;
83 	adv_set->lll.sync = &g_sync_set.lll;
84 	lll_hdr_init(&adv_set->lll, adv_set);
85 	g_sync_set.lll.adv = &adv_set->lll;
86 	lll_hdr_init(lll_sync, &g_sync_set);
87 
88 	err = lll_adv_init();
89 	zassert_equal(err, 0, "Unexpected error while initialization advertising set, err: %d",
90 		      err);
91 
92 	lll_hdr_init(lll_sync, &g_sync_set);
93 
94 	lll_adv_data_reset(&lll_sync->data);
95 	err = lll_adv_data_init(&lll_sync->data);
96 	zassert_equal(err, 0,
97 		      "Unexpected error while initialization advertising data init, err: %d", err);
98 
99 	adv_set->is_created = 1U;
100 
101 	return adv_set;
102 }
103 
104 /*
105  * @brief Release advertising set.
106  *
107  * @param adv_set Pointer to advertising set to be released.
108  */
common_release_adv_set(struct ll_adv_set * adv_set)109 void common_release_adv_set(struct ll_adv_set *adv_set)
110 {
111 	struct ll_adv_sync_set *sync;
112 
113 	if (adv_set->lll.sync) {
114 		sync = HDR_LLL2ULL(adv_set->lll.sync);
115 		if (sync) {
116 			sync->is_started = 0U;
117 		}
118 
119 		lll_adv_data_reset(&sync->lll.data);
120 	}
121 	adv_set->lll.sync = NULL;
122 	if (adv_set->df_cfg->is_enabled) {
123 		adv_set->df_cfg->is_enabled = 0U;
124 	}
125 	adv_set->df_cfg = NULL;
126 	adv_set->is_created = 0U;
127 }
128 
129 /*
130  * @brief Helper function that creates periodic advertising chain.
131  *
132  * The function creates periodic advertising chain with provided number of PDUs @p pdu_count.
133  * The created chain is enqueued in provided advertising set. Number of requested PDUs includes
134  * head of a chain AUX_SYNC_IND.
135  * Each created PDU will hold payload data in following pattern:
136  * "test%d test%d test%d", where '%d' is substituted by PDU index.
137  *
138  * @param adv_set   Pointer to advertising set to enqueue created chain.
139  * @param pdu_count Requested number of PDUs in a chain.
140  */
common_create_per_adv_chain(struct ll_adv_set * adv_set,uint8_t pdu_count)141 void common_create_per_adv_chain(struct ll_adv_set *adv_set, uint8_t pdu_count)
142 {
143 	struct pdu_adv *pdu_prev, *pdu, *pdu_new;
144 	char pdu_buff[PDU_PAULOAD_BUFF_SIZE];
145 	void *extra_data_prev, *extra_data;
146 	struct lll_adv_sync *lll_sync;
147 	bool adi_in_sync_ind;
148 	uint8_t err, pdu_idx;
149 
150 	lll_sync = adv_set->lll.sync;
151 	pdu = lll_adv_sync_data_peek(lll_sync, NULL);
152 	ull_adv_sync_pdu_init(pdu, 0U, 0U, 0U, NULL);
153 
154 	err = ull_adv_sync_pdu_alloc(adv_set, ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST, &pdu_prev,
155 				     &pdu, &extra_data_prev, &extra_data, &pdu_idx);
156 	zassert_equal(err, 0, "Unexpected error while PDU allocation, err: %d", err);
157 
158 	if (extra_data) {
159 		ull_adv_sync_extra_data_set_clear(extra_data_prev, extra_data, 0, 0, NULL);
160 	}
161 
162 	if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)) {
163 		adi_in_sync_ind = ull_adv_sync_pdu_had_adi(pdu_prev);
164 	}
165 
166 	/* Create AUX_SYNC_IND PDU as a head of chain */
167 	if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT) && adi_in_sync_ind) {
168 		ull_adv_sync_pdu_init(pdu, (pdu_count > 1 ? ULL_ADV_PDU_HDR_FIELD_AUX_PTR |
169 							    ULL_ADV_PDU_HDR_FIELD_ADI :
170 							    ULL_ADV_PDU_HDR_FIELD_ADI),
171 				      lll_sync->adv->phy_s,
172 				      lll_sync->adv->phy_flags, NULL);
173 
174 	} else {
175 		ull_adv_sync_pdu_init(pdu, (pdu_count > 1 ? ULL_ADV_PDU_HDR_FIELD_AUX_PTR :
176 							    ULL_ADV_PDU_HDR_FIELD_NONE),
177 				      lll_sync->adv->phy_s,
178 				      lll_sync->adv->phy_flags, NULL);
179 
180 	}
181 
182 	/* Add some AD for testing */
183 	snprintf(pdu_buff, ARRAY_SIZE(pdu_buff), "test%" PRIu8 " test%" PRIu8 " test%" PRIu8 "", 0,
184 		 0, 0);
185 	common_pdu_adv_data_set(pdu, pdu_buff, strlen(pdu_buff));
186 	/* Create AUX_CHAIN_IND PDUs. Start from 1, AUX_SYNC_IND is first PDU. */
187 	for (uint8_t idx = 1; idx < pdu_count; ++idx) {
188 		snprintf(pdu_buff, ARRAY_SIZE(pdu_buff),
189 			 "test%" PRIu8 " test%" PRIu8 " test%" PRIu8 "", idx, idx, idx);
190 		/* Allocate new PDU */
191 		pdu_new = lll_adv_pdu_alloc_pdu_adv();
192 		zassert_not_null(pdu_new, "Cannot allocate new PDU.");
193 		/* Initialize new empty PDU. Last AUX_CHAIN_IND may not include AuxPtr. */
194 		if (idx < pdu_count - 1) {
195 			if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT) &&
196 			    adi_in_sync_ind) {
197 				ull_adv_sync_pdu_init(pdu_new,
198 						ULL_ADV_PDU_HDR_FIELD_AUX_PTR |
199 						ULL_ADV_PDU_HDR_FIELD_ADI,
200 						lll_sync->adv->phy_s,
201 						lll_sync->adv->phy_flags, NULL);
202 			} else {
203 				ull_adv_sync_pdu_init(pdu_new,
204 						ULL_ADV_PDU_HDR_FIELD_AUX_PTR,
205 						lll_sync->adv->phy_s,
206 						lll_sync->adv->phy_flags, NULL);
207 			}
208 		} else {
209 			if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT) &&
210 			    adi_in_sync_ind) {
211 				ull_adv_sync_pdu_init(pdu_new,
212 						ULL_ADV_PDU_HDR_FIELD_ADI,
213 						0U, 0U, NULL);
214 			} else {
215 				ull_adv_sync_pdu_init(pdu_new,
216 						ULL_ADV_PDU_HDR_FIELD_NONE,
217 						0U, 0U, NULL);
218 			}
219 		}
220 		/* Add some AD for testing */
221 		common_pdu_adv_data_set(pdu_new, pdu_buff, strlen(pdu_buff));
222 		/* Link to previous PDU */
223 		lll_adv_pdu_linked_append(pdu_new, pdu);
224 		pdu = pdu_new;
225 	}
226 
227 	lll_adv_sync_data_enqueue(lll_sync, pdu_idx);
228 }
229 
230 /*
231  * @brief Helper function to release periodic advertising chain that was enqueued for
232  * advertising set.
233  *
234  * @param adv_set Pointer to advertising set to release a PDUs chain.
235  */
common_release_per_adv_chain(struct ll_adv_set * adv_set)236 void common_release_per_adv_chain(struct ll_adv_set *adv_set)
237 {
238 	struct lll_adv_sync *lll_sync;
239 	struct pdu_adv *pdu;
240 
241 	lll_sync = adv_set->lll.sync;
242 	pdu = lll_adv_sync_data_peek(lll_sync, NULL);
243 	if (pdu != NULL) {
244 		lll_adv_pdu_linked_release_all(pdu);
245 	}
246 
247 	pdu = (void *)lll_sync->data.pdu[lll_sync->data.first];
248 	if (pdu != NULL) {
249 		lll_adv_pdu_linked_release_all(pdu);
250 	}
251 }
252 
253 /*
254  * @brief Helper function that validates content of periodic advertising PDU.
255  *
256  * The function verifies if content of periodic advertising PDU as expected. The function
257  * verifies two types of PDUs: AUX_SYNC_IND and AUX_CHAIN_IND. AUX_CHAIN_IND is validated
258  * as if its superior PDU is AUX_SYNC_IND only.
259  *
260  * Expected fields in extended advertising header are provided by @p exp_ext_hdr_flags.
261  *
262  * Note: The function expects that there is no ACAD data in the PDU.
263  *
264  * @param pdu Pointer to PDU to be verified.
265  * @param type Type of the PDU.
266  * @param exp_ext_hdr_flags Bitfield with expected extended header flags.
267  */
common_validate_per_adv_pdu(struct pdu_adv * pdu,enum test_pdu_ext_adv_type type,uint16_t exp_ext_hdr_flags)268 void common_validate_per_adv_pdu(struct pdu_adv *pdu, enum test_pdu_ext_adv_type type,
269 				 uint16_t exp_ext_hdr_flags)
270 {
271 	struct pdu_adv_com_ext_adv *com_hdr;
272 	struct pdu_adv_ext_hdr *ext_hdr;
273 	uint8_t ext_hdr_len;
274 	uint8_t *dptr;
275 
276 	if (pdu->len > 1) {
277 		com_hdr = &pdu->adv_ext_ind;
278 		/* Non-connectable and Non-scannable adv mode */
279 		zassert_equal(com_hdr->adv_mode, 0U,
280 			      "Unexpected mode of extended advertising PDU: %" PRIu8,
281 			      com_hdr->adv_mode);
282 
283 		ext_hdr = &com_hdr->ext_hdr;
284 		dptr = ext_hdr->data;
285 
286 		if (com_hdr->ext_hdr_len > 0) {
287 			zassert_false(ext_hdr->adv_addr,
288 				      "Unexpected AdvA field in extended advertising header");
289 			zassert_false(ext_hdr->tgt_addr,
290 				      "Unexpected TargetA field in extended advertising header");
291 			if (exp_ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_CTE_INFO) {
292 				zassert_true(
293 					ext_hdr->cte_info,
294 					"Missing expected CteInfo field in extended advertising header");
295 				dptr += sizeof(struct pdu_cte_info);
296 			} else {
297 				zassert_false(
298 					ext_hdr->cte_info,
299 					"Unexpected CteInfo field in extended advertising header");
300 			}
301 			if (exp_ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_ADI) {
302 				zassert_true(
303 					ext_hdr->adi,
304 					"Missing expected ADI field in extended advertising header");
305 				dptr += sizeof(struct pdu_adv_adi);
306 			} else {
307 				zassert_false(
308 					ext_hdr->adi,
309 					"Unexpected ADI field in extended advertising header");
310 			}
311 			if (exp_ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_AUX_PTR) {
312 				zassert_true(
313 					ext_hdr->aux_ptr,
314 					"Missing expected AuxPtr field in extended advertising header");
315 				dptr += sizeof(struct pdu_adv_aux_ptr);
316 			} else {
317 				zassert_false(
318 					ext_hdr->aux_ptr,
319 					"Unexpected AuxPtr field in extended advertising header");
320 			}
321 			zassert_false(ext_hdr->sync_info,
322 				      "Unexpected SyncInfo field in extended advertising header");
323 			if (exp_ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_TX_POWER) {
324 				zassert_true(
325 					ext_hdr->tx_pwr,
326 					"Missing expected CteInfo field in extended advertising header");
327 				dptr += sizeof(uint8_t);
328 			} else {
329 				zassert_false(
330 					ext_hdr->tx_pwr,
331 					"Unexpected CteInfo field in extended advertising header");
332 			}
333 
334 			/* Calculate extended header len, ACAD should not be available.
335 			 * ull_adv_aux_hdr_len_calc returns ext hdr length without it.
336 			 */
337 			ext_hdr_len = ull_adv_aux_hdr_len_calc(com_hdr, &dptr);
338 			zassert_equal(com_hdr->ext_hdr_len,
339 				      ext_hdr_len - PDU_AC_EXT_HEADER_SIZE_MIN,
340 				      "Extended header length: %" PRIu8
341 				      " different than expected %" PRIu8,
342 				      ext_hdr_len, com_hdr->ext_hdr_len);
343 
344 			if (exp_ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_AD_DATA) {
345 				zassert_true((pdu->len - ext_hdr_len) > 0,
346 					     "Missing expected advertising data in PDU");
347 			} else {
348 				zassert_equal(pdu->len - ext_hdr_len, 0,
349 					      "Unexpected advertising data in PDU");
350 			}
351 		} else {
352 			zassert_equal(exp_ext_hdr_flags, ULL_ADV_PDU_HDR_FIELD_AD_DATA,
353 				      "Unexpected extended header flags: %" PRIu16,
354 				      exp_ext_hdr_flags);
355 		}
356 	}
357 }
358 
359 /*
360  * @brief Helper function to prepare CTE configuration for a given advertising set.
361  *
362  * Note: There is a single instance of CTE configuration. In case there is a need
363  * to use multiple advertising sets at once, all will use the same CTE configuration.
364  *
365  * @param adv       Pointer to advertising set
366  * @param cte_count Requested number of CTEs to be send
367  */
common_prepare_df_cfg(struct ll_adv_set * adv,uint8_t cte_count)368 void common_prepare_df_cfg(struct ll_adv_set *adv, uint8_t cte_count)
369 {
370 	/* Prepare CTE configuration */
371 	g_df_cfg.cte_count = cte_count;
372 	g_df_cfg.cte_length = TEST_CTE_LENGTH;
373 	g_df_cfg.cte_type = BT_HCI_LE_AOD_CTE_2US;
374 
375 	adv->df_cfg = &g_df_cfg;
376 }
377 
378 /*
379  * @brief Helper function that validates correctness of periodic advertising chain.
380  *
381  * The function expects that all periodic advertising chain PDUs will have advertising data.
382  *
383  * @param adv       Pointer to advertising set
384  * @param pdu_count Number of PDUs in a chain
385  */
common_validate_per_adv_chain(struct ll_adv_set * adv,uint8_t pdu_count)386 void common_validate_per_adv_chain(struct ll_adv_set *adv, uint8_t pdu_count)
387 {
388 	uint16_t ext_hdr_flags;
389 	struct pdu_adv *pdu;
390 
391 	pdu = lll_adv_sync_data_peek(adv->lll.sync, NULL);
392 
393 	/* Validate AUX_SYNC_IND */
394 	if (pdu_count > 1) {
395 		ext_hdr_flags = ULL_ADV_PDU_HDR_FIELD_AUX_PTR | ULL_ADV_PDU_HDR_FIELD_AD_DATA;
396 	} else {
397 		ext_hdr_flags = ULL_ADV_PDU_HDR_FIELD_AD_DATA;
398 	}
399 
400 	common_validate_per_adv_pdu(pdu, TEST_PDU_EXT_ADV_SYNC_IND, ext_hdr_flags);
401 	pdu = lll_adv_pdu_linked_next_get(pdu);
402 	if (pdu_count > 1) {
403 		zassert_not_null(pdu, "Expected PDU in periodic advertising chain is NULL");
404 	} else {
405 		zassert_is_null(pdu, "Unexpected PDU in a single PDU periodic advertising chain");
406 	}
407 	/* Validate AUX_CHAIN_IND PDUs in a periodic advertising chain. Start from 1, because
408 	 * first PDU is AUX_SYNC_IND.
409 	 */
410 	for (uint8_t idx = 1; idx < pdu_count; ++idx) {
411 		if (idx != (pdu_count - 1)) {
412 			ext_hdr_flags =
413 				ULL_ADV_PDU_HDR_FIELD_AUX_PTR | ULL_ADV_PDU_HDR_FIELD_AD_DATA;
414 		} else {
415 			ext_hdr_flags = ULL_ADV_PDU_HDR_FIELD_AD_DATA;
416 		}
417 
418 		common_validate_per_adv_pdu(pdu, TEST_PDU_EXT_ADV_CHAIN_IND, ext_hdr_flags);
419 		pdu = lll_adv_pdu_linked_next_get(pdu);
420 		if (idx != (pdu_count - 1)) {
421 			zassert_not_null(pdu, "Expected PDU in periodic advertising chain is NULL");
422 		} else {
423 			zassert_is_null(pdu, "Unexpected PDU at end of periodic advertising chain");
424 		}
425 	}
426 }
427 
428 /*
429  * @brief Helper function that validates correctness of periodic advertising chain including CTE
430  *
431  * The number of PDUs including advertising data or CTE is provided by appropriate function
432  * arguments. PUDs including CTE are always first #N PDUs. The same rule applies to PDUs including
433  * advertising data. So maximum number of PDUs in a chain is maximum value from pair @p cte_count
434  * and @p ad_data_count.
435  *
436  * @param adv               Pointer to advertising set
437  * @param cte_count         Number of PDUs including CTE
438  * @param ad_data_pdu_count Number of PDUs including advertising data
439  */
common_validate_chain_with_cte(struct ll_adv_set * adv,uint8_t cte_count,uint8_t ad_data_pdu_count)440 void common_validate_chain_with_cte(struct ll_adv_set *adv, uint8_t cte_count,
441 				    uint8_t ad_data_pdu_count)
442 {
443 	uint16_t ext_hdr_flags;
444 	struct pdu_adv *pdu;
445 	uint8_t pdu_count;
446 
447 	pdu = lll_adv_sync_data_peek(adv->lll.sync, NULL);
448 	if (cte_count > 1) {
449 		ext_hdr_flags = ULL_ADV_PDU_HDR_FIELD_AUX_PTR | ULL_ADV_PDU_HDR_FIELD_CTE_INFO;
450 
451 	} else {
452 		ext_hdr_flags = ULL_ADV_PDU_HDR_FIELD_CTE_INFO;
453 	}
454 	if (ad_data_pdu_count > 0) {
455 		ext_hdr_flags |= ULL_ADV_PDU_HDR_FIELD_AD_DATA;
456 	}
457 
458 	common_validate_per_adv_pdu(pdu, TEST_PDU_EXT_ADV_SYNC_IND, ext_hdr_flags);
459 
460 	pdu_count = MAX(cte_count, ad_data_pdu_count);
461 
462 	pdu = lll_adv_pdu_linked_next_get(pdu);
463 	if (pdu_count > 1) {
464 		zassert_not_null(pdu, "Expected PDU in periodic advertising chain is NULL");
465 	} else {
466 		zassert_is_null(pdu, "Unexpected PDU in a single PDU periodic advertising chain");
467 	}
468 
469 	for (uint8_t idx = 1; idx < pdu_count; ++idx) {
470 		if (idx < pdu_count - 1) {
471 			ext_hdr_flags = ULL_ADV_PDU_HDR_FIELD_AUX_PTR;
472 		} else {
473 			ext_hdr_flags = 0U;
474 		}
475 		if (idx < cte_count) {
476 			ext_hdr_flags |= ULL_ADV_PDU_HDR_FIELD_CTE_INFO;
477 		}
478 		if (idx < ad_data_pdu_count) {
479 			ext_hdr_flags |= ULL_ADV_PDU_HDR_FIELD_AD_DATA;
480 		}
481 
482 		common_validate_per_adv_pdu(pdu, TEST_PDU_EXT_ADV_CHAIN_IND, ext_hdr_flags);
483 
484 		pdu = lll_adv_pdu_linked_next_get(pdu);
485 		if (idx < (pdu_count - 1)) {
486 			zassert_not_null(pdu, "Expected PDU in periodic advertising chain is NULL");
487 		} else {
488 			zassert_is_null(pdu, "Unexpected PDU at end of periodic advertising chain");
489 		}
490 	}
491 }
492 
493 /*
494  * @brief Helper function to cleanup after test case end.
495  *
496  * @param adv               Pointer to advertising set
497  */
common_teardown(struct ll_adv_set * adv)498 void common_teardown(struct ll_adv_set *adv)
499 {
500 	common_release_per_adv_chain(adv);
501 	common_release_adv_set(adv);
502 	lll_adv_init();
503 }
504 /*
505  * @brief Helper function to add payload data to extended advertising PDU.
506  *
507  * @param pdu Pointer to extended advertising PDU.
508  * @param data Pointer to data to be added.
509  * @param len  Length of the data.
510  */
common_pdu_adv_data_set(struct pdu_adv * pdu,const uint8_t * data,uint8_t len)511 static void common_pdu_adv_data_set(struct pdu_adv *pdu, const uint8_t *data, uint8_t len)
512 {
513 	struct pdu_adv_com_ext_adv *com_hdr;
514 	uint8_t len_max;
515 	uint8_t *dptr;
516 
517 	com_hdr = &pdu->adv_ext_ind;
518 
519 	dptr = &com_hdr->ext_hdr_adv_data[com_hdr->ext_hdr_len];
520 
521 	len_max = PDU_AC_PAYLOAD_SIZE_MAX - (dptr - pdu->payload);
522 	zassert_false(len > len_max,
523 		      "Provided data length exceeds maximum supported payload length: %" PRIu8,
524 		      len_max);
525 
526 	memcpy(dptr, data, len);
527 	dptr += len;
528 
529 	pdu->len = dptr - pdu->payload;
530 }
531