Commit 22346b47 authored by Lyle Zhu's avatar Lyle Zhu Committed by Benjamin Cabé
Browse files

Bluetooth: Classic: SDP: Support ATTR ID list setting for SA/SSA REQ



In current implementation, the ATTR ID list is set with fixed value
(0x0000, 0xffff). For the case that responding a lot of SDP record
data, the responded data cannot be processed properly due to the
receiving buffer size limitation. In this case, the ATTR ID list can
be used to reduce the length of the responding data. In this way, it
will help reduce the SDP's requirement for receiving data buffer size.

Add the attribute ID list configuration to the SDP discovery request
structure `struct bt_sdp_discover_params`.

If the `struct bt_sdp_discover_params::ids` is NULL, or
`struct bt_sdp_discover_params::ids::count` is 0, the default range
(0x0000, 0xffff) is used.

Signed-off-by: default avatarLyle Zhu <lyle.zhu@nxp.com>
parent fc6fe95c
Loading
Loading
Loading
Loading
+34 −1
Original line number Diff line number Diff line
@@ -566,6 +566,30 @@ enum {
	BT_SDP_DISCOVER_SERVICE_SEARCH_ATTR,
};

/** Initializes SDP attribute ID range */
#define BT_SDP_ATTR_ID_RANGE(beginning, ending) {(beginning), (ending)}

/**
 * @brief SDP attribute ID range
 *
 * If the beginning attribute ID is same with the ending attribute ID, the range represents a
 * single attribute ID.
 */
struct bt_sdp_attribute_id_range {
	/** Beginning attribute ID of the range */
	uint16_t beginning;
	/** Ending attribute ID of the range */
	uint16_t ending;
};

/** @brief SDP attribute ID list for Service Attribute and Service Search Attribute transactions */
struct bt_sdp_attribute_id_list {
	/** Count of the SDP attribute ID range */
	size_t count;
	/** Attribute ID range array list */
	struct bt_sdp_attribute_id_range *ranges;
};

/** @brief Main user structure used in SDP discovery of remote. */
struct bt_sdp_discover_params {
	sys_snode_t _node;
@@ -581,6 +605,13 @@ struct bt_sdp_discover_params {
	struct net_buf_pool *pool;
	/** Discover type */
	uint8_t type;
	/**
	 * Attribute ID list for Service Attribute and Service Search Attribute transactions
	 *
	 * If the `ids` is NULL or `ids->count` is 0, the default range `(0x0000, 0xffff)` will
	 * be used.
	 */
	struct bt_sdp_attribute_id_list *ids;
};

/** @brief Allows user to start SDP discovery session.
@@ -604,12 +635,14 @@ struct bt_sdp_discover_params {
 *  Service Attribute:             The SDP Client generates an
 *                                 SDP_SERVICE_ATTR_REQ to retrieve specified
 *                                 attribute values from a specific service
 *                                 record (`params->handle`).
 *                                 record (`params->handle`). The AttributeIDList
 *                                 is specified by `params->ids`.
 *  Service Search Attribute:      The SDP Client generates an
 *                                 SDP_SERVICE_SEARCH_ATTR_REQ to retrieve
 *                                 specified attribute values that match the
 *                                 service search pattern (`params->uuid`)
 *                                 given as the first parameter of the PDU.
 *                                 The AttributeIDList is specified by `params->ids`.
 *
 * @param conn Object identifying connection to remote.
 * @param params SDP discovery parameters.
+118 −23
Original line number Diff line number Diff line
@@ -1773,11 +1773,89 @@ static int sdp_client_ss_search(struct bt_sdp_client *session,
	return bt_sdp_send(&session->chan.chan, buf, BT_SDP_SVC_SEARCH_REQ, session->tid);
}

static uint16_t sdp_client_get_attribute_id_list_len(struct bt_sdp_attribute_id_list *ids)
{
	uint16_t len = 0;

	if (ids == NULL || ids->count == 0) {
		return sizeof(uint8_t) + sizeof(uint32_t);
	}

	for (size_t i = 0; i < ids->count; i++) {
		if (ids->ranges[i].beginning == ids->ranges[i].ending) {
			len += sizeof(uint8_t) + sizeof(uint16_t);
		} else {
			len += sizeof(uint8_t) + sizeof(uint32_t);
		}
	}

	return len;
}

static void sdp_client_add_attribute_id(struct net_buf *buf, struct bt_sdp_attribute_id_list *ids)
{
	uint16_t len;

	len = sdp_client_get_attribute_id_list_len(ids);
	/*
	 * Sequence definition where data is sequence of elements and where
	 * additional next byte points the size of elements within
	 */
	if (len > UINT8_MAX) {
		net_buf_add_u8(buf, BT_SDP_SEQ16);
		net_buf_add_be16(buf, len);
	} else {
		net_buf_add_u8(buf, BT_SDP_SEQ8);
		net_buf_add_u8(buf, len);
	}

	if (ids == NULL || ids->count == 0) {
		/* Data element definition for two following 16bits range elements */
		net_buf_add_u8(buf, BT_SDP_UINT32);
		/* Get all attributes. It enables filter out wanted only attributes */
		net_buf_add_be16(buf, 0x0000);
		net_buf_add_be16(buf, 0xffff);
		return;
	}

