Skip to content

Commit ed45960

Browse files
lylezhu2012kartben
authored andcommitted
Bluetooth: SDP: Fix the issue of not handling the next discovery req
The pending discovery request will not be handled in some cases. The cases include, - The received data length is not aligned with frame length - The continuation status length is more than maximum value - Total length of the response is less than the frame length - Unknown operation code is received There is also a case where the current discovery result was not notified when processing the pending discovery request. The cases include, - Fail to send SDP request - No tail room of received buffer to save the response data Fix the issue by using the following steps, - Notify the application that the discovery is done - Process the pending discovery request Signed-off-by: Lyle Zhu <lyle.zhu@nxp.com>
1 parent 6c5c3a5 commit ed45960

File tree

1 file changed

+97
-86
lines changed
  • subsys/bluetooth/host/classic

1 file changed

+97
-86
lines changed

subsys/bluetooth/host/classic/sdp.c

Lines changed: 97 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1659,55 +1659,7 @@ static int sdp_client_ssa_search(struct bt_sdp_client *session,
16591659
session->tid);
16601660
}
16611661

1662-
static void sdp_client_params_iterator(struct bt_sdp_client *session);
1663-
1664-
static int sdp_client_discover(struct bt_sdp_client *session)
1665-
{
1666-
const struct bt_sdp_discover_params *param;
1667-
int err;
1668-
1669-
/*
1670-
* Select proper user params, if session->param is invalid it means
1671-
* getting new UUID from top of to be resolved params list. Otherwise
1672-
* the context is in a middle of partial SDP PDU responses and cached
1673-
* value from context can be used.
1674-
*/
1675-
if (!session->param) {
1676-
param = GET_PARAM(sys_slist_peek_head(&session->reqs));
1677-
} else {
1678-
param = session->param;
1679-
}
1680-
1681-
if (!param) {
1682-
struct bt_l2cap_chan *chan = &session->chan.chan;
1683-
1684-
LOG_WRN("No more request, disconnect channel");
1685-
/* No UUID items, disconnect channel */
1686-
return bt_l2cap_chan_disconnect(chan);
1687-
}
1688-
1689-
switch (param->type) {
1690-
case BT_SDP_DISCOVER_SERVICE_SEARCH:
1691-
err = sdp_client_ss_search(session, param);
1692-
break;
1693-
case BT_SDP_DISCOVER_SERVICE_ATTR:
1694-
err = sdp_client_sa_search(session, param);
1695-
break;
1696-
case BT_SDP_DISCOVER_SERVICE_SEARCH_ATTR:
1697-
err = sdp_client_ssa_search(session, param);
1698-
break;
1699-
default:
1700-
err = -EINVAL;
1701-
break;
1702-
}
1703-
1704-
if (err) {
1705-
/* Get next UUID and start resolving it */
1706-
sdp_client_params_iterator(session);
1707-
}
1708-
1709-
return 0;
1710-
}
1662+
static int sdp_client_discover(struct bt_sdp_client *session);
17111663

17121664
static void sdp_client_params_iterator(struct bt_sdp_client *session)
17131665
{
@@ -1910,6 +1862,56 @@ static void sdp_client_notify_result(struct bt_sdp_client *session,
19101862
}
19111863
}
19121864

