163bf37cdSMilanka Ringwald /* 263bf37cdSMilanka Ringwald * Copyright (C) 2014 BlueKitchen GmbH 363bf37cdSMilanka Ringwald * 463bf37cdSMilanka Ringwald * Redistribution and use in source and binary forms, with or without 563bf37cdSMilanka Ringwald * modification, are permitted provided that the following conditions 663bf37cdSMilanka Ringwald * are met: 763bf37cdSMilanka Ringwald * 863bf37cdSMilanka Ringwald * 1. Redistributions of source code must retain the above copyright 963bf37cdSMilanka Ringwald * notice, this list of conditions and the following disclaimer. 1063bf37cdSMilanka Ringwald * 2. Redistributions in binary form must reproduce the above copyright 1163bf37cdSMilanka Ringwald * notice, this list of conditions and the following disclaimer in the 1263bf37cdSMilanka Ringwald * documentation and/or other materials provided with the distribution. 1363bf37cdSMilanka Ringwald * 3. Neither the name of the copyright holders nor the names of 1463bf37cdSMilanka Ringwald * contributors may be used to endorse or promote products derived 1563bf37cdSMilanka Ringwald * from this software without specific prior written permission. 1663bf37cdSMilanka Ringwald * 4. Any redistribution, use, or modification is done solely for 1763bf37cdSMilanka Ringwald * personal benefit and not for any commercial purpose or for 1863bf37cdSMilanka Ringwald * monetary gain. 1963bf37cdSMilanka Ringwald * 2063bf37cdSMilanka Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 2163bf37cdSMilanka Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2263bf37cdSMilanka Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 2363bf37cdSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 2463bf37cdSMilanka Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2563bf37cdSMilanka Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2663bf37cdSMilanka Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 2763bf37cdSMilanka Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2863bf37cdSMilanka Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2963bf37cdSMilanka Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 3063bf37cdSMilanka Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3163bf37cdSMilanka Ringwald * SUCH DAMAGE. 3263bf37cdSMilanka Ringwald * 3363bf37cdSMilanka Ringwald * Please inquire about commercial licensing options at 3463bf37cdSMilanka Ringwald * [email protected] 3563bf37cdSMilanka Ringwald * 3663bf37cdSMilanka Ringwald */ 3763bf37cdSMilanka Ringwald 3863bf37cdSMilanka Ringwald #define BTSTACK_FILE__ "hid_host.c" 3963bf37cdSMilanka Ringwald 4063bf37cdSMilanka Ringwald #include <string.h> 4163bf37cdSMilanka Ringwald 4263bf37cdSMilanka Ringwald #include "bluetooth.h" 4363bf37cdSMilanka Ringwald #include "bluetooth_psm.h" 4463bf37cdSMilanka Ringwald #include "bluetooth_sdp.h" 4563bf37cdSMilanka Ringwald #include "btstack_debug.h" 4663bf37cdSMilanka Ringwald #include "btstack_event.h" 4763bf37cdSMilanka Ringwald #include "btstack_hid_parser.h" 48*fd7ba7a6SMilanka Ringwald #include "btstack_memory.h" 4963bf37cdSMilanka Ringwald #include "classic/hid.h" 5063bf37cdSMilanka Ringwald #include "classic/hid_host.h" 5163bf37cdSMilanka Ringwald #include "classic/sdp_util.h" 52*fd7ba7a6SMilanka Ringwald #include "classic/sdp_client.h" 5363bf37cdSMilanka Ringwald #include "l2cap.h" 5463bf37cdSMilanka Ringwald 55*fd7ba7a6SMilanka Ringwald #define MAX_ATTRIBUTE_VALUE_SIZE 300 5663bf37cdSMilanka Ringwald 57*fd7ba7a6SMilanka Ringwald static btstack_packet_handler_t hid_callback; 5863bf37cdSMilanka Ringwald 59*fd7ba7a6SMilanka Ringwald static uint8_t * hid_host_descriptor_storage; 6063bf37cdSMilanka Ringwald static uint16_t hid_host_descriptor_storage_len; 6163bf37cdSMilanka Ringwald 62*fd7ba7a6SMilanka Ringwald static btstack_linked_list_t connections; 63*fd7ba7a6SMilanka Ringwald static uint16_t hid_host_cid_counter = 0; 64*fd7ba7a6SMilanka Ringwald 65*fd7ba7a6SMilanka Ringwald // SDP 66*fd7ba7a6SMilanka Ringwald static uint8_t attribute_value[MAX_ATTRIBUTE_VALUE_SIZE]; 67*fd7ba7a6SMilanka Ringwald static const unsigned int attribute_value_buffer_size = MAX_ATTRIBUTE_VALUE_SIZE; 68*fd7ba7a6SMilanka Ringwald 69*fd7ba7a6SMilanka Ringwald static uint16_t sdp_query_context_hid_host_control_cid = 0; 70*fd7ba7a6SMilanka Ringwald 71*fd7ba7a6SMilanka Ringwald static btstack_context_callback_registration_t hid_host_handle_sdp_client_query_request; 72*fd7ba7a6SMilanka Ringwald static void hid_host_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 73*fd7ba7a6SMilanka Ringwald 74*fd7ba7a6SMilanka Ringwald static uint16_t hid_descriptor_storage_get_available_space(void){ 75*fd7ba7a6SMilanka Ringwald // assumes all descriptors are back to back 76*fd7ba7a6SMilanka Ringwald uint16_t free_space = hid_host_descriptor_storage_len; 77*fd7ba7a6SMilanka Ringwald 78*fd7ba7a6SMilanka Ringwald btstack_linked_list_iterator_t it; 79*fd7ba7a6SMilanka Ringwald btstack_linked_list_iterator_init(&it, &connections); 80*fd7ba7a6SMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 81*fd7ba7a6SMilanka Ringwald hid_host_connection_t * connection = (hid_host_connection_t *)btstack_linked_list_iterator_next(&it); 82*fd7ba7a6SMilanka Ringwald free_space -= connection->hid_descriptor_len; 83*fd7ba7a6SMilanka Ringwald } 84*fd7ba7a6SMilanka Ringwald return free_space; 85*fd7ba7a6SMilanka Ringwald } 86*fd7ba7a6SMilanka Ringwald 87*fd7ba7a6SMilanka Ringwald static void hid_descriptor_storage_init(hid_host_connection_t * connection){ 88*fd7ba7a6SMilanka Ringwald connection->hid_descriptor_len = 0; 89*fd7ba7a6SMilanka Ringwald connection->hid_descriptor_max_len = hid_descriptor_storage_get_available_space(); 90*fd7ba7a6SMilanka Ringwald connection->hid_descriptor_offset = hid_host_descriptor_storage_len - connection->hid_descriptor_max_len; 91*fd7ba7a6SMilanka Ringwald } 92*fd7ba7a6SMilanka Ringwald 93*fd7ba7a6SMilanka Ringwald static bool hid_descriptor_storage_store(hid_host_connection_t * connection, uint8_t byte){ 94*fd7ba7a6SMilanka Ringwald if (connection->hid_descriptor_len >= connection->hid_descriptor_max_len) return false; 95*fd7ba7a6SMilanka Ringwald 96*fd7ba7a6SMilanka Ringwald hid_host_descriptor_storage[connection->hid_descriptor_offset + connection->hid_descriptor_len] = byte; 97*fd7ba7a6SMilanka Ringwald connection->hid_descriptor_len++; 98*fd7ba7a6SMilanka Ringwald return true; 99*fd7ba7a6SMilanka Ringwald } 100*fd7ba7a6SMilanka Ringwald 101*fd7ba7a6SMilanka Ringwald 102*fd7ba7a6SMilanka Ringwald static void hid_descriptor_storage_delete(hid_host_connection_t * connection){ 103*fd7ba7a6SMilanka Ringwald uint16_t next_offset = connection->hid_descriptor_offset + connection->hid_descriptor_len; 104*fd7ba7a6SMilanka Ringwald 105*fd7ba7a6SMilanka Ringwald memmove(&hid_host_descriptor_storage[connection->hid_descriptor_offset], 106*fd7ba7a6SMilanka Ringwald &hid_host_descriptor_storage[next_offset], 107*fd7ba7a6SMilanka Ringwald hid_host_descriptor_storage_len - next_offset); 108*fd7ba7a6SMilanka Ringwald 109*fd7ba7a6SMilanka Ringwald connection->hid_descriptor_len = 0; 110*fd7ba7a6SMilanka Ringwald connection->hid_descriptor_offset = 0; 111*fd7ba7a6SMilanka Ringwald 112*fd7ba7a6SMilanka Ringwald btstack_linked_list_iterator_t it; 113*fd7ba7a6SMilanka Ringwald btstack_linked_list_iterator_init(&it, &connections); 114*fd7ba7a6SMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 115*fd7ba7a6SMilanka Ringwald hid_host_connection_t * conn = (hid_host_connection_t *)btstack_linked_list_iterator_next(&it); 116*fd7ba7a6SMilanka Ringwald if (conn->hid_descriptor_offset >= next_offset){ 117*fd7ba7a6SMilanka Ringwald conn->hid_descriptor_offset = next_offset; 118*fd7ba7a6SMilanka Ringwald next_offset += conn->hid_descriptor_len; 119*fd7ba7a6SMilanka Ringwald } 120*fd7ba7a6SMilanka Ringwald } 121*fd7ba7a6SMilanka Ringwald } 122*fd7ba7a6SMilanka Ringwald 123*fd7ba7a6SMilanka Ringwald // HID Util 124*fd7ba7a6SMilanka Ringwald static inline void hid_emit_connected_event(hid_host_connection_t * context, uint8_t status){ 125*fd7ba7a6SMilanka Ringwald uint8_t event[15]; 126*fd7ba7a6SMilanka Ringwald int pos = 0; 127*fd7ba7a6SMilanka Ringwald event[pos++] = HCI_EVENT_HID_META; 128*fd7ba7a6SMilanka Ringwald pos++; // skip len 129*fd7ba7a6SMilanka Ringwald event[pos++] = HID_SUBEVENT_CONNECTION_OPENED; 130*fd7ba7a6SMilanka Ringwald little_endian_store_16(event, pos, context->hid_cid); 131*fd7ba7a6SMilanka Ringwald pos+=2; 132*fd7ba7a6SMilanka Ringwald event[pos++] = status; 133*fd7ba7a6SMilanka Ringwald reverse_bd_addr(context->remote_addr, &event[pos]); 134*fd7ba7a6SMilanka Ringwald pos += 6; 135*fd7ba7a6SMilanka Ringwald little_endian_store_16(event,pos,context->con_handle); 136*fd7ba7a6SMilanka Ringwald pos += 2; 137*fd7ba7a6SMilanka Ringwald event[pos++] = context->incoming; 138*fd7ba7a6SMilanka Ringwald event[1] = pos - 2; 139*fd7ba7a6SMilanka Ringwald hid_callback(HCI_EVENT_PACKET, context->hid_cid, &event[0], pos); 140*fd7ba7a6SMilanka Ringwald } 141*fd7ba7a6SMilanka Ringwald 142*fd7ba7a6SMilanka Ringwald // HID Host 143*fd7ba7a6SMilanka Ringwald 144*fd7ba7a6SMilanka Ringwald static uint16_t hid_host_get_next_cid(void){ 145*fd7ba7a6SMilanka Ringwald if (hid_host_cid_counter == 0xffff) { 146*fd7ba7a6SMilanka Ringwald hid_host_cid_counter = 1; 147*fd7ba7a6SMilanka Ringwald } else { 148*fd7ba7a6SMilanka Ringwald hid_host_cid_counter++; 149*fd7ba7a6SMilanka Ringwald } 150*fd7ba7a6SMilanka Ringwald return hid_host_cid_counter; 151*fd7ba7a6SMilanka Ringwald } 152*fd7ba7a6SMilanka Ringwald 153*fd7ba7a6SMilanka Ringwald static hid_host_connection_t * hid_host_create_connection(bd_addr_t remote_addr){ 154*fd7ba7a6SMilanka Ringwald hid_host_connection_t * connection = btstack_memory_hid_host_connection_get(); 155*fd7ba7a6SMilanka Ringwald if (!connection){ 156*fd7ba7a6SMilanka Ringwald log_error("Not enough memory to create connection"); 157*fd7ba7a6SMilanka Ringwald return NULL; 158*fd7ba7a6SMilanka Ringwald } 159*fd7ba7a6SMilanka Ringwald connection->state = HID_HOST_IDLE; 160*fd7ba7a6SMilanka Ringwald connection->hid_cid = hid_host_get_next_cid(); 161*fd7ba7a6SMilanka Ringwald (void)memcpy(connection->remote_addr, remote_addr, 6); 162*fd7ba7a6SMilanka Ringwald printf("hid_host_create_connection, cid 0x%02x, %s \n", connection->hid_cid, bd_addr_to_str(connection->remote_addr)); 163*fd7ba7a6SMilanka Ringwald 164*fd7ba7a6SMilanka Ringwald btstack_linked_list_add(&connections, (btstack_linked_item_t *) connection); 165*fd7ba7a6SMilanka Ringwald return connection; 166*fd7ba7a6SMilanka Ringwald } 167*fd7ba7a6SMilanka Ringwald 168*fd7ba7a6SMilanka Ringwald static hid_host_connection_t * hid_host_get_connection_for_bd_addr(bd_addr_t addr){ 169*fd7ba7a6SMilanka Ringwald btstack_linked_list_iterator_t it; 170*fd7ba7a6SMilanka Ringwald btstack_linked_list_iterator_init(&it, &connections); 171*fd7ba7a6SMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 172*fd7ba7a6SMilanka Ringwald hid_host_connection_t * connection = (hid_host_connection_t *)btstack_linked_list_iterator_next(&it); 173*fd7ba7a6SMilanka Ringwald if (memcmp(addr, connection->remote_addr, 6) != 0) continue; 174*fd7ba7a6SMilanka Ringwald return connection; 175*fd7ba7a6SMilanka Ringwald } 176*fd7ba7a6SMilanka Ringwald return NULL; 177*fd7ba7a6SMilanka Ringwald } 178*fd7ba7a6SMilanka Ringwald 179*fd7ba7a6SMilanka Ringwald static hid_host_connection_t * hid_host_connection_for_hid_cid(uint16_t hid_cid){ 180*fd7ba7a6SMilanka Ringwald btstack_linked_list_iterator_t it; 181*fd7ba7a6SMilanka Ringwald btstack_linked_list_iterator_init(&it, &connections); 182*fd7ba7a6SMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 183*fd7ba7a6SMilanka Ringwald hid_host_connection_t * connection = (hid_host_connection_t *)btstack_linked_list_iterator_next(&it); 184*fd7ba7a6SMilanka Ringwald if (connection->hid_cid != hid_cid) continue; 185*fd7ba7a6SMilanka Ringwald return connection; 186*fd7ba7a6SMilanka Ringwald } 187*fd7ba7a6SMilanka Ringwald return NULL; 188*fd7ba7a6SMilanka Ringwald } 189*fd7ba7a6SMilanka Ringwald 190*fd7ba7a6SMilanka Ringwald static void hid_host_finalize_connection(hid_host_connection_t * connection){ 191*fd7ba7a6SMilanka Ringwald btstack_linked_list_remove(&connections, (btstack_linked_item_t*) connection); 192*fd7ba7a6SMilanka Ringwald btstack_memory_hid_host_connection_free(connection); 193*fd7ba7a6SMilanka Ringwald } 194*fd7ba7a6SMilanka Ringwald 195*fd7ba7a6SMilanka Ringwald static void hid_host_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { 196*fd7ba7a6SMilanka Ringwald UNUSED(packet_type); 197*fd7ba7a6SMilanka Ringwald UNUSED(channel); 198*fd7ba7a6SMilanka Ringwald UNUSED(size); 199*fd7ba7a6SMilanka Ringwald 200*fd7ba7a6SMilanka Ringwald des_iterator_t attribute_list_it; 201*fd7ba7a6SMilanka Ringwald des_iterator_t additional_des_it; 202*fd7ba7a6SMilanka Ringwald des_iterator_t prot_it; 203*fd7ba7a6SMilanka Ringwald uint8_t *des_element; 204*fd7ba7a6SMilanka Ringwald uint8_t *element; 205*fd7ba7a6SMilanka Ringwald uint32_t uuid; 206*fd7ba7a6SMilanka Ringwald uint8_t status = ERROR_CODE_SUCCESS; 207*fd7ba7a6SMilanka Ringwald 208*fd7ba7a6SMilanka Ringwald hid_host_connection_t * connection = hid_host_connection_for_hid_cid(sdp_query_context_hid_host_control_cid); 209*fd7ba7a6SMilanka Ringwald if (!connection) { 210*fd7ba7a6SMilanka Ringwald log_error("SDP query, connection with 0x%02x cid not found", sdp_query_context_hid_host_control_cid); 211*fd7ba7a6SMilanka Ringwald return; 212*fd7ba7a6SMilanka Ringwald } 213*fd7ba7a6SMilanka Ringwald 214*fd7ba7a6SMilanka Ringwald switch (hci_event_packet_get_type(packet)){ 215*fd7ba7a6SMilanka Ringwald case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 216*fd7ba7a6SMilanka Ringwald 217*fd7ba7a6SMilanka Ringwald if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= attribute_value_buffer_size) { 218*fd7ba7a6SMilanka Ringwald 219*fd7ba7a6SMilanka Ringwald attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet); 220*fd7ba7a6SMilanka Ringwald 221*fd7ba7a6SMilanka Ringwald if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) { 222*fd7ba7a6SMilanka Ringwald switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) { 223*fd7ba7a6SMilanka Ringwald 224*fd7ba7a6SMilanka Ringwald case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: 225*fd7ba7a6SMilanka Ringwald for (des_iterator_init(&attribute_list_it, attribute_value); des_iterator_has_more(&attribute_list_it); des_iterator_next(&attribute_list_it)) { 226*fd7ba7a6SMilanka Ringwald if (des_iterator_get_type(&attribute_list_it) != DE_DES) continue; 227*fd7ba7a6SMilanka Ringwald des_element = des_iterator_get_element(&attribute_list_it); 228*fd7ba7a6SMilanka Ringwald des_iterator_init(&prot_it, des_element); 229*fd7ba7a6SMilanka Ringwald element = des_iterator_get_element(&prot_it); 230*fd7ba7a6SMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 231*fd7ba7a6SMilanka Ringwald uuid = de_get_uuid32(element); 232*fd7ba7a6SMilanka Ringwald switch (uuid){ 233*fd7ba7a6SMilanka Ringwald case BLUETOOTH_PROTOCOL_L2CAP: 234*fd7ba7a6SMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 235*fd7ba7a6SMilanka Ringwald des_iterator_next(&prot_it); 236*fd7ba7a6SMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &connection->control_psm); 237*fd7ba7a6SMilanka Ringwald log_info("HID Control PSM: 0x%04x", (int) &connection->control_psm); 238*fd7ba7a6SMilanka Ringwald break; 239*fd7ba7a6SMilanka Ringwald default: 240*fd7ba7a6SMilanka Ringwald break; 241*fd7ba7a6SMilanka Ringwald } 242*fd7ba7a6SMilanka Ringwald } 243*fd7ba7a6SMilanka Ringwald break; 244*fd7ba7a6SMilanka Ringwald case BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: 245*fd7ba7a6SMilanka Ringwald for (des_iterator_init(&attribute_list_it, attribute_value); des_iterator_has_more(&attribute_list_it); des_iterator_next(&attribute_list_it)) { 246*fd7ba7a6SMilanka Ringwald if (des_iterator_get_type(&attribute_list_it) != DE_DES) continue; 247*fd7ba7a6SMilanka Ringwald des_element = des_iterator_get_element(&attribute_list_it); 248*fd7ba7a6SMilanka Ringwald for (des_iterator_init(&additional_des_it, des_element); des_iterator_has_more(&additional_des_it); des_iterator_next(&additional_des_it)) { 249*fd7ba7a6SMilanka Ringwald if (des_iterator_get_type(&additional_des_it) != DE_DES) continue; 250*fd7ba7a6SMilanka Ringwald des_element = des_iterator_get_element(&additional_des_it); 251*fd7ba7a6SMilanka Ringwald des_iterator_init(&prot_it, des_element); 252*fd7ba7a6SMilanka Ringwald element = des_iterator_get_element(&prot_it); 253*fd7ba7a6SMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 254*fd7ba7a6SMilanka Ringwald uuid = de_get_uuid32(element); 255*fd7ba7a6SMilanka Ringwald switch (uuid){ 256*fd7ba7a6SMilanka Ringwald case BLUETOOTH_PROTOCOL_L2CAP: 257*fd7ba7a6SMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 258*fd7ba7a6SMilanka Ringwald des_iterator_next(&prot_it); 259*fd7ba7a6SMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &connection->interrupt_psm); 260*fd7ba7a6SMilanka Ringwald log_info("HID Interrupt PSM: 0x%04x", (int) &connection->interrupt_psm); 261*fd7ba7a6SMilanka Ringwald break; 262*fd7ba7a6SMilanka Ringwald default: 263*fd7ba7a6SMilanka Ringwald break; 264*fd7ba7a6SMilanka Ringwald } 265*fd7ba7a6SMilanka Ringwald } 266*fd7ba7a6SMilanka Ringwald } 267*fd7ba7a6SMilanka Ringwald break; 268*fd7ba7a6SMilanka Ringwald 269*fd7ba7a6SMilanka Ringwald case BLUETOOTH_ATTRIBUTE_HID_DESCRIPTOR_LIST: 270*fd7ba7a6SMilanka Ringwald for (des_iterator_init(&attribute_list_it, attribute_value); des_iterator_has_more(&attribute_list_it); des_iterator_next(&attribute_list_it)) { 271*fd7ba7a6SMilanka Ringwald if (des_iterator_get_type(&attribute_list_it) != DE_DES) continue; 272*fd7ba7a6SMilanka Ringwald des_element = des_iterator_get_element(&attribute_list_it); 273*fd7ba7a6SMilanka Ringwald for (des_iterator_init(&additional_des_it, des_element); des_iterator_has_more(&additional_des_it); des_iterator_next(&additional_des_it)) { 274*fd7ba7a6SMilanka Ringwald if (des_iterator_get_type(&additional_des_it) != DE_STRING) continue; 275*fd7ba7a6SMilanka Ringwald element = des_iterator_get_element(&additional_des_it); 276*fd7ba7a6SMilanka Ringwald 277*fd7ba7a6SMilanka Ringwald const uint8_t * descriptor = de_get_string(element); 278*fd7ba7a6SMilanka Ringwald uint16_t descriptor_len = de_get_data_size(element); 279*fd7ba7a6SMilanka Ringwald 280*fd7ba7a6SMilanka Ringwald uint16_t i; 281*fd7ba7a6SMilanka Ringwald for (i = 0; i < descriptor_len; i++){ 282*fd7ba7a6SMilanka Ringwald hid_descriptor_storage_store(connection, descriptor[i]); 283*fd7ba7a6SMilanka Ringwald } 284*fd7ba7a6SMilanka Ringwald printf("HID Descriptor:\n"); 285*fd7ba7a6SMilanka Ringwald printf_hexdump(descriptor, descriptor_len); 286*fd7ba7a6SMilanka Ringwald } 287*fd7ba7a6SMilanka Ringwald } 288*fd7ba7a6SMilanka Ringwald break; 289*fd7ba7a6SMilanka Ringwald default: 290*fd7ba7a6SMilanka Ringwald break; 291*fd7ba7a6SMilanka Ringwald } 292*fd7ba7a6SMilanka Ringwald } 293*fd7ba7a6SMilanka Ringwald } else { 294*fd7ba7a6SMilanka Ringwald fprintf(stderr, "SDP attribute value buffer size exceeded: available %d, required %d\n", attribute_value_buffer_size, sdp_event_query_attribute_byte_get_attribute_length(packet)); 295*fd7ba7a6SMilanka Ringwald } 296*fd7ba7a6SMilanka Ringwald break; 297*fd7ba7a6SMilanka Ringwald 298*fd7ba7a6SMilanka Ringwald case SDP_EVENT_QUERY_COMPLETE: 299*fd7ba7a6SMilanka Ringwald if (!connection->control_psm) { 300*fd7ba7a6SMilanka Ringwald printf("HID Control PSM missing\n"); 301*fd7ba7a6SMilanka Ringwald status = ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 302*fd7ba7a6SMilanka Ringwald break; 303*fd7ba7a6SMilanka Ringwald } 304*fd7ba7a6SMilanka Ringwald if (!connection->interrupt_psm) { 305*fd7ba7a6SMilanka Ringwald printf("HID Interrupt PSM missing\n"); 306*fd7ba7a6SMilanka Ringwald status = ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 307*fd7ba7a6SMilanka Ringwald break; 308*fd7ba7a6SMilanka Ringwald } 309*fd7ba7a6SMilanka Ringwald 310*fd7ba7a6SMilanka Ringwald printf("Setup HID\n"); 311*fd7ba7a6SMilanka Ringwald status = l2cap_create_channel(hid_host_packet_handler, connection->remote_addr, connection->control_psm, 48, &connection->control_cid); 312*fd7ba7a6SMilanka Ringwald if (status){ 313*fd7ba7a6SMilanka Ringwald printf("Connecting to HID Control failed: 0x%02x\n", status); 314*fd7ba7a6SMilanka Ringwald } 315*fd7ba7a6SMilanka Ringwald break; 316*fd7ba7a6SMilanka Ringwald 317*fd7ba7a6SMilanka Ringwald default: 318*fd7ba7a6SMilanka Ringwald // bail out, we must have had an incoming connection in the meantime; just trigger next sdp query on complete 319*fd7ba7a6SMilanka Ringwald if (hci_event_packet_get_type(packet) == SDP_EVENT_QUERY_COMPLETE){ 320*fd7ba7a6SMilanka Ringwald (void) sdp_client_register_query_callback(&hid_host_handle_sdp_client_query_request); 321*fd7ba7a6SMilanka Ringwald } 322*fd7ba7a6SMilanka Ringwald return; 323*fd7ba7a6SMilanka Ringwald } 324*fd7ba7a6SMilanka Ringwald 325*fd7ba7a6SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 326*fd7ba7a6SMilanka Ringwald hid_emit_connected_event(connection, status); 327*fd7ba7a6SMilanka Ringwald hid_host_finalize_connection(connection); 328*fd7ba7a6SMilanka Ringwald sdp_query_context_hid_host_control_cid = 0; 329*fd7ba7a6SMilanka Ringwald } 330*fd7ba7a6SMilanka Ringwald } 331*fd7ba7a6SMilanka Ringwald 332*fd7ba7a6SMilanka Ringwald static void hid_host_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 333*fd7ba7a6SMilanka Ringwald UNUSED(channel); 334*fd7ba7a6SMilanka Ringwald UNUSED(size); 335*fd7ba7a6SMilanka Ringwald 33663bf37cdSMilanka Ringwald uint8_t event; 337*fd7ba7a6SMilanka Ringwald bd_addr_t address; 338*fd7ba7a6SMilanka Ringwald uint8_t status; 339*fd7ba7a6SMilanka Ringwald uint16_t cid; 340*fd7ba7a6SMilanka Ringwald hid_host_connection_t * connection; 341*fd7ba7a6SMilanka Ringwald 34263bf37cdSMilanka Ringwald // uint8_t param; 34363bf37cdSMilanka Ringwald // hid_message_type_t message_type; 34463bf37cdSMilanka Ringwald // hid_handshake_param_type_t message_status; 34563bf37cdSMilanka Ringwald 34663bf37cdSMilanka Ringwald switch (packet_type) { 34763bf37cdSMilanka Ringwald case HCI_EVENT_PACKET: 34863bf37cdSMilanka Ringwald event = hci_event_packet_get_type(packet); 34963bf37cdSMilanka Ringwald switch (event) { 350*fd7ba7a6SMilanka Ringwald case L2CAP_EVENT_INCOMING_CONNECTION: 351*fd7ba7a6SMilanka Ringwald l2cap_event_incoming_connection_get_address(packet, address); 352*fd7ba7a6SMilanka Ringwald connection = hid_host_get_connection_for_bd_addr(address); 353*fd7ba7a6SMilanka Ringwald 354*fd7ba7a6SMilanka Ringwald if (connection && connection->unplugged){ 355*fd7ba7a6SMilanka Ringwald log_info("Decline connection for %s, host is unplugged", bd_addr_to_str(address)); 356*fd7ba7a6SMilanka Ringwald l2cap_decline_connection(channel); 357*fd7ba7a6SMilanka Ringwald break; 358*fd7ba7a6SMilanka Ringwald } 359*fd7ba7a6SMilanka Ringwald 360*fd7ba7a6SMilanka Ringwald switch (l2cap_event_incoming_connection_get_psm(packet)){ 361*fd7ba7a6SMilanka Ringwald case PSM_HID_CONTROL: 362*fd7ba7a6SMilanka Ringwald if (connection){ 363*fd7ba7a6SMilanka Ringwald log_error("Connection already exists %s", bd_addr_to_str(address)); 364*fd7ba7a6SMilanka Ringwald l2cap_decline_connection(channel); 365*fd7ba7a6SMilanka Ringwald break; 366*fd7ba7a6SMilanka Ringwald } 367*fd7ba7a6SMilanka Ringwald 368*fd7ba7a6SMilanka Ringwald connection = hid_host_create_connection(address); 369*fd7ba7a6SMilanka Ringwald if (!connection) { 370*fd7ba7a6SMilanka Ringwald log_error("Cannot create connection for %s", bd_addr_to_str(address)); 371*fd7ba7a6SMilanka Ringwald l2cap_decline_connection(channel); 372*fd7ba7a6SMilanka Ringwald break; 373*fd7ba7a6SMilanka Ringwald } 374*fd7ba7a6SMilanka Ringwald 375*fd7ba7a6SMilanka Ringwald connection->state = HID_HOST_W4_CONTROL_CONNECTION_ESTABLISHED; 376*fd7ba7a6SMilanka Ringwald connection->con_handle = l2cap_event_incoming_connection_get_handle(packet); 377*fd7ba7a6SMilanka Ringwald connection->control_cid = l2cap_event_incoming_connection_get_local_cid(packet); 378*fd7ba7a6SMilanka Ringwald connection->incoming = true; 379*fd7ba7a6SMilanka Ringwald log_info("Accept connection on Control channel %s", bd_addr_to_str(address)); 380*fd7ba7a6SMilanka Ringwald l2cap_accept_connection(channel); 381*fd7ba7a6SMilanka Ringwald break; 382*fd7ba7a6SMilanka Ringwald 383*fd7ba7a6SMilanka Ringwald case PSM_HID_INTERRUPT: 384*fd7ba7a6SMilanka Ringwald if (!connection || (connection->interrupt_cid != 0) || (l2cap_event_incoming_connection_get_handle(packet) != connection->con_handle)){ 385*fd7ba7a6SMilanka Ringwald log_error("Decline connection for %s", bd_addr_to_str(address)); 386*fd7ba7a6SMilanka Ringwald l2cap_decline_connection(channel); 387*fd7ba7a6SMilanka Ringwald break; 388*fd7ba7a6SMilanka Ringwald } 389*fd7ba7a6SMilanka Ringwald 390*fd7ba7a6SMilanka Ringwald connection->state = HID_HOST_W4_INTERRUPT_CONNECTION_ESTABLISHED; 391*fd7ba7a6SMilanka Ringwald connection->interrupt_cid = l2cap_event_incoming_connection_get_local_cid(packet); 392*fd7ba7a6SMilanka Ringwald log_info("Accept connection on Interrupt channel %s", bd_addr_to_str(address)); 393*fd7ba7a6SMilanka Ringwald l2cap_accept_connection(channel); 394*fd7ba7a6SMilanka Ringwald break; 395*fd7ba7a6SMilanka Ringwald 396*fd7ba7a6SMilanka Ringwald default: 397*fd7ba7a6SMilanka Ringwald log_info("Decline connection for %s", bd_addr_to_str(address)); 398*fd7ba7a6SMilanka Ringwald l2cap_decline_connection(channel); 399*fd7ba7a6SMilanka Ringwald break; 40063bf37cdSMilanka Ringwald } 40163bf37cdSMilanka Ringwald break; 402*fd7ba7a6SMilanka Ringwald 403*fd7ba7a6SMilanka Ringwald case L2CAP_EVENT_CHANNEL_OPENED: 404*fd7ba7a6SMilanka Ringwald l2cap_event_channel_opened_get_address(packet, address); 405*fd7ba7a6SMilanka Ringwald 406*fd7ba7a6SMilanka Ringwald status = l2cap_event_channel_opened_get_status(packet); 407*fd7ba7a6SMilanka Ringwald if (status){ 408*fd7ba7a6SMilanka Ringwald log_info("L2CAP connection %s failed: 0x%02xn", bd_addr_to_str(address), status); 409*fd7ba7a6SMilanka Ringwald break; 410*fd7ba7a6SMilanka Ringwald } 411*fd7ba7a6SMilanka Ringwald 412*fd7ba7a6SMilanka Ringwald connection = hid_host_get_connection_for_bd_addr(address); 413*fd7ba7a6SMilanka Ringwald if (!connection){ 414*fd7ba7a6SMilanka Ringwald log_error("Connection does not exist %s", bd_addr_to_str(address)); 415*fd7ba7a6SMilanka Ringwald break; 416*fd7ba7a6SMilanka Ringwald } 417*fd7ba7a6SMilanka Ringwald 418*fd7ba7a6SMilanka Ringwald cid = l2cap_event_channel_opened_get_local_cid(packet); 419*fd7ba7a6SMilanka Ringwald 420*fd7ba7a6SMilanka Ringwald switch (l2cap_event_channel_opened_get_psm(packet)){ 421*fd7ba7a6SMilanka Ringwald case PSM_HID_CONTROL: 422*fd7ba7a6SMilanka Ringwald if (connection->state != HID_HOST_W4_CONTROL_CONNECTION_ESTABLISHED) break; 423*fd7ba7a6SMilanka Ringwald connection->state = HID_HOST_CONTROL_CONNECTION_ESTABLISHED; 424*fd7ba7a6SMilanka Ringwald 425*fd7ba7a6SMilanka Ringwald if (connection->boot_mode){ 426*fd7ba7a6SMilanka Ringwald break; 427*fd7ba7a6SMilanka Ringwald } 428*fd7ba7a6SMilanka Ringwald 429*fd7ba7a6SMilanka Ringwald if (!connection->incoming){ 430*fd7ba7a6SMilanka Ringwald status = l2cap_create_channel(hid_host_packet_handler, address, connection->interrupt_psm, 48, &connection->interrupt_cid); 431*fd7ba7a6SMilanka Ringwald if (status){ 432*fd7ba7a6SMilanka Ringwald log_info("Connecting to HID Interrupt failed: 0x%02x", status); 433*fd7ba7a6SMilanka Ringwald break; 434*fd7ba7a6SMilanka Ringwald } 435*fd7ba7a6SMilanka Ringwald connection->con_handle = l2cap_event_channel_opened_get_handle(packet); 436*fd7ba7a6SMilanka Ringwald connection->state = HID_HOST_W4_INTERRUPT_CONNECTION_ESTABLISHED; 437*fd7ba7a6SMilanka Ringwald } 438*fd7ba7a6SMilanka Ringwald break; 439*fd7ba7a6SMilanka Ringwald 440*fd7ba7a6SMilanka Ringwald case PSM_HID_INTERRUPT: 441*fd7ba7a6SMilanka Ringwald if (connection->state != HID_HOST_W4_INTERRUPT_CONNECTION_ESTABLISHED) break; 442*fd7ba7a6SMilanka Ringwald if (connection->con_handle != l2cap_event_channel_opened_get_handle(packet)) break; 443*fd7ba7a6SMilanka Ringwald 444*fd7ba7a6SMilanka Ringwald connection->state = HID_HOST_CONNECTION_ESTABLISHED; 445*fd7ba7a6SMilanka Ringwald hid_emit_connected_event(connection, ERROR_CODE_SUCCESS); 446*fd7ba7a6SMilanka Ringwald 447*fd7ba7a6SMilanka Ringwald log_info("Connection on interrupt channel established, interrupt_cid 0x%02x", connection->interrupt_cid); 448*fd7ba7a6SMilanka Ringwald break; 449*fd7ba7a6SMilanka Ringwald 450*fd7ba7a6SMilanka Ringwald default: 451*fd7ba7a6SMilanka Ringwald break; 452*fd7ba7a6SMilanka Ringwald } 453*fd7ba7a6SMilanka Ringwald // disconnect? 454*fd7ba7a6SMilanka Ringwald break; 455*fd7ba7a6SMilanka Ringwald 45663bf37cdSMilanka Ringwald default: 45763bf37cdSMilanka Ringwald break; 45863bf37cdSMilanka Ringwald } 45963bf37cdSMilanka Ringwald default: 46063bf37cdSMilanka Ringwald break; 46163bf37cdSMilanka Ringwald } 46263bf37cdSMilanka Ringwald } 46363bf37cdSMilanka Ringwald 464*fd7ba7a6SMilanka Ringwald 465*fd7ba7a6SMilanka Ringwald void hid_host_init(uint8_t * hid_descriptor_storage, uint16_t hid_descriptor_storage_len){ 46663bf37cdSMilanka Ringwald hid_host_descriptor_storage = hid_descriptor_storage; 46763bf37cdSMilanka Ringwald hid_host_descriptor_storage_len = hid_descriptor_storage_len; 46863bf37cdSMilanka Ringwald 46963bf37cdSMilanka Ringwald // register L2CAP Services for reconnections 470*fd7ba7a6SMilanka Ringwald l2cap_register_service(hid_host_packet_handler, PSM_HID_INTERRUPT, 0xffff, gap_get_security_level()); 471*fd7ba7a6SMilanka Ringwald l2cap_register_service(hid_host_packet_handler, PSM_HID_CONTROL, 0xffff, gap_get_security_level()); 47263bf37cdSMilanka Ringwald } 47363bf37cdSMilanka Ringwald 47463bf37cdSMilanka Ringwald void hid_host_register_packet_handler(btstack_packet_handler_t callback){ 475*fd7ba7a6SMilanka Ringwald hid_callback = callback; 47663bf37cdSMilanka Ringwald } 47763bf37cdSMilanka Ringwald 478*fd7ba7a6SMilanka Ringwald 479*fd7ba7a6SMilanka Ringwald static void hid_host_handle_start_sdp_client_query(void * context){ 480*fd7ba7a6SMilanka Ringwald UNUSED(context); 481*fd7ba7a6SMilanka Ringwald 482*fd7ba7a6SMilanka Ringwald btstack_linked_list_iterator_t it; 483*fd7ba7a6SMilanka Ringwald btstack_linked_list_iterator_init(&it, &connections); 484*fd7ba7a6SMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 485*fd7ba7a6SMilanka Ringwald hid_host_connection_t * connection = (hid_host_connection_t *)btstack_linked_list_iterator_next(&it); 486*fd7ba7a6SMilanka Ringwald 487*fd7ba7a6SMilanka Ringwald switch (connection->state){ 488*fd7ba7a6SMilanka Ringwald case HID_HOST_W2_SEND_SDP_QUERY: 489*fd7ba7a6SMilanka Ringwald connection->state = HID_HOST_W4_SDP_QUERY_RESULT; 490*fd7ba7a6SMilanka Ringwald break; 491*fd7ba7a6SMilanka Ringwald default: 492*fd7ba7a6SMilanka Ringwald continue; 493*fd7ba7a6SMilanka Ringwald } 494*fd7ba7a6SMilanka Ringwald printf("hid_descriptor_storage_init, start query, cid 0x%02x, %s \n", connection->hid_cid, bd_addr_to_str(connection->remote_addr)); 495*fd7ba7a6SMilanka Ringwald hid_descriptor_storage_init(connection); 496*fd7ba7a6SMilanka Ringwald sdp_query_context_hid_host_control_cid = connection->hid_cid; 497*fd7ba7a6SMilanka Ringwald sdp_client_query_uuid16(&hid_host_handle_sdp_client_query_result, (uint8_t *) connection->remote_addr, BLUETOOTH_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE_SERVICE); 498*fd7ba7a6SMilanka Ringwald return; 499*fd7ba7a6SMilanka Ringwald } 500*fd7ba7a6SMilanka Ringwald } 501*fd7ba7a6SMilanka Ringwald 502*fd7ba7a6SMilanka Ringwald uint8_t hid_host_connect(bd_addr_t remote_addr, hid_protocol_mode_t protocol_mode, uint16_t * hid_cid){ 50363bf37cdSMilanka Ringwald UNUSED(protocol_mode); 504*fd7ba7a6SMilanka Ringwald 505*fd7ba7a6SMilanka Ringwald if (hid_cid == NULL) { 506*fd7ba7a6SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 507*fd7ba7a6SMilanka Ringwald } 508*fd7ba7a6SMilanka Ringwald 509*fd7ba7a6SMilanka Ringwald hid_host_connection_t * connection = hid_host_get_connection_for_bd_addr(remote_addr); 510*fd7ba7a6SMilanka Ringwald if (connection){ 511*fd7ba7a6SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 512*fd7ba7a6SMilanka Ringwald } 513*fd7ba7a6SMilanka Ringwald 514*fd7ba7a6SMilanka Ringwald connection = hid_host_create_connection(remote_addr); 515*fd7ba7a6SMilanka Ringwald if (!connection) return BTSTACK_MEMORY_ALLOC_FAILED; 516*fd7ba7a6SMilanka Ringwald 517*fd7ba7a6SMilanka Ringwald 518*fd7ba7a6SMilanka Ringwald *hid_cid = connection->hid_cid; 519*fd7ba7a6SMilanka Ringwald 520*fd7ba7a6SMilanka Ringwald connection->state = HID_HOST_W2_SEND_SDP_QUERY; 521*fd7ba7a6SMilanka Ringwald connection->incoming = false; 522*fd7ba7a6SMilanka Ringwald connection->control_cid = 0; 523*fd7ba7a6SMilanka Ringwald connection->control_psm = 0; 524*fd7ba7a6SMilanka Ringwald connection->interrupt_cid = 0; 525*fd7ba7a6SMilanka Ringwald connection->interrupt_psm = 0; 526*fd7ba7a6SMilanka Ringwald printf("hid_host_connect, cid 0x%02x, %s \n", connection->hid_cid, bd_addr_to_str(connection->remote_addr)); 527*fd7ba7a6SMilanka Ringwald 528*fd7ba7a6SMilanka Ringwald hid_host_handle_sdp_client_query_request.callback = &hid_host_handle_start_sdp_client_query; 529*fd7ba7a6SMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 530*fd7ba7a6SMilanka Ringwald (void) sdp_client_register_query_callback(&hid_host_handle_sdp_client_query_request); 531*fd7ba7a6SMilanka Ringwald 53263bf37cdSMilanka Ringwald return ERROR_CODE_SUCCESS; 53363bf37cdSMilanka Ringwald } 53463bf37cdSMilanka Ringwald 53563bf37cdSMilanka Ringwald 53663bf37cdSMilanka Ringwald void hid_host_disconnect(uint16_t hid_cid){ 53763bf37cdSMilanka Ringwald UNUSED(hid_cid); 53863bf37cdSMilanka Ringwald } 53963bf37cdSMilanka Ringwald 54063bf37cdSMilanka Ringwald void hid_host_request_can_send_now_event(uint16_t hid_cid){ 54163bf37cdSMilanka Ringwald UNUSED(hid_cid); 54263bf37cdSMilanka Ringwald } 54363bf37cdSMilanka Ringwald 54463bf37cdSMilanka Ringwald void hid_host_send_interrupt_message(uint16_t hid_cid, const uint8_t * message, uint16_t message_len){ 54563bf37cdSMilanka Ringwald UNUSED(hid_cid); 54663bf37cdSMilanka Ringwald UNUSED(message); 54763bf37cdSMilanka Ringwald UNUSED(message_len); 54863bf37cdSMilanka Ringwald } 54963bf37cdSMilanka Ringwald 55063bf37cdSMilanka Ringwald void hid_host_send_control_message(uint16_t hid_cid, const uint8_t * message, uint16_t message_len){ 55163bf37cdSMilanka Ringwald UNUSED(hid_cid); 55263bf37cdSMilanka Ringwald UNUSED(message); 55363bf37cdSMilanka Ringwald UNUSED(message_len); 55463bf37cdSMilanka Ringwald }