@@ -460,12 +460,9 @@ uint8_t ll_adv_sync_ad_data_set(uint8_t handle, uint8_t op, uint8_t len,
460460 return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER ;
461461 }
462462
463- hdr_data [ULL_ADV_HDR_DATA_LEN_OFFSET ] = len ;
464- (void )memcpy ((void * )& hdr_data [ULL_ADV_HDR_DATA_DATA_PTR_OFFSET ], & data ,
465- ULL_ADV_HDR_DATA_DATA_PTR_SIZE );
466-
467- err = ull_adv_sync_pdu_alloc (adv , ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST , & pdu_prev , & pdu ,
468- & extra_data_prev , & extra_data , & ter_idx );
463+ err = ull_adv_sync_pdu_alloc (adv , ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST ,
464+ & pdu_prev , & pdu , & extra_data_prev ,
465+ & extra_data , & ter_idx );
469466 if (err ) {
470467 return err ;
471468 }
@@ -477,20 +474,61 @@ uint8_t ll_adv_sync_ad_data_set(uint8_t handle, uint8_t op, uint8_t len,
477474 }
478475#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
479476
480- err = ull_adv_sync_pdu_set_clear (lll_sync , pdu_prev , pdu , ULL_ADV_PDU_HDR_FIELD_AD_DATA , 0 ,
477+ /* Use length = 0 and NULL pointer to retain old data in the PDU.
478+ * Use length = 0 and valid pointer of `data` (auto/local variable) to
479+ * remove old data.
480+ * User length > 0 and valid pointer of `data` (auto/local variable) to
481+ * set new data.
482+ */
483+ if (op == BT_HCI_LE_EXT_ADV_OP_UNCHANGED_DATA ) {
484+ hdr_data [ULL_ADV_HDR_DATA_LEN_OFFSET ] = 0U ;
485+ (void )memset ((void * )& hdr_data [ULL_ADV_HDR_DATA_DATA_PTR_OFFSET ],
486+ 0U , ULL_ADV_HDR_DATA_DATA_PTR_SIZE );
487+ } else {
488+ hdr_data [ULL_ADV_HDR_DATA_LEN_OFFSET ] = len ;
489+ (void )memcpy ((void * )& hdr_data [ULL_ADV_HDR_DATA_DATA_PTR_OFFSET ],
490+ & data , ULL_ADV_HDR_DATA_DATA_PTR_SIZE );
491+ }
492+
493+ err = ull_adv_sync_pdu_set_clear (lll_sync , pdu_prev , pdu ,
494+ ULL_ADV_PDU_HDR_FIELD_AD_DATA , 0 ,
481495 hdr_data );
482496 if (err ) {
483497 return err ;
484498 }
485499
500+ sync = HDR_LLL2ULL (lll_sync );
501+
502+ /* Parameter validation, if operation is 0x04 (unchanged data)
503+ * - periodic advertising is disabled, or
504+ * - periodic advertising contains no data, or
505+ * - Advertising Data Length is zero
506+ */
507+ if (IS_ENABLED (CONFIG_BT_CTLR_PARAM_CHECK ) &&
508+ (op == BT_HCI_LE_EXT_ADV_OP_UNCHANGED_DATA ) &&
509+ ((!sync -> is_enabled ) ||
510+ (hdr_data [ULL_ADV_HDR_DATA_LEN_OFFSET ] == 0U ) ||
511+ (len != 0U ))) {
512+ /* NOTE: latest PDU was not consumed by LLL and as
513+ * ull_adv_sync_pdu_alloc() has reverted back the double buffer
514+ * with the first PDU, and returned the latest PDU as the new
515+ * PDU, we need to enqueue back the new PDU which is infact
516+ * the latest PDU.
517+ */
518+ if (pdu_prev == pdu ) {
519+ lll_adv_sync_data_enqueue (lll_sync , ter_idx );
520+ }
521+
522+ return BT_HCI_ERR_INVALID_PARAM ;
523+ }
524+
486525 /* alloc() will return the same PDU as peek() in case there was PDU
487526 * queued but not switched to current before alloc() - no need to deal
488527 * with chain as it's already there. In other case we need to duplicate
489528 * chain from current PDU and append it to new PDU.
490529 */
491530 adv_sync_pdu_chain_check_and_duplicate (pdu , pdu_prev );
492531
493- sync = HDR_LLL2ULL (lll_sync );
494532 if (sync -> is_started ) {
495533 err = ull_adv_sync_time_update (sync , pdu );
496534 if (err ) {
@@ -1302,10 +1340,26 @@ uint8_t ull_adv_sync_pdu_set_clear(struct lll_adv_sync *lll_sync,
13021340
13031341 /* Get Adv data from function parameters */
13041342 if (hdr_add_fields & ULL_ADV_PDU_HDR_FIELD_AD_DATA ) {
1343+ uint8_t ad_len_prev ;
1344+
13051345 ad_len = * (uint8_t * )hdr_data ;
1346+
1347+ /* return prev ad data length */
1348+ ad_len_prev = ter_pdu_prev -> len - ter_len_prev ;
1349+ * (uint8_t * )hdr_data = ad_len_prev ;
13061350 hdr_data = (uint8_t * )hdr_data + sizeof (ad_len );
13071351
1352+ /* remember the reference to new ad data */
13081353 (void )memcpy (& ad_data , hdr_data , sizeof (ad_data ));
1354+
1355+ /* return the reference to prev ad data */
1356+ (void )memcpy (hdr_data , & ter_dptr , sizeof (ter_dptr ));
1357+
1358+ /* unchanged data */
1359+ if (!ad_len && !ad_data ) {
1360+ ad_len = ad_len_prev ;
1361+ ad_data = ter_dptr_prev ;
1362+ }
13091363 } else if (!(hdr_rem_fields & ULL_ADV_PDU_HDR_FIELD_AD_DATA )) {
13101364 ad_len = ter_pdu_prev -> len - ter_len_prev ;
13111365 ad_data = ter_dptr_prev ;
0 commit comments