@@ -121,6 +121,181 @@ static uint8_t adv_sync_pdu_init(struct pdu_adv *pdu, uint8_t ext_hdr_flags)
121121
122122	return  0 ;
123123}
124+ 
125+ static  uint8_t  adv_sync_pdu_init_from_prev_pdu (struct  pdu_adv  * pdu ,
126+ 					       struct  pdu_adv  * pdu_prev ,
127+ 					       uint16_t  ext_hdr_flags_add ,
128+ 					       uint16_t  ext_hdr_flags_rem )
129+ {
130+ 	struct  pdu_adv_com_ext_adv  * com_hdr_prev ;
131+ 	struct  pdu_adv_ext_hdr  * ext_hdr_prev ;
132+ 	struct  pdu_adv_com_ext_adv  * com_hdr ;
133+ 	struct  pdu_adv_ext_hdr  * ext_hdr ;
134+ 	uint8_t  ext_hdr_flags_prev ;
135+ 	uint8_t  ext_hdr_flags ;
136+ 	uint8_t  * dptr_prev ;
137+ 	uint8_t  len_prev ;
138+ 	uint8_t  * dptr ;
139+ 	uint8_t  len ;
140+ 
141+ 	/* Copy complete header, assume it was set properly in old PDU */ 
142+ 	* (uint8_t  * )pdu  =  * (uint8_t  * )pdu_prev ;
143+ 
144+ 	com_hdr_prev  =  & pdu_prev -> adv_ext_ind ;
145+ 	com_hdr  =  & pdu -> adv_ext_ind ;
146+ 
147+ 	com_hdr -> adv_mode  =  0U ;
148+ 
149+ 	ext_hdr_prev  =  & com_hdr_prev -> ext_hdr ;
150+ 	ext_hdr  =  & com_hdr -> ext_hdr ;
151+ 
152+ 	ext_hdr_flags_prev  =  * (uint8_t  * )ext_hdr_prev ;
153+ 	ext_hdr_flags  =  ext_hdr_flags_prev  |
154+ 			(ext_hdr_flags_add  &  (~ext_hdr_flags_rem ));
155+ 
156+ 	* (uint8_t  * )ext_hdr  =  ext_hdr_flags ;
157+ 
158+ 	LL_ASSERT (!ext_hdr -> adv_addr );
159+ 	LL_ASSERT (!ext_hdr -> tgt_addr );
160+ 	LL_ASSERT (!ext_hdr -> adi );
161+ 	LL_ASSERT (!ext_hdr -> sync_info );
162+ 
163+ 	dptr  =  ext_hdr -> data ;
164+ 	dptr_prev  =  ext_hdr_prev -> data ;
165+ 
166+ 	/* Note: skip length verification of ext header writes as we assume that 
167+ 	 *       all PDUs are large enough to store at least complete ext header. 
168+ 	 */ 
169+ 
170+ 	/* Copy CTEInfo, if applicable */ 
171+ 	if  (ext_hdr -> cte_info ) {
172+ 		if  (ext_hdr_prev -> cte_info ) {
173+ 			memcpy (dptr , dptr_prev , sizeof (struct  pdu_cte_info ));
174+ 		}
175+ 		dptr  +=  sizeof (struct  pdu_cte_info );
176+ 	}
177+ 	if  (ext_hdr_prev -> cte_info ) {
178+ 		dptr_prev  +=  sizeof (struct  pdu_cte_info );
179+ 	}
180+ 
181+ 	/* Add AuxPtr, if applicable. Do not copy since it will be updated later 
182+ 	 * anyway. 
183+ 	 */ 
184+ 	if  (ext_hdr -> aux_ptr ) {
185+ 		dptr  +=  sizeof (struct  pdu_adv_aux_ptr );
186+ 	}
187+ 	if  (ext_hdr_prev -> aux_ptr ) {
188+ 		dptr_prev  +=  sizeof (struct  pdu_adv_aux_ptr );
189+ 	}
190+ 
191+ 	/* Copy TxPower, if applicable */ 
192+ 	if  (ext_hdr -> tx_pwr ) {
193+ 		if  (ext_hdr_prev -> tx_pwr ) {
194+ 			memcpy (dptr , dptr_prev , sizeof (uint8_t ));
195+ 		}
196+ 		dptr  +=  sizeof (uint8_t );
197+ 	}
198+ 	if  (ext_hdr_prev -> tx_pwr ) {
199+ 		dptr_prev  +=  sizeof (uint8_t );
200+ 	}
201+ 
202+ 	LL_ASSERT (ext_hdr_prev   >= 0 );
203+ 
204+ 	/* Copy ACAD */ 
205+ 	len  =  com_hdr_prev -> ext_hdr_len  -  (dptr_prev  -  (uint8_t  * )ext_hdr_prev );
206+ 	memcpy (dptr , dptr_prev , len );
207+ 	dptr  +=  len ;
208+ 
209+ 	/* Check populated ext header length excluding length itself. If 0, then 
210+ 	 * there was neither field nor ACAD populated and we skip ext header 
211+ 	 * entirely. 
212+ 	 */ 
213+ 	len  =  dptr  -  ext_hdr -> data ;
214+ 	if  (len  ==  0 ) {
215+ 		com_hdr -> ext_hdr_len  =  0 ;
216+ 	} else  {
217+ 		com_hdr -> ext_hdr_len  =  len  + 
218+ 				       offsetof(struct  pdu_adv_ext_hdr , data );
219+ 	}
220+ 
221+ 	/* Both PDUs have now ext header length calculated properly, reset 
222+ 	 * pointers to start of AD. 
223+ 	 */ 
224+ 	dptr  =  & com_hdr -> ext_hdr_adv_data [com_hdr -> ext_hdr_len ];
225+ 	dptr_prev  =  & com_hdr_prev -> ext_hdr_adv_data [com_hdr_prev -> ext_hdr_len ];
226+ 
227+ 	/* Calculate length of AD to copy and AD length available in new PDU */ 
228+ 	len_prev  =  pdu_prev -> len  -  (dptr_prev  -  pdu_prev -> payload );
229+ 	len  =  PDU_AC_PAYLOAD_SIZE_MAX  -  (dptr  -  pdu -> payload );
230+ 
231+ 	/* TODO: we should allow partial copy and let caller refragment data */ 
232+ 	if  (len  <  len_prev ) {
233+ 		return  BT_HCI_ERR_PACKET_TOO_LONG ;
234+ 	}
235+ 
236+ 	/* Copy AD */ 
237+ 	if  (!(ext_hdr_flags_rem  &  ULL_ADV_PDU_HDR_FIELD_AD_DATA )) {
238+ 		len  =  MIN (len , len_prev );
239+ 		memcpy (dptr , dptr_prev , len );
240+ 		dptr  +=  len ;
241+ 	}
242+ 
243+ 	/* Finalize PDU */ 
244+ 	pdu -> len  =  dptr  -  pdu -> payload ;
245+ 
246+ 	return  0 ;
247+ }
248+ 
249+ static  uint8_t  adv_sync_pdu_ad_data_set (struct  pdu_adv  * pdu ,
250+ 					const  uint8_t  * data , uint8_t  len )
251+ {
252+ 	struct  pdu_adv_com_ext_adv  * com_hdr ;
253+ 	uint8_t  len_max ;
254+ 	uint8_t  * dptr ;
255+ 
256+ 	com_hdr  =  & pdu -> adv_ext_ind ;
257+ 
258+ 	dptr  =  & com_hdr -> ext_hdr_adv_data [com_hdr -> ext_hdr_len ];
259+ 
260+ 	len_max  =  PDU_AC_PAYLOAD_SIZE_MAX  -  (dptr  -  pdu -> payload );
261+ 	/* TODO: we should allow partial copy and let caller refragment data */ 
262+ 	if  (len  >  len_max ) {
263+ 		return  BT_HCI_ERR_PACKET_TOO_LONG ;
264+ 	}
265+ 
266+ 	memcpy (dptr , data , len );
267+ 	dptr  +=  len ;
268+ 
269+ 	pdu -> len  =  dptr  -  pdu -> payload ;
270+ 
271+ 	return  0 ;
272+ }
273+ 
274+ #if  defined(CONFIG_BT_CTLR_ADV_PDU_LINK )
275+ static  void  adv_sync_pdu_duplicate_chain (struct  pdu_adv  * pdu ,
276+ 					 struct  pdu_adv  * pdu_prev )
277+ {
278+ 	uint8_t  err ;
279+ 
280+ 	while  (lll_adv_pdu_linked_next_get (pdu_prev )) {
281+ 		struct  pdu_adv  * pdu_new ;
282+ 
283+ 		pdu_prev  =  lll_adv_pdu_linked_next_get (pdu_prev );
284+ 		pdu_new  =  lll_adv_pdu_alloc_pdu_adv ();
285+ 
286+ 		/* We make exact copy of old PDU, there's really nothing that 
287+ 		 * can go wrong there assuming original PDU was created properly 
288+ 		 */ 
289+ 		err  =  adv_sync_pdu_init_from_prev_pdu (pdu_new , pdu_prev , 0 , 0 );
290+ 		LL_ASSERT (err );
291+ 
292+ 		lll_adv_pdu_linked_append (pdu_new , pdu );
293+ 
294+ 		pdu  =  pdu_new ;
295+ 	}
296+ }
297+ #endif  /* CONFIG_BT_CTLR_ADV_PDU_LINK */ 
298+ 
124299uint8_t  ll_adv_sync_param_set (uint8_t  handle , uint16_t  interval , uint16_t  flags )
125300{
126301	struct  lll_adv_sync  * lll_sync ;
@@ -195,10 +370,11 @@ uint8_t ll_adv_sync_param_set(uint8_t handle, uint16_t interval, uint16_t flags)
195370uint8_t  ll_adv_sync_ad_data_set (uint8_t  handle , uint8_t  op , uint8_t  len ,
196371				uint8_t  const  * const  data )
197372{
198- 	struct  adv_pdu_field_data  pdu_data ;
199373	struct  lll_adv_sync  * lll_sync ;
374+ 	struct  pdu_adv  * pdu_prev ;
200375	struct  ll_adv_set  * adv ;
201- 	uint8_t  value [5 ];
376+ 	void  * extra_data_prev ;
377+ 	struct  pdu_adv  * pdu ;
202378	uint8_t  ter_idx ;
203379	uint8_t  err ;
204380
@@ -219,16 +395,39 @@ uint8_t ll_adv_sync_ad_data_set(uint8_t handle, uint8_t op, uint8_t len,
219395		return  BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER ;
220396	}
221397
222- 	pdu_data .field_data  =  value ;
223- 	* pdu_data .field_data  =  len ;
224- 	sys_put_le32 ((uint32_t )data , pdu_data .field_data  +  1 );
398+ 	pdu_prev  =  lll_adv_sync_data_peek (lll_sync , & extra_data_prev );
399+ 	pdu  =  lll_adv_sync_data_alloc (lll_sync , extra_data_prev , & ter_idx );
400+ 
401+ 	/* TODO: pdu_prev will be the same as pdu if data are still enqueued 
402+ 	 *       and waiting for LLL to swap, creating new chain will not work 
403+ 	 *       in such case since we cannot update it in-place. 
404+ 	 */ 
405+ 	LL_ASSERT (pdu_prev  !=  pdu );
225406
226- 	err  =  ull_adv_sync_pdu_set_clear (adv , ULL_ADV_PDU_HDR_FIELD_AD_DATA ,
227- 					 0 , & pdu_data , & ter_idx );
407+ 	/* Initialize new PDU to be the same as old, except for AD which we 
408+ 	 * replace with new ones. 
409+ 	 */ 
410+ 	err  =  adv_sync_pdu_init_from_prev_pdu (pdu , pdu_prev , 0 ,
411+ 					      ULL_ADV_PDU_HDR_FIELD_AD_DATA );
228412	if  (err ) {
229413		return  err ;
230414	}
231415
416+ 	/* TODO: only data in 1st PDU is supported as for now, need to add 
417+ 	 *       support for fragmentation. 
418+ 	 */ 
419+ 	err  =  adv_sync_pdu_ad_data_set (pdu , data , len );
420+ 	if  (err ) {
421+ 		return  err ;
422+ 	}
423+ 
424+ #if  defined(CONFIG_BT_CTLR_ADV_PDU_LINK )
425+ 	/* There may be linked PDUs due to e.g. CTEInfo so need to duplicate 
426+ 	 * all of them to new chain. 
427+ 	 */ 
428+ 	adv_sync_pdu_duplicate_chain (pdu , pdu_prev );
429+ #endif 
430+ 
232431	lll_adv_sync_data_enqueue (lll_sync , ter_idx );
233432
234433	return  0 ;
0 commit comments