Skip to content

Commit 9990332

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 b7674a1 commit 9990332

File tree

1 file changed

+53
-13
lines changed

1 file changed

+53
-13
lines changed

nimble/host/src/ble_att_svr.c

Lines changed: 53 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;
@@ -1100,6 +1101,17 @@ ble_att_svr_fill_type_value(uint16_t conn_handle,
11001101
prev = 0;
11011102
rc = 0;
11021103

1104+
/* Length of the attribute value in the request. */
1105+
req_val_len = OS_MBUF_PKTLEN(rxom) -
1106+
sizeof(struct ble_att_find_type_value_req);
1107+
1108+
/* Allocate a temporary mbuf for reading attribute values. */
1109+
attr_om = ble_hs_mbuf_l2cap_pkt();
1110+
if (attr_om == NULL) {
1111+
*out_att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
1112+
return BLE_HS_ENOMEM;
1113+
}
1114+
11031115
/* Iterate through the attribute list, keeping track of the current
11041116
* matching group. For each attribute entry, determine if data needs to be
11051117
* written to the response.
@@ -1141,15 +1153,20 @@ ble_att_svr_fill_type_value(uint16_t conn_handle,
11411153
* determine if this attribute matches.
11421154
*/
11431155
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);
1156+
/* Read attribute value into temporary mbuf. */
1157+
os_mbuf_adj(attr_om, OS_MBUF_PKTLEN(attr_om));
1158+
rc = ble_att_svr_read(conn_handle, ha, 0, attr_om, out_att_err);
11461159
if (rc != 0) {
11471160
goto done;
11481161
}
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) {
1162+
1163+
attr_len = OS_MBUF_PKTLEN(attr_om);
1164+
1165+
/* Compare attribute value with the value from the request. */
1166+
if (attr_len == req_val_len &&
1167+
os_mbuf_cmpm(rxom,
1168+
sizeof(struct ble_att_find_type_value_req),
1169+
attr_om, 0, attr_len) == 0) {
11531170
first = ha->ha_handle_id;
11541171
prev = ha->ha_handle_id;
11551172
}
@@ -1170,6 +1187,8 @@ ble_att_svr_fill_type_value(uint16_t conn_handle,
11701187
}
11711188

11721189
done:
1190+
os_mbuf_free_chain(attr_om);
1191+
11731192
any_entries = OS_MBUF_PKTHDR(txom)->omp_len >
11741193
BLE_ATT_FIND_TYPE_VALUE_RSP_BASE_SZ;
11751194
if (rc == 0 && !any_entries) {
@@ -1293,9 +1312,10 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle, uint16_t cid,
12931312
struct ble_att_read_type_rsp *rsp;
12941313
struct ble_att_svr_entry *entry;
12951314
struct os_mbuf *txom;
1315+
struct os_mbuf *attr_om;
12961316
uint16_t attr_len;
1317+
uint16_t max_attr_len;
12971318
uint16_t mtu;
1298-
uint8_t buf[19];
12991319
int entry_written;
13001320
int txomlen;
13011321
int prev_attr_len;
@@ -1306,6 +1326,7 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle, uint16_t cid,
13061326
*err_handle = start_handle;
13071327
entry_written = 0;
13081328
prev_attr_len = 0;
1329+
attr_om = NULL;
13091330

13101331
/* Just reuse the request buffer for the response. */
13111332
txom = *rxom;
@@ -1326,6 +1347,21 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle, uint16_t cid,
13261347

13271348
mtu = ble_att_mtu_by_cid(conn_handle, cid);
13281349

1350+
/* Per Core Spec: max attribute value length is min(ATT_MTU - 4, 253). */
1351+
max_attr_len = mtu - 4;
1352+
if (max_attr_len > 253) {
1353+
max_attr_len = 253;
1354+
}
1355+
1356+
/* Allocate a temporary mbuf for reading attribute values. */
1357+
attr_om = ble_hs_mbuf_l2cap_pkt();
1358+
if (attr_om == NULL) {
1359+
*att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
1360+
*err_handle = 0;
1361+
rc = BLE_HS_ENOMEM;
1362+
goto done;
1363+
}
1364+
13291365
/* Find all matching attributes, writing a record for each. */
13301366
entry = NULL;
13311367
while (1) {
@@ -1336,15 +1372,17 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle, uint16_t cid,
13361372
}
13371373

13381374
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);
1375+
/* Read attribute value into temporary mbuf. */
1376+
os_mbuf_adj(attr_om, OS_MBUF_PKTLEN(attr_om));
1377+
rc = ble_att_svr_read(conn_handle, entry, 0, attr_om, att_err);
13411378
if (rc != 0) {
13421379
*err_handle = entry->ha_handle_id;
13431380
goto done;
13441381
}
13451382

1346-
if (attr_len > mtu - 4) {
1347-
attr_len = mtu - 4;
1383+
attr_len = OS_MBUF_PKTLEN(attr_om);
1384+
if (attr_len > max_attr_len) {
1385+
attr_len = max_attr_len;
13481386
}
13491387

13501388
if (prev_attr_len == 0) {
@@ -1367,12 +1405,14 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle, uint16_t cid,
13671405
}
13681406

13691407
data->handle = htole16(entry->ha_handle_id);
1370-
memcpy(data->value, buf, attr_len);
1408+
os_mbuf_copydata(attr_om, 0, attr_len, data->value);
13711409
entry_written = 1;
13721410
}
13731411
}
13741412

13751413
done:
1414+
os_mbuf_free_chain(attr_om);
1415+
13761416
if (!entry_written) {
13771417
/* No matching attributes. */
13781418
if (*att_err == 0) {

0 commit comments

Comments
 (0)