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 	uint8_t hdr_data[ULL_ADV_HDR_DATA_LEN_SIZE +
144 			 ULL_ADV_HDR_DATA_AUX_PTR_PTR_SIZE];
145 	struct pdu_adv *pdu_prev, *pdu, *pdu_new;
146 	char pdu_buff[PDU_PAULOAD_BUFF_SIZE];
147 	void *extra_data_prev, *extra_data;
148 	struct lll_adv_sync *lll_sync;
149 	bool adi_in_sync_ind;
150 	uint8_t err, pdu_idx;
151 
152 	lll_sync = adv_set->lll.sync;
153 	pdu = lll_adv_sync_data_peek(lll_sync, NULL);
154 	ull_adv_sync_pdu_init(pdu, 0U, 0U, 0U, NULL);
155 
156 	err = ull_adv_sync_pdu_alloc(adv_set, ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST, &pdu_prev,
157 				     &pdu, &extra_data_prev, &extra_data, &pdu_idx);
158 	zassert_equal(err, 0, "Unexpected error while PDU allocation, err: %d", err);
159 
160 	if (extra_data) {
161 		ull_adv_sync_extra_data_set_clear(extra_data_prev, extra_data, 0, 0, NULL);
162 	}
163 
164 	/* Create AUX_SYNC_IND PDU as a head of chain */
165 	err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev, pdu,
166 					 (pdu_count > 1 ? ULL_ADV_PDU_HDR_FIELD_AUX_PTR :
167 								ULL_ADV_PDU_HDR_FIELD_NONE),
168 					 ULL_ADV_PDU_HDR_FIELD_NONE, hdr_data);
169 	zassert_equal(err, 0, "Unexpected error during initialization of extended PDU, err: %d",
170 		      err);
171 
172 	if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)) {
173 		adi_in_sync_ind = ull_adv_sync_pdu_had_adi(pdu);
174 	}
175 
176 	/* Add some AD for testing */
177 	snprintf(pdu_buff, ARRAY_SIZE(pdu_buff), "test%" PRIu8 " test%" PRIu8 " test%" PRIu8 "", 0,
178 		 0, 0);
179 	common_pdu_adv_data_set(pdu, pdu_buff, strlen(pdu_buff));
180 	/* Create AUX_CHAIN_IND PDUs. Start from 1, AUX_SYNC_IND is first PDU. */
181 	for (uint8_t idx = 1; idx < pdu_count; ++idx) {
182 		snprintf(pdu_buff, ARRAY_SIZE(pdu_buff),
183 			 "test%" PRIu8 " test%" PRIu8 " test%" PRIu8 "", idx, idx, idx);
184 		/* Allocate new PDU */
185 		pdu_new = lll_adv_pdu_alloc_pdu_adv();
186 		zassert_not_null(pdu_new, "Cannot allocate new PDU.");
187 		/* Initialize new empty PDU. Last AUX_CHAIN_IND may not include AuxPtr. */
188 		if (idx < pdu_count - 1) {
189 			if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT) &&
190 			    adi_in_sync_ind) {
191 				ull_adv_sync_pdu_init(pdu_new,
192 						ULL_ADV_PDU_HDR_FIELD_AUX_PTR |
193 						ULL_ADV_PDU_HDR_FIELD_ADI,
194 						lll_sync->adv->phy_s,
195 						lll_sync->adv->phy_flags, NULL);
196 			} else {
197 				ull_adv_sync_pdu_init(pdu_new,
198 						ULL_ADV_PDU_HDR_FIELD_AUX_PTR,
199 						lll_sync->adv->phy_s,
200 						lll_sync->adv->phy_flags, NULL);
201 			}
202 		} else {
203 			if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT) &&
204 			    adi_in_sync_ind) {
205 				ull_adv_sync_pdu_init(pdu_new,
206 						ULL_ADV_PDU_HDR_FIELD_ADI,
207 						0U, 0U, NULL);
208 			} else {
209 				ull_adv_sync_pdu_init(pdu_new,
210 						ULL_ADV_PDU_HDR_FIELD_NONE,
211 						0U, 0U, NULL);
212 			}
213 		}
214 		/* Add some AD for testing */
215 		common_pdu_adv_data_set(pdu_new, pdu_buff, strlen(pdu_buff));
216 		/* Link to previous PDU */
217 		lll_adv_pdu_linked_append(pdu_new, pdu);
218 		pdu = pdu_new;
219 	}
220 
221 	lll_adv_sync_data_enqueue(lll_sync, pdu_idx);
222 }
223 
224 /*
225  * @brief Helper function to release periodic advertising chain that was enqueued for
226  * advertising set.
227  *
228  * @param adv_set Pointer to advertising set to release a PDUs chain.
229  */
common_release_per_adv_chain(struct ll_adv_set * adv_set)230 void common_release_per_adv_chain(struct ll_adv_set *adv_set)
231 {
232 	struct lll_adv_sync *lll_sync;
233 	struct pdu_adv *pdu;
234 
235 	lll_sync = adv_set->lll.sync;
236 	pdu = lll_adv_sync_data_peek(lll_sync, NULL);
237 	if (pdu != NULL) {
238 		lll_adv_pdu_linked_release_all(pdu);
239 	}
240 
241 	pdu = (void *)lll_sync->data.pdu[lll_sync->data.first];
242 	if (pdu != NULL) {
243 		lll_adv_pdu_linked_release_all(pdu);
244 	}
245 }
246 
247 /*
248  * @brief Helper function that validates content of periodic advertising PDU.
249  *
250  * The function verifies if content of periodic advertising PDU as as expected. The function
251  * verifies two types of PDUs: AUX_SYNC_IND and AUX_CHAIN_IND. AUX_CHAIN_IND is validated
252  * as if its superior PDU is AUX_SYNC_IND only.
253  *
254  * Expected fields in extended advertising header are provided by @p exp_ext_hdr_flags.
255  *
256  * Note: The function expects that there is no ACAD data in the PDU.
257  *
258  * @param pdu Pointer to PDU to be verified.
259  * @param type Type of the PDU.
260  * @param exp_ext_hdr_flags Bitfield with expected extended header flags.
261  */
common_validate_per_adv_pdu(struct pdu_adv * pdu,enum test_pdu_ext_adv_type type,uint16_t exp_ext_hdr_flags)262 void common_validate_per_adv_pdu(struct pdu_adv *pdu, enum test_pdu_ext_adv_type type,
263 				 uint16_t exp_ext_hdr_flags)
264 {
265 	struct pdu_adv_com_ext_adv *com_hdr;
266 	struct pdu_adv_ext_hdr *ext_hdr;
267 	uint8_t ext_hdr_len;
268 	uint8_t *dptr;
269 
270 	if (pdu->len > 1) {
271 		com_hdr = &pdu->adv_ext_ind;
272 		/* Non-connectable and Non-scannable adv mode */
273 		zassert_equal(com_hdr->adv_mode, 0U,
274 			      "Unexpected mode of extended advertising PDU: %" PRIu8,
275 			      com_hdr->adv_mode);
276 
277 		ext_hdr = &com_hdr->ext_hdr;
278 		dptr = ext_hdr->data;
279 
280 		if (com_hdr->ext_hdr_len > 0) {
281 			zassert_false(ext_hdr->adv_addr,
282 				      "Unexpected AdvA field in extended advertising header");
283 			zassert_false(ext_hdr->tgt_addr,
284 				      "Unexpected TargetA field in extended advertising header");
285 			if (exp_ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_CTE_INFO) {
286 				zassert_true(
287 					ext_hdr->cte_info,
288 					"Missing expected CteInfo field in extended advertising header");
289 				dptr += sizeof(struct pdu_cte_info);
290 			} else {
291 				zassert_false(
292 					ext_hdr->cte_info,
293 					"Unexpected CteInfo field in extended advertising header");
294 			}
295 			if (exp_ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_ADI) {
296 				zassert_true(
297 					ext_hdr->adi,
298 					"Missing expected ADI field in extended advertising header");
299 				dptr += sizeof(struct pdu_adv_adi);
300 			} else {
301 				zassert_false(
302 					ext_hdr->adi,
303 					"Unexpected ADI field in extended advertising header");
304 			}
305 			if (exp_ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_AUX_PTR) {
306 				zassert_true(
307 					ext_hdr->aux_ptr,
308 					"Missing expected AuxPtr field in extended advertising header");
309 				dptr += sizeof(struct pdu_adv_aux_ptr);
310 			} else {
311 				zassert_false(
312 					ext_hdr->aux_ptr,
313 					"Unexpected AuxPtr field in extended advertising header");
314 			}
315 			zassert_false(ext_hdr->sync_info,
316 				      "Unexpected SyncInfo field in extended advertising header");
317 			if (exp_ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_TX_POWER) {
318 				zassert_true(
319 					ext_hdr->tx_pwr,
320 					"Missing expected CteInfo field in extended advertising header");
321 				dptr += sizeof(uint8_t);
322 			} else {
323 				zassert_false(
324 					ext_hdr->tx_pwr,
325 					"Unexpected CteInfo field in extended advertising header");
326 			}
327 
328 			/* Calculate extended header len, ACAD should not be available.
329 			 * ull_adv_aux_hdr_len_calc returns ext hdr length without it.
330 			 */
331 			ext_hdr_len = ull_adv_aux_hdr_len_calc(com_hdr, &dptr);
332 			zassert_equal(com_hdr->ext_hdr_len,
333 				      ext_hdr_len - PDU_AC_EXT_HEADER_SIZE_MIN,
334 				      "Extended header length: %" PRIu8
335 				      " different than expected %" PRIu8,
336 				      ext_hdr_len, com_hdr->ext_hdr_len);
337 
338 			if (exp_ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_AD_DATA) {
339 				zassert_true((pdu->len - ext_hdr_len) > 0,
340 					     "Missing expected advertising data in PDU");
341 			} else {
342 				zassert_equal(pdu->len - ext_hdr_len, 0,
343 					      "Unexpected advertising data in PDU");
344 			}
345 		} else {
346 			zassert_equal(exp_ext_hdr_flags, ULL_ADV_PDU_HDR_FIELD_AD_DATA,
347 				      "Unexpected extended header flags: %" PRIu16,
348 				      exp_ext_hdr_flags);
349 		}
350 	}
351 }
352 
353 /*
354  * @brief Helper function to prepare CTE configuration for a given advertising set.
355  *
356  * Note: There is a single instance of CTE configuration. In case there is a need
357  * to use multiple advertising sets at once, all will use the same CTE configuration.
358  *
359  * @param adv       Pointer to advertising set
360  * @param cte_count Requested number of CTEs to be send
361  */
common_prepare_df_cfg(struct ll_adv_set * adv,uint8_t cte_count)362 void common_prepare_df_cfg(struct ll_adv_set *adv, uint8_t cte_count)
363 {
364 	/* Prepare CTE configuration */
365 	g_df_cfg.cte_count = cte_count;
366 	g_df_cfg.cte_length = TEST_CTE_LENGTH;
367 	g_df_cfg.cte_type = BT_HCI_LE_AOD_CTE_2US;
368 
369 	adv->df_cfg = &g_df_cfg;
370 }
371 
372 /*
373  * @brief Helper function that validates correctness of periodic advertising chain.
374  *
375  * The function expects that all periodic advertising chain PDUs will have advertising data.
376  *
377  * @param adv       Pointer to advertising set
378  * @param pdu_count Number of PDUs in a chain
379  */
common_validate_per_adv_chain(struct ll_adv_set * adv,uint8_t pdu_count)380 void common_validate_per_adv_chain(struct ll_adv_set *adv, uint8_t pdu_count)
381 {
382 	uint16_t ext_hdr_flags;
383 	struct pdu_adv *pdu;
384 
385 	pdu = lll_adv_sync_data_peek(adv->lll.sync, NULL);
386 
387 	/* Validate AUX_SYNC_IND */
388 	if (pdu_count > 1) {
389 		ext_hdr_flags = ULL_ADV_PDU_HDR_FIELD_AUX_PTR | ULL_ADV_PDU_HDR_FIELD_AD_DATA;
390 	} else {
391 		ext_hdr_flags = ULL_ADV_PDU_HDR_FIELD_AD_DATA;
392 	}
393 
394 	common_validate_per_adv_pdu(pdu, TEST_PDU_EXT_ADV_SYNC_IND, ext_hdr_flags);
395 	pdu = lll_adv_pdu_linked_next_get(pdu);
396 	if (pdu_count > 1) {
397 		zassert_not_null(pdu, "Expected PDU in periodic advertising chain is NULL");
398 	} else {
399 		zassert_is_null(pdu, "Unexpected PDU in a single PDU periodic advertising chain");
400 	}
401 	/* Validate AUX_CHAIN_IND PDUs in a periodic advertising chain. Start from 1, because
402 	 * first PDU is AUX_SYNC_IND.
403 	 */
404 	for (uint8_t idx = 1; idx < pdu_count; ++idx) {
405 		if (idx != (pdu_count - 1)) {
406 			ext_hdr_flags =
407 				ULL_ADV_PDU_HDR_FIELD_AUX_PTR | ULL_ADV_PDU_HDR_FIELD_AD_DATA;
408 		} else {
409 			ext_hdr_flags = ULL_ADV_PDU_HDR_FIELD_AD_DATA;
410 		}
411 
412 		common_validate_per_adv_pdu(pdu, TEST_PDU_EXT_ADV_CHAIN_IND, ext_hdr_flags);
413 		pdu = lll_adv_pdu_linked_next_get(pdu);
414 		if (idx != (pdu_count - 1)) {
415 			zassert_not_null(pdu, "Expected PDU in periodic advertising chain is NULL");
416 		} else {
417 			zassert_is_null(pdu, "Unexpected PDU at end of periodic advertising chain");
418 		}
419 	}
420 }
421 
422 /*
423  * @brief Helper function that validates correctness of periodic advertising chain including CTE
424  *
425  * The number of PDUs including advertising data or CTE is provided by appropriate function
426  * arguments. PUDs including CTE are always first #N PDUs. The same rule applies to PDUs including
427  * advertising data. So maximum number of PDUs in a chain is maximum value from pair @p cte_count
428  * and @p ad_data_count.
429  *
430  * @param adv               Pointer to advertising set
431  * @param cte_count         Number of PDUs including CTE
432  * @param ad_data_pdu_count Number of PDUs including advertising data
433  */
common_validate_chain_with_cte(struct ll_adv_set * adv,uint8_t cte_count,uint8_t ad_data_pdu_count)434 void common_validate_chain_with_cte(struct ll_adv_set *adv, uint8_t cte_count,
435 				    uint8_t ad_data_pdu_count)
436 {
437 	uint16_t ext_hdr_flags;
438 	struct pdu_adv *pdu;
439 	uint8_t pdu_count;
440 
441 	pdu = lll_adv_sync_data_peek(adv->lll.sync, NULL);
442 	if (cte_count > 1) {
443 		ext_hdr_flags = ULL_ADV_PDU_HDR_FIELD_AUX_PTR | ULL_ADV_PDU_HDR_FIELD_CTE_INFO;
444 
445 	} else {
446 		ext_hdr_flags = ULL_ADV_PDU_HDR_FIELD_CTE_INFO;
447 	}
448 	if (ad_data_pdu_count > 0) {
449 		ext_hdr_flags |= ULL_ADV_PDU_HDR_FIELD_AD_DATA;
450 	}
451 
452 	common_validate_per_adv_pdu(pdu, TEST_PDU_EXT_ADV_SYNC_IND, ext_hdr_flags);
453 
454 	pdu_count = MAX(cte_count, ad_data_pdu_count);
455 
456 	pdu = lll_adv_pdu_linked_next_get(pdu);
457 	if (pdu_count > 1) {
458 		zassert_not_null(pdu, "Expected PDU in periodic advertising chain is NULL");
459 	} else {
460 		zassert_is_null(pdu, "Unexpected PDU in a single PDU periodic advertising chain");
461 	}
462 
463 	for (uint8_t idx = 1; idx < pdu_count; ++idx) {
464 		if (idx < pdu_count - 1) {
465 			ext_hdr_flags = ULL_ADV_PDU_HDR_FIELD_AUX_PTR;
466 		} else {
467 			ext_hdr_flags = 0U;
468 		}
469 		if (idx < cte_count) {
470 			ext_hdr_flags |= ULL_ADV_PDU_HDR_FIELD_CTE_INFO;
471 		}
472 		if (idx < ad_data_pdu_count) {
473 			ext_hdr_flags |= ULL_ADV_PDU_HDR_FIELD_AD_DATA;
474 		}
475 
476 		common_validate_per_adv_pdu(pdu, TEST_PDU_EXT_ADV_CHAIN_IND, ext_hdr_flags);
477 
478 		pdu = lll_adv_pdu_linked_next_get(pdu);
479 		if (idx < (pdu_count - 1)) {
480 			zassert_not_null(pdu, "Expected PDU in periodic advertising chain is NULL");
481 		} else {
482 			zassert_is_null(pdu, "Unexpected PDU at end of periodic advertising chain");
483 		}
484 	}
485 }
486 
487 /*
488  * @brief Helper function to cleanup after test case end.
489  *
490  * @param adv               Pointer to advertising set
491  */
common_teardown(struct ll_adv_set * adv)492 void common_teardown(struct ll_adv_set *adv)
493 {
494 	common_release_per_adv_chain(adv);
495 	common_release_adv_set(adv);
496 	lll_adv_init();
497 }
498 /*
499  * @brief Helper function to add payload data to extended advertising PDU.
500  *
501  * @param pdu Pointer to extended advertising PDU.
502  * @param data Pointer to data to be added.
503  * @param len  Length of the data.
504  */
common_pdu_adv_data_set(struct pdu_adv * pdu,const uint8_t * data,uint8_t len)505 static void common_pdu_adv_data_set(struct pdu_adv *pdu, const uint8_t *data, uint8_t len)
506 {
507 	struct pdu_adv_com_ext_adv *com_hdr;
508 	uint8_t len_max;
509 	uint8_t *dptr;
510 
511 	com_hdr = &pdu->adv_ext_ind;
512 
513 	dptr = &com_hdr->ext_hdr_adv_data[com_hdr->ext_hdr_len];
514 
515 	len_max = PDU_AC_PAYLOAD_SIZE_MAX - (dptr - pdu->payload);
516 	zassert_false(len > len_max,
517 		      "Provided data length exceeds maximum supported payload length: %" PRIu8,
518 		      len_max);
519 
520 	memcpy(dptr, data, len);
521 	dptr += len;
522 
523 	pdu->len = dptr - pdu->payload;
524 }
525