Skip to content

Commit c34aa22

Browse files
committed
nimble/host: Fix Read By Type and Find By Type Val hardcoded buff limits
ble_att_svr_build_read_type_rsp() used a fixed 19-byte stack buffer for reading attribute values, causing BLE_ATT_ERR_UNLIKELY for any value exceeding 19 bytes. Per Core Spec 3.4.4.2, the limit should be min(ATT_MTU - 4, 253). Similarly, ble_att_svr_fill_type_value() used a 16-byte buffer, failing to match attributes with longer values. Replace both flat buffers with a reusable mbuf, reading via ble_att_svr_read() directly and truncating per spec. This aligns with the approach already used in the code.
1 parent 8a926c5 commit c34aa22

File tree

1 file changed

+61
-13
lines changed

1 file changed

+61
-13
lines changed

nimble/host/src/ble_att_svr.c

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,8 +1089,9 @@ ble_att_svr_fill_type_value(uint16_t conn_handle,
10891089
uint16_t mtu, uint8_t *out_att_err)
10901090
{
10911091
struct ble_att_svr_entry *ha;
1092-
uint8_t buf[16];
1092+
struct os_mbuf *attr_om;
10931093
uint16_t attr_len;
1094+
uint16_t req_val_len;
10941095
uint16_t first;
10951096
uint16_t prev;
10961097
int any_entries;
@@ -1099,6 +1100,11 @@ ble_att_svr_fill_type_value(uint16_t conn_handle,
10991100
first = 0;
11001101
prev = 0;
11011102
rc = 0;
1103+
attr_om = NULL;
1104+
1105+
/* Length of the attribute value in the request. */
1106+
req_val_len = OS_MBUF_PKTLEN(rxom) -
1107+
sizeof(struct ble_att_find_type_value_req);
11021108

11031109
/* Iterate through the attribute list, keeping track of the current
11041110
* matching group. For each attribute entry, determine if data needs to be
@@ -1141,15 +1147,31 @@ ble_att_svr_fill_type_value(uint16_t conn_handle,
11411147
* determine if this attribute matches.
11421148
*/
11431149
if (ble_uuid_cmp(ha->ha_uuid, &attr_type.u) == 0) {
1144-
rc = ble_att_svr_read_flat(conn_handle, ha, 0, sizeof buf, buf,
1145-
&attr_len, out_att_err);
1150+
/* Lazily allocate a temporary mbuf for reading attribute values. */
1151+
if (attr_om == NULL) {
1152+
attr_om = ble_hs_mbuf_l2cap_pkt();
1153+
if (attr_om == NULL) {
1154+
*out_att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
1155+
rc = BLE_HS_ENOMEM;
1156+
goto done;
1157+
}
1158+
} else {
1159+
os_mbuf_adj(attr_om, OS_MBUF_PKTLEN(attr_om));
1160+
}
1161+
1162+
/* Read attribute value into temporary mbuf. */
1163+
rc = ble_att_svr_read(conn_handle, ha, 0, attr_om, out_att_err);
11461164
if (rc != 0) {
11471165
goto done;
11481166
}
1149-
/* value is at the end of req */
1150-
rc = os_mbuf_cmpf(rxom, sizeof(struct ble_att_find_type_value_req),
1151-
buf, attr_len);
1152-
if (rc == 0) {
1167+
1168+
attr_len = OS_MBUF_PKTLEN(attr_om);
1169+
1170+
/* Compare attribute value with the value from the request. */
1171+
if (attr_len == req_val_len &&
1172+
os_mbuf_cmpm(rxom,
1173+
sizeof(struct ble_att_find_type_value_req),
1174+
attr_om, 0, attr_len) == 0) {
11531175
first = ha->ha_handle_id;
11541176
prev = ha->ha_handle_id;
11551177
}
@@ -1170,6 +1192,8 @@ ble_att_svr_fill_type_value(uint16_t conn_handle,
11701192
}
11711193

11721194
done:
1195+
os_mbuf_free_chain(attr_om);
1196+
11731197
any_entries = OS_MBUF_PKTHDR(txom)->omp_len >
11741198
BLE_ATT_FIND_TYPE_VALUE_RSP_BASE_SZ;
11751199
if (rc == 0 && !any_entries) {
@@ -1293,9 +1317,10 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle, uint16_t cid,
12931317
struct ble_att_read_type_rsp *rsp;
12941318
struct ble_att_svr_entry *entry;
12951319
struct os_mbuf *txom;
1320+
struct os_mbuf *attr_om;
12961321
uint16_t attr_len;
1322+
uint16_t max_attr_len;
12971323
uint16_t mtu;
1298-
uint8_t buf[19];
12991324
int entry_written;
13001325
int txomlen;
13011326
int prev_attr_len;
@@ -1306,6 +1331,7 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle, uint16_t cid,
13061331
*err_handle = start_handle;
13071332
entry_written = 0;
13081333
prev_attr_len = 0;
1334+
attr_om = NULL;
13091335

13101336
/* Just reuse the request buffer for the response. */
13111337
txom = *rxom;
@@ -1326,6 +1352,12 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle, uint16_t cid,
13261352

13271353
mtu = ble_att_mtu_by_cid(conn_handle, cid);
13281354

1355+
/* Per Core Spec: max attribute value length is min(ATT_MTU - 4, 253). */
1356+
max_attr_len = mtu - 4;
1357+
if (max_attr_len > 253) {
1358+
max_attr_len = 253;
1359+
}
1360+
13291361
/* Find all matching attributes, writing a record for each. */
13301362
entry = NULL;
13311363
while (1) {
@@ -1336,15 +1368,29 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle, uint16_t cid,
13361368
}
13371369

13381370
if (entry->ha_handle_id >= start_handle) {
1339-
rc = ble_att_svr_read_flat(conn_handle, entry, 0, sizeof buf, buf,
1340-
&attr_len, att_err);
1371+
/* Lazily allocate a temporary mbuf for reading attribute values. */
1372+
if (attr_om == NULL) {
1373+
attr_om = ble_hs_mbuf_l2cap_pkt();
1374+
if (attr_om == NULL) {
1375+
*att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
1376+
*err_handle = entry->ha_handle_id;
1377+
rc = BLE_HS_ENOMEM;
1378+
goto done;
1379+
}
1380+
} else {
1381+
os_mbuf_adj(attr_om, OS_MBUF_PKTLEN(attr_om));
1382+
}
1383+
1384+
/* Read attribute value into temporary mbuf. */
1385+
rc = ble_att_svr_read(conn_handle, entry, 0, attr_om, att_err);
13411386
if (rc != 0) {
13421387
*err_handle = entry->ha_handle_id;
13431388
goto done;
13441389
}
13451390

1346-
if (attr_len > mtu - 4) {
1347-
attr_len = mtu - 4;
1391+
attr_len = OS_MBUF_PKTLEN(attr_om);
1392+
if (attr_len > max_attr_len) {
1393+
attr_len = max_attr_len;
13481394
}
13491395

13501396
if (prev_attr_len == 0) {
@@ -1367,12 +1413,14 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle, uint16_t cid,
13671413
}
13681414

13691415
data->handle = htole16(entry->ha_handle_id);
1370-
memcpy(data->value, buf, attr_len);
1416+
os_mbuf_copydata(attr_om, 0, attr_len, data->value);
13711417
entry_written = 1;
13721418
}
13731419
}
13741420

13751421
done:
1422+
os_mbuf_free_chain(attr_om);
1423+
13761424
if (!entry_written) {
13771425
/* No matching attributes. */
13781426
if (*att_err == 0) {

0 commit comments

Comments
 (0)