void iter(des_iterator_t * des_list_it){ CHECK_EQUAL(des_iterator_get_type(des_list_it), DE_DES); des_iterator_t prot_it; des_iterator_t packet_it; uint8_t * des_element; uint8_t * packet_des; des_element = des_iterator_get_element(des_list_it); for (des_iterator_init(&prot_it, des_element) ; des_iterator_has_more(&prot_it) ; des_iterator_next(&prot_it) ){ if (des_iterator_get_type(&prot_it) != DE_DES){ CHECK_EQUAL_UINT16(&prot_it); continue; } packet_des = des_iterator_get_element(&prot_it); for (des_iterator_init(&packet_it, packet_des) ; des_iterator_has_more(&packet_it) ; des_iterator_next(&packet_it)){ CHECK_EQUAL_UINT16(&packet_it); } } }
static void handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { UNUSED(packet_type); UNUSED(channel); UNUSED(size); des_iterator_t attribute_list_it; des_iterator_t additional_des_it; des_iterator_t prot_it; uint8_t *des_element; uint8_t *element; uint32_t uuid; uint8_t status; switch (hci_event_packet_get_type(packet)){ case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= attribute_value_buffer_size) { attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet); if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) { switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) { case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: for (des_iterator_init(&attribute_list_it, attribute_value); des_iterator_has_more(&attribute_list_it); des_iterator_next(&attribute_list_it)) { if (des_iterator_get_type(&attribute_list_it) != DE_DES) continue; des_element = des_iterator_get_element(&attribute_list_it); des_iterator_init(&prot_it, des_element); element = des_iterator_get_element(&prot_it); if (de_get_element_type(element) != DE_UUID) continue; uuid = de_get_uuid32(element); switch (uuid){ case BLUETOOTH_PROTOCOL_L2CAP: if (!des_iterator_has_more(&prot_it)) continue; des_iterator_next(&prot_it); de_element_get_uint16(des_iterator_get_element(&prot_it), &hid_control_psm); printf("HID Control PSM: 0x%04x\n", (int) hid_control_psm); break; default: break; } } break; case BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: for (des_iterator_init(&attribute_list_it, attribute_value); des_iterator_has_more(&attribute_list_it); des_iterator_next(&attribute_list_it)) { if (des_iterator_get_type(&attribute_list_it) != DE_DES) continue; des_element = des_iterator_get_element(&attribute_list_it); for (des_iterator_init(&additional_des_it, des_element); des_iterator_has_more(&additional_des_it); des_iterator_next(&additional_des_it)) { if (des_iterator_get_type(&additional_des_it) != DE_DES) continue; des_element = des_iterator_get_element(&additional_des_it); des_iterator_init(&prot_it, des_element); element = des_iterator_get_element(&prot_it); if (de_get_element_type(element) != DE_UUID) continue; uuid = de_get_uuid32(element); switch (uuid){ case BLUETOOTH_PROTOCOL_L2CAP: if (!des_iterator_has_more(&prot_it)) continue; des_iterator_next(&prot_it); de_element_get_uint16(des_iterator_get_element(&prot_it), &hid_interrupt_psm); printf("HID Interrupt PSM: 0x%04x\n", (int) hid_interrupt_psm); break; default: break; } } } break; case BLUETOOTH_ATTRIBUTE_HID_DESCRIPTOR_LIST: for (des_iterator_init(&attribute_list_it, attribute_value); des_iterator_has_more(&attribute_list_it); des_iterator_next(&attribute_list_it)) { if (des_iterator_get_type(&attribute_list_it) != DE_DES) continue; des_element = des_iterator_get_element(&attribute_list_it); for (des_iterator_init(&additional_des_it, des_element); des_iterator_has_more(&additional_des_it); des_iterator_next(&additional_des_it)) { if (des_iterator_get_type(&additional_des_it) != DE_STRING) continue; element = des_iterator_get_element(&additional_des_it); const uint8_t * descriptor = de_get_string(element); hid_descriptor_len = de_get_data_size(element); memcpy(hid_descriptor, descriptor, hid_descriptor_len); printf("HID Descriptor:\n"); printf_hexdump(hid_descriptor, hid_descriptor_len); } } break; default: break; } } } else { 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)); } break; case SDP_EVENT_QUERY_COMPLETE: if (!hid_control_psm) { printf("HID Control PSM missing\n"); break; } if (!hid_interrupt_psm) { printf("HID Interrupt PSM missing\n"); break; } printf("Setup HID\n"); status = l2cap_create_channel(packet_handler, remote_addr, hid_control_psm, 48, &l2cap_hid_control_cid); if (status){ printf("Connecting to HID Control failed: 0x%02x\n", status); } break; } }
/* LISTING_START(HandleSDPQUeryResult): Extracting BNEP Protcol UUID and L2CAP PSM */ static void handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ /* LISTING_PAUSE */ des_iterator_t des_list_it; des_iterator_t prot_it; char *str; switch (hci_event_packet_get_type(packet)){ case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: // handle new record if (sdp_event_query_attribute_byte_get_record_id(packet) != record_id){ record_id = sdp_event_query_attribute_byte_get_record_id(packet); printf("\n---\nRecord nr. %u\n", record_id); } assertBuffer(sdp_event_query_attribute_byte_get_attribute_length(packet)); attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet); if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)){ /* LISTING_RESUME */ /* @text The Service Class ID List is a Data Element Sequence (DES) of UUIDs. * The BNEP PAN protocol UUID is within this list. */ switch(sdp_event_query_attribute_byte_get_attribute_id(packet)){ // 0x0001 "Service Class ID List" case SDP_ServiceClassIDList: if (de_get_element_type(attribute_value) != DE_DES) break; for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)){ uint8_t * element = des_iterator_get_element(&des_list_it); if (de_get_element_type(element) != DE_UUID) continue; uint32_t uuid = de_get_uuid32(element); switch (uuid){ case PANU_UUID: case NAP_UUID: case GN_UUID: printf(" ** Attribute 0x%04x: BNEP PAN protocol UUID: %04x\n", sdp_event_query_attribute_byte_get_attribute_id(packet), uuid); break; default: break; } } break; /* LISTING_PAUSE */ // 0x0100 "Service Name" case 0x0100: // 0x0101 "Service Description" case 0x0101: str = get_string_from_data_element(attribute_value); printf(" ** Attribute 0x%04x: %s\n", sdp_event_query_attribute_byte_get_attribute_id(packet), str); free(str); break; /* LISTING_RESUME */ /* @text The Protocol Descriptor List is DES * which contains one DES for each protocol. For PAN serivces, it contains * a DES with the L2CAP Protocol UUID and a PSM, * and another DES with the BNEP UUID and the the BNEP version. */ case SDP_ProtocolDescriptorList:{ printf(" ** Attribute 0x%04x: ", sdp_event_query_attribute_byte_get_attribute_id(packet)); uint16_t l2cap_psm = 0; uint16_t bnep_version = 0; for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)){ if (des_iterator_get_type(&des_list_it) != DE_DES) continue; uint8_t * des_element = des_iterator_get_element(&des_list_it); des_iterator_init(&prot_it, des_element); uint8_t * element = des_iterator_get_element(&prot_it); if (de_get_element_type(element) != DE_UUID) continue; uint32_t uuid = de_get_uuid32(element); switch (uuid){ case SDP_L2CAPProtocol: if (!des_iterator_has_more(&prot_it)) continue; des_iterator_next(&prot_it); de_element_get_uint16(des_iterator_get_element(&prot_it), &l2cap_psm); break; case SDP_BNEPProtocol: if (!des_iterator_has_more(&prot_it)) continue; des_iterator_next(&prot_it); de_element_get_uint16(des_iterator_get_element(&prot_it), &bnep_version); break; default: break; } } printf("l2cap_psm 0x%04x, bnep_version 0x%04x\n", l2cap_psm, bnep_version); } break; /* LISTING_PAUSE */ default: break; } } break; case SDP_EVENT_QUERY_COMPLETE: printf("General query done with status %d.\n\n", sdp_event_query_complete_get_status(packet)); break; } /* LISTING_RESUME */ }