gatt_client.c (b3f03c843f6a029757848cf4db52890477de181b) gatt_client.c (a6121b51b229b883431c4a1600b0f46db31d32dc)
1/*
2 * Copyright (C) 2014 BlueKitchen GmbH
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright

--- 663 unchanged lines hidden (view full) ---

672 emit_gatt_included_service_query_result_event(peripheral, include_handle, peripheral->query_start_handle,
673 peripheral->query_end_handle, uuid128);
674}
675
676// @returns packet pointer
677// @note assume that value is part of an l2cap buffer - overwrite HCI + L2CAP packet headers
678static const int characteristic_value_event_header_size = 8;
679static uint8_t * setup_characteristic_value_packet(uint8_t type, hci_con_handle_t con_handle, uint16_t attribute_handle, uint8_t * value, uint16_t length){
1/*
2 * Copyright (C) 2014 BlueKitchen GmbH
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright

--- 663 unchanged lines hidden (view full) ---

672 emit_gatt_included_service_query_result_event(peripheral, include_handle, peripheral->query_start_handle,
673 peripheral->query_end_handle, uuid128);
674}
675
676// @returns packet pointer
677// @note assume that value is part of an l2cap buffer - overwrite HCI + L2CAP packet headers
678static const int characteristic_value_event_header_size = 8;
679static uint8_t * setup_characteristic_value_packet(uint8_t type, hci_con_handle_t con_handle, uint16_t attribute_handle, uint8_t * value, uint16_t length){
680#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
681 // avoid using pre ATT headers.
682 return NULL;
683#endif
680 // before the value inside the ATT PDU
681 uint8_t * packet = value - characteristic_value_event_header_size;
682 packet[0] = type;
683 packet[1] = characteristic_value_event_header_size - 2 + length;
684 little_endian_store_16(packet, 2, con_handle);
685 little_endian_store_16(packet, 4, attribute_handle);
686 little_endian_store_16(packet, 6, length);
687 return packet;
688}
689
690// @returns packet pointer
691// @note assume that value is part of an l2cap buffer - overwrite parts of the HCI/L2CAP/ATT packet (4/4/3) bytes
692static const int long_characteristic_value_event_header_size = 10;
693static uint8_t * setup_long_characteristic_value_packet(uint8_t type, hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t offset, uint8_t * value, uint16_t length){
684 // before the value inside the ATT PDU
685 uint8_t * packet = value - characteristic_value_event_header_size;
686 packet[0] = type;
687 packet[1] = characteristic_value_event_header_size - 2 + length;
688 little_endian_store_16(packet, 2, con_handle);
689 little_endian_store_16(packet, 4, attribute_handle);
690 little_endian_store_16(packet, 6, length);
691 return packet;
692}
693
694// @returns packet pointer
695// @note assume that value is part of an l2cap buffer - overwrite parts of the HCI/L2CAP/ATT packet (4/4/3) bytes
696static const int long_characteristic_value_event_header_size = 10;
697static uint8_t * setup_long_characteristic_value_packet(uint8_t type, hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t offset, uint8_t * value, uint16_t length){
698#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
699 // avoid using pre ATT headers.
700 return NULL;
701#endif
694#if defined(HCI_INCOMING_PRE_BUFFER_SIZE) && (HCI_INCOMING_PRE_BUFFER_SIZE >= 10 - 8) // L2CAP Header (4) - ACL Header (4)
695 // before the value inside the ATT PDU
696 uint8_t * packet = value - long_characteristic_value_event_header_size;
697 packet[0] = type;
698 packet[1] = long_characteristic_value_event_header_size - 2 + length;
699 little_endian_store_16(packet, 2, con_handle);
700 little_endian_store_16(packet, 4, attribute_handle);
701 little_endian_store_16(packet, 6, offset);

--- 40 unchanged lines hidden (view full) ---

742static void report_gatt_long_characteristic_descriptor(gatt_client_t * peripheral, uint16_t descriptor_handle, uint8_t *blob, uint16_t blob_length, uint16_t value_offset){
743 uint8_t * packet = setup_long_characteristic_value_packet(GATT_EVENT_LONG_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT, peripheral->con_handle, descriptor_handle, value_offset, blob, blob_length);
744 if (!packet) return;
745 emit_event_new(peripheral->callback, packet, blob_length + long_characteristic_value_event_header_size);
746}
747
748static void report_gatt_all_characteristic_descriptors(gatt_client_t * peripheral, uint8_t * packet, uint16_t size, uint16_t pair_size){
749 int i;
702#if defined(HCI_INCOMING_PRE_BUFFER_SIZE) && (HCI_INCOMING_PRE_BUFFER_SIZE >= 10 - 8) // L2CAP Header (4) - ACL Header (4)
703 // before the value inside the ATT PDU
704 uint8_t * packet = value - long_characteristic_value_event_header_size;
705 packet[0] = type;
706 packet[1] = long_characteristic_value_event_header_size - 2 + length;
707 little_endian_store_16(packet, 2, con_handle);
708 little_endian_store_16(packet, 4, attribute_handle);
709 little_endian_store_16(packet, 6, offset);

--- 40 unchanged lines hidden (view full) ---

750static void report_gatt_long_characteristic_descriptor(gatt_client_t * peripheral, uint16_t descriptor_handle, uint8_t *blob, uint16_t blob_length, uint16_t value_offset){
751 uint8_t * packet = setup_long_characteristic_value_packet(GATT_EVENT_LONG_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT, peripheral->con_handle, descriptor_handle, value_offset, blob, blob_length);
752 if (!packet) return;
753 emit_event_new(peripheral->callback, packet, blob_length + long_characteristic_value_event_header_size);
754}
755
756static void report_gatt_all_characteristic_descriptors(gatt_client_t * peripheral, uint8_t * packet, uint16_t size, uint16_t pair_size){
757 int i;
750 for (i = 0; i<size; i+=pair_size){
758 for (i = 0; (i + pair_size) <= size; i += pair_size){
751 uint16_t descriptor_handle = little_endian_read_16(packet,i);
752 uint8_t uuid128[16];
753 uint16_t uuid16 = 0;
754 if (pair_size == 4){
755 uuid16 = little_endian_read_16(packet,i+2);
756 uuid_add_bluetooth_prefix(uuid128, uuid16);
757 } else {
758 reverse_128(&packet[i+2], uuid128);

--- 394 unchanged lines hidden (view full) ---

1153 default:
1154 break;
1155 }
1156
1157 gatt_client_run();
1158}
1159
1160static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size){
759 uint16_t descriptor_handle = little_endian_read_16(packet,i);
760 uint8_t uuid128[16];
761 uint16_t uuid16 = 0;
762 if (pair_size == 4){
763 uuid16 = little_endian_read_16(packet,i+2);
764 uuid_add_bluetooth_prefix(uuid128, uuid16);
765 } else {
766 reverse_128(&packet[i+2], uuid128);

--- 394 unchanged lines hidden (view full) ---

1161 default:
1162 break;
1163 }
1164
1165 gatt_client_run();
1166}
1167
1168static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size){
1161
1162 gatt_client_t * peripheral;
1169 gatt_client_t * peripheral;
1170 if (size < 1) return;
1163
1164 if (packet_type == HCI_EVENT_PACKET) {
1165 switch (packet[0]){
1166 case L2CAP_EVENT_CAN_SEND_NOW:
1167 gatt_client_run();
1168 break;
1169 // att_server has negotiated the mtu for this connection, cache if context exists
1170 case ATT_EVENT_MTU_EXCHANGE_COMPLETE:
1171
1172 if (packet_type == HCI_EVENT_PACKET) {
1173 switch (packet[0]){
1174 case L2CAP_EVENT_CAN_SEND_NOW:
1175 gatt_client_run();
1176 break;
1177 // att_server has negotiated the mtu for this connection, cache if context exists
1178 case ATT_EVENT_MTU_EXCHANGE_COMPLETE:
1179 if (size < 6) break;
1171 peripheral = get_gatt_client_context_for_handle(handle);
1172 if (peripheral == NULL) break;
1173 peripheral->mtu = little_endian_read_16(packet, 4);
1174 break;
1175 default:
1176 break;
1177 }
1178 return;
1179 }
1180
1181 if (packet_type != ATT_DATA_PACKET) return;
1182
1183 // special cases: notifications don't need a context while indications motivate creating one
1184 switch (packet[0]){
1185 case ATT_HANDLE_VALUE_NOTIFICATION:
1180 peripheral = get_gatt_client_context_for_handle(handle);
1181 if (peripheral == NULL) break;
1182 peripheral->mtu = little_endian_read_16(packet, 4);
1183 break;
1184 default:
1185 break;
1186 }
1187 return;
1188 }
1189
1190 if (packet_type != ATT_DATA_PACKET) return;
1191
1192 // special cases: notifications don't need a context while indications motivate creating one
1193 switch (packet[0]){
1194 case ATT_HANDLE_VALUE_NOTIFICATION:
1195 if (size < 3) return;
1186 report_gatt_notification(handle, little_endian_read_16(packet,1), &packet[3], size-3);
1187 return;
1188 case ATT_HANDLE_VALUE_INDICATION:
1189 peripheral = provide_context_for_conn_handle(handle);
1190 break;
1191 default:
1192 peripheral = get_gatt_client_context_for_handle(handle);
1193 break;
1194 }
1195
1196 if (peripheral == NULL) return;
1197
1198 switch (packet[0]){
1199 case ATT_EXCHANGE_MTU_RESPONSE:
1200 {
1196 report_gatt_notification(handle, little_endian_read_16(packet,1), &packet[3], size-3);
1197 return;
1198 case ATT_HANDLE_VALUE_INDICATION:
1199 peripheral = provide_context_for_conn_handle(handle);
1200 break;
1201 default:
1202 peripheral = get_gatt_client_context_for_handle(handle);
1203 break;
1204 }
1205
1206 if (peripheral == NULL) return;
1207
1208 switch (packet[0]){
1209 case ATT_EXCHANGE_MTU_RESPONSE:
1210 {
1211 if (size < 3) break;
1201 uint16_t remote_rx_mtu = little_endian_read_16(packet, 1);
1202 uint16_t local_rx_mtu = l2cap_max_le_mtu();
1203 peripheral->mtu = (remote_rx_mtu < local_rx_mtu) ? remote_rx_mtu : local_rx_mtu;
1204 peripheral->mtu_state = MTU_EXCHANGED;
1205 emit_gatt_mtu_exchanged_result_event(peripheral, peripheral->mtu);
1206 break;
1207 }
1208 case ATT_READ_BY_GROUP_TYPE_RESPONSE:
1209 switch(peripheral->gatt_client_state){
1210 case P_W4_SERVICE_QUERY_RESULT:
1211 report_gatt_services(peripheral, packet, size);
1212 trigger_next_service_query(peripheral, get_last_result_handle_from_service_list(packet, size));
1213 // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
1214 break;
1215 default:
1216 break;
1217 }
1218 break;
1219 case ATT_HANDLE_VALUE_INDICATION:
1212 uint16_t remote_rx_mtu = little_endian_read_16(packet, 1);
1213 uint16_t local_rx_mtu = l2cap_max_le_mtu();
1214 peripheral->mtu = (remote_rx_mtu < local_rx_mtu) ? remote_rx_mtu : local_rx_mtu;
1215 peripheral->mtu_state = MTU_EXCHANGED;
1216 emit_gatt_mtu_exchanged_result_event(peripheral, peripheral->mtu);
1217 break;
1218 }
1219 case ATT_READ_BY_GROUP_TYPE_RESPONSE:
1220 switch(peripheral->gatt_client_state){
1221 case P_W4_SERVICE_QUERY_RESULT:
1222 report_gatt_services(peripheral, packet, size);
1223 trigger_next_service_query(peripheral, get_last_result_handle_from_service_list(packet, size));
1224 // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
1225 break;
1226 default:
1227 break;
1228 }
1229 break;
1230 case ATT_HANDLE_VALUE_INDICATION:
1231 if (size < 3) break;
1220 report_gatt_indication(handle, little_endian_read_16(packet,1), &packet[3], size-3);
1221 peripheral->send_confirmation = 1;
1222 break;
1223
1224 case ATT_READ_BY_TYPE_RESPONSE:
1225 switch (peripheral->gatt_client_state){
1226 case P_W4_ALL_CHARACTERISTICS_OF_SERVICE_QUERY_RESULT:
1227 report_gatt_characteristics(peripheral, packet, size);
1228 trigger_next_characteristic_query(peripheral, get_last_result_handle_from_characteristics_list(packet, size));
1229 // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done, or by ATT_ERROR
1230 break;
1231 case P_W4_CHARACTERISTIC_WITH_UUID_QUERY_RESULT:
1232 report_gatt_characteristics(peripheral, packet, size);
1233 trigger_next_characteristic_query(peripheral, get_last_result_handle_from_characteristics_list(packet, size));
1234 // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done, or by ATT_ERROR
1235 break;
1236 case P_W4_INCLUDED_SERVICE_QUERY_RESULT:
1237 {
1232 report_gatt_indication(handle, little_endian_read_16(packet,1), &packet[3], size-3);
1233 peripheral->send_confirmation = 1;
1234 break;
1235
1236 case ATT_READ_BY_TYPE_RESPONSE:
1237 switch (peripheral->gatt_client_state){
1238 case P_W4_ALL_CHARACTERISTICS_OF_SERVICE_QUERY_RESULT:
1239 report_gatt_characteristics(peripheral, packet, size);
1240 trigger_next_characteristic_query(peripheral, get_last_result_handle_from_characteristics_list(packet, size));
1241 // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done, or by ATT_ERROR
1242 break;
1243 case P_W4_CHARACTERISTIC_WITH_UUID_QUERY_RESULT:
1244 report_gatt_characteristics(peripheral, packet, size);
1245 trigger_next_characteristic_query(peripheral, get_last_result_handle_from_characteristics_list(packet, size));
1246 // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done, or by ATT_ERROR
1247 break;
1248 case P_W4_INCLUDED_SERVICE_QUERY_RESULT:
1249 {
1250 if (size < 2) break;
1238 uint16_t uuid16 = 0;
1239 uint16_t pair_size = packet[1];
1240
1241 if (pair_size < 7){
1251 uint16_t uuid16 = 0;
1252 uint16_t pair_size = packet[1];
1253
1254 if (pair_size < 7){
1255 if (size < 8) break;
1242 // UUIDs not available, query first included service
1243 peripheral->start_group_handle = little_endian_read_16(packet, 2); // ready for next query
1244 peripheral->query_start_handle = little_endian_read_16(packet, 4);
1245 peripheral->query_end_handle = little_endian_read_16(packet,6);
1246 peripheral->gatt_client_state = P_W2_SEND_INCLUDED_SERVICE_WITH_UUID_QUERY;
1247 break;
1248 }
1249
1250 uint16_t offset;
1256 // UUIDs not available, query first included service
1257 peripheral->start_group_handle = little_endian_read_16(packet, 2); // ready for next query
1258 peripheral->query_start_handle = little_endian_read_16(packet, 4);
1259 peripheral->query_end_handle = little_endian_read_16(packet,6);
1260 peripheral->gatt_client_state = P_W2_SEND_INCLUDED_SERVICE_WITH_UUID_QUERY;
1261 break;
1262 }
1263
1264 uint16_t offset;
1251 for (offset = 2; offset < size; offset += pair_size){
1265 for (offset = 2; (offset + 8) < size; offset += pair_size){
1252 uint16_t include_handle = little_endian_read_16(packet, offset);
1253 peripheral->query_start_handle = little_endian_read_16(packet,offset+2);
1254 peripheral->query_end_handle = little_endian_read_16(packet,offset+4);
1255 uuid16 = little_endian_read_16(packet, offset+6);
1256 report_gatt_included_service_uuid16(peripheral, include_handle, uuid16);
1257 }
1258
1259 trigger_next_included_service_query(peripheral, get_last_result_handle_from_included_services_list(packet, size));

--- 50 unchanged lines hidden (view full) ---

1310 break;
1311
1312 case ATT_FIND_BY_TYPE_VALUE_RESPONSE:
1313 {
1314 uint8_t pair_size = 4;
1315 int i;
1316 uint16_t start_group_handle;
1317 uint16_t end_group_handle= 0xffff; // asserts GATT_EVENT_QUERY_COMPLETE is emitted if no results
1266 uint16_t include_handle = little_endian_read_16(packet, offset);
1267 peripheral->query_start_handle = little_endian_read_16(packet,offset+2);
1268 peripheral->query_end_handle = little_endian_read_16(packet,offset+4);
1269 uuid16 = little_endian_read_16(packet, offset+6);
1270 report_gatt_included_service_uuid16(peripheral, include_handle, uuid16);
1271 }
1272
1273 trigger_next_included_service_query(peripheral, get_last_result_handle_from_included_services_list(packet, size));

--- 50 unchanged lines hidden (view full) ---

1324 break;
1325
1326 case ATT_FIND_BY_TYPE_VALUE_RESPONSE:
1327 {
1328 uint8_t pair_size = 4;
1329 int i;
1330 uint16_t start_group_handle;
1331 uint16_t end_group_handle= 0xffff; // asserts GATT_EVENT_QUERY_COMPLETE is emitted if no results
1318 for (i = 1; i<size; i+=pair_size){
1332 for (i = 1; (i + pair_size) <= size; i += pair_size){
1319 start_group_handle = little_endian_read_16(packet,i);
1320 end_group_handle = little_endian_read_16(packet,i+2);
1321 emit_gatt_service_query_result_event(peripheral, start_group_handle, end_group_handle, peripheral->uuid128);
1322 }
1323 trigger_next_service_by_uuid_query(peripheral, end_group_handle);
1324 // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
1325 break;
1326 }
1327 case ATT_FIND_INFORMATION_REPLY:
1328 {
1333 start_group_handle = little_endian_read_16(packet,i);
1334 end_group_handle = little_endian_read_16(packet,i+2);
1335 emit_gatt_service_query_result_event(peripheral, start_group_handle, end_group_handle, peripheral->uuid128);
1336 }
1337 trigger_next_service_by_uuid_query(peripheral, end_group_handle);
1338 // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
1339 break;
1340 }
1341 case ATT_FIND_INFORMATION_REPLY:
1342 {
1343 if (size < 2) break;
1344
1329 uint8_t pair_size = 4;
1330 if (packet[1] == 2){
1331 pair_size = 18;
1332 }
1345 uint8_t pair_size = 4;
1346 if (packet[1] == 2){
1347 pair_size = 18;
1348 }
1349 uint16_t offset = 2;
1350
1351 if (size < (pair_size + offset)) break;
1333 uint16_t last_descriptor_handle = little_endian_read_16(packet, size - pair_size);
1334
1335#ifdef ENABLE_GATT_FIND_INFORMATION_FOR_CCC_DISCOVERY
1336 log_info("ENABLE_GATT_FIND_INFORMATION_FOR_CCC_DISCOVERY, state %x", peripheral->gatt_client_state);
1337 if (peripheral->gatt_client_state == P_W4_FIND_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY_RESULT){
1338 // iterate over descriptors looking for CCC
1339 if (pair_size == 4){
1352 uint16_t last_descriptor_handle = little_endian_read_16(packet, size - pair_size);
1353
1354#ifdef ENABLE_GATT_FIND_INFORMATION_FOR_CCC_DISCOVERY
1355 log_info("ENABLE_GATT_FIND_INFORMATION_FOR_CCC_DISCOVERY, state %x", peripheral->gatt_client_state);
1356 if (peripheral->gatt_client_state == P_W4_FIND_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY_RESULT){
1357 // iterate over descriptors looking for CCC
1358 if (pair_size == 4){
1340 int offset = 2;
1341 while (offset < size){
1359 while ((offset + 4) <= size){
1342 uint16_t uuid16 = little_endian_read_16(packet, offset + 2);
1343 if (uuid16 == GATT_CLIENT_CHARACTERISTICS_CONFIGURATION){
1344 peripheral->client_characteristic_configuration_handle = little_endian_read_16(packet, offset);
1345 peripheral->gatt_client_state = P_W2_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION;
1346 log_info("CCC found %x", peripheral->client_characteristic_configuration_handle);
1347 break;
1348 }
1349 offset += pair_size;

--- 124 unchanged lines hidden (view full) ---

1474 emit_gatt_complete_event(peripheral, ATT_ERROR_SUCCESS);
1475 break;
1476 default:
1477 break;
1478 }
1479 break;
1480
1481 case ATT_ERROR_RESPONSE:
1360 uint16_t uuid16 = little_endian_read_16(packet, offset + 2);
1361 if (uuid16 == GATT_CLIENT_CHARACTERISTICS_CONFIGURATION){
1362 peripheral->client_characteristic_configuration_handle = little_endian_read_16(packet, offset);
1363 peripheral->gatt_client_state = P_W2_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION;
1364 log_info("CCC found %x", peripheral->client_characteristic_configuration_handle);
1365 break;
1366 }
1367 offset += pair_size;

--- 124 unchanged lines hidden (view full) ---

1492 emit_gatt_complete_event(peripheral, ATT_ERROR_SUCCESS);
1493 break;
1494 default:
1495 break;
1496 }
1497 break;
1498
1499 case ATT_ERROR_RESPONSE:
1482
1500 if (size < 5) return;
1483 switch (packet[4]){
1484 case ATT_ERROR_ATTRIBUTE_NOT_FOUND: {
1485 switch(peripheral->gatt_client_state){
1486 case P_W4_SERVICE_QUERY_RESULT:
1487 case P_W4_SERVICE_WITH_UUID_RESULT:
1488 case P_W4_INCLUDED_SERVICE_QUERY_RESULT:
1489 case P_W4_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT:
1490 gatt_client_handle_transaction_complete(peripheral);

--- 641 unchanged lines hidden (view full) ---

2132uint8_t gatt_client_request_can_write_without_response_event(btstack_packet_handler_t callback, hci_con_handle_t con_handle){
2133 gatt_client_t * context = provide_context_for_conn_handle(con_handle);
2134 if (context == NULL) return BTSTACK_MEMORY_ALLOC_FAILED;
2135 if (context->write_without_response_callback != NULL) return GATT_CLIENT_IN_WRONG_STATE;
2136 context->write_without_response_callback = callback;
2137 att_dispatch_client_request_can_send_now_event(context->con_handle);
2138 return ERROR_CODE_SUCCESS;
2139}
1501 switch (packet[4]){
1502 case ATT_ERROR_ATTRIBUTE_NOT_FOUND: {
1503 switch(peripheral->gatt_client_state){
1504 case P_W4_SERVICE_QUERY_RESULT:
1505 case P_W4_SERVICE_WITH_UUID_RESULT:
1506 case P_W4_INCLUDED_SERVICE_QUERY_RESULT:
1507 case P_W4_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT:
1508 gatt_client_handle_transaction_complete(peripheral);

--- 641 unchanged lines hidden (view full) ---

2150uint8_t gatt_client_request_can_write_without_response_event(btstack_packet_handler_t callback, hci_con_handle_t con_handle){
2151 gatt_client_t * context = provide_context_for_conn_handle(con_handle);
2152 if (context == NULL) return BTSTACK_MEMORY_ALLOC_FAILED;
2153 if (context->write_without_response_callback != NULL) return GATT_CLIENT_IN_WRONG_STATE;
2154 context->write_without_response_callback = callback;
2155 att_dispatch_client_request_can_send_now_event(context->con_handle);
2156 return ERROR_CODE_SUCCESS;
2157}
2158
2159#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
2160void gatt_client_att_packet_handler_fuzz(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size){
2161 gatt_client_att_packet_handler(packet_type, handle, packet, size);
2162}
2163#endif