Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 78b781ca authored by Johan Hedberg's avatar Johan Hedberg Committed by Marcel Holtmann
Browse files

Bluetooth: Add support for Start Limited Discovery command



This patch implements the mgmt Start Limited Discovery command. Most
of existing Start Discovery code is reused since the only difference
is the presence of a 'limited' flag as part of the discovery state.

Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 0d3b7f64
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -77,6 +77,7 @@ struct discovery_state {
	u8			last_adv_data_len;
	u8			last_adv_data_len;
	bool			report_invalid_rssi;
	bool			report_invalid_rssi;
	bool			result_filtering;
	bool			result_filtering;
	bool			limited;
	s8			rssi;
	s8			rssi;
	u16			uuid_count;
	u16			uuid_count;
	u8			(*uuids)[16];
	u8			(*uuids)[16];
+2 −0
Original line number Original line Diff line number Diff line
@@ -584,6 +584,8 @@ struct mgmt_rp_get_adv_size_info {
	__u8	max_scan_rsp_len;
	__u8	max_scan_rsp_len;
} __packed;
} __packed;


#define MGMT_OP_START_LIMITED_DISCOVERY	0x0041

#define MGMT_EV_CMD_COMPLETE		0x0001
#define MGMT_EV_CMD_COMPLETE		0x0001
struct mgmt_ev_cmd_complete {
struct mgmt_ev_cmd_complete {
	__le16	opcode;
	__le16	opcode;
+8 −3
Original line number Original line Diff line number Diff line
@@ -1737,8 +1737,8 @@ static int le_scan_disable(struct hci_request *req, unsigned long opt)
static int bredr_inquiry(struct hci_request *req, unsigned long opt)
static int bredr_inquiry(struct hci_request *req, unsigned long opt)
{
{
	u8 length = opt;
	u8 length = opt;
	/* General inquiry access code (GIAC) */
	const u8 giac[3] = { 0x33, 0x8b, 0x9e };
	u8 lap[3] = { 0x33, 0x8b, 0x9e };
	const u8 liac[3] = { 0x00, 0x8b, 0x9e };
	struct hci_cp_inquiry cp;
	struct hci_cp_inquiry cp;


	BT_DBG("%s", req->hdev->name);
	BT_DBG("%s", req->hdev->name);
@@ -1748,7 +1748,12 @@ static int bredr_inquiry(struct hci_request *req, unsigned long opt)
	hci_dev_unlock(req->hdev);
	hci_dev_unlock(req->hdev);


	memset(&cp, 0, sizeof(cp));
	memset(&cp, 0, sizeof(cp));
	memcpy(&cp.lap, lap, sizeof(cp.lap));

	if (req->hdev->discovery.limited)
		memcpy(&cp.lap, liac, sizeof(cp.lap));
	else
		memcpy(&cp.lap, giac, sizeof(cp.lap));

	cp.length = length;
	cp.length = length;


	hci_req_add(req, HCI_OP_INQUIRY, sizeof(cp), &cp);
	hci_req_add(req, HCI_OP_INQUIRY, sizeof(cp), &cp);
+44 −9
Original line number Original line Diff line number Diff line
@@ -103,6 +103,7 @@ static const u16 mgmt_commands[] = {
	MGMT_OP_ADD_ADVERTISING,
	MGMT_OP_ADD_ADVERTISING,
	MGMT_OP_REMOVE_ADVERTISING,
	MGMT_OP_REMOVE_ADVERTISING,
	MGMT_OP_GET_ADV_SIZE_INFO,
	MGMT_OP_GET_ADV_SIZE_INFO,
	MGMT_OP_START_LIMITED_DISCOVERY,
};
};


static const u16 mgmt_events[] = {
static const u16 mgmt_events[] = {
@@ -3283,6 +3284,9 @@ void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
	if (!cmd)
	if (!cmd)
		cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
		cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);


	if (!cmd)
		cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);

	if (cmd) {
	if (cmd) {
		cmd->cmd_complete(cmd, mgmt_status(status));
		cmd->cmd_complete(cmd, mgmt_status(status));
		mgmt_pending_remove(cmd);
		mgmt_pending_remove(cmd);
@@ -3318,8 +3322,8 @@ static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
	return true;
	return true;
}
}


static int start_discovery(struct sock *sk, struct hci_dev *hdev,
static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
			   void *data, u16 len)
				    u16 op, void *data, u16 len)
{
{
	struct mgmt_cp_start_discovery *cp = data;
	struct mgmt_cp_start_discovery *cp = data;
	struct mgmt_pending_cmd *cmd;
	struct mgmt_pending_cmd *cmd;
@@ -3331,7 +3335,7 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
	hci_dev_lock(hdev);
	hci_dev_lock(hdev);


	if (!hdev_is_powered(hdev)) {
	if (!hdev_is_powered(hdev)) {
		err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
		err = mgmt_cmd_complete(sk, hdev->id, op,
					MGMT_STATUS_NOT_POWERED,
					MGMT_STATUS_NOT_POWERED,
					&cp->type, sizeof(cp->type));
					&cp->type, sizeof(cp->type));
		goto failed;
		goto failed;
@@ -3339,15 +3343,14 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,


	if (hdev->discovery.state != DISCOVERY_STOPPED ||
	if (hdev->discovery.state != DISCOVERY_STOPPED ||
	    hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
	    hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
		err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
		err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
					MGMT_STATUS_BUSY, &cp->type,
					&cp->type, sizeof(cp->type));
					sizeof(cp->type));
		goto failed;
		goto failed;
	}
	}


	if (!discovery_type_is_valid(hdev, cp->type, &status)) {
	if (!discovery_type_is_valid(hdev, cp->type, &status)) {
		err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
		err = mgmt_cmd_complete(sk, hdev->id, op, status,
					status, &cp->type, sizeof(cp->type));
					&cp->type, sizeof(cp->type));
		goto failed;
		goto failed;
	}
	}


@@ -3358,8 +3361,12 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,