	for (size_t i = 0; i < ids->count; i++) {
		if (ids->ranges[i].beginning == ids->ranges[i].ending) {
			/* Data element definition for one following 16bits range elements */
			net_buf_add_u8(buf, BT_SDP_UINT16);
			/* Get all attributes. It enables filter out wanted only attributes */
			net_buf_add_be16(buf, ids->ranges[i].beginning);
		} else {
			/* Data element definition for two following 16bits range elements */
			net_buf_add_u8(buf, BT_SDP_UINT32);
			/* Get all attributes. It enables filter out wanted only attributes */
			net_buf_add_be16(buf, ids->ranges[i].beginning);
			net_buf_add_be16(buf, ids->ranges[i].ending);
		}
	}
}

static uint16_t sdp_client_get_total_len(struct bt_sdp_client *session,
					 const struct bt_sdp_discover_params *param)
{
	uint16_t len;

	len = sdp_client_get_attribute_id_list_len(param->ids);
	if (len > UINT8_MAX) {
		len += sizeof(uint8_t) + sizeof(uint16_t);
	} else {
		len += sizeof(uint8_t) + sizeof(uint8_t);
	}
	len += sizeof(session->cstate.length) + session->cstate.length;

	return len;
}

/* ServiceAttribute PDU, ref to BT Core 5.4, Vol 3, part B, 4.6.1 */
static int sdp_client_sa_search(struct bt_sdp_client *session,
				const struct bt_sdp_discover_params *param)
{
	struct net_buf *buf;
	uint16_t len;

	/* Update context param directly. */
	session->param = param;
@@ -1789,17 +1867,17 @@ static int sdp_client_sa_search(struct bt_sdp_client *session,

	/* Set attribute max bytes count to be returned from server */
	net_buf_add_be16(buf, net_buf_tailroom(session->rec_buf));
	/*
	 * Sequence definition where data is sequence of elements and where
	 * additional next byte points the size of elements within
	 */
	net_buf_add_u8(buf, BT_SDP_SEQ8);
	net_buf_add_u8(buf, 0x05);
	/* Data element definition for two following 16bits range elements */
	net_buf_add_u8(buf, BT_SDP_UINT32);
	/* Get all attributes. It enables filter out wanted only attributes */
	net_buf_add_be16(buf, 0x0000);
	net_buf_add_be16(buf, 0xffff);

	/* Check the tailroom of the buffer */
	len = sdp_client_get_total_len(session, param);
	if (len > net_buf_tailroom(buf)) {
		LOG_ERR("No space to add attribute ID");
		net_buf_unref(buf);
		return -ENOMEM;
	}

	/* Add attribute ID List */
	sdp_client_add_attribute_id(buf, param->ids);

	/*
	 * Update and validate PDU ContinuationState. Initial SSA Request has
@@ -1825,6 +1903,7 @@ static int sdp_client_ssa_search(struct bt_sdp_client *session,
{
	struct net_buf *buf;
	uint8_t uuid128[BT_UUID_SIZE_128];
	uint16_t len;

	/* Update context param directly. */
	session->param = param;
@@ -1862,17 +1941,17 @@ static int sdp_client_ssa_search(struct bt_sdp_client *session,

	/* Set attribute max bytes count to be returned from server */
	net_buf_add_be16(buf, net_buf_tailroom(session->rec_buf));
	/*
	 * Sequence definition where data is sequence of elements and where
	 * additional next byte points the size of elements within
	 */
	net_buf_add_u8(buf, BT_SDP_SEQ8);
	net_buf_add_u8(buf, 0x05);
	/* Data element definition for two following 16bits range elements */
	net_buf_add_u8(buf, BT_SDP_UINT32);
	/* Get all attributes. It enables filter out wanted only attributes */
	net_buf_add_be16(buf, 0x0000);
	net_buf_add_be16(buf, 0xffff);

	/* Check the tailroom of the buffer */
	len = sdp_client_get_total_len(session, param);
	if (len > net_buf_tailroom(buf)) {
		LOG_ERR("No space to add attribute ID");
		net_buf_unref(buf);
		return -ENOMEM;
	}

	/* Add attribute ID List */
	sdp_client_add_attribute_id(buf, param->ids);

	/*
	 * Update and validate PDU ContinuationState. Initial SSA Request has
@@ -2714,11 +2793,27 @@ static int sdp_client_discovery_start(struct bt_conn *conn,
int bt_sdp_discover(struct bt_conn *conn,
		    struct bt_sdp_discover_params *params)
{
	if (!params || !params->uuid || !params->func || !params->pool) {
	if (params == NULL || params->uuid == NULL || params->func == NULL ||
	    params->pool == NULL ||
	    (params->ids != NULL && params->ids->count != 0 && params->ids->ranges == NULL)) {
		LOG_WRN("Invalid user params");
		return -EINVAL;
	}

	if (params->ids != NULL) {
		for (size_t i = 0; i < params->ids->count; i++) {
			struct bt_sdp_attribute_id_range *range;

			range = &params->ids->ranges[i];
			if (range->beginning <= range->ending) {
				continue;
			}

			LOG_WRN("Invalid range %u > %u", range->beginning, range->ending);
			return -EINVAL;
		}
	}

	return sdp_client_discovery_start(conn, params);
}