Commit bd2fbc6c authored by Miao-chen Chou's avatar Miao-chen Chou Committed by Johan Hedberg
Browse files

Bluetooth: Add handler of MGMT_OP_REMOVE_ADV_MONITOR



This adds the request handler of MGMT_OP_REMOVE_ADV_MONITOR command.
Note that the controller-based monitoring is not yet in place. This
removes the internal monitor(s) without sending HCI traffic, so the
request returns immediately.

The following test was performed.
- Issue btmgmt advmon-remove with valid and invalid handles.

Signed-off-by: default avatarMiao-chen Chou <mcchou@chromium.org>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
parent b139553d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1283,6 +1283,7 @@ void hci_adv_instances_set_rpa_expired(struct hci_dev *hdev, bool rpa_expired);
void hci_adv_monitors_clear(struct hci_dev *hdev);
void hci_free_adv_monitor(struct adv_monitor *monitor);
int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor);
int hci_remove_adv_monitor(struct hci_dev *hdev, u16 handle);

void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);

+31 −0
Original line number Diff line number Diff line
@@ -3041,6 +3041,37 @@ int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor)
	return 0;
}

static int free_adv_monitor(int id, void *ptr, void *data)
{
	struct hci_dev *hdev = data;
	struct adv_monitor *monitor = ptr;

	idr_remove(&hdev->adv_monitors_idr, monitor->handle);
	hci_free_adv_monitor(monitor);

	return 0;
}

/* This function requires the caller holds hdev->lock */
int hci_remove_adv_monitor(struct hci_dev *hdev, u16 handle)
{
	struct adv_monitor *monitor;

	if (handle) {
		monitor = idr_find(&hdev->adv_monitors_idr, handle);
		if (!monitor)
			return -ENOENT;

		idr_remove(&hdev->adv_monitors_idr, monitor->handle);
		hci_free_adv_monitor(monitor);
	} else {
		/* Remove all monitors if handle is 0. */
		idr_for_each(&hdev->adv_monitors_idr, &free_adv_monitor, hdev);
	}

	return 0;
}

struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list,
					 bdaddr_t *bdaddr, u8 type)
{
+35 −0
Original line number Diff line number Diff line
@@ -121,6 +121,7 @@ static const u16 mgmt_commands[] = {
	MGMT_OP_SET_DEVICE_FLAGS,
	MGMT_OP_READ_ADV_MONITOR_FEATURES,
	MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
	MGMT_OP_REMOVE_ADV_MONITOR,
};

static const u16 mgmt_events[] = {
@@ -4118,6 +4119,39 @@ static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
	return err;
}

static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev,
			      void *data, u16 len)
{
	struct mgmt_cp_remove_adv_monitor *cp = data;
	struct mgmt_rp_remove_adv_monitor rp;
	u16 handle;
	int err;

	BT_DBG("request for %s", hdev->name);

	hci_dev_lock(hdev);

	handle = __le16_to_cpu(cp->monitor_handle);

	err = hci_remove_adv_monitor(hdev, handle);
	if (err == -ENOENT) {
		err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADV_MONITOR,
				      MGMT_STATUS_INVALID_INDEX);
		goto unlock;
	}

	hci_dev_unlock(hdev);

	rp.monitor_handle = cp->monitor_handle;

	return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_ADV_MONITOR,
				 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));

unlock:
	hci_dev_unlock(hdev);
	return err;
}

static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
				         u16 opcode, struct sk_buff *skb)
{
@@ -7589,6 +7623,7 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
	{ read_adv_mon_features,   MGMT_READ_ADV_MONITOR_FEATURES_SIZE },
	{ add_adv_patterns_monitor,MGMT_ADD_ADV_PATTERNS_MONITOR_SIZE,
						HCI_MGMT_VAR_LEN },
	{ remove_adv_monitor,      MGMT_REMOVE_ADV_MONITOR_SIZE },
};

void mgmt_index_added(struct hci_dev *hdev)