Re: [PATCH 3/4] Bluetooth: Merge ADV_IND/ADV_SCAN_IND and SCAN_RSP together

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

 



Hi Johan,

> To avoid too many events being sent to user space and to help parsing of
> all available remote device data it makes sense for us to wait for the
> scan response and send a single merged Device Found event to user space.
> 
> This patch adds a few new variables to hci_dev to track the last
> received ADV_IND/ADV_SCAN_IND, i.e. those which will cause a SCAN_REQ to
> be send in the case of active scanning. When the SCAN_RSP is received
> the pending data is passed together with the SCAN_RSP to the
> mgmt_device_found function which takes care of merging them into a
> single Device Found event.
> 
> We also need a bit of extra logic to handle situations where we don't
> receive a SCAN_RSP after caching some data. In such a scenario we simply
> have to send out the pending data as it is and then operate on the new
> report as if there was no pending data.
> 
> We also need to send out any pending data when scanning stops as
> well as ensure that the storage is empty at the start of a new active
> scanning session. These both cases are covered by the update to the
> hci_cc_le_set_scan_enable function in this patch.
> 
> Signed-off-by: Johan Hedberg <johan.hedberg@xxxxxxxxx>
> ---
> include/net/bluetooth/hci_core.h |  4 ++
> net/bluetooth/hci_event.c        | 99 +++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 101 insertions(+), 2 deletions(-)
> 
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index a1b8eab8a47d..59b112397d39 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -68,6 +68,10 @@ struct discovery_state {
> 	struct list_head	unknown;	/* Name state not known */
> 	struct list_head	resolve;	/* Name needs to be resolved */
> 	__u32			timestamp;
> +	bdaddr_t		last_adv_addr;
> +	u8			last_adv_addr_type;
> +	u8			last_adv_data[HCI_MAX_AD_LENGTH];
> +	u8			last_adv_data_len;
> };
> 
> struct hci_conn_hash {
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index 4a2c919d5908..b9f0b20c9a51 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -1018,6 +1018,32 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
> 	hci_dev_unlock(hdev);
> }
> 
> +static bool has_pending_adv_report(struct hci_dev *hdev)
> +{
> +	struct discovery_state *d = &hdev->discovery;
> +
> +	return bacmp(&d->last_adv_addr, BDADDR_ANY);
> +}
> +
> +static void clear_pending_adv_report(struct hci_dev *hdev)
> +{
> +	struct discovery_state *d = &hdev->discovery;
> +
> +	bacpy(&d->last_adv_addr, BDADDR_ANY);
> +	d->last_adv_data_len = 0;
> +}
> +
> +static void store_pending_adv_report(struct hci_dev *hdev, bdaddr_t *bdaddr,
> +				     u8 bdaddr_type, u8 *data, u8 len)
> +{
> +	struct discovery_state *d = &hdev->discovery;
> +
> +	bacpy(&d->last_adv_addr, bdaddr);
> +	d->last_adv_addr_type = bdaddr_type;
> +	memcpy(d->last_adv_data, data, len);
> +	d->last_adv_data_len = len;
> +}
> +
> static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
> 				      struct sk_buff *skb)
> {
> @@ -1036,9 +1062,25 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
> 	switch (cp->enable) {
> 	case LE_SCAN_ENABLE:
> 		set_bit(HCI_LE_SCAN, &hdev->dev_flags);
> +		if (hdev->le_scan_type == LE_SCAN_ACTIVE)
> +			clear_pending_adv_report(hdev);
> 		break;
> 
> 	case LE_SCAN_DISABLE:
> +		/* We do this here instead of when setting DISCOVERY_STOPPED
> +		 * since the latter would potentially require waiting for
> +		 * inquiry to stop too.
> +		 */
> +		if (has_pending_adv_report(hdev)) {
> +			struct discovery_state *d = &hdev->discovery;
> +
> +			mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK,
> +						  d->last_adv_addr_type, NULL,
> +						  0, 0, 1, d->last_adv_data,
> +						  d->last_adv_data_len,
> +						  NULL, 0);

indentation is wrong here.

> +		}
> +
> 		/* Cancel this timer so that we don't try to disable scanning
> 		 * when it's already disabled.
> 		 */
> @@ -3964,6 +4006,8 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr,
> static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
> 			       u8 bdaddr_type, s8 rssi, u8 *data, u8 len)
> {
> +	struct discovery_state *d = &hdev->discovery;
> +
> 	/* Passive scanning shouldn't trigger any device found events */
> 	if (hdev->le_scan_type == LE_SCAN_PASSIVE) {
> 		if (type == LE_ADV_IND || type == LE_ADV_DIRECT_IND)
> @@ -3971,8 +4015,59 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
> 		return;
> 	}
> 
> -	mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL, rssi, 0, 1,
> -			  data, len, NULL, 0);
> +	/* If there's nothing pending either store the data from this
> +	 * event or send an immediate device found event if the data
> +	 * should not be stored for later.
> +	 */
> +	if (!has_pending_adv_report(hdev)) {
> +		if (type == LE_ADV_IND || type == LE_ADV_SCAN_IND) {
> +			store_pending_adv_report(hdev, bdaddr, bdaddr_type,
> +						 data, len);
> +			return;
> +		}
> +
> +		mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL,
> +				  rssi, 0, 1, data, len, NULL, 0);
> +		return;
> +	}
> +
> +	/* If the pending data doesn't match this report or this isn't a
> +	 * scan response (e.g. we got a duplicate ADV_IND) then force
> +	 * sending of the pending data.
> +	 */
> +	if (type != LE_ADV_SCAN_RSP || bacmp(bdaddr, &d->last_adv_addr) ||
> +	    bdaddr_type != d->last_adv_addr_type) {
> +		/* Send out whatever is in the cache */
> +		mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK,
> +				  d->last_adv_addr_type, NULL, 0, 0, 1,
> +				  d->last_adv_data, d->last_adv_data_len,
> +				  NULL, 0);
> +
> +		/* If the new event should be cached store it there */

I can not parse this comment. What to cached store where ;)

> +		if (type == LE_ADV_IND || type == LE_ADV_SCAN_IND) {
> +			store_pending_adv_report(hdev, bdaddr, bdaddr_type,
> +						 data, len);
> +			return;
> +		}
> +
> +		/* The event can't be cached so clear the cache and send
> +		 * an immediate event based on this report.
> +		 */

The advertising reports can not be merged, so clear the pending report and send out the event. Or something like that.

> +		clear_pending_adv_report(hdev);
> +		mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK,
> +				  d->last_adv_addr_type, NULL, rssi, 0, 1,
> +				  data, len, NULL, 0);
> +		return;
> +	}
> +
> +	/* If we get here we've got a pending ADV_IND or ADV_SCAN_IND and
> +	 * the new event is a SCAN_RSP. We can therefore proceed with
> +	 * sending a merged device found event.
> +	 */
> +	mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK,
> +			  d->last_adv_addr_type, NULL, rssi, 0, 1, data, len,
> +			  d->last_adv_data, d->last_adv_data_len);
> +	clear_pending_adv_report(hdev);
> }

Regards

Marcel

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[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