gatt_client: extract gatt_client_handle_att_response

This commit is contained in:
Matthias Ringwald 2023-04-11 14:54:50 +02:00
parent 0fde3c5edb
commit cf8e571806

View File

@ -1380,47 +1380,10 @@ static void gatt_client_event_packet_handler(uint8_t packet_type, uint16_t chann
gatt_client_run(); gatt_client_run();
} }
static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size){ static void gatt_client_handle_att_response(gatt_client_t * gatt_client, uint8_t * packet, uint16_t size) {
gatt_client_t * gatt_client;
if (size < 1u) return;
if (packet_type == HCI_EVENT_PACKET) {
switch (packet[0]){
case L2CAP_EVENT_CAN_SEND_NOW:
gatt_client_run();
break;
// att_server has negotiated the mtu for this connection, cache if context exists
case ATT_EVENT_MTU_EXCHANGE_COMPLETE:
if (size < 6u) break;
gatt_client = gatt_client_get_context_for_handle(handle);
if (gatt_client == NULL) break;
gatt_client->mtu = little_endian_read_16(packet, 4);
break;
default:
break;
}
return;
}
if (packet_type != ATT_DATA_PACKET) return;
// special cases: notifications & indications motivate creating context
switch (packet[0]){
case ATT_HANDLE_VALUE_NOTIFICATION:
case ATT_HANDLE_VALUE_INDICATION:
gatt_client_provide_context_for_handle(handle, &gatt_client);
break;
default:
gatt_client = gatt_client_get_context_for_handle(handle);
break;
}
if (gatt_client == NULL) return;
uint8_t error_code; uint8_t error_code;
switch (packet[0]){ switch (packet[0]) {
case ATT_EXCHANGE_MTU_RESPONSE: case ATT_EXCHANGE_MTU_RESPONSE: {
{
if (size < 3u) break; if (size < 3u) break;
uint16_t remote_rx_mtu = little_endian_read_16(packet, 1); uint16_t remote_rx_mtu = little_endian_read_16(packet, 1);
uint16_t local_rx_mtu = l2cap_max_le_mtu(); uint16_t local_rx_mtu = l2cap_max_le_mtu();
@ -1430,8 +1393,8 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
gatt_client->mtu = mtu; gatt_client->mtu = mtu;
gatt_client->mtu_state = MTU_EXCHANGED; gatt_client->mtu_state = MTU_EXCHANGED;
// set per connection mtu state // set per connection mtu state - for fixed channel
hci_connection_t * hci_connection = hci_connection_for_handle(handle); hci_connection_t *hci_connection = hci_connection_for_handle(gatt_client->con_handle);
hci_connection->att_connection.mtu = gatt_client->mtu; hci_connection->att_connection.mtu = gatt_client->mtu;
hci_connection->att_connection.mtu_exchanged = true; hci_connection->att_connection.mtu_exchanged = true;
@ -1439,7 +1402,7 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
break; break;
} }
case ATT_READ_BY_GROUP_TYPE_RESPONSE: case ATT_READ_BY_GROUP_TYPE_RESPONSE:
switch(gatt_client->gatt_client_state){ switch (gatt_client->gatt_client_state) {
case P_W4_SERVICE_QUERY_RESULT: case P_W4_SERVICE_QUERY_RESULT:
report_gatt_services(gatt_client, packet, size); report_gatt_services(gatt_client, packet, size);
trigger_next_service_query(gatt_client, get_last_result_handle_from_service_list(packet, size)); trigger_next_service_query(gatt_client, get_last_result_handle_from_service_list(packet, size));
@ -1458,26 +1421,27 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
report_gatt_indication(gatt_client, little_endian_read_16(packet, 1u), &packet[3], size - 3u); report_gatt_indication(gatt_client, little_endian_read_16(packet, 1u), &packet[3], size - 3u);
gatt_client->send_confirmation = 1; gatt_client->send_confirmation = 1;
break; break;
case ATT_READ_BY_TYPE_RESPONSE: case ATT_READ_BY_TYPE_RESPONSE:
switch (gatt_client->gatt_client_state){ switch (gatt_client->gatt_client_state) {
case P_W4_ALL_CHARACTERISTICS_OF_SERVICE_QUERY_RESULT: case P_W4_ALL_CHARACTERISTICS_OF_SERVICE_QUERY_RESULT:
report_gatt_characteristics(gatt_client, packet, size); report_gatt_characteristics(gatt_client, packet, size);
trigger_next_characteristic_query(gatt_client, get_last_result_handle_from_characteristics_list(packet, size)); trigger_next_characteristic_query(gatt_client,
get_last_result_handle_from_characteristics_list(packet, size));
// GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done, or by ATT_ERROR // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done, or by ATT_ERROR
break; break;
case P_W4_CHARACTERISTIC_WITH_UUID_QUERY_RESULT: case P_W4_CHARACTERISTIC_WITH_UUID_QUERY_RESULT:
report_gatt_characteristics(gatt_client, packet, size); report_gatt_characteristics(gatt_client, packet, size);
trigger_next_characteristic_query(gatt_client, get_last_result_handle_from_characteristics_list(packet, size)); trigger_next_characteristic_query(gatt_client,
get_last_result_handle_from_characteristics_list(packet, size));
// GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done, or by ATT_ERROR // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done, or by ATT_ERROR
break; break;
case P_W4_INCLUDED_SERVICE_QUERY_RESULT: case P_W4_INCLUDED_SERVICE_QUERY_RESULT: {
{
if (size < 2u) break; if (size < 2u) break;
uint16_t uuid16 = 0; uint16_t uuid16 = 0;
uint16_t pair_size = packet[1]; uint16_t pair_size = packet[1];
if (pair_size == 6u){ if (pair_size == 6u) {
if (size < 8u) break; if (size < 8u) break;
// UUIDs not available, query first included service // UUIDs not available, query first included service
gatt_client->start_group_handle = little_endian_read_16(packet, 2); // ready for next query gatt_client->start_group_handle = little_endian_read_16(packet, 2); // ready for next query
@ -1491,15 +1455,17 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
// UUIDs included, report all of them // UUIDs included, report all of them
uint16_t offset; uint16_t offset;
for (offset = 2u; (offset + 8u) <= size; offset += pair_size){ for (offset = 2u; (offset + 8u) <= size; offset += pair_size) {
uint16_t include_handle = little_endian_read_16(packet, offset); uint16_t include_handle = little_endian_read_16(packet, offset);
gatt_client->query_start_handle = little_endian_read_16(packet, offset + 2u); gatt_client->query_start_handle = little_endian_read_16(packet, offset + 2u);
gatt_client->query_end_handle = little_endian_read_16(packet, offset + 4u); gatt_client->query_end_handle = little_endian_read_16(packet, offset + 4u);
uuid16 = little_endian_read_16(packet, offset+6u); uuid16 = little_endian_read_16(packet, offset + 6u);
report_gatt_included_service_uuid16(gatt_client, include_handle, uuid16); report_gatt_included_service_uuid16(gatt_client, include_handle, uuid16);
} }
trigger_next_included_service_query(gatt_client, get_last_result_handle_from_included_services_list(packet, size)); trigger_next_included_service_query(gatt_client,
get_last_result_handle_from_included_services_list(packet,
size));
// GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
break; break;
} }
@ -1513,11 +1479,12 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
uint16_t pair_size = packet[1]; uint16_t pair_size = packet[1];
// set last result handle to last valid handle, only used if pair_size invalid // set last result handle to last valid handle, only used if pair_size invalid
uint16_t last_result_handle = 0xffff; uint16_t last_result_handle = 0xffff;
if (pair_size > 2){ if (pair_size > 2) {
uint16_t offset; uint16_t offset;
for (offset = 2; offset < size ; offset += pair_size){ for (offset = 2; offset < size; offset += pair_size) {
uint16_t value_handle = little_endian_read_16(packet, offset); uint16_t value_handle = little_endian_read_16(packet, offset);
report_gatt_characteristic_value(gatt_client, value_handle, &packet[offset + 2u], pair_size - 2u); report_gatt_characteristic_value(gatt_client, value_handle, &packet[offset + 2u],
pair_size - 2u);
last_result_handle = value_handle; last_result_handle = value_handle;
} }
} }
@ -1529,9 +1496,9 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
} }
break; break;
case ATT_READ_RESPONSE: case ATT_READ_RESPONSE:
switch (gatt_client->gatt_client_state){ switch (gatt_client->gatt_client_state) {
case P_W4_INCLUDED_SERVICE_UUID_WITH_QUERY_RESULT: case P_W4_INCLUDED_SERVICE_UUID_WITH_QUERY_RESULT:
if (size >= 17){ if (size >= 17) {
uint8_t uuid128[16]; uint8_t uuid128[16];
reverse_128(&packet[1], uuid128); reverse_128(&packet[1], uuid128);
report_gatt_included_service_uuid128(gatt_client, gatt_client->start_group_handle, uuid128); report_gatt_included_service_uuid128(gatt_client, gatt_client->start_group_handle, uuid128);
@ -1548,21 +1515,25 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
case P_W4_READ_CHARACTERISTIC_DESCRIPTOR_RESULT: case P_W4_READ_CHARACTERISTIC_DESCRIPTOR_RESULT:
gatt_client_handle_transaction_complete(gatt_client); gatt_client_handle_transaction_complete(gatt_client);
report_gatt_characteristic_descriptor(gatt_client, gatt_client->attribute_handle, &packet[1], size - 1u, 0u); report_gatt_characteristic_descriptor(gatt_client, gatt_client->attribute_handle, &packet[1],
size - 1u, 0u);
emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS); emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS);
break; break;
// Use ATT_READ_REQUEST for first blob of Read Long Characteristic // Use ATT_READ_REQUEST for first blob of Read Long Characteristic
case P_W4_READ_BLOB_RESULT: case P_W4_READ_BLOB_RESULT:
report_gatt_long_characteristic_value_blob(gatt_client, gatt_client->attribute_handle, &packet[1], size - 1u, gatt_client->attribute_offset); report_gatt_long_characteristic_value_blob(gatt_client, gatt_client->attribute_handle, &packet[1],
size - 1u, gatt_client->attribute_offset);
trigger_next_blob_query(gatt_client, P_W2_SEND_READ_BLOB_QUERY, size - 1u); trigger_next_blob_query(gatt_client, P_W2_SEND_READ_BLOB_QUERY, size - 1u);
// GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
break; break;
// Use ATT_READ_REQUEST for first blob of Read Long Characteristic Descriptor // Use ATT_READ_REQUEST for first blob of Read Long Characteristic Descriptor
case P_W4_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_RESULT: case P_W4_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_RESULT:
report_gatt_long_characteristic_descriptor(gatt_client, gatt_client->attribute_handle, &packet[1], size-1u, gatt_client->attribute_offset); report_gatt_long_characteristic_descriptor(gatt_client, gatt_client->attribute_handle, &packet[1],
trigger_next_blob_query(gatt_client, P_W2_SEND_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_QUERY, size-1u); size - 1u, gatt_client->attribute_offset);
trigger_next_blob_query(gatt_client, P_W2_SEND_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_QUERY,
size - 1u);
// GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
break; break;
@ -1570,28 +1541,27 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
break; break;
} }
break; break;
case ATT_FIND_BY_TYPE_VALUE_RESPONSE: case ATT_FIND_BY_TYPE_VALUE_RESPONSE: {
{
uint8_t pair_size = 4; uint8_t pair_size = 4;
int i; int i;
uint16_t start_group_handle; uint16_t start_group_handle;
uint16_t end_group_handle= 0xffff; // asserts GATT_EVENT_QUERY_COMPLETE is emitted if no results uint16_t end_group_handle = 0xffff; // asserts GATT_EVENT_QUERY_COMPLETE is emitted if no results
for (i = 1u; (i + pair_size) <= size; i += pair_size){ for (i = 1u; (i + pair_size) <= size; i += pair_size) {
start_group_handle = little_endian_read_16(packet,i); start_group_handle = little_endian_read_16(packet, i);
end_group_handle = little_endian_read_16(packet,i+2); end_group_handle = little_endian_read_16(packet, i + 2);
emit_gatt_service_query_result_event(gatt_client, start_group_handle, end_group_handle, gatt_client->uuid128); emit_gatt_service_query_result_event(gatt_client, start_group_handle, end_group_handle,
gatt_client->uuid128);
} }
trigger_next_service_by_uuid_query(gatt_client, end_group_handle); trigger_next_service_by_uuid_query(gatt_client, end_group_handle);
// GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
break; break;
} }
case ATT_FIND_INFORMATION_REPLY: case ATT_FIND_INFORMATION_REPLY: {
{
if (size < 2u) break; if (size < 2u) break;
uint8_t pair_size = 4; uint8_t pair_size = 4;
if (packet[1u] == 2u){ if (packet[1u] == 2u) {
pair_size = 18; pair_size = 18;
} }
uint16_t offset = 2; uint16_t offset = 2;
@ -1632,7 +1602,7 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
} }
case ATT_WRITE_RESPONSE: case ATT_WRITE_RESPONSE:
switch (gatt_client->gatt_client_state){ switch (gatt_client->gatt_client_state) {
case P_W4_WRITE_CHARACTERISTIC_VALUE_RESULT: case P_W4_WRITE_CHARACTERISTIC_VALUE_RESULT:
gatt_client_handle_transaction_complete(gatt_client); gatt_client_handle_transaction_complete(gatt_client);
emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS); emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS);
@ -1649,12 +1619,13 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
break; break;
} }
break; break;
case ATT_READ_BLOB_RESPONSE:{ case ATT_READ_BLOB_RESPONSE: {
uint16_t received_blob_length = size-1u; uint16_t received_blob_length = size - 1u;
switch(gatt_client->gatt_client_state){ switch (gatt_client->gatt_client_state) {
case P_W4_READ_BLOB_RESULT: case P_W4_READ_BLOB_RESULT:
report_gatt_long_characteristic_value_blob(gatt_client, gatt_client->attribute_handle, &packet[1], received_blob_length, gatt_client->attribute_offset); report_gatt_long_characteristic_value_blob(gatt_client, gatt_client->attribute_handle, &packet[1],
received_blob_length, gatt_client->attribute_offset);
trigger_next_blob_query(gatt_client, P_W2_SEND_READ_BLOB_QUERY, received_blob_length); trigger_next_blob_query(gatt_client, P_W2_SEND_READ_BLOB_QUERY, received_blob_length);
// GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
break; break;
@ -1662,7 +1633,8 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
report_gatt_long_characteristic_descriptor(gatt_client, gatt_client->attribute_handle, report_gatt_long_characteristic_descriptor(gatt_client, gatt_client->attribute_handle,
&packet[1], received_blob_length, &packet[1], received_blob_length,
gatt_client->attribute_offset); gatt_client->attribute_offset);
trigger_next_blob_query(gatt_client, P_W2_SEND_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_QUERY, received_blob_length); trigger_next_blob_query(gatt_client, P_W2_SEND_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_QUERY,
received_blob_length);
// GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
break; break;
default: default:
@ -1671,32 +1643,34 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
break; break;
} }
case ATT_PREPARE_WRITE_RESPONSE: case ATT_PREPARE_WRITE_RESPONSE:
switch (gatt_client->gatt_client_state){ switch (gatt_client->gatt_client_state) {
case P_W4_PREPARE_WRITE_SINGLE_RESULT: case P_W4_PREPARE_WRITE_SINGLE_RESULT:
gatt_client_handle_transaction_complete(gatt_client); gatt_client_handle_transaction_complete(gatt_client);
if (is_value_valid(gatt_client, packet, size)){ if (is_value_valid(gatt_client, packet, size)) {
emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS); emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS);
} else { } else {
emit_gatt_complete_event(gatt_client, ATT_ERROR_DATA_MISMATCH); emit_gatt_complete_event(gatt_client, ATT_ERROR_DATA_MISMATCH);
} }
break; break;
case P_W4_PREPARE_WRITE_RESULT:{ case P_W4_PREPARE_WRITE_RESULT: {
gatt_client->attribute_offset = little_endian_read_16(packet, 3); gatt_client->attribute_offset = little_endian_read_16(packet, 3);
trigger_next_prepare_write_query(gatt_client, P_W2_PREPARE_WRITE, P_W2_EXECUTE_PREPARED_WRITE); trigger_next_prepare_write_query(gatt_client, P_W2_PREPARE_WRITE, P_W2_EXECUTE_PREPARED_WRITE);
// GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
break; break;
} }
case P_W4_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT:{ case P_W4_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT: {
gatt_client->attribute_offset = little_endian_read_16(packet, 3); gatt_client->attribute_offset = little_endian_read_16(packet, 3);
trigger_next_prepare_write_query(gatt_client, P_W2_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR, P_W2_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR); trigger_next_prepare_write_query(gatt_client, P_W2_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR,
P_W2_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR);
// GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
break; break;
} }
case P_W4_PREPARE_RELIABLE_WRITE_RESULT:{ case P_W4_PREPARE_RELIABLE_WRITE_RESULT: {
if (is_value_valid(gatt_client, packet, size)){ if (is_value_valid(gatt_client, packet, size)) {
gatt_client->attribute_offset = little_endian_read_16(packet, 3); gatt_client->attribute_offset = little_endian_read_16(packet, 3);
trigger_next_prepare_write_query(gatt_client, P_W2_PREPARE_RELIABLE_WRITE, P_W2_EXECUTE_PREPARED_WRITE); trigger_next_prepare_write_query(gatt_client, P_W2_PREPARE_RELIABLE_WRITE,
P_W2_EXECUTE_PREPARED_WRITE);
// GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
break; break;
} }
@ -1707,9 +1681,9 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
break; break;
} }
break; break;
case ATT_EXECUTE_WRITE_RESPONSE: case ATT_EXECUTE_WRITE_RESPONSE:
switch (gatt_client->gatt_client_state){ switch (gatt_client->gatt_client_state) {
case P_W4_EXECUTE_PREPARED_WRITE_RESULT: case P_W4_EXECUTE_PREPARED_WRITE_RESULT:
gatt_client_handle_transaction_complete(gatt_client); gatt_client_handle_transaction_complete(gatt_client);
emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS); emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS);
@ -1728,12 +1702,12 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
break; break;
default: default:
break; break;
} }
break; break;
case ATT_READ_MULTIPLE_RESPONSE: case ATT_READ_MULTIPLE_RESPONSE:
switch(gatt_client->gatt_client_state){ switch (gatt_client->gatt_client_state) {
case P_W4_READ_MULTIPLE_RESPONSE: case P_W4_READ_MULTIPLE_RESPONSE:
report_gatt_characteristic_value(gatt_client, 0u, &packet[1], size - 1u); report_gatt_characteristic_value(gatt_client, 0u, &packet[1], size - 1u);
gatt_client_handle_transaction_complete(gatt_client); gatt_client_handle_transaction_complete(gatt_client);
@ -1747,9 +1721,9 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
case ATT_ERROR_RESPONSE: case ATT_ERROR_RESPONSE:
if (size < 5u) return; if (size < 5u) return;
error_code = packet[4]; error_code = packet[4];
switch (error_code){ switch (error_code) {
case ATT_ERROR_ATTRIBUTE_NOT_FOUND: { case ATT_ERROR_ATTRIBUTE_NOT_FOUND: {
switch(gatt_client->gatt_client_state){ switch (gatt_client->gatt_client_state) {
case P_W4_SERVICE_QUERY_RESULT: case P_W4_SERVICE_QUERY_RESULT:
case P_W4_SERVICE_WITH_UUID_RESULT: case P_W4_SERVICE_WITH_UUID_RESULT:
case P_W4_INCLUDED_SERVICE_QUERY_RESULT: case P_W4_INCLUDED_SERVICE_QUERY_RESULT:
@ -1765,7 +1739,7 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
break; break;
case P_W4_READ_BY_TYPE_RESPONSE: case P_W4_READ_BY_TYPE_RESPONSE:
gatt_client_handle_transaction_complete(gatt_client); gatt_client_handle_transaction_complete(gatt_client);
if (gatt_client->start_group_handle == gatt_client->query_start_handle){ if (gatt_client->start_group_handle == gatt_client->query_start_handle) {
emit_gatt_complete_event(gatt_client, ATT_ERROR_ATTRIBUTE_NOT_FOUND); emit_gatt_complete_event(gatt_client, ATT_ERROR_ATTRIBUTE_NOT_FOUND);
} else { } else {
emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS); emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS);
@ -1780,111 +1754,151 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
#ifdef ENABLE_GATT_CLIENT_PAIRING #ifdef ENABLE_GATT_CLIENT_PAIRING
case ATT_ERROR_INSUFFICIENT_AUTHENTICATION: case ATT_ERROR_INSUFFICIENT_AUTHENTICATION:
case ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE: case ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE:
case ATT_ERROR_INSUFFICIENT_ENCRYPTION: { case ATT_ERROR_INSUFFICIENT_ENCRYPTION: {
// security too low // security too low
if (gatt_client->security_counter > 0) { if (gatt_client->security_counter > 0) {
gatt_client_report_error_if_pending(gatt_client, error_code); gatt_client_report_error_if_pending(gatt_client, error_code);
break; break;
} }
// start security // start security
gatt_client->security_counter++; gatt_client->security_counter++;
// setup action // setup action
int retry = 1; int retry = 1;
switch (gatt_client->gatt_client_state){ switch (gatt_client->gatt_client_state){
case P_W4_READ_CHARACTERISTIC_VALUE_RESULT: case P_W4_READ_CHARACTERISTIC_VALUE_RESULT:
gatt_client->gatt_client_state = P_W2_SEND_READ_CHARACTERISTIC_VALUE_QUERY ; gatt_client->gatt_client_state = P_W2_SEND_READ_CHARACTERISTIC_VALUE_QUERY ;
break; break;
case P_W4_READ_BLOB_RESULT: case P_W4_READ_BLOB_RESULT:
gatt_client->gatt_client_state = P_W2_SEND_READ_BLOB_QUERY; gatt_client->gatt_client_state = P_W2_SEND_READ_BLOB_QUERY;
break; break;
case P_W4_READ_BY_TYPE_RESPONSE: case P_W4_READ_BY_TYPE_RESPONSE:
gatt_client->gatt_client_state = P_W2_SEND_READ_BY_TYPE_REQUEST; gatt_client->gatt_client_state = P_W2_SEND_READ_BY_TYPE_REQUEST;
break; break;
case P_W4_READ_MULTIPLE_RESPONSE: case P_W4_READ_MULTIPLE_RESPONSE:
gatt_client->gatt_client_state = P_W2_SEND_READ_MULTIPLE_REQUEST; gatt_client->gatt_client_state = P_W2_SEND_READ_MULTIPLE_REQUEST;
break; break;
case P_W4_WRITE_CHARACTERISTIC_VALUE_RESULT: case P_W4_WRITE_CHARACTERISTIC_VALUE_RESULT:
gatt_client->gatt_client_state = P_W2_SEND_WRITE_CHARACTERISTIC_VALUE; gatt_client->gatt_client_state = P_W2_SEND_WRITE_CHARACTERISTIC_VALUE;
break; break;
case P_W4_PREPARE_WRITE_RESULT: case P_W4_PREPARE_WRITE_RESULT:
gatt_client->gatt_client_state = P_W2_PREPARE_WRITE; gatt_client->gatt_client_state = P_W2_PREPARE_WRITE;
break; break;
case P_W4_PREPARE_WRITE_SINGLE_RESULT: case P_W4_PREPARE_WRITE_SINGLE_RESULT:
gatt_client->gatt_client_state = P_W2_PREPARE_WRITE_SINGLE; gatt_client->gatt_client_state = P_W2_PREPARE_WRITE_SINGLE;
break; break;
case P_W4_PREPARE_RELIABLE_WRITE_RESULT: case P_W4_PREPARE_RELIABLE_WRITE_RESULT:
gatt_client->gatt_client_state = P_W2_PREPARE_RELIABLE_WRITE; gatt_client->gatt_client_state = P_W2_PREPARE_RELIABLE_WRITE;
break; break;
case P_W4_EXECUTE_PREPARED_WRITE_RESULT: case P_W4_EXECUTE_PREPARED_WRITE_RESULT:
gatt_client->gatt_client_state = P_W2_EXECUTE_PREPARED_WRITE; gatt_client->gatt_client_state = P_W2_EXECUTE_PREPARED_WRITE;
break; break;
case P_W4_CANCEL_PREPARED_WRITE_RESULT: case P_W4_CANCEL_PREPARED_WRITE_RESULT:
gatt_client->gatt_client_state = P_W2_CANCEL_PREPARED_WRITE; gatt_client->gatt_client_state = P_W2_CANCEL_PREPARED_WRITE;
break; break;
case P_W4_CANCEL_PREPARED_WRITE_DATA_MISMATCH_RESULT: case P_W4_CANCEL_PREPARED_WRITE_DATA_MISMATCH_RESULT:
gatt_client->gatt_client_state = P_W2_CANCEL_PREPARED_WRITE_DATA_MISMATCH; gatt_client->gatt_client_state = P_W2_CANCEL_PREPARED_WRITE_DATA_MISMATCH;
break; break;
case P_W4_READ_CHARACTERISTIC_DESCRIPTOR_RESULT: case P_W4_READ_CHARACTERISTIC_DESCRIPTOR_RESULT:
gatt_client->gatt_client_state = P_W2_SEND_READ_CHARACTERISTIC_DESCRIPTOR_QUERY; gatt_client->gatt_client_state = P_W2_SEND_READ_CHARACTERISTIC_DESCRIPTOR_QUERY;
break; break;
case P_W4_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_RESULT: case P_W4_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_RESULT:
gatt_client->gatt_client_state = P_W2_SEND_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_QUERY; gatt_client->gatt_client_state = P_W2_SEND_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_QUERY;
break; break;
case P_W4_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT: case P_W4_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT:
gatt_client->gatt_client_state = P_W2_SEND_WRITE_CHARACTERISTIC_DESCRIPTOR; gatt_client->gatt_client_state = P_W2_SEND_WRITE_CHARACTERISTIC_DESCRIPTOR;
break; break;
case P_W4_CLIENT_CHARACTERISTIC_CONFIGURATION_RESULT: case P_W4_CLIENT_CHARACTERISTIC_CONFIGURATION_RESULT:
gatt_client->gatt_client_state = P_W2_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION; gatt_client->gatt_client_state = P_W2_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION;
break; break;
case P_W4_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT: case P_W4_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT:
gatt_client->gatt_client_state = P_W2_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR; gatt_client->gatt_client_state = P_W2_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR;
break; break;
case P_W4_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT: case P_W4_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT:
gatt_client->gatt_client_state = P_W2_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR; gatt_client->gatt_client_state = P_W2_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR;
break; break;
#ifdef ENABLE_LE_SIGNED_WRITE #ifdef ENABLE_LE_SIGNED_WRITE
case P_W4_SEND_SINGED_WRITE_DONE: case P_W4_SEND_SINGED_WRITE_DONE:
gatt_client->gatt_client_state = P_W2_SEND_SIGNED_WRITE; gatt_client->gatt_client_state = P_W2_SEND_SIGNED_WRITE;
break; break;
#endif #endif
default: default:
log_info("retry not supported for state %x", gatt_client->gatt_client_state); log_info("retry not supported for state %x", gatt_client->gatt_client_state);
retry = 0; retry = 0;
break; break;
} }
if (!retry) { if (!retry) {
gatt_client_report_error_if_pending(gatt_client, error_code); gatt_client_report_error_if_pending(gatt_client, error_code);
break;
}
log_info("security error, start pairing");
// start pairing for higher security level
gatt_client->wait_for_authentication_complete = 1;
gatt_client->pending_error_code = error_code;
sm_request_pairing(gatt_client->con_handle);
break; break;
} }
log_info("security error, start pairing");
// start pairing for higher security level
gatt_client->wait_for_authentication_complete = 1;
gatt_client->pending_error_code = error_code;
sm_request_pairing(gatt_client->con_handle);
break;
}
#endif #endif
// nothing we can do about that // nothing we can do about that
case ATT_ERROR_INSUFFICIENT_AUTHORIZATION: case ATT_ERROR_INSUFFICIENT_AUTHORIZATION:
default: default:
gatt_client_report_error_if_pending(gatt_client, error_code); gatt_client_report_error_if_pending(gatt_client, error_code);
break; break;
} }
break; break;
default: default:
log_info("ATT Handler, unhandled response type 0x%02x", packet[0]); log_info("ATT Handler, unhandled response type 0x%02x", packet[0]);
break; break;
} }
gatt_client_run(); }
static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size) {
gatt_client_t *gatt_client;
if (size < 1u) return;
if (packet_type == HCI_EVENT_PACKET) {
switch (packet[0]) {
case L2CAP_EVENT_CAN_SEND_NOW:
gatt_client_run();
break;
// att_server has negotiated the mtu for this connection, cache if context exists
case ATT_EVENT_MTU_EXCHANGE_COMPLETE:
if (size < 6u) break;
gatt_client = gatt_client_get_context_for_handle(handle);
if (gatt_client == NULL) break;
gatt_client->mtu = little_endian_read_16(packet, 4);
break;
default:
break;
}
return;
}
if (packet_type != ATT_DATA_PACKET) return;
// special cases: notifications & indications motivate creating context
switch (packet[0]) {
case ATT_HANDLE_VALUE_NOTIFICATION:
case ATT_HANDLE_VALUE_INDICATION:
gatt_client_provide_context_for_handle(handle, &gatt_client);
break;
default:
gatt_client = gatt_client_get_context_for_handle(handle);
break;
}
if (gatt_client != NULL) {
gatt_client_handle_att_response(gatt_client, packet, size);
gatt_client_run();
}
} }
#ifdef ENABLE_LE_SIGNED_WRITE #ifdef ENABLE_LE_SIGNED_WRITE