Bluetooth: Classic: SDP: Improve SDP discover
Extend the function `bt_sdp_discover` to support service search transaction and service attribute transaction. Improve the `session->rec_buf`. If the net buffer cannot be allocated from the channel, disconnect the SDP session. Set the `MaximumAttributeByteCount` of the request `SDP_SERVICE_SEARCH_ATTR_REQ` with the tail room of `session->rec_buf`. Set the `MaximumAttributeByteCount` of the request `SDP_SERVICE_ATTR_REQ` with the tail room of `session->rec_buf`. Set the `MaximumServiceRecordCount` of the request `SDP_SERVICE_SEARCH_REQ` according to the tail room of `session->rec_buf`. Handle the response code `SDP_SERVICE_SEARCH_RSP`, and `SDP_SERVICE_ATTR_RSP`. Handle the error `SDP_ERROR_RSP`. Start the next SDP discovery if the error received. If there no more request, disconnect the session. If the request cannot be sent, start the next SDP discovery. Signed-off-by: Lyle Zhu <lyle.zhu@nxp.com>
This commit is contained in:
parent
ff5a4581b2
commit
a047113556
@ -481,8 +481,6 @@ struct bt_sdp_client_result {
|
||||
struct net_buf *resp_buf;
|
||||
/** flag pointing that there are more result chunks for given UUID */
|
||||
bool next_record_hint;
|
||||
/** Reference to UUID object on behalf one discovery was started */
|
||||
const struct bt_uuid *uuid;
|
||||
};
|
||||
|
||||
/** @brief Helper enum to be used as return value of bt_sdp_discover_func_t.
|
||||
@ -493,6 +491,8 @@ enum {
|
||||
BT_SDP_DISCOVER_UUID_CONTINUE,
|
||||
};
|
||||
|
||||
struct bt_sdp_discover_params;
|
||||
|
||||
/** @typedef bt_sdp_discover_func_t
|
||||
*
|
||||
* @brief Callback type reporting to user that there is a resolved result
|
||||
@ -514,24 +514,41 @@ enum {
|
||||
*
|
||||
* @param conn Connection object identifying connection to queried remote.
|
||||
* @param result Object pointing to logical unparsed SDP record collected on
|
||||
* base of response driven by given UUID.
|
||||
* base of response driven by given discover params.
|
||||
* @param params Discover parameters.
|
||||
*
|
||||
* @return BT_SDP_DISCOVER_UUID_STOP in case of no more need to read next
|
||||
* record data and continue discovery for given UUID. By returning
|
||||
* BT_SDP_DISCOVER_UUID_CONTINUE user allows this discovery continuation.
|
||||
* @return BT_SDP_DISCOVER_UUID_CONTINUE user allows this discovery continuation.
|
||||
*/
|
||||
typedef uint8_t (*bt_sdp_discover_func_t)
|
||||
(struct bt_conn *conn, struct bt_sdp_client_result *result);
|
||||
typedef uint8_t (*bt_sdp_discover_func_t)(struct bt_conn *conn, struct bt_sdp_client_result *result,
|
||||
const struct bt_sdp_discover_params *params);
|
||||
|
||||
/** SDP Discover types */
|
||||
enum {
|
||||
/** Discover Service Search. */
|
||||
BT_SDP_DISCOVER_SERVICE_SEARCH,
|
||||
/** Discover Service Attribute. */
|
||||
BT_SDP_DISCOVER_SERVICE_ATTR,
|
||||
/** Discover Service Search Attribute. */
|
||||
BT_SDP_DISCOVER_SERVICE_SEARCH_ATTR,
|
||||
};
|
||||
|
||||
/** @brief Main user structure used in SDP discovery of remote. */
|
||||
struct bt_sdp_discover_params {
|
||||
sys_snode_t _node;
|
||||
/** UUID (service) to be discovered on remote SDP entity */
|
||||
const struct bt_uuid *uuid;
|
||||
sys_snode_t _node;
|
||||
union {
|
||||
/** UUID (service) to be discovered on remote SDP entity */
|
||||
const struct bt_uuid *uuid;
|
||||
/** Service record handle */
|
||||
uint32_t handle;
|
||||
};
|
||||
/** Discover callback to be called on resolved SDP record */
|
||||
bt_sdp_discover_func_t func;
|
||||
bt_sdp_discover_func_t func;
|
||||
/** Memory buffer enabled by user for SDP query results */
|
||||
struct net_buf_pool *pool;
|
||||
struct net_buf_pool *pool;
|
||||
/** Discover type */
|
||||
uint8_t type;
|
||||
};
|
||||
|
||||
/** @brief Allows user to start SDP discovery session.
|
||||
@ -543,6 +560,21 @@ struct bt_sdp_discover_params {
|
||||
* On the service discovery completion the callback function will be
|
||||
* called to get feedback to user about findings.
|
||||
*
|
||||
* Service Search: The SDP Client generates an
|
||||
* SDP_SERVICE_SEARCH_REQ to locate service
|
||||
* records that match the service search
|
||||
* pattern (`params->uuid`) given as the first
|
||||
* parameter of the PDU.
|
||||
* Service Attribute: The SDP Client generates an
|
||||
* SDP_SERVICE_ATTR_REQ to retrieve specified
|
||||
* attribute values from a specific service
|
||||
* record (`params->handle`).
|
||||
* 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.
|
||||
*
|
||||
* @param conn Object identifying connection to remote.
|
||||
* @param params SDP discovery parameters.
|
||||
*
|
||||
|
||||
@ -58,6 +58,9 @@ LOG_MODULE_REGISTER(bt_sdp);
|
||||
|
||||
#define SDP_INVALID 0xff
|
||||
|
||||
/* SDP record handle size */
|
||||
#define SDP_RECORD_HANDLE_SIZE 4
|
||||
|
||||
struct bt_sdp {
|
||||
struct bt_l2cap_br_chan chan;
|
||||
struct k_fifo partial_resp_queue;
|
||||
@ -1476,29 +1479,115 @@ int bt_sdp_register_service(struct bt_sdp_record *service)
|
||||
#define GET_PARAM(__node) \
|
||||
CONTAINER_OF(__node, struct bt_sdp_discover_params, _node)
|
||||
|
||||
/* ServiceSearchAttribute PDU, ref to BT Core 4.2, Vol 3, part B, 4.7.1 */
|
||||
static int sdp_client_ssa_search(struct bt_sdp_client *session)
|
||||
/* ServiceSearch PDU, ref to BT Core 5.4, Vol 3, part B, 4.5.1 */
|
||||
static int sdp_client_ss_search(struct bt_sdp_client *session,
|
||||
const struct bt_sdp_discover_params *param)
|
||||
{
|
||||
const struct bt_sdp_discover_params *param;
|
||||
struct net_buf *buf;
|
||||
|
||||
/*
|
||||
* Select proper user params, if session->param is invalid it means
|
||||
* getting new UUID from top of to be resolved params list. Otherwise
|
||||
* the context is in a middle of partial SDP PDU responses and cached
|
||||
* value from context can be used.
|
||||
*/
|
||||
if (!session->param) {
|
||||
param = GET_PARAM(sys_slist_peek_head(&session->reqs));
|
||||
} else {
|
||||
param = session->param;
|
||||
}
|
||||
buf = bt_sdp_create_pdu();
|
||||
|
||||
if (!param) {
|
||||
LOG_WRN("No UUIDs to be resolved on remote");
|
||||
/* BT_SDP_SEQ8 means length of sequence is on additional next byte */
|
||||
net_buf_add_u8(buf, BT_SDP_SEQ8);
|
||||
|
||||
switch (param->uuid->type) {
|
||||
case BT_UUID_TYPE_16:
|
||||
/* Seq length */
|
||||
net_buf_add_u8(buf, 0x03);
|
||||
/* Seq type */
|
||||
net_buf_add_u8(buf, BT_SDP_UUID16);
|
||||
/* Seq value */
|
||||
net_buf_add_be16(buf, BT_UUID_16(param->uuid)->val);
|
||||
break;
|
||||
case BT_UUID_TYPE_32:
|
||||
net_buf_add_u8(buf, 0x05);
|
||||
net_buf_add_u8(buf, BT_SDP_UUID32);
|
||||
net_buf_add_be32(buf, BT_UUID_32(param->uuid)->val);
|
||||
break;
|
||||
case BT_UUID_TYPE_128:
|
||||
net_buf_add_u8(buf, 0x11);
|
||||
net_buf_add_u8(buf, BT_SDP_UUID128);
|
||||
net_buf_add_mem(buf, BT_UUID_128(param->uuid)->val,
|
||||
ARRAY_SIZE(BT_UUID_128(param->uuid)->val));
|
||||
break;
|
||||
default:
|
||||
LOG_ERR("Unknown UUID type %u", param->uuid->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Set maximum number of service record handles */
|
||||
net_buf_add_be16(buf, net_buf_tailroom(session->rec_buf) / SDP_RECORD_HANDLE_SIZE);
|
||||
/*
|
||||
* Update and validate PDU ContinuationState. Initial SSA Request has
|
||||
* zero length continuation state since no interaction has place with
|
||||
* server so far, otherwise use the original state taken from remote's
|
||||
* last response PDU that is cached by SDP client context.
|
||||
*/
|
||||
if (session->cstate.length == 0U) {
|
||||
net_buf_add_u8(buf, 0x00);
|
||||
} else {
|
||||
net_buf_add_u8(buf, session->cstate.length);
|
||||
net_buf_add_mem(buf, session->cstate.data, session->cstate.length);
|
||||
}
|
||||
|
||||
/* Update context param to the one being resolving now */
|
||||
session->param = param;
|
||||
session->tid++;
|
||||
|
||||
return bt_sdp_send(&session->chan.chan, buf, BT_SDP_SVC_SEARCH_REQ, session->tid);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
buf = bt_sdp_create_pdu();
|
||||
|
||||
/* Add service record handle */
|
||||
net_buf_add_be32(buf, param->handle);
|
||||
|
||||
/* 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);
|
||||
|
||||
/*
|
||||
* Update and validate PDU ContinuationState. Initial SSA Request has
|
||||
* zero length continuation state since no interaction has place with
|
||||
* server so far, otherwise use the original state taken from remote's
|
||||
* last response PDU that is cached by SDP client context.
|
||||
*/
|
||||
if (session->cstate.length == 0U) {
|
||||
net_buf_add_u8(buf, 0x00);
|
||||
} else {
|
||||
net_buf_add_u8(buf, session->cstate.length);
|
||||
net_buf_add_mem(buf, session->cstate.data, session->cstate.length);
|
||||
}
|
||||
|
||||
/* Update context param to the one being resolving now */
|
||||
session->param = param;
|
||||
session->tid++;
|
||||
|
||||
return bt_sdp_send(&session->chan.chan, buf, BT_SDP_SVC_ATTR_REQ, session->tid);
|
||||
}
|
||||
|
||||
/* ServiceSearchAttribute PDU, ref to BT Core 4.2, Vol 3, part B, 4.7.1 */
|
||||
static int sdp_client_ssa_search(struct bt_sdp_client *session,
|
||||
const struct bt_sdp_discover_params *param)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
|
||||
buf = bt_sdp_create_pdu();
|
||||
|
||||
/* BT_SDP_SEQ8 means length of sequence is on additional next byte */
|
||||
@ -1530,7 +1619,7 @@ 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, BT_SDP_MAX_ATTR_LEN);
|
||||
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
|
||||
@ -1565,6 +1654,56 @@ static int sdp_client_ssa_search(struct bt_sdp_client *session)
|
||||
session->tid);
|
||||
}
|
||||
|
||||
static void sdp_client_params_iterator(struct bt_sdp_client *session);
|
||||
|
||||
static int sdp_client_discover(struct bt_sdp_client *session)
|
||||
{
|
||||
const struct bt_sdp_discover_params *param;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* Select proper user params, if session->param is invalid it means
|
||||
* getting new UUID from top of to be resolved params list. Otherwise
|
||||
* the context is in a middle of partial SDP PDU responses and cached
|
||||
* value from context can be used.
|
||||
*/
|
||||
if (!session->param) {
|
||||
param = GET_PARAM(sys_slist_peek_head(&session->reqs));
|
||||
} else {
|
||||
param = session->param;
|
||||
}
|
||||
|
||||
if (!param) {
|
||||
struct bt_l2cap_chan *chan = &session->chan.chan;
|
||||
|
||||
LOG_WRN("No more request, disconnect channel");
|
||||
/* No UUID items, disconnect channel */
|
||||
return bt_l2cap_chan_disconnect(chan);
|
||||
}
|
||||
|
||||
switch (param->type) {
|
||||
case BT_SDP_DISCOVER_SERVICE_SEARCH:
|
||||
err = sdp_client_ss_search(session, param);
|
||||
break;
|
||||
case BT_SDP_DISCOVER_SERVICE_ATTR:
|
||||
err = sdp_client_sa_search(session, param);
|
||||
break;
|
||||
case BT_SDP_DISCOVER_SERVICE_SEARCH_ATTR:
|
||||
err = sdp_client_ssa_search(session, param);
|
||||
break;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
/* Get next UUID and start resolving it */
|
||||
sdp_client_params_iterator(session);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sdp_client_params_iterator(struct bt_sdp_client *session)
|
||||
{
|
||||
struct bt_l2cap_chan *chan = &session->chan.chan;
|
||||
@ -1586,7 +1725,7 @@ static void sdp_client_params_iterator(struct bt_sdp_client *session)
|
||||
|
||||
/* Check if there's valid next UUID */
|
||||
if (!sys_slist_is_empty(&session->reqs)) {
|
||||
sdp_client_ssa_search(session);
|
||||
sdp_client_discover(session);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1640,7 +1779,17 @@ static uint16_t sdp_client_get_total(struct bt_sdp_client *session,
|
||||
return pulled;
|
||||
}
|
||||
|
||||
static uint16_t get_record_len(struct net_buf *buf)
|
||||
static uint16_t get_ss_record_len(struct net_buf *buf)
|
||||
{
|
||||
if (buf->len >= SDP_RECORD_HANDLE_SIZE) {
|
||||
return SDP_RECORD_HANDLE_SIZE;
|
||||
}
|
||||
|
||||
LOG_WRN("Invalid service record handle length");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint16_t get_ssa_sa_record_len(struct net_buf *buf)
|
||||
{
|
||||
uint16_t len;
|
||||
uint8_t seq;
|
||||
@ -1663,6 +1812,33 @@ static uint16_t get_record_len(struct net_buf *buf)
|
||||
break;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static uint16_t get_record_len(struct bt_sdp_client *session)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
uint16_t len;
|
||||
|
||||
buf = session->rec_buf;
|
||||
|
||||
if (!session->param) {
|
||||
return buf->len;
|
||||
}
|
||||
|
||||
switch (session->param->type) {
|
||||
case BT_SDP_DISCOVER_SERVICE_SEARCH:
|
||||
len = get_ss_record_len(buf);
|
||||
break;
|
||||
case BT_SDP_DISCOVER_SERVICE_ATTR:
|
||||
__fallthrough;
|
||||
case BT_SDP_DISCOVER_SERVICE_SEARCH_ATTR:
|
||||
len = get_ssa_sa_record_len(buf);
|
||||
break;
|
||||
default:
|
||||
len = buf->len;
|
||||
}
|
||||
|
||||
LOG_DBG("Record len %u", len);
|
||||
|
||||
return len;
|
||||
@ -1681,19 +1857,17 @@ static void sdp_client_notify_result(struct bt_sdp_client *session,
|
||||
uint16_t rec_len;
|
||||
uint8_t user_ret;
|
||||
|
||||
result.uuid = session->param->uuid;
|
||||
|
||||
if (state == UUID_NOT_RESOLVED) {
|
||||
result.resp_buf = NULL;
|
||||
result.next_record_hint = false;
|
||||
session->param->func(conn, &result);
|
||||
session->param->func(conn, &result, session->param);
|
||||
return;
|
||||
}
|
||||
|
||||
while (session->rec_buf->len) {
|
||||
struct net_buf_simple_state buf_state;
|
||||
|
||||
rec_len = get_record_len(session->rec_buf);
|
||||
rec_len = get_record_len(session);
|
||||
/* tell the user about multi record resolution */
|
||||
if (session->rec_buf->len > rec_len) {
|
||||
result.next_record_hint = true;
|
||||
@ -1712,7 +1886,7 @@ static void sdp_client_notify_result(struct bt_sdp_client *session,
|
||||
*/
|
||||
result.resp_buf->len = rec_len;
|
||||
|
||||
user_ret = session->param->func(conn, &result);
|
||||
user_ret = session->param->func(conn, &result, session->param);
|
||||
|
||||
/* restore original session buffer */
|
||||
net_buf_simple_restore(&session->rec_buf->b, &buf_state);
|
||||
@ -1727,13 +1901,194 @@ static void sdp_client_notify_result(struct bt_sdp_client *session,
|
||||
}
|
||||
}
|
||||
|
||||
static int sdp_client_receive_ss(struct bt_sdp_client *session, struct net_buf *buf)
|
||||
{
|
||||
struct bt_sdp_pdu_cstate *cstate;
|
||||
uint16_t current_count;
|
||||
uint16_t total_count;
|
||||
uint32_t record_len;
|
||||
uint32_t received_count;
|
||||
|
||||
/* Check the buffer len for the total_count field */
|
||||
if (buf->len < sizeof(total_count)) {
|
||||
LOG_ERR("Invalid frame payload length");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get total service record count. */
|
||||
total_count = net_buf_pull_be16(buf);
|
||||
|
||||
/* Check the buffer len for the current_count field */
|
||||
if (buf->len < sizeof(current_count)) {
|
||||
LOG_ERR("Invalid frame payload length");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get current service record count. */
|
||||
current_count = net_buf_pull_be16(buf);
|
||||
/* Check valid of current service record count */
|
||||
if (current_count > total_count) {
|
||||
LOG_ERR("Invalid current service record count");
|
||||
return 0;
|
||||
}
|
||||
|
||||
received_count = session->rec_buf->len / SDP_RECORD_HANDLE_SIZE;
|
||||
if ((received_count + current_count) > total_count) {
|
||||
LOG_ERR("Excess data received");
|
||||
return 0;
|
||||
}
|
||||
|
||||
record_len = current_count * SDP_RECORD_HANDLE_SIZE;
|
||||
if (record_len >= buf->len) {
|
||||
LOG_ERR("Invalid packet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get PDU continuation state */
|
||||
cstate = (struct bt_sdp_pdu_cstate *)(buf->data + record_len);
|
||||
|
||||
if (cstate->length > BT_SDP_MAX_PDU_CSTATE_LEN) {
|
||||
LOG_ERR("Invalid SDP PDU Continuation State length %u", cstate->length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((record_len + SDP_CONT_STATE_LEN_SIZE + cstate->length) > buf->len) {
|
||||
LOG_ERR("Invalid payload length");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* No record found for given UUID. The check catches case when
|
||||
* current response frame has Continuation State shortest and
|
||||
* valid and this is the first response frame as well.
|
||||
*/
|
||||
if (!current_count && cstate->length == 0U && session->cstate.length == 0U) {
|
||||
LOG_DBG("Service record handle 0x%x not found", session->param->handle);
|
||||
/* Call user UUID handler */
|
||||
sdp_client_notify_result(session, UUID_NOT_RESOLVED);
|
||||
net_buf_pull(buf, sizeof(cstate->length));
|
||||
goto iterate;
|
||||
}
|
||||
|
||||
if (record_len > net_buf_tailroom(session->rec_buf)) {
|
||||
LOG_WRN("Not enough room for getting records data");
|
||||
goto iterate;
|
||||
}
|
||||
|
||||
net_buf_add_mem(session->rec_buf, buf->data, record_len);
|
||||
net_buf_pull(buf, record_len);
|
||||
|
||||
/* check if current response says there's next portion to be fetched */
|
||||
if (cstate->length) {
|
||||
/* Cache original Continuation State in context */
|
||||
memcpy(&session->cstate, cstate, sizeof(struct bt_sdp_pdu_cstate));
|
||||
|
||||
net_buf_pull(buf, cstate->length + sizeof(cstate->length));
|
||||
|
||||
/* Request for next portion of attributes data */
|
||||
return sdp_client_discover(session);
|
||||
}
|
||||
|
||||
net_buf_pull(buf, sizeof(cstate->length));
|
||||
|
||||
LOG_DBG("UUID 0x%s resolved", bt_uuid_str(session->param->uuid));
|
||||
sdp_client_notify_result(session, UUID_RESOLVED);
|
||||
iterate:
|
||||
/* Get next UUID and start resolving it */
|
||||
sdp_client_params_iterator(session);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdp_client_receive_ssa_sa(struct bt_sdp_client *session, struct net_buf *buf)
|
||||
{
|
||||
struct bt_sdp_pdu_cstate *cstate;
|
||||
uint16_t frame_len;
|
||||
uint16_t total;
|
||||
|
||||
/* Check the buffer len for the frame_len field */
|
||||
if (buf->len < sizeof(frame_len)) {
|
||||
LOG_ERR("Invalid frame payload length");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get number of attributes in this frame. */
|
||||
frame_len = net_buf_pull_be16(buf);
|
||||
/* Check valid buf len for attribute list and cont state */
|
||||
if (buf->len < frame_len + SDP_CONT_STATE_LEN_SIZE) {
|
||||
LOG_ERR("Invalid frame payload length");
|
||||
return 0;
|
||||
}
|
||||
/* Check valid range of attributes length */
|
||||
if (frame_len < 2) {
|
||||
LOG_ERR("Invalid attributes data length");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get PDU continuation state */
|
||||
cstate = (struct bt_sdp_pdu_cstate *)(buf->data + frame_len);
|
||||
|
||||
if (cstate->length > BT_SDP_MAX_PDU_CSTATE_LEN) {
|
||||
LOG_ERR("Invalid SDP PDU Continuation State length %u", cstate->length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((frame_len + SDP_CONT_STATE_LEN_SIZE + cstate->length) > buf->len) {
|
||||
LOG_ERR("Invalid frame payload length");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* No record found for given UUID. The check catches case when
|
||||
* current response frame has Continuation State shortest and
|
||||
* valid and this is the first response frame as well.
|
||||
*/
|
||||
if (frame_len == 2U && cstate->length == 0U && session->cstate.length == 0U) {
|
||||
LOG_DBG("Record for UUID 0x%s not found", bt_uuid_str(session->param->uuid));
|
||||
/* Call user UUID handler */
|
||||
sdp_client_notify_result(session, UUID_NOT_RESOLVED);
|
||||
net_buf_pull(buf, frame_len + sizeof(cstate->length));
|
||||
goto iterate;
|
||||
}
|
||||
|
||||
/* Get total value of all attributes to be collected */
|
||||
frame_len -= sdp_client_get_total(session, buf, &total);
|
||||
|
||||
if (total > net_buf_tailroom(session->rec_buf)) {
|
||||
LOG_WRN("Not enough room for getting records data");
|
||||
goto iterate;
|
||||
}
|
||||
|
||||
net_buf_add_mem(session->rec_buf, buf->data, frame_len);
|
||||
net_buf_pull(buf, frame_len);
|
||||
|
||||
/* check if current response says there's next portion to be fetched */
|
||||
if (cstate->length) {
|
||||
/* Cache original Continuation State in context */
|
||||
memcpy(&session->cstate, cstate, sizeof(struct bt_sdp_pdu_cstate));
|
||||
|
||||
net_buf_pull(buf, cstate->length + sizeof(cstate->length));
|
||||
|
||||
/* Request for next portion of attributes data */
|
||||
return sdp_client_discover(session);
|
||||
}
|
||||
|
||||
net_buf_pull(buf, sizeof(cstate->length));
|
||||
|
||||
LOG_DBG("UUID 0x%s resolved", bt_uuid_str(session->param->uuid));
|
||||
sdp_client_notify_result(session, UUID_RESOLVED);
|
||||
iterate:
|
||||
/* Get next UUID and start resolving it */
|
||||
sdp_client_params_iterator(session);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdp_client_receive(struct bt_l2cap_chan *chan, struct net_buf *buf)
|
||||
{
|
||||
struct bt_sdp_client *session = SDP_CLIENT_CHAN(chan);
|
||||
struct bt_sdp_hdr *hdr;
|
||||
struct bt_sdp_pdu_cstate *cstate;
|
||||
uint16_t len, tid, frame_len;
|
||||
uint16_t total;
|
||||
uint16_t len, tid;
|
||||
|
||||
LOG_DBG("session %p buf %p", session, buf);
|
||||
|
||||
@ -1764,88 +2119,13 @@ static int sdp_client_receive(struct bt_l2cap_chan *chan, struct net_buf *buf)
|
||||
}
|
||||
|
||||
switch (hdr->op_code) {
|
||||
case BT_SDP_SVC_SEARCH_RSP:
|
||||
return sdp_client_receive_ss(session, buf);
|
||||
case BT_SDP_SVC_ATTR_RSP:
|
||||
__fallthrough;
|
||||
case BT_SDP_SVC_SEARCH_ATTR_RSP:
|
||||
/* Check the buffer len for the length field */
|
||||
if (buf->len < sizeof(uint16_t)) {
|
||||
LOG_ERR("Invalid frame payload length");
|
||||
return 0;
|
||||
}
|
||||
/* Get number of attributes in this frame. */
|
||||
frame_len = net_buf_pull_be16(buf);
|
||||
/* Check valid buf len for attribute list and cont state */
|
||||
if (buf->len < frame_len + SDP_CONT_STATE_LEN_SIZE) {
|
||||
LOG_ERR("Invalid frame payload length");
|
||||
return 0;
|
||||
}
|
||||
/* Check valid range of attributes length */
|
||||
if (frame_len < 2) {
|
||||
LOG_ERR("Invalid attributes data length");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get PDU continuation state */
|
||||
cstate = (struct bt_sdp_pdu_cstate *)(buf->data + frame_len);
|
||||
|
||||
if (cstate->length > BT_SDP_MAX_PDU_CSTATE_LEN) {
|
||||
LOG_ERR("Invalid SDP PDU Continuation State length %u", cstate->length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((frame_len + SDP_CONT_STATE_LEN_SIZE + cstate->length) >
|
||||
buf->len) {
|
||||
LOG_ERR("Invalid frame payload length");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* No record found for given UUID. The check catches case when
|
||||
* current response frame has Continuation State shortest and
|
||||
* valid and this is the first response frame as well.
|
||||
*/
|
||||
if (frame_len == 2U && cstate->length == 0U &&
|
||||
session->cstate.length == 0U) {
|
||||
LOG_DBG("record for UUID 0x%s not found",
|
||||
bt_uuid_str(session->param->uuid));
|
||||
/* Call user UUID handler */
|
||||
sdp_client_notify_result(session, UUID_NOT_RESOLVED);
|
||||
net_buf_pull(buf, frame_len + sizeof(cstate->length));
|
||||
goto iterate;
|
||||
}
|
||||
|
||||
/* Get total value of all attributes to be collected */
|
||||
frame_len -= sdp_client_get_total(session, buf, &total);
|
||||
|
||||
if (total > net_buf_tailroom(session->rec_buf)) {
|
||||
LOG_WRN("Not enough room for getting records data");
|
||||
goto iterate;
|
||||
}
|
||||
|
||||
net_buf_add_mem(session->rec_buf, buf->data, frame_len);
|
||||
net_buf_pull(buf, frame_len);
|
||||
|
||||
/*
|
||||
* check if current response says there's next portion to be
|
||||
* fetched
|
||||
*/
|
||||
if (cstate->length) {
|
||||
/* Cache original Continuation State in context */
|
||||
memcpy(&session->cstate, cstate,
|
||||
sizeof(struct bt_sdp_pdu_cstate));
|
||||
|
||||
net_buf_pull(buf, cstate->length +
|
||||
sizeof(cstate->length));
|
||||
|
||||
/* Request for next portion of attributes data */
|
||||
sdp_client_ssa_search(session);
|
||||
break;
|
||||
}
|
||||
|
||||
net_buf_pull(buf, sizeof(cstate->length));
|
||||
|
||||
LOG_DBG("UUID 0x%s resolved", bt_uuid_str(session->param->uuid));
|
||||
sdp_client_notify_result(session, UUID_RESOLVED);
|
||||
iterate:
|
||||
/* Get next UUID and start resolving it */
|
||||
return sdp_client_receive_ssa_sa(session, buf);
|
||||
case BT_SDP_ERROR_RSP:
|
||||
sdp_client_params_iterator(session);
|
||||
break;
|
||||
default:
|
||||
@ -1858,8 +2138,7 @@ iterate:
|
||||
|
||||
static int sdp_client_chan_connect(struct bt_sdp_client *session)
|
||||
{
|
||||
return bt_l2cap_br_chan_connect(session->chan.chan.conn,
|
||||
&session->chan.chan, SDP_PSM);
|
||||
return bt_l2cap_br_chan_connect(session->chan.chan.conn, &session->chan.chan, SDP_PSM);
|
||||
}
|
||||
|
||||
static struct net_buf *sdp_client_alloc_buf(struct bt_l2cap_chan *chan)
|
||||
@ -1884,8 +2163,12 @@ static void sdp_client_connected(struct bt_l2cap_chan *chan)
|
||||
LOG_DBG("session %p chan %p connected", session, chan);
|
||||
|
||||
session->rec_buf = chan->ops->alloc_buf(chan);
|
||||
if (!session->rec_buf) {
|
||||
bt_l2cap_chan_disconnect(chan);
|
||||
return;
|
||||
}
|
||||
|
||||
sdp_client_ssa_search(session);
|
||||
sdp_client_discover(session);
|
||||
}
|
||||
|
||||
static void sdp_client_disconnected(struct bt_l2cap_chan *chan)
|
||||
@ -1894,7 +2177,9 @@ static void sdp_client_disconnected(struct bt_l2cap_chan *chan)
|
||||
|
||||
LOG_DBG("session %p chan %p disconnected", session, chan);
|
||||
|
||||
net_buf_unref(session->rec_buf);
|
||||
if (session->rec_buf) {
|
||||
net_buf_unref(session->rec_buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset session excluding L2CAP channel member. Let's the channel
|
||||
|
||||
Loading…
Reference in New Issue
Block a user