static void att_event_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ switch (packet_type) { case HCI_EVENT_PACKET: switch (packet[0]) { case DAEMON_EVENT_HCI_PACKET_SENT: att_run(); break; case HCI_EVENT_LE_META: switch (packet[2]) { case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: // store connection info att_client_addr_type = packet[7]; bt_flip_addr(att_client_address, &packet[8]); // reset connection properties att_connection.con_handle = READ_BT_16(packet, 4); att_connection.mtu = ATT_DEFAULT_MTU; att_connection.max_mtu = l2cap_max_le_mtu(); att_connection.encryption_key_size = 0; att_connection.authenticated = 0; att_connection.authorized = 0; break; default: break; } break; case HCI_EVENT_ENCRYPTION_CHANGE: // check handle if (att_connection.con_handle != READ_BT_16(packet, 3)) break; att_connection.encryption_key_size = sm_encryption_key_size(att_client_addr_type, att_client_address); att_connection.authenticated = sm_authenticated(att_client_addr_type, att_client_address); break; case HCI_EVENT_DISCONNECTION_COMPLETE: att_clear_transaction_queue(&att_connection); att_connection.con_handle = 0; att_handle_value_indication_handle = 0; // reset error state // restart advertising if we have been connected before // -> avoid sending advertise enable a second time before command complete was received att_server_state = ATT_SERVER_IDLE; break; case SM_IDENTITY_RESOLVING_STARTED: log_info("SM_IDENTITY_RESOLVING_STARTED"); att_ir_lookup_active = 1; break; case SM_IDENTITY_RESOLVING_SUCCEEDED: att_ir_lookup_active = 0; att_ir_le_device_db_index = ((sm_event_t*) packet)->le_device_db_index; log_info("SM_IDENTITY_RESOLVING_SUCCEEDED id %u", att_ir_le_device_db_index); att_run(); break; case SM_IDENTITY_RESOLVING_FAILED: log_info("SM_IDENTITY_RESOLVING_FAILED"); att_ir_lookup_active = 0; att_ir_le_device_db_index = -1; att_run(); break; case SM_AUTHORIZATION_RESULT: { sm_event_t * event = (sm_event_t *) packet; if (event->addr_type != att_client_addr_type) break; if (memcmp(event->address, att_client_address, 6) != 0) break; att_connection.authorized = event->authorization_result; att_run(); break; } default: break; } } if (att_client_packet_handler){ att_client_packet_handler(packet_type, channel, packet, size); } }
static void att_event_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ UNUSED(channel); // ok: there is no channel UNUSED(size); // ok: handling own l2cap events att_server_t * att_server; hci_con_handle_t con_handle; switch (packet_type) { case HCI_EVENT_PACKET: switch (hci_event_packet_get_type(packet)) { case HCI_EVENT_LE_META: switch (packet[2]) { case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: con_handle = little_endian_read_16(packet, 4); att_server = att_server_for_handle(con_handle); if (!att_server) break; // store connection info att_server->peer_addr_type = packet[7]; reverse_bd_addr(&packet[8], att_server->peer_address); att_server->connection.con_handle = con_handle; // reset connection properties att_server->state = ATT_SERVER_IDLE; att_server->connection.mtu = ATT_DEFAULT_MTU; att_server->connection.max_mtu = l2cap_max_le_mtu(); if (att_server->connection.max_mtu > ATT_REQUEST_BUFFER_SIZE){ att_server->connection.max_mtu = ATT_REQUEST_BUFFER_SIZE; } att_server->connection.encryption_key_size = 0; att_server->connection.authenticated = 0; att_server->connection.authorized = 0; // workaround: identity resolving can already be complete, at least store result att_server->ir_le_device_db_index = sm_le_device_index(con_handle); att_server->pairing_active = 0; break; default: break; } break; case HCI_EVENT_ENCRYPTION_CHANGE: case HCI_EVENT_ENCRYPTION_KEY_REFRESH_COMPLETE: // check handle con_handle = little_endian_read_16(packet, 3); att_server = att_server_for_handle(con_handle); if (!att_server) break; att_server->connection.encryption_key_size = gap_encryption_key_size(con_handle); att_server->connection.authenticated = gap_authenticated(con_handle); if (hci_event_packet_get_type(packet) == HCI_EVENT_ENCRYPTION_CHANGE){ // restore CCC values when encrypted if (hci_event_encryption_change_get_encryption_enabled(packet)){ att_server_persistent_ccc_restore(att_server); } } break; case HCI_EVENT_DISCONNECTION_COMPLETE: // check handle con_handle = hci_event_disconnection_complete_get_connection_handle(packet); att_server = att_server_for_handle(con_handle); if (!att_server) break; att_clear_transaction_queue(&att_server->connection); att_server->connection.con_handle = 0; att_server->value_indication_handle = 0; // reset error state att_server->pairing_active = 0; att_server->state = ATT_SERVER_IDLE; break; // Identity Resolving case SM_EVENT_IDENTITY_RESOLVING_STARTED: con_handle = sm_event_identity_resolving_started_get_handle(packet); att_server = att_server_for_handle(con_handle); if (!att_server) break; log_info("SM_EVENT_IDENTITY_RESOLVING_STARTED"); att_server->ir_lookup_active = 1; break; case SM_EVENT_IDENTITY_RESOLVING_SUCCEEDED: con_handle = sm_event_identity_created_get_handle(packet); att_server = att_server_for_handle(con_handle); if (!att_server) return; att_server->ir_lookup_active = 0; att_server->ir_le_device_db_index = sm_event_identity_resolving_succeeded_get_index(packet); log_info("SM_EVENT_IDENTITY_RESOLVING_SUCCEEDED"); att_run_for_context(att_server); break; case SM_EVENT_IDENTITY_RESOLVING_FAILED: con_handle = sm_event_identity_resolving_failed_get_handle(packet); att_server = att_server_for_handle(con_handle); if (!att_server) break; log_info("SM_EVENT_IDENTITY_RESOLVING_FAILED"); att_server->ir_lookup_active = 0; att_server->ir_le_device_db_index = -1; att_run_for_context(att_server); break; // Pairing started - delete stored CCC values // - assumes pairing indicates either new device or re-pairing, in both cases there should be no stored CCC values // - assumes that all events have the con handle as the first field case SM_EVENT_JUST_WORKS_REQUEST: case SM_EVENT_PASSKEY_DISPLAY_NUMBER: case SM_EVENT_PASSKEY_INPUT_NUMBER: case SM_EVENT_NUMERIC_COMPARISON_REQUEST: con_handle = sm_event_just_works_request_get_handle(packet); att_server = att_server_for_handle(con_handle); if (!att_server) break; att_server->pairing_active = 1; log_info("SM Pairing started"); if (att_server->ir_le_device_db_index < 0) break; att_server_persistent_ccc_clear(att_server); // index not valid anymore att_server->ir_le_device_db_index = -1; break; // Bonding completed case SM_EVENT_IDENTITY_CREATED: con_handle = sm_event_identity_created_get_handle(packet); att_server = att_server_for_handle(con_handle); if (!att_server) return; att_server->pairing_active = 0; att_server->ir_le_device_db_index = sm_event_identity_created_get_index(packet); att_run_for_context(att_server); break; // Pairing complete (with/without bonding=storing of pairing information) case SM_EVENT_PAIRING_COMPLETE: con_handle = sm_event_pairing_complete_get_handle(packet); att_server = att_server_for_handle(con_handle); if (!att_server) return; att_server->pairing_active = 0; att_run_for_context(att_server); break; // Authorization case SM_EVENT_AUTHORIZATION_RESULT: { con_handle = sm_event_authorization_result_get_handle(packet); att_server = att_server_for_handle(con_handle); if (!att_server) break; att_server->connection.authorized = sm_event_authorization_result_get_authorization_result(packet); att_dispatch_server_request_can_send_now_event(con_handle); break; } default: break; } break; default: break; } }