1865+
static int sdp_client_discover(struct bt_sdp_client *session)
1866+
{
1867+
const struct bt_sdp_discover_params *param;
1868+
int err;
1869+
1870+
/*
1871+
* Select proper user params, if session->param is invalid it means
1872+
* getting new UUID from top of to be resolved params list. Otherwise
1873+
* the context is in a middle of partial SDP PDU responses and cached
1874+
* value from context can be used.
1875+
*/
1876+
if (!session->param) {
1877+
param = GET_PARAM(sys_slist_peek_head(&session->reqs));
1878+
} else {
1879+
param = session->param;
1880+
}
1881+
1882+
if (!param) {
1883+
struct bt_l2cap_chan *chan = &session->chan.chan;
1884+
1885+
LOG_WRN("No more request, disconnect channel");
1886+
/* No UUID items, disconnect channel */
1887+
return bt_l2cap_chan_disconnect(chan);
1888+
}
1889+
1890+
switch (param->type) {
1891+
case BT_SDP_DISCOVER_SERVICE_SEARCH:
1892+
err = sdp_client_ss_search(session, param);
1893+
break;
1894+
case BT_SDP_DISCOVER_SERVICE_ATTR:
1895+
err = sdp_client_sa_search(session, param);
1896+
break;
1897+
case BT_SDP_DISCOVER_SERVICE_SEARCH_ATTR:
1898+
err = sdp_client_ssa_search(session, param);
1899+
break;
1900+
default:
1901+
err = -EINVAL;
1902+
break;
1903+
}
1904+
1905+
if (err) {
1906+
/* Notify the result */
1907+
sdp_client_notify_result(session, UUID_NOT_RESOLVED);
1908+
/* Get next UUID and start resolving it */
1909+
sdp_client_params_iterator(session);
1910+
}
1911+
1912+
return 0;
1913+
}
1914+
19131915
static int sdp_client_receive_ss(struct bt_sdp_client *session, struct net_buf *buf)
19141916
{
19151917
struct bt_sdp_pdu_cstate *cstate;
@@ -1921,7 +1923,7 @@ static int sdp_client_receive_ss(struct bt_sdp_client *session, struct net_buf *
19211923
/* Check the buffer len for the total_count field */
19221924
if (buf->len < sizeof(total_count)) {
19231925
LOG_ERR("Invalid frame payload length");
1924-
return 0;
1926+
return -EINVAL;
19251927
}
19261928

19271929
/* Get total service record count. */
@@ -1930,40 +1932,40 @@ static int sdp_client_receive_ss(struct bt_sdp_client *session, struct net_buf *
19301932
/* Check the buffer len for the current_count field */
19311933
if (buf->len < sizeof(current_count)) {
19321934
LOG_ERR("Invalid frame payload length");
1933-
return 0;
1935+
return -EINVAL;
19341936
}
19351937

19361938
/* Get current service record count. */
19371939
current_count = net_buf_pull_be16(buf);
19381940
/* Check valid of current service record count */
19391941
if (current_count > total_count) {
19401942
LOG_ERR("Invalid current service record count");
1941-
return 0;
1943+
return -EINVAL;
19421944
}
19431945

19441946
received_count = session->rec_buf->len / SDP_RECORD_HANDLE_SIZE;
19451947
if ((received_count + current_count) > total_count) {
19461948
LOG_ERR("Excess data received");
1947-
return 0;
1949+
return -EINVAL;
19481950
}
19491951

19501952
record_len = current_count * SDP_RECORD_HANDLE_SIZE;
19511953
if (record_len >= buf->len) {
19521954
LOG_ERR("Invalid packet");
1953-
return 0;
1955+
return -EINVAL;
19541956
}
19551957

19561958
/* Get PDU continuation state */
19571959
cstate = (struct bt_sdp_pdu_cstate *)(buf->data + record_len);
19581960

19591961
if (cstate->length > BT_SDP_MAX_PDU_CSTATE_LEN) {
19601962
LOG_ERR("Invalid SDP PDU Continuation State length %u", cstate->length);
1961-
return 0;
1963+
return -EINVAL;
19621964
}
19631965

19641966
if ((record_len + SDP_CONT_STATE_LEN_SIZE + cstate->length) > buf->len) {
19651967
LOG_ERR("Invalid payload length");
1966-
return 0;
1968+
return -EINVAL;
19671969
}
19681970

19691971
/*
@@ -1972,16 +1974,13 @@ static int sdp_client_receive_ss(struct bt_sdp_client *session, struct net_buf *
19721974
* valid and this is the first response frame as well.
19731975
*/
19741976
if (!current_count && cstate->length == 0U && session->cstate.length == 0U) {
1975-
LOG_DBG("Service record handle 0x%x not found", session->param->handle);
1976-
/* Call user UUID handler */
1977-
sdp_client_notify_result(session, UUID_NOT_RESOLVED);
1978-
net_buf_pull(buf, sizeof(cstate->length));
1979-
goto iterate;
1977+
LOG_WRN("Service record handle 0x%x not found", session->param->handle);
1978+
return -EINVAL;
19801979
}
19811980

19821981
if (record_len > net_buf_tailroom(session->rec_buf)) {
19831982
LOG_WRN("Not enough room for getting records data");
1984-
goto iterate;
1983+
return -EINVAL;
19851984
}
19861985

19871986
net_buf_add_mem(session->rec_buf, buf->data, record_len);
@@ -1994,15 +1993,20 @@ static int sdp_client_receive_ss(struct bt_sdp_client *session, struct net_buf *
19941993

19951994
net_buf_pull(buf, cstate->length + sizeof(cstate->length));
19961995

1997-
/* Request for next portion of attributes data */
1998-
return sdp_client_discover(session);
1996+
/*
1997+
* Request for next portion of attributes data.
1998+
* All failure case are handled internally in the function.
1999+
* Ignore the return value.
2000+
*/
2001+
(void)sdp_client_discover(session);
2002+
2003+
return 0;
19992004
}
20002005

20012006
net_buf_pull(buf, sizeof(cstate->length));
20022007

20032008
LOG_DBG("UUID 0x%s resolved", bt_uuid_str(session->param->uuid));
20042009
sdp_client_notify_result(session, UUID_RESOLVED);
2005-
iterate:
20062010
/* Get next UUID and start resolving it */
20072011
sdp_client_params_iterator(session);
20082012

@@ -2018,33 +2022,33 @@ static int sdp_client_receive_ssa_sa(struct bt_sdp_client *session, struct net_b
20182022
/* Check the buffer len for the frame_len field */
20192023
if (buf->len < sizeof(frame_len)) {
20202024
LOG_ERR("Invalid frame payload length");
2021-
return 0;
2025+
return -EINVAL;
20222026
}
20232027

20242028
/* Get number of attributes in this frame. */
20252029
frame_len = net_buf_pull_be16(buf);
20262030
/* Check valid buf len for attribute list and cont state */
20272031
if (buf->len < frame_len + SDP_CONT_STATE_LEN_SIZE) {
20282032
LOG_ERR("Invalid frame payload length");
2029-
return 0;
2033+
return -EINVAL;
20302034
}
20312035
/* Check valid range of attributes length */
20322036
if (frame_len < 2) {
20332037
LOG_ERR("Invalid attributes data length");
2034-
return 0;
2038+
return -EINVAL;
20352039
}
20362040

20372041
/* Get PDU continuation state */
20382042
cstate = (struct bt_sdp_pdu_cstate *)(buf->data + frame_len);
20392043

20402044
if (cstate->length > BT_SDP_MAX_PDU_CSTATE_LEN) {
20412045
LOG_ERR("Invalid SDP PDU Continuation State length %u", cstate->length);
2042-
return 0;
2046+
return -EINVAL;
20432047
}
20442048

20452049
if ((frame_len + SDP_CONT_STATE_LEN_SIZE + cstate->length) > buf->len) {
20462050
LOG_ERR("Invalid frame payload length");
2047-
return 0;
2051+
return -EINVAL;
20482052
}
20492053

20502054
/*
@@ -2053,11 +2057,8 @@ static int sdp_client_receive_ssa_sa(struct bt_sdp_client *session, struct net_b
20532057
* valid and this is the first response frame as well.
20542058
*/
20552059
if (frame_len == 2U && cstate->length == 0U && session->cstate.length == 0U) {
2056-
LOG_DBG("Record for UUID 0x%s not found", bt_uuid_str(session->param->uuid));
2057-
/* Call user UUID handler */
2058-
sdp_client_notify_result(session, UUID_NOT_RESOLVED);
2059-
net_buf_pull(buf, frame_len + sizeof(cstate->length));
2060-
goto iterate;
2060+
LOG_WRN("Record for UUID 0x%s not found", bt_uuid_str(session->param->uuid));
2061+
return -EINVAL;
20612062
}
20622063

20632064
/* Get total value of all attributes to be collected */
@@ -2070,7 +2071,7 @@ static int sdp_client_receive_ssa_sa(struct bt_sdp_client *session, struct net_b
20702071
*/
20712072
if (total && (frame_len > total)) {
20722073
LOG_ERR("Invalid attribute lists");
2073-
return 0;
2074+
return -EINVAL;
20742075
}
20752076

20762077
if (session->cstate.length == 0U) {
@@ -2081,7 +2082,7 @@ static int sdp_client_receive_ssa_sa(struct bt_sdp_client *session, struct net_b
20812082

20822083
if (frame_len > net_buf_tailroom(session->rec_buf)) {
20832084
LOG_WRN("Not enough room for getting records data");
2084-
goto iterate;
2085+
return -EINVAL;
20852086
}
20862087

20872088
net_buf_add_mem(session->rec_buf, buf->data, frame_len);
@@ -2094,8 +2095,14 @@ static int sdp_client_receive_ssa_sa(struct bt_sdp_client *session, struct net_b
20942095

20952096
net_buf_pull(buf, cstate->length + sizeof(cstate->length));
20962097

2097-
/* Request for next portion of attributes data */
2098-
return sdp_client_discover(session);
2098+
/*
2099+
* Request for next portion of attributes data.
2100+
* All failure case are handled internally in the function.
2101+
* Ignore the return value.
2102+
*/
2103+
(void)sdp_client_discover(session);
2104+
2105+
return 0;
20992106
}
21002107

21012108
if (session->total_len && (session->recv_len != session->total_len)) {
@@ -2108,7 +2115,6 @@ static int sdp_client_receive_ssa_sa(struct bt_sdp_client *session, struct net_b
21082115

21092116
LOG_DBG("UUID 0x%s resolved", bt_uuid_str(session->param->uuid));
21102117
sdp_client_notify_result(session, UUID_RESOLVED);
2111-
iterate:
21122118
/* Get next UUID and start resolving it */
21132119
sdp_client_params_iterator(session);
21142120

@@ -2120,6 +2126,7 @@ static int sdp_client_receive(struct bt_l2cap_chan *chan, struct net_buf *buf)
21202126
struct bt_sdp_client *session = SDP_CLIENT_CHAN(chan);
21212127
struct bt_sdp_hdr *hdr;
21222128
uint16_t len, tid;
2129+
int err = -EINVAL;
21232130

21242131
LOG_DBG("session %p buf %p", session, buf);
21252132

@@ -2151,21 +2158,25 @@ static int sdp_client_receive(struct bt_l2cap_chan *chan, struct net_buf *buf)
21512158

21522159
switch (hdr->op_code) {
21532160
case BT_SDP_SVC_SEARCH_RSP:
2154-
return sdp_client_receive_ss(session, buf);
2161+
err = sdp_client_receive_ss(session, buf);
2162+
break;
21552163
case BT_SDP_SVC_ATTR_RSP:
2156-
__fallthrough;
21572164
case BT_SDP_SVC_SEARCH_ATTR_RSP:
2158-
return sdp_client_receive_ssa_sa(session, buf);
2165+
err = sdp_client_receive_ssa_sa(session, buf);
2166+
break;
21592167
case BT_SDP_ERROR_RSP:
21602168
LOG_INF("Invalid SDP request");
2161-
sdp_client_notify_result(session, UUID_NOT_RESOLVED);
2162-
sdp_client_params_iterator(session);
2163-
return 0;
2169+
break;
21642170
default:
21652171
LOG_DBG("PDU 0x%0x response not handled", hdr->op_code);
21662172
break;
21672173
}
21682174

2175+
if (err < 0) {
2176+
sdp_client_notify_result(session, UUID_NOT_RESOLVED);
2177+
sdp_client_params_iterator(session);
2178+
}
2179+
21692180
return 0;
21702181
}
21712182

0 commit comments

Comments
 (0)