@@ -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
11721194done :
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
13751421done :
1422+ os_mbuf_free_chain (attr_om );
1423+
13761424 if (!entry_written ) {
13771425 /* No matching attributes. */
13781426 if (* att_err == 0 ) {
0 commit comments