	hdev->discovery.type = cp->type;
	hdev->discovery.type = cp->type;
	hdev->discovery.report_invalid_rssi = false;
	hdev->discovery.report_invalid_rssi = false;
	if (op == MGMT_OP_START_LIMITED_DISCOVERY)
		hdev->discovery.limited = true;
	else
		hdev->discovery.limited = false;


	cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, data, len);
	cmd = mgmt_pending_add(sk, op, hdev, data, len);
	if (!cmd) {
	if (!cmd) {
		err = -ENOMEM;
		err = -ENOMEM;
		goto failed;
		goto failed;
@@ -3376,6 +3383,21 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
	return err;
	return err;
}
}


static int start_discovery(struct sock *sk, struct hci_dev *hdev,
			   void *data, u16 len)
{
	return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
					data, len);
}

static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
				   void *data, u16 len)
{
	return start_discovery_internal(sk, hdev,
					MGMT_OP_START_LIMITED_DISCOVERY,
					data, len);
}

static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
					  u8 status)
					  u8 status)
{
{
@@ -6313,6 +6335,7 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
						HCI_MGMT_VAR_LEN },
						HCI_MGMT_VAR_LEN },
	{ remove_advertising,	   MGMT_REMOVE_ADVERTISING_SIZE },
	{ remove_advertising,	   MGMT_REMOVE_ADVERTISING_SIZE },
	{ get_adv_size_info,       MGMT_GET_ADV_SIZE_INFO_SIZE },
	{ get_adv_size_info,       MGMT_GET_ADV_SIZE_INFO_SIZE },
	{ start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
};
};


void mgmt_index_added(struct hci_dev *hdev)
void mgmt_index_added(struct hci_dev *hdev)
@@ -7237,6 +7260,18 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
			return;
			return;
	}
	}


	if (hdev->discovery.limited) {
		/* Check for limited discoverable bit */
		if (dev_class) {
			if (!(dev_class[1] & 0x20))
				return;
		} else {
			u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
			if (!flags || !(flags[0] & LE_AD_LIMITED))
				return;
		}
	}

	/* Make sure that the buffer is big enough. The 5 extra bytes
	/* Make sure that the buffer is big enough. The 5 extra bytes
	 * are for the potential CoD field.
	 * are for the potential CoD field.
	 */
	 */