[no subject]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



	if (adv && !adv->pending) {

to

	if (adv && adv->enabled) {

it seems to do the job correctly. What do you think?


regards,
Christian


On Friday, 27 June 2025, 09:05:08 CEST, Christian Eggers wrote:
> Currently, for controllers with extended advertising, the advertising
> data is set in the asynchronous response handler for extended
> adverstising params. As most advertising settings are performed in a
> synchronous context, the (asynchronous) setting of the advertising data
> is done too late (after enabling the advertising).
> 
> Move setting of adverstising data from asynchronous response handler
> into synchronous context to fix ordering of HCI commands.
> 
> Signed-off-by: Christian Eggers <ceggers@xxxxxxx>
> Fixes: a0fb3726ba55 ("Bluetooth: Use Set ext adv/scan rsp data if controller supports")
> Cc: stable@xxxxxxxxxxxxxxx
> v2: https://lore.kernel.org/linux-bluetooth/20250626115209.17839-1-ceggers@xxxxxxx/
> ---
> v3: refactor: store adv_addr_type/tx_power within hci_set_ext_adv_params_sync()
> 
> v2: convert setting of adv data into synchronous context (rather than moving
> more methods into asynchronous response handlers).
> - hci_set_ext_adv_params_sync: new method
> - hci_set_ext_adv_data_sync: move within source file (no changes)
> - hci_set_adv_data_sync: dito
> - hci_update_adv_data_sync: dito
> - hci_cc_set_ext_adv_param: remove (performed synchronously now)
> 
>  net/bluetooth/hci_event.c |  36 -------
>  net/bluetooth/hci_sync.c  | 207 ++++++++++++++++++++++++--------------
>  2 files changed, 130 insertions(+), 113 deletions(-)
> 
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index 66052d6aaa1d..4d5ace9d245d 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -2150,40 +2150,6 @@ static u8 hci_cc_set_adv_param(struct hci_dev *hdev, void *data,
>  	return rp->status;
>  }
>  
> -static u8 hci_cc_set_ext_adv_param(struct hci_dev *hdev, void *data,
> -				   struct sk_buff *skb)
> -{
> -	struct hci_rp_le_set_ext_adv_params *rp = data;
> -	struct hci_cp_le_set_ext_adv_params *cp;
> -	struct adv_info *adv_instance;
> -
> -	bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
> -
> -	if (rp->status)
> -		return rp->status;
> -
> -	cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_EXT_ADV_PARAMS);
> -	if (!cp)
> -		return rp->status;
> -
> -	hci_dev_lock(hdev);
> -	hdev->adv_addr_type = cp->own_addr_type;
> -	if (!cp->handle) {
> -		/* Store in hdev for instance 0 */
> -		hdev->adv_tx_power = rp->tx_power;
> -	} else {
> -		adv_instance = hci_find_adv_instance(hdev, cp->handle);
> -		if (adv_instance)
> -			adv_instance->tx_power = rp->tx_power;
> -	}
> -	/* Update adv data as tx power is known now */
> -	hci_update_adv_data(hdev, cp->handle);
> -
> -	hci_dev_unlock(hdev);
> -
> -	return rp->status;
> -}
> -
>  static u8 hci_cc_read_rssi(struct hci_dev *hdev, void *data,
>  			   struct sk_buff *skb)
>  {
> @@ -4164,8 +4130,6 @@ static const struct hci_cc {
>  	HCI_CC(HCI_OP_LE_READ_NUM_SUPPORTED_ADV_SETS,
>  	       hci_cc_le_read_num_adv_sets,
>  	       sizeof(struct hci_rp_le_read_num_supported_adv_sets)),
> -	HCI_CC(HCI_OP_LE_SET_EXT_ADV_PARAMS, hci_cc_set_ext_adv_param,
> -	       sizeof(struct hci_rp_le_set_ext_adv_params)),
>  	HCI_CC_STATUS(HCI_OP_LE_SET_EXT_ADV_ENABLE,
>  		      hci_cc_le_set_ext_adv_enable),
>  	HCI_CC_STATUS(HCI_OP_LE_SET_ADV_SET_RAND_ADDR,
> diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
> index 1f8806dfa556..563614b53485 100644
> --- a/net/bluetooth/hci_sync.c
> +++ b/net/bluetooth/hci_sync.c
> @@ -1205,9 +1205,126 @@ static int hci_set_adv_set_random_addr_sync(struct hci_dev *hdev, u8 instance,
>  				     sizeof(cp), &cp, HCI_CMD_TIMEOUT);
>  }
>  
> +static int
> +hci_set_ext_adv_params_sync(struct hci_dev *hdev, struct adv_info *adv,
> +			    const struct hci_cp_le_set_ext_adv_params *cp,
> +			    struct hci_rp_le_set_ext_adv_params *rp)
> +{
> +	struct sk_buff *skb;
> +
> +	skb = __hci_cmd_sync(hdev, HCI_OP_LE_SET_EXT_ADV_PARAMS, sizeof(*cp),
> +			     cp, HCI_CMD_TIMEOUT);
> +
> +	/* If command return a status event, skb will be set to -ENODATA */
> +	if (skb == ERR_PTR(-ENODATA))
> +		return 0;
> +
> +	if (IS_ERR(skb)) {
> +		bt_dev_err(hdev, "Opcode 0x%4.4x failed: %ld",
> +			   HCI_OP_LE_SET_EXT_ADV_PARAMS, PTR_ERR(skb));
> +		return PTR_ERR(skb);
> +	}
> +
> +	if (skb->len != sizeof(*rp)) {
> +		bt_dev_err(hdev, "Invalid response length for "
> +			   "HCI_OP_LE_SET_EXT_ADV_PARAMS: %u", skb->len);
> +		kfree_skb(skb);
> +		return -EIO;
> +	}
> +
> +	memcpy(rp, skb->data, sizeof(*rp));
> +	kfree_skb(skb);
> +
> +	if (!rp->status) {
> +		hdev->adv_addr_type = cp->own_addr_type;
> +		if (!cp->handle) {
> +			/* Store in hdev for instance 0 */
> +			hdev->adv_tx_power = rp->tx_power;
> +		} else if (adv) {
> +			adv->tx_power = rp->tx_power;
> +		}
> +	}
> +
> +	return rp->status;
> +}
> +
> +static int hci_set_ext_adv_data_sync(struct hci_dev *hdev, u8 instance)
> +{
> +	DEFINE_FLEX(struct hci_cp_le_set_ext_adv_data, pdu, data, length,
> +		    HCI_MAX_EXT_AD_LENGTH);
> +	u8 len;
> +	struct adv_info *adv = NULL;
> +	int err;
> +
> +	if (instance) {
> +		adv = hci_find_adv_instance(hdev, instance);
> +		if (!adv || !adv->adv_data_changed)
> +			return 0;
> +	}
> +
> +	len = eir_create_adv_data(hdev, instance, pdu->data,
> +				  HCI_MAX_EXT_AD_LENGTH);
> +
> +	pdu->length = len;
> +	pdu->handle = adv ? adv->handle : instance;
> +	pdu->operation = LE_SET_ADV_DATA_OP_COMPLETE;
> +	pdu->frag_pref = LE_SET_ADV_DATA_NO_FRAG;
> +
> +	err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_DATA,
> +				    struct_size(pdu, data, len), pdu,
> +				    HCI_CMD_TIMEOUT);
> +	if (err)
> +		return err;
> +
> +	/* Update data if the command succeed */
> +	if (adv) {
> +		adv->adv_data_changed = false;
> +	} else {
> +		memcpy(hdev->adv_data, pdu->data, len);
> +		hdev->adv_data_len = len;
> +	}
> +
> +	return 0;
> +}
> +
> +static int hci_set_adv_data_sync(struct hci_dev *hdev, u8 instance)
> +{
> +	struct hci_cp_le_set_adv_data cp;
> +	u8 len;
> +
> +	memset(&cp, 0, sizeof(cp));
> +
> +	len = eir_create_adv_data(hdev, instance, cp.data, sizeof(cp.data));
> +
> +	/* There's nothing to do if the data hasn't changed */
> +	if (hdev->adv_data_len == len &&
> +	    memcmp(cp.data, hdev->adv_data, len) == 0)
> +		return 0;
> +
> +	memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
> +	hdev->adv_data_len = len;
> +
> +	cp.length = len;
> +
> +	return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_DATA,
> +				     sizeof(cp), &cp, HCI_CMD_TIMEOUT);
> +}
> +
> +int hci_update_adv_data_sync(struct hci_dev *hdev, u8 instance)
> +{
> +	if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
> +		return 0;
> +
> +	if (ext_adv_capable(hdev))
> +		return hci_set_ext_adv_data_sync(hdev, instance);
> +
> +	return hci_set_adv_data_sync(hdev, instance);
> +}
> +
>  int hci_setup_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance)
>  {
>  	struct hci_cp_le_set_ext_adv_params cp;
> +	struct hci_rp_le_set_ext_adv_params rp;
>  	bool connectable;
>  	u32 flags;
>  	bdaddr_t random_addr;
> @@ -1316,8 +1433,12 @@ int hci_setup_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance)
>  		cp.secondary_phy = HCI_ADV_PHY_1M;
>  	}
>  
> -	err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_PARAMS,
> -				    sizeof(cp), &cp, HCI_CMD_TIMEOUT);
> +	err = hci_set_ext_adv_params_sync(hdev, adv, &cp, &rp);
> +	if (err)
> +		return err;
> +
> +	/* Update adv data as tx power is known now */
> +	err = hci_set_ext_adv_data_sync(hdev, cp.handle);
>  	if (err)
>  		return err;
>  
> @@ -1822,79 +1943,6 @@ int hci_le_terminate_big_sync(struct hci_dev *hdev, u8 handle, u8 reason)
>  				     sizeof(cp), &cp, HCI_CMD_TIMEOUT);
>  }
>  
> -static int hci_set_ext_adv_data_sync(struct hci_dev *hdev, u8 instance)
> -{
> -	DEFINE_FLEX(struct hci_cp_le_set_ext_adv_data, pdu, data, length,
> -		    HCI_MAX_EXT_AD_LENGTH);
> -	u8 len;
> -	struct adv_info *adv = NULL;
> -	int err;
> -
> -	if (instance) {
> -		adv = hci_find_adv_instance(hdev, instance);
> -		if (!adv || !adv->adv_data_changed)
> -			return 0;
> -	}
> -
> -	len = eir_create_adv_data(hdev, instance, pdu->data,
> -				  HCI_MAX_EXT_AD_LENGTH);
> -
> -	pdu->length = len;
> -	pdu->handle = adv ? adv->handle : instance;
> -	pdu->operation = LE_SET_ADV_DATA_OP_COMPLETE;
> -	pdu->frag_pref = LE_SET_ADV_DATA_NO_FRAG;
> -
> -	err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_DATA,
> -				    struct_size(pdu, data, len), pdu,
> -				    HCI_CMD_TIMEOUT);
> -	if (err)
> -		return err;
> -
> -	/* Update data if the command succeed */
> -	if (adv) {
> -		adv->adv_data_changed = false;
> -	} else {
> -		memcpy(hdev->adv_data, pdu->data, len);
> -		hdev->adv_data_len = len;
> -	}
> -
> -	return 0;
> -}
> -
> -static int hci_set_adv_data_sync(struct hci_dev *hdev, u8 instance)
> -{
> -	struct hci_cp_le_set_adv_data cp;
> -	u8 len;
> -
> -	memset(&cp, 0, sizeof(cp));
> -
> -	len = eir_create_adv_data(hdev, instance, cp.data, sizeof(cp.data));
> -
> -	/* There's nothing to do if the data hasn't changed */
> -	if (hdev->adv_data_len == len &&
> -	    memcmp(cp.data, hdev->adv_data, len) == 0)
> -		return 0;
> -
> -	memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
> -	hdev->adv_data_len = len;
> -
> -	cp.length = len;
> -
> -	return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_DATA,
> -				     sizeof(cp), &cp, HCI_CMD_TIMEOUT);
> -}
> -
> -int hci_update_adv_data_sync(struct hci_dev *hdev, u8 instance)
> -{
> -	if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
> -		return 0;
> -
> -	if (ext_adv_capable(hdev))
> -		return hci_set_ext_adv_data_sync(hdev, instance);
> -
> -	return hci_set_adv_data_sync(hdev, instance);
> -}
> -
>  int hci_schedule_adv_instance_sync(struct hci_dev *hdev, u8 instance,
>  				   bool force)
>  {
> @@ -6269,6 +6317,7 @@ static int hci_le_ext_directed_advertising_sync(struct hci_dev *hdev,
>  						struct hci_conn *conn)
>  {
>  	struct hci_cp_le_set_ext_adv_params cp;
> +	struct hci_rp_le_set_ext_adv_params rp;
>  	int err;
>  	bdaddr_t random_addr;
>  	u8 own_addr_type;
> @@ -6310,8 +6359,12 @@ static int hci_le_ext_directed_advertising_sync(struct hci_dev *hdev,
>  	if (err)
>  		return err;
>  
> -	err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_PARAMS,
> -				    sizeof(cp), &cp, HCI_CMD_TIMEOUT);
> +	err = hci_set_ext_adv_params_sync(hdev, NULL, &cp, &rp);
> +	if (err)
> +		return err;
> +
> +	/* Update adv data as tx power is known now */
> +	err = hci_set_ext_adv_data_sync(hdev, cp.handle);
>  	if (err)
>  		return err;
>  
> 








[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux