13deb3ec6SMatthias Ringwald /*
23deb3ec6SMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH
33deb3ec6SMatthias Ringwald *
43deb3ec6SMatthias Ringwald * Redistribution and use in source and binary forms, with or without
53deb3ec6SMatthias Ringwald * modification, are permitted provided that the following conditions
63deb3ec6SMatthias Ringwald * are met:
73deb3ec6SMatthias Ringwald *
83deb3ec6SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright
93deb3ec6SMatthias Ringwald * notice, this list of conditions and the following disclaimer.
103deb3ec6SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright
113deb3ec6SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the
123deb3ec6SMatthias Ringwald * documentation and/or other materials provided with the distribution.
133deb3ec6SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of
143deb3ec6SMatthias Ringwald * contributors may be used to endorse or promote products derived
153deb3ec6SMatthias Ringwald * from this software without specific prior written permission.
163deb3ec6SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for
173deb3ec6SMatthias Ringwald * personal benefit and not for any commercial purpose or for
183deb3ec6SMatthias Ringwald * monetary gain.
193deb3ec6SMatthias Ringwald *
203deb3ec6SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
213deb3ec6SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
223deb3ec6SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
242fca4dadSMilanka Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
253deb3ec6SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
263deb3ec6SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
273deb3ec6SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
283deb3ec6SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
293deb3ec6SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
303deb3ec6SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
313deb3ec6SMatthias Ringwald * SUCH DAMAGE.
323deb3ec6SMatthias Ringwald *
333deb3ec6SMatthias Ringwald * Please inquire about commercial licensing options at
343deb3ec6SMatthias Ringwald * contact@bluekitchen-gmbh.com
353deb3ec6SMatthias Ringwald *
363deb3ec6SMatthias Ringwald */
373deb3ec6SMatthias Ringwald
38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "sdp_client.c"
39ab2c6ae4SMatthias Ringwald
403deb3ec6SMatthias Ringwald /*
413deb3ec6SMatthias Ringwald * sdp_client.c
423deb3ec6SMatthias Ringwald */
437907f069SMatthias Ringwald #include "btstack_config.h"
4484e3541eSMilanka Ringwald
4584e3541eSMilanka Ringwald #include "bluetooth_psm.h"
4684e3541eSMilanka Ringwald #include "bluetooth_sdp.h"
4759c6af15SMatthias Ringwald #include "btstack_debug.h"
480e2df43fSMatthias Ringwald #include "btstack_event.h"
4959c6af15SMatthias Ringwald #include "classic/core.h"
5059c6af15SMatthias Ringwald #include "classic/sdp_client.h"
51746ccb7eSMatthias Ringwald #include "classic/sdp_server.h"
52e5057641SMatthias Ringwald #include "classic/sdp_util.h"
5359c6af15SMatthias Ringwald #include "hci_cmd.h"
5459c6af15SMatthias Ringwald #include "l2cap.h"
553deb3ec6SMatthias Ringwald
566c927b22SMatthias Ringwald // Types SDP Parser - Data Element stream helper
576c927b22SMatthias Ringwald typedef enum {
586c927b22SMatthias Ringwald GET_LIST_LENGTH = 1,
596c927b22SMatthias Ringwald GET_RECORD_LENGTH,
606c927b22SMatthias Ringwald GET_ATTRIBUTE_ID_HEADER_LENGTH,
616c927b22SMatthias Ringwald GET_ATTRIBUTE_ID,
626c927b22SMatthias Ringwald GET_ATTRIBUTE_VALUE_LENGTH,
636c927b22SMatthias Ringwald GET_ATTRIBUTE_VALUE
646c927b22SMatthias Ringwald } sdp_parser_state_t;
656c927b22SMatthias Ringwald
666c927b22SMatthias Ringwald // Types SDP Client
673deb3ec6SMatthias Ringwald typedef enum {
683deb3ec6SMatthias Ringwald INIT, W4_CONNECT, W2_SEND, W4_RESPONSE, QUERY_COMPLETE
693deb3ec6SMatthias Ringwald } sdp_client_state_t;
703deb3ec6SMatthias Ringwald
71f20b4214SMatthias Ringwald static uint8_t sdp_client_des_attribute_id_list[] = {0x35, 0x05, 0x0A, 0x00, 0x00, 0xff, 0xff}; // Attribute: 0x0000 - 0xffff
723deb3ec6SMatthias Ringwald
736c927b22SMatthias Ringwald // Prototypes SDP Parser
746c927b22SMatthias Ringwald void sdp_parser_init(btstack_packet_handler_t callback);
756c927b22SMatthias Ringwald void sdp_parser_handle_chunk(uint8_t * data, uint16_t size);
766c927b22SMatthias Ringwald void sdp_parser_handle_done(uint8_t status);
776c927b22SMatthias Ringwald void sdp_parser_init_service_attribute_search(void);
786c927b22SMatthias Ringwald void sdp_parser_init_service_search(void);
796c927b22SMatthias Ringwald void sdp_parser_handle_service_search(uint8_t * data, uint16_t total_count, uint16_t record_handle_count);
803deb3ec6SMatthias Ringwald
816c927b22SMatthias Ringwald // Prototypes SDP Client
826c927b22SMatthias Ringwald void sdp_client_reset(void);
836c927b22SMatthias Ringwald void sdp_client_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
846c927b22SMatthias Ringwald static uint16_t sdp_client_setup_service_search_attribute_request(uint8_t * data);
85a9a4c409SMatthias Ringwald #ifdef ENABLE_SDP_EXTRA_QUERIES
866c927b22SMatthias Ringwald static uint16_t sdp_client_setup_service_search_request(uint8_t * data);
87dbbeec25SMatthias Ringwald static uint16_t sdp_client_setup_service_attribute_request(uint8_t * data);
8823cb683aSMatthias Ringwald static void sdp_client_parse_service_search_response(uint8_t* packet, uint16_t size);
8923cb683aSMatthias Ringwald static void sdp_client_parse_service_attribute_response(uint8_t* packet, uint16_t size);
903deb3ec6SMatthias Ringwald #endif
913deb3ec6SMatthias Ringwald
926c927b22SMatthias Ringwald // State DES Parser
93f20b4214SMatthias Ringwald static de_state_t des_parser_de_header_state;
946c927b22SMatthias Ringwald
956c927b22SMatthias Ringwald // State SDP Parser
96f20b4214SMatthias Ringwald static sdp_parser_state_t sdp_parser_state;
97f20b4214SMatthias Ringwald static uint16_t sdp_parser_attribute_id = 0;
98f20b4214SMatthias Ringwald static uint16_t sdp_parser_attribute_bytes_received;
99f20b4214SMatthias Ringwald static uint16_t sdp_parser_attribute_bytes_delivered;
100f20b4214SMatthias Ringwald static uint16_t sdp_parser_list_offset;
101f20b4214SMatthias Ringwald static uint16_t sdp_parser_list_size;
102f20b4214SMatthias Ringwald static uint16_t sdp_parser_record_offset;
103f20b4214SMatthias Ringwald static uint16_t sdp_parser_record_size;
104f20b4214SMatthias Ringwald static uint16_t sdp_parser_attribute_value_size;
105f20b4214SMatthias Ringwald static int sdp_parser_record_counter;
1066c927b22SMatthias Ringwald static btstack_packet_handler_t sdp_parser_callback;
1076c927b22SMatthias Ringwald
1086c927b22SMatthias Ringwald // State SDP Client
109f20b4214SMatthias Ringwald static uint16_t sdp_client_mtu;
110f20b4214SMatthias Ringwald static uint16_t sdp_client_sdp_cid = 0x40;
111f20b4214SMatthias Ringwald static const uint8_t * sdp_client_service_search_pattern;
112f20b4214SMatthias Ringwald static const uint8_t * sdp_client_attribute_id_list;
113f20b4214SMatthias Ringwald static uint16_t sdp_client_transaction_id;
114f20b4214SMatthias Ringwald static uint8_t sdp_client_continuation_state[16];
115f20b4214SMatthias Ringwald static uint8_t sdp_client_continuation_state_len;
1163deb3ec6SMatthias Ringwald static sdp_client_state_t sdp_client_state = INIT;
117f20b4214SMatthias Ringwald static sdp_pdu_id_t sdp_client_pdu_id = SDP_Invalid;
118e094740eSMatthias Ringwald
119e094740eSMatthias Ringwald // Query registration
120e094740eSMatthias Ringwald static btstack_linked_list_t sdp_client_query_requests;
121e094740eSMatthias Ringwald
122023f2764SMatthias Ringwald #ifdef ENABLE_SDP_EXTRA_QUERIES
123f20b4214SMatthias Ringwald static uint32_t sdp_client_service_record_handle;
124f20b4214SMatthias Ringwald static uint32_t sdp_client_record_handle;
125023f2764SMatthias Ringwald #endif
1263deb3ec6SMatthias Ringwald
1276c927b22SMatthias Ringwald // DES Parser
de_state_init(de_state_t * de_state)1286c927b22SMatthias Ringwald void de_state_init(de_state_t * de_state){
1296c927b22SMatthias Ringwald de_state->in_state_GET_DE_HEADER_LENGTH = 1;
1306c927b22SMatthias Ringwald de_state->addon_header_bytes = 0;
1316c927b22SMatthias Ringwald de_state->de_size = 0;
1326c927b22SMatthias Ringwald de_state->de_offset = 0;
1336c927b22SMatthias Ringwald }
1346c927b22SMatthias Ringwald
de_state_size(uint8_t eventByte,de_state_t * de_state)1356c927b22SMatthias Ringwald int de_state_size(uint8_t eventByte, de_state_t *de_state){
1366c927b22SMatthias Ringwald if (de_state->in_state_GET_DE_HEADER_LENGTH){
1376c927b22SMatthias Ringwald de_state->addon_header_bytes = de_get_header_size(&eventByte) - 1;
1386c927b22SMatthias Ringwald de_state->de_size = 0;
1396c927b22SMatthias Ringwald de_state->de_offset = 0;
1406c927b22SMatthias Ringwald
1416c927b22SMatthias Ringwald if (de_state->addon_header_bytes == 0){
14218e1cd23SMatthias Ringwald // de_nil has no size
14318e1cd23SMatthias Ringwald de_type_t de_type = (de_type_t) (eventByte >> 3);
14418e1cd23SMatthias Ringwald if (de_type == DE_NIL){
14518e1cd23SMatthias Ringwald return 1;
1466c927b22SMatthias Ringwald }
14718e1cd23SMatthias Ringwald // addon_header_bytes == 0 <-> de_size_type in [DE_SIZE_8, ..., DE_SIZE_128]
14818e1cd23SMatthias Ringwald de_state->de_size = 1 << (eventByte & 7);
1496c927b22SMatthias Ringwald return 1;
1506c927b22SMatthias Ringwald }
1516c927b22SMatthias Ringwald de_state->in_state_GET_DE_HEADER_LENGTH = 0;
1526c927b22SMatthias Ringwald return 0;
1536c927b22SMatthias Ringwald }
1546c927b22SMatthias Ringwald
1556c927b22SMatthias Ringwald if (de_state->addon_header_bytes > 0){
1566c927b22SMatthias Ringwald de_state->de_size = (de_state->de_size << 8) | eventByte;
1576c927b22SMatthias Ringwald de_state->addon_header_bytes--;
1586c927b22SMatthias Ringwald }
1596c927b22SMatthias Ringwald if (de_state->addon_header_bytes > 0) return 0;
1606c927b22SMatthias Ringwald // log_info("Data element payload is %d bytes.", de_state->de_size);
1616c927b22SMatthias Ringwald de_state->in_state_GET_DE_HEADER_LENGTH = 1;
1626c927b22SMatthias Ringwald return 1;
1636c927b22SMatthias Ringwald }
1646c927b22SMatthias Ringwald
1656c927b22SMatthias Ringwald // SDP Parser
sdp_parser_emit_value_byte(uint8_t event_byte)1666c927b22SMatthias Ringwald static void sdp_parser_emit_value_byte(uint8_t event_byte){
1676c927b22SMatthias Ringwald uint8_t event[11];
1686c927b22SMatthias Ringwald event[0] = SDP_EVENT_QUERY_ATTRIBUTE_VALUE;
1696c927b22SMatthias Ringwald event[1] = 9;
170f20b4214SMatthias Ringwald little_endian_store_16(event, 2, sdp_parser_record_counter);
171f20b4214SMatthias Ringwald little_endian_store_16(event, 4, sdp_parser_attribute_id);
172f20b4214SMatthias Ringwald little_endian_store_16(event, 6, sdp_parser_attribute_value_size);
173f20b4214SMatthias Ringwald little_endian_store_16(event, 8, sdp_parser_attribute_bytes_delivered);
1746c927b22SMatthias Ringwald event[10] = event_byte;
1756c927b22SMatthias Ringwald (*sdp_parser_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
1766c927b22SMatthias Ringwald }
1776c927b22SMatthias Ringwald
sdp_parser_process_byte(uint8_t eventByte)1786c927b22SMatthias Ringwald static void sdp_parser_process_byte(uint8_t eventByte){
1796c927b22SMatthias Ringwald // count all bytes
180f20b4214SMatthias Ringwald sdp_parser_list_offset++;
181f20b4214SMatthias Ringwald sdp_parser_record_offset++;
1826c927b22SMatthias Ringwald
1836c927b22SMatthias Ringwald // log_info(" parse BYTE_RECEIVED %02x", eventByte);
184f20b4214SMatthias Ringwald switch(sdp_parser_state){
1856c927b22SMatthias Ringwald case GET_LIST_LENGTH:
186f20b4214SMatthias Ringwald if (!de_state_size(eventByte, &des_parser_de_header_state)) break;
187f20b4214SMatthias Ringwald sdp_parser_list_offset = des_parser_de_header_state.de_offset;
188f20b4214SMatthias Ringwald sdp_parser_list_size = des_parser_de_header_state.de_size;
1896c927b22SMatthias Ringwald // log_info("parser: List offset %u, list size %u", list_offset, list_size);
1906c927b22SMatthias Ringwald
191f20b4214SMatthias Ringwald sdp_parser_record_counter = 0;
192f20b4214SMatthias Ringwald sdp_parser_state = GET_RECORD_LENGTH;
1936c927b22SMatthias Ringwald break;
1946c927b22SMatthias Ringwald
1956c927b22SMatthias Ringwald case GET_RECORD_LENGTH:
1966c927b22SMatthias Ringwald // check size
197f20b4214SMatthias Ringwald if (!de_state_size(eventByte, &des_parser_de_header_state)) break;
1986c927b22SMatthias Ringwald // log_info("parser: Record payload is %d bytes.", de_header_state.de_size);
199f20b4214SMatthias Ringwald sdp_parser_record_offset = des_parser_de_header_state.de_offset;
200f20b4214SMatthias Ringwald sdp_parser_record_size = des_parser_de_header_state.de_size;
201f20b4214SMatthias Ringwald sdp_parser_state = GET_ATTRIBUTE_ID_HEADER_LENGTH;
2026c927b22SMatthias Ringwald break;
2036c927b22SMatthias Ringwald
2046c927b22SMatthias Ringwald case GET_ATTRIBUTE_ID_HEADER_LENGTH:
205f20b4214SMatthias Ringwald if (!de_state_size(eventByte, &des_parser_de_header_state)) break;
206f20b4214SMatthias Ringwald sdp_parser_attribute_id = 0;
207f20b4214SMatthias Ringwald log_debug("ID data is stored in %d bytes.", (int) des_parser_de_header_state.de_size);
208f20b4214SMatthias Ringwald sdp_parser_state = GET_ATTRIBUTE_ID;
2096c927b22SMatthias Ringwald break;
2106c927b22SMatthias Ringwald
2116c927b22SMatthias Ringwald case GET_ATTRIBUTE_ID:
212f20b4214SMatthias Ringwald sdp_parser_attribute_id = (sdp_parser_attribute_id << 8) | eventByte;
213f20b4214SMatthias Ringwald des_parser_de_header_state.de_size--;
214f20b4214SMatthias Ringwald if (des_parser_de_header_state.de_size > 0) break;
215f20b4214SMatthias Ringwald log_debug("parser: Attribute ID: %04x.", sdp_parser_attribute_id);
2166c927b22SMatthias Ringwald
217f20b4214SMatthias Ringwald sdp_parser_state = GET_ATTRIBUTE_VALUE_LENGTH;
218f20b4214SMatthias Ringwald sdp_parser_attribute_bytes_received = 0;
219f20b4214SMatthias Ringwald sdp_parser_attribute_bytes_delivered = 0;
220f20b4214SMatthias Ringwald sdp_parser_attribute_value_size = 0;
221f20b4214SMatthias Ringwald de_state_init(&des_parser_de_header_state);
2226c927b22SMatthias Ringwald break;
2236c927b22SMatthias Ringwald
2246c927b22SMatthias Ringwald case GET_ATTRIBUTE_VALUE_LENGTH:
225f20b4214SMatthias Ringwald sdp_parser_attribute_bytes_received++;
2266c927b22SMatthias Ringwald sdp_parser_emit_value_byte(eventByte);
227f20b4214SMatthias Ringwald sdp_parser_attribute_bytes_delivered++;
228f20b4214SMatthias Ringwald if (!de_state_size(eventByte, &des_parser_de_header_state)) break;
2296c927b22SMatthias Ringwald
230f20b4214SMatthias Ringwald sdp_parser_attribute_value_size = des_parser_de_header_state.de_size + sdp_parser_attribute_bytes_received;
2316c927b22SMatthias Ringwald
232f20b4214SMatthias Ringwald sdp_parser_state = GET_ATTRIBUTE_VALUE;
2336c927b22SMatthias Ringwald break;
2346c927b22SMatthias Ringwald
2356c927b22SMatthias Ringwald case GET_ATTRIBUTE_VALUE:
236f20b4214SMatthias Ringwald sdp_parser_attribute_bytes_received++;
2376c927b22SMatthias Ringwald sdp_parser_emit_value_byte(eventByte);
238f20b4214SMatthias Ringwald sdp_parser_attribute_bytes_delivered++;
239b6011ef1SMatthias Ringwald // log_debug("paser: attribute_bytes_received %u, attribute_value_size %u", attribute_bytes_received, attribute_value_size);
2406c927b22SMatthias Ringwald
241f20b4214SMatthias Ringwald if (sdp_parser_attribute_bytes_received < sdp_parser_attribute_value_size) break;
242b6011ef1SMatthias Ringwald // log_debug("parser: Record offset %u, record size %u", record_offset, record_size);
243f20b4214SMatthias Ringwald if (sdp_parser_record_offset != sdp_parser_record_size){
244f20b4214SMatthias Ringwald sdp_parser_state = GET_ATTRIBUTE_ID_HEADER_LENGTH;
245b6011ef1SMatthias Ringwald // log_debug("Get next attribute");
2466c927b22SMatthias Ringwald break;
2476c927b22SMatthias Ringwald }
248f20b4214SMatthias Ringwald sdp_parser_record_offset = 0;
249b6011ef1SMatthias Ringwald // log_debug("parser: List offset %u, list size %u", list_offset, list_size);
2506c927b22SMatthias Ringwald
251f20b4214SMatthias Ringwald if ((sdp_parser_list_size > 0) && (sdp_parser_list_offset != sdp_parser_list_size)){
252f20b4214SMatthias Ringwald sdp_parser_record_counter++;
253f20b4214SMatthias Ringwald sdp_parser_state = GET_RECORD_LENGTH;
254b6011ef1SMatthias Ringwald log_debug("parser: END_OF_RECORD");
2556c927b22SMatthias Ringwald break;
2566c927b22SMatthias Ringwald }
257f20b4214SMatthias Ringwald sdp_parser_list_offset = 0;
258f20b4214SMatthias Ringwald de_state_init(&des_parser_de_header_state);
259f20b4214SMatthias Ringwald sdp_parser_state = GET_LIST_LENGTH;
260f20b4214SMatthias Ringwald sdp_parser_record_counter = 0;
261b6011ef1SMatthias Ringwald log_debug("parser: END_OF_RECORD & DONE");
2626c927b22SMatthias Ringwald break;
2636c927b22SMatthias Ringwald default:
2646c927b22SMatthias Ringwald break;
2656c927b22SMatthias Ringwald }
2666c927b22SMatthias Ringwald }
2676c927b22SMatthias Ringwald
sdp_parser_init(btstack_packet_handler_t callback)2686c927b22SMatthias Ringwald void sdp_parser_init(btstack_packet_handler_t callback){
2696c927b22SMatthias Ringwald // init
2706c927b22SMatthias Ringwald sdp_parser_callback = callback;
271f20b4214SMatthias Ringwald de_state_init(&des_parser_de_header_state);
272f20b4214SMatthias Ringwald sdp_parser_state = GET_LIST_LENGTH;
273f20b4214SMatthias Ringwald sdp_parser_list_offset = 0;
274f20b4214SMatthias Ringwald sdp_parser_list_size = 0;
275f20b4214SMatthias Ringwald sdp_parser_record_offset = 0;
276f20b4214SMatthias Ringwald sdp_parser_record_counter = 0;
277f20b4214SMatthias Ringwald sdp_parser_record_size = 0;
278f20b4214SMatthias Ringwald sdp_parser_attribute_id = 0;
279f20b4214SMatthias Ringwald sdp_parser_attribute_bytes_received = 0;
280f20b4214SMatthias Ringwald sdp_parser_attribute_bytes_delivered = 0;
2810396d6ccSMatthias Ringwald }
2820396d6ccSMatthias Ringwald
sdp_parser_deinit(void)2830396d6ccSMatthias Ringwald static void sdp_parser_deinit(void) {
2840396d6ccSMatthias Ringwald sdp_parser_callback = NULL;
285f20b4214SMatthias Ringwald sdp_parser_attribute_value_size = 0;
286f20b4214SMatthias Ringwald sdp_parser_record_counter = 0;
2870396d6ccSMatthias Ringwald }
2880396d6ccSMatthias Ringwald
sdp_client_init(void)2890396d6ccSMatthias Ringwald void sdp_client_init(void){
2900396d6ccSMatthias Ringwald }
2910396d6ccSMatthias Ringwald
sdp_client_deinit(void)2920396d6ccSMatthias Ringwald void sdp_client_deinit(void){
2930396d6ccSMatthias Ringwald sdp_parser_deinit();
2940396d6ccSMatthias Ringwald sdp_client_state = INIT;
295f20b4214SMatthias Ringwald sdp_client_sdp_cid = 0x40;
296f20b4214SMatthias Ringwald sdp_client_service_search_pattern = NULL;
297f20b4214SMatthias Ringwald sdp_client_attribute_id_list = NULL;
298f20b4214SMatthias Ringwald sdp_client_transaction_id = 0;
299f20b4214SMatthias Ringwald sdp_client_continuation_state_len = 0;
3000396d6ccSMatthias Ringwald sdp_client_state = INIT;
301f20b4214SMatthias Ringwald sdp_client_pdu_id = SDP_Invalid;
3020396d6ccSMatthias Ringwald #ifdef ENABLE_SDP_EXTRA_QUERIES
303f20b4214SMatthias Ringwald sdp_client_service_record_handle = 0;
304f20b4214SMatthias Ringwald sdp_client_record_handle = 0;
3050396d6ccSMatthias Ringwald #endif
3060396d6ccSMatthias Ringwald }
3070396d6ccSMatthias Ringwald
3080396d6ccSMatthias Ringwald // for testing only
sdp_client_reset(void)3090396d6ccSMatthias Ringwald void sdp_client_reset(void){
3100396d6ccSMatthias Ringwald sdp_client_deinit();
3116c927b22SMatthias Ringwald }
3126c927b22SMatthias Ringwald
sdp_parser_handle_chunk(uint8_t * data,uint16_t size)3136c927b22SMatthias Ringwald void sdp_parser_handle_chunk(uint8_t * data, uint16_t size){
3146c927b22SMatthias Ringwald int i;
3156c927b22SMatthias Ringwald for (i=0;i<size;i++){
3166c927b22SMatthias Ringwald sdp_parser_process_byte(data[i]);
3176c927b22SMatthias Ringwald }
3186c927b22SMatthias Ringwald }
3196c927b22SMatthias Ringwald
3206c927b22SMatthias Ringwald #ifdef ENABLE_SDP_EXTRA_QUERIES
sdp_parser_init_service_attribute_search(void)3216c927b22SMatthias Ringwald void sdp_parser_init_service_attribute_search(void){
3226c927b22SMatthias Ringwald // init
323f20b4214SMatthias Ringwald de_state_init(&des_parser_de_header_state);
324f20b4214SMatthias Ringwald sdp_parser_state = GET_RECORD_LENGTH;
325f20b4214SMatthias Ringwald sdp_parser_list_offset = 0;
326f20b4214SMatthias Ringwald sdp_parser_record_offset = 0;
327f20b4214SMatthias Ringwald sdp_parser_record_counter = 0;
3286c927b22SMatthias Ringwald }
3296c927b22SMatthias Ringwald
sdp_parser_init_service_search(void)3306c927b22SMatthias Ringwald void sdp_parser_init_service_search(void){
331f20b4214SMatthias Ringwald sdp_parser_record_offset = 0;
3326c927b22SMatthias Ringwald }
3336c927b22SMatthias Ringwald
sdp_parser_handle_service_search(uint8_t * data,uint16_t total_count,uint16_t record_handle_count)3346c927b22SMatthias Ringwald void sdp_parser_handle_service_search(uint8_t * data, uint16_t total_count, uint16_t record_handle_count){
3356c927b22SMatthias Ringwald int i;
3366c927b22SMatthias Ringwald for (i=0;i<record_handle_count;i++){
337f20b4214SMatthias Ringwald sdp_client_record_handle = big_endian_read_32(data, i * 4);
338f20b4214SMatthias Ringwald sdp_parser_record_counter++;
3396c927b22SMatthias Ringwald uint8_t event[10];
3406c927b22SMatthias Ringwald event[0] = SDP_EVENT_QUERY_SERVICE_RECORD_HANDLE;
3416c927b22SMatthias Ringwald event[1] = 8;
3426c927b22SMatthias Ringwald little_endian_store_16(event, 2, total_count);
343f20b4214SMatthias Ringwald little_endian_store_16(event, 4, sdp_parser_record_counter);
344f20b4214SMatthias Ringwald little_endian_store_32(event, 6, sdp_client_record_handle);
3456c927b22SMatthias Ringwald (*sdp_parser_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
3466c927b22SMatthias Ringwald }
3476c927b22SMatthias Ringwald }
3486c927b22SMatthias Ringwald #endif
3496c927b22SMatthias Ringwald
sdp_client_notify_callbacks(void)350e094740eSMatthias Ringwald static void sdp_client_notify_callbacks(void){
351*166d44a1SMatthias Ringwald while (sdp_client_ready()) {
35297b601cfSMatthias Ringwald btstack_context_callback_registration_t *callback = (btstack_context_callback_registration_t *) btstack_linked_list_pop(&sdp_client_query_requests);
353*166d44a1SMatthias Ringwald if (callback != NULL) {
354*166d44a1SMatthias Ringwald (*callback->callback)(callback->context);
355*166d44a1SMatthias Ringwald } else {
356e094740eSMatthias Ringwald return;
357e094740eSMatthias Ringwald }
358*166d44a1SMatthias Ringwald }
359e094740eSMatthias Ringwald }
360e094740eSMatthias Ringwald
sdp_parser_handle_done(uint8_t status)3616c927b22SMatthias Ringwald void sdp_parser_handle_done(uint8_t status){
362e094740eSMatthias Ringwald // reset state
363e094740eSMatthias Ringwald sdp_client_state = INIT;
364e094740eSMatthias Ringwald
365e094740eSMatthias Ringwald // emit query complete event
3666c927b22SMatthias Ringwald uint8_t event[3];
3676c927b22SMatthias Ringwald event[0] = SDP_EVENT_QUERY_COMPLETE;
3686c927b22SMatthias Ringwald event[1] = 1;
3696c927b22SMatthias Ringwald event[2] = status;
3706c927b22SMatthias Ringwald (*sdp_parser_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
371e094740eSMatthias Ringwald
372e094740eSMatthias Ringwald // trigger next query if pending
373e094740eSMatthias Ringwald sdp_client_notify_callbacks();
3746c927b22SMatthias Ringwald }
3756c927b22SMatthias Ringwald
3766c927b22SMatthias Ringwald // SDP Client
3776c927b22SMatthias Ringwald
3783deb3ec6SMatthias Ringwald // TODO: inline if not needed (des(des))
3793deb3ec6SMatthias Ringwald
sdp_client_parse_attribute_lists(uint8_t * packet,uint16_t length)3806c927b22SMatthias Ringwald static void sdp_client_parse_attribute_lists(uint8_t* packet, uint16_t length){
3816c927b22SMatthias Ringwald sdp_parser_handle_chunk(packet, length);
3826c927b22SMatthias Ringwald }
3836c927b22SMatthias Ringwald
3846c927b22SMatthias Ringwald
sdp_client_send_request(uint16_t channel)3856c927b22SMatthias Ringwald static void sdp_client_send_request(uint16_t channel){
386fffd8860SMatthias Ringwald
387fffd8860SMatthias Ringwald if (sdp_client_state != W2_SEND) return;
388fffd8860SMatthias Ringwald
3893deb3ec6SMatthias Ringwald l2cap_reserve_packet_buffer();
3903deb3ec6SMatthias Ringwald uint8_t * data = l2cap_get_outgoing_buffer();
3913deb3ec6SMatthias Ringwald uint16_t request_len = 0;
3923deb3ec6SMatthias Ringwald
393f20b4214SMatthias Ringwald switch (sdp_client_pdu_id){
394a9a4c409SMatthias Ringwald #ifdef ENABLE_SDP_EXTRA_QUERIES
3953deb3ec6SMatthias Ringwald case SDP_ServiceSearchResponse:
3966c927b22SMatthias Ringwald request_len = sdp_client_setup_service_search_request(data);
3973deb3ec6SMatthias Ringwald break;
3983deb3ec6SMatthias Ringwald case SDP_ServiceAttributeResponse:
3996c927b22SMatthias Ringwald request_len = sdp_client_setup_service_attribute_request(data);
4003deb3ec6SMatthias Ringwald break;
4013deb3ec6SMatthias Ringwald #endif
4023deb3ec6SMatthias Ringwald case SDP_ServiceSearchAttributeResponse:
4036c927b22SMatthias Ringwald request_len = sdp_client_setup_service_search_attribute_request(data);
4043deb3ec6SMatthias Ringwald break;
4053deb3ec6SMatthias Ringwald default:
406f20b4214SMatthias Ringwald log_error("SDP Client sdp_client_send_request :: PDU ID invalid. %u", sdp_client_pdu_id);
4073deb3ec6SMatthias Ringwald return;
4083deb3ec6SMatthias Ringwald }
4093deb3ec6SMatthias Ringwald
4103deb3ec6SMatthias Ringwald // prevent re-entrance
4113deb3ec6SMatthias Ringwald sdp_client_state = W4_RESPONSE;
412f20b4214SMatthias Ringwald sdp_client_pdu_id = SDP_Invalid;
413fffd8860SMatthias Ringwald l2cap_send_prepared(channel, request_len);
4143deb3ec6SMatthias Ringwald }
4153deb3ec6SMatthias Ringwald
4163deb3ec6SMatthias Ringwald
sdp_client_parse_service_search_attribute_response(uint8_t * packet,uint16_t size)41723cb683aSMatthias Ringwald static void sdp_client_parse_service_search_attribute_response(uint8_t* packet, uint16_t size){
41823cb683aSMatthias Ringwald
4193deb3ec6SMatthias Ringwald uint16_t offset = 3;
420c1ab6cc1SMatthias Ringwald if ((offset + 2 + 2) > size) return; // parameterLength + attributeListByteCount
421f8fbdce0SMatthias Ringwald uint16_t parameterLength = big_endian_read_16(packet,offset);
4223deb3ec6SMatthias Ringwald offset+=2;
423c1ab6cc1SMatthias Ringwald if ((offset + parameterLength) > size) return;
4245fce6058SMatthias Ringwald
4253deb3ec6SMatthias Ringwald // AttributeListByteCount <= mtu
426f8fbdce0SMatthias Ringwald uint16_t attributeListByteCount = big_endian_read_16(packet,offset);
4273deb3ec6SMatthias Ringwald offset+=2;
428f20b4214SMatthias Ringwald if (attributeListByteCount > sdp_client_mtu){
4293deb3ec6SMatthias Ringwald log_error("Error parsing ServiceSearchAttributeResponse: Number of bytes in found attribute list is larger then the MaximumAttributeByteCount.");
4303deb3ec6SMatthias Ringwald return;
4313deb3ec6SMatthias Ringwald }
4323deb3ec6SMatthias Ringwald
4333deb3ec6SMatthias Ringwald // AttributeLists
434c1ab6cc1SMatthias Ringwald if ((offset + attributeListByteCount) > size) return;
4356c927b22SMatthias Ringwald sdp_client_parse_attribute_lists(packet+offset, attributeListByteCount);
4363deb3ec6SMatthias Ringwald offset+=attributeListByteCount;
4373deb3ec6SMatthias Ringwald
4385fce6058SMatthias Ringwald // continuation state len
439c1ab6cc1SMatthias Ringwald if ((offset + 1) > size) return;
440f20b4214SMatthias Ringwald sdp_client_continuation_state_len = packet[offset];
4413deb3ec6SMatthias Ringwald offset++;
442f20b4214SMatthias Ringwald if (sdp_client_continuation_state_len > 16){
443f20b4214SMatthias Ringwald sdp_client_continuation_state_len = 0;
4443deb3ec6SMatthias Ringwald log_error("Error parsing ServiceSearchAttributeResponse: Number of bytes in continuation state exceedes 16.");
4453deb3ec6SMatthias Ringwald return;
4463deb3ec6SMatthias Ringwald }
4473deb3ec6SMatthias Ringwald
4485fce6058SMatthias Ringwald // continuation state
449f20b4214SMatthias Ringwald if ((offset + sdp_client_continuation_state_len) > size) return;
450f20b4214SMatthias Ringwald (void)memcpy(sdp_client_continuation_state, packet + offset, sdp_client_continuation_state_len);
4515fce6058SMatthias Ringwald // offset+=continuationStateLen;
4523deb3ec6SMatthias Ringwald }
4533deb3ec6SMatthias Ringwald
sdp_client_packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)4546c927b22SMatthias Ringwald void sdp_client_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
4559ec2630cSMatthias Ringwald
4563deb3ec6SMatthias Ringwald // uint16_t handle;
4573deb3ec6SMatthias Ringwald if (packet_type == L2CAP_DATA_PACKET){
4587a26a620SMatthias Ringwald if (size < 3) return;
459f8fbdce0SMatthias Ringwald uint16_t responseTransactionID = big_endian_read_16(packet,1);
460f20b4214SMatthias Ringwald if (responseTransactionID != sdp_client_transaction_id){
461f20b4214SMatthias Ringwald log_error("Mismatching transaction ID, expected %u, found %u.", sdp_client_transaction_id, responseTransactionID);
46263155797SMatthias Ringwald return;
46363155797SMatthias Ringwald }
46463155797SMatthias Ringwald
465f20b4214SMatthias Ringwald sdp_client_pdu_id = (sdp_pdu_id_t)packet[0];
466f20b4214SMatthias Ringwald switch (sdp_client_pdu_id){
4677a26a620SMatthias Ringwald case SDP_ErrorResponse:
46863155797SMatthias Ringwald log_error("Received error response with code %u, disconnecting", packet[2]);
469b93f8966SMatthias Ringwald l2cap_disconnect(sdp_client_sdp_cid);
4703deb3ec6SMatthias Ringwald return;
471a9a4c409SMatthias Ringwald #ifdef ENABLE_SDP_EXTRA_QUERIES
4723deb3ec6SMatthias Ringwald case SDP_ServiceSearchResponse:
47323cb683aSMatthias Ringwald sdp_client_parse_service_search_response(packet, size);
4743deb3ec6SMatthias Ringwald break;
4753deb3ec6SMatthias Ringwald case SDP_ServiceAttributeResponse:
47623cb683aSMatthias Ringwald sdp_client_parse_service_attribute_response(packet, size);
4773deb3ec6SMatthias Ringwald break;
4783deb3ec6SMatthias Ringwald #endif
4793deb3ec6SMatthias Ringwald case SDP_ServiceSearchAttributeResponse:
48023cb683aSMatthias Ringwald sdp_client_parse_service_search_attribute_response(packet, size);
4813deb3ec6SMatthias Ringwald break;
4823deb3ec6SMatthias Ringwald default:
483f20b4214SMatthias Ringwald log_error("PDU ID %u unexpected/invalid", sdp_client_pdu_id);
4843deb3ec6SMatthias Ringwald return;
4853deb3ec6SMatthias Ringwald }
4863deb3ec6SMatthias Ringwald
4873deb3ec6SMatthias Ringwald // continuation set or DONE?
488f20b4214SMatthias Ringwald if (sdp_client_continuation_state_len == 0){
489b6011ef1SMatthias Ringwald log_debug("SDP Client Query DONE! ");
4903deb3ec6SMatthias Ringwald sdp_client_state = QUERY_COMPLETE;
491b93f8966SMatthias Ringwald l2cap_disconnect(sdp_client_sdp_cid);
4923deb3ec6SMatthias Ringwald return;
4933deb3ec6SMatthias Ringwald }
4943deb3ec6SMatthias Ringwald // prepare next request and send
4953deb3ec6SMatthias Ringwald sdp_client_state = W2_SEND;
496f20b4214SMatthias Ringwald l2cap_request_can_send_now_event(sdp_client_sdp_cid);
4973deb3ec6SMatthias Ringwald return;
4983deb3ec6SMatthias Ringwald }
4993deb3ec6SMatthias Ringwald
5003deb3ec6SMatthias Ringwald if (packet_type != HCI_EVENT_PACKET) return;
5013deb3ec6SMatthias Ringwald
5020e2df43fSMatthias Ringwald switch(hci_event_packet_get_type(packet)){
5033deb3ec6SMatthias Ringwald case L2CAP_EVENT_CHANNEL_OPENED:
5043deb3ec6SMatthias Ringwald if (sdp_client_state != W4_CONNECT) break;
5053deb3ec6SMatthias Ringwald // data: event (8), len(8), status (8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16), local_mtu(16), remote_mtu(16)
5063deb3ec6SMatthias Ringwald if (packet[2]) {
5078590747aSMilanka Ringwald log_info("SDP Client Connection failed, status 0x%02x.", packet[2]);
5083deb3ec6SMatthias Ringwald sdp_parser_handle_done(packet[2]);
5093deb3ec6SMatthias Ringwald break;
5103deb3ec6SMatthias Ringwald }
511f20b4214SMatthias Ringwald sdp_client_sdp_cid = channel;
512f20b4214SMatthias Ringwald sdp_client_mtu = little_endian_read_16(packet, 17);
513f8fbdce0SMatthias Ringwald // handle = little_endian_read_16(packet, 9);
514f20b4214SMatthias Ringwald log_debug("SDP Client Connected, cid %x, mtu %u.", sdp_client_sdp_cid, sdp_client_mtu);
5153deb3ec6SMatthias Ringwald
5163deb3ec6SMatthias Ringwald sdp_client_state = W2_SEND;
517f20b4214SMatthias Ringwald l2cap_request_can_send_now_event(sdp_client_sdp_cid);
5183deb3ec6SMatthias Ringwald break;
519fffd8860SMatthias Ringwald
5201b89a84bSMatthias Ringwald case L2CAP_EVENT_CAN_SEND_NOW:
521f20b4214SMatthias Ringwald if(l2cap_event_can_send_now_get_local_cid(packet) == sdp_client_sdp_cid){
522f20b4214SMatthias Ringwald sdp_client_send_request(sdp_client_sdp_cid);
523fffd8860SMatthias Ringwald }
5243deb3ec6SMatthias Ringwald break;
5253deb3ec6SMatthias Ringwald case L2CAP_EVENT_CHANNEL_CLOSED: {
526f20b4214SMatthias Ringwald if (sdp_client_sdp_cid != little_endian_read_16(packet, 2)) {
527f8fbdce0SMatthias Ringwald // log_info("Received L2CAP_EVENT_CHANNEL_CLOSED for cid %x, current cid %x\n", little_endian_read_16(packet, 2),sdp_cid);
5283deb3ec6SMatthias Ringwald break;
5293deb3ec6SMatthias Ringwald }
5303deb3ec6SMatthias Ringwald log_info("SDP Client disconnected.");
531505f1c30SMatthias Ringwald uint8_t status = (sdp_client_state == QUERY_COMPLETE) ? 0 : SDP_QUERY_INCOMPLETE;
5323deb3ec6SMatthias Ringwald sdp_parser_handle_done(status);
5333deb3ec6SMatthias Ringwald break;
5343deb3ec6SMatthias Ringwald }
5353deb3ec6SMatthias Ringwald default:
5363deb3ec6SMatthias Ringwald break;
5373deb3ec6SMatthias Ringwald }
5383deb3ec6SMatthias Ringwald }
5393deb3ec6SMatthias Ringwald
5403deb3ec6SMatthias Ringwald
sdp_client_setup_service_search_attribute_request(uint8_t * data)5416c927b22SMatthias Ringwald static uint16_t sdp_client_setup_service_search_attribute_request(uint8_t * data){
5423deb3ec6SMatthias Ringwald
5433deb3ec6SMatthias Ringwald uint16_t offset = 0;
544f20b4214SMatthias Ringwald sdp_client_transaction_id++;
5453deb3ec6SMatthias Ringwald // uint8_t SDP_PDU_ID_t.SDP_ServiceSearchRequest;
5463deb3ec6SMatthias Ringwald data[offset++] = SDP_ServiceSearchAttributeRequest;
5473deb3ec6SMatthias Ringwald // uint16_t transactionID
548f20b4214SMatthias Ringwald big_endian_store_16(data, offset, sdp_client_transaction_id);
5493deb3ec6SMatthias Ringwald offset += 2;
5503deb3ec6SMatthias Ringwald
5513deb3ec6SMatthias Ringwald // param legnth
5523deb3ec6SMatthias Ringwald offset += 2;
5533deb3ec6SMatthias Ringwald
5543deb3ec6SMatthias Ringwald // parameters:
5556c927b22SMatthias Ringwald // Service_search_pattern - DES (min 1 UUID, max 12)
556f20b4214SMatthias Ringwald uint16_t service_search_pattern_len = de_get_len(sdp_client_service_search_pattern);
557f20b4214SMatthias Ringwald (void)memcpy(data + offset, sdp_client_service_search_pattern,
5586535961aSMatthias Ringwald service_search_pattern_len);
5596c927b22SMatthias Ringwald offset += service_search_pattern_len;
5603deb3ec6SMatthias Ringwald
5613deb3ec6SMatthias Ringwald // MaximumAttributeByteCount - uint16_t 0x0007 - 0xffff -> mtu
562f20b4214SMatthias Ringwald big_endian_store_16(data, offset, sdp_client_mtu);
5633deb3ec6SMatthias Ringwald offset += 2;
5643deb3ec6SMatthias Ringwald
5653deb3ec6SMatthias Ringwald // AttibuteIDList
566f20b4214SMatthias Ringwald uint16_t attribute_id_list_len = de_get_len(sdp_client_attribute_id_list);
567f20b4214SMatthias Ringwald (void)memcpy(data + offset, sdp_client_attribute_id_list, attribute_id_list_len);
5686c927b22SMatthias Ringwald offset += attribute_id_list_len;
5693deb3ec6SMatthias Ringwald
5703deb3ec6SMatthias Ringwald // ContinuationState - uint8_t number of cont. bytes N<=16
571f20b4214SMatthias Ringwald data[offset++] = sdp_client_continuation_state_len;
5723deb3ec6SMatthias Ringwald // - N-bytes previous response from server
573f20b4214SMatthias Ringwald (void)memcpy(data + offset, sdp_client_continuation_state, sdp_client_continuation_state_len);
574f20b4214SMatthias Ringwald offset += sdp_client_continuation_state_len;
5753deb3ec6SMatthias Ringwald
5763deb3ec6SMatthias Ringwald // uint16_t paramLength
577f8fbdce0SMatthias Ringwald big_endian_store_16(data, 3, offset - 5);
5783deb3ec6SMatthias Ringwald
5793deb3ec6SMatthias Ringwald return offset;
5803deb3ec6SMatthias Ringwald }
5813deb3ec6SMatthias Ringwald
582a9a4c409SMatthias Ringwald #ifdef ENABLE_SDP_EXTRA_QUERIES
sdp_client_parse_service_record_handle_list(uint8_t * packet,uint16_t total_count,uint16_t current_count)5836c927b22SMatthias Ringwald void sdp_client_parse_service_record_handle_list(uint8_t* packet, uint16_t total_count, uint16_t current_count){
5843deb3ec6SMatthias Ringwald sdp_parser_handle_service_search(packet, total_count, current_count);
5853deb3ec6SMatthias Ringwald }
5863deb3ec6SMatthias Ringwald
sdp_client_setup_service_search_request(uint8_t * data)5876c927b22SMatthias Ringwald static uint16_t sdp_client_setup_service_search_request(uint8_t * data){
5883deb3ec6SMatthias Ringwald uint16_t offset = 0;
589f20b4214SMatthias Ringwald sdp_client_transaction_id++;
5903deb3ec6SMatthias Ringwald // uint8_t SDP_PDU_ID_t.SDP_ServiceSearchRequest;
5913deb3ec6SMatthias Ringwald data[offset++] = SDP_ServiceSearchRequest;
5923deb3ec6SMatthias Ringwald // uint16_t transactionID
593f20b4214SMatthias Ringwald big_endian_store_16(data, offset, sdp_client_transaction_id);
5943deb3ec6SMatthias Ringwald offset += 2;
5953deb3ec6SMatthias Ringwald
5963deb3ec6SMatthias Ringwald // param legnth
5973deb3ec6SMatthias Ringwald offset += 2;
5983deb3ec6SMatthias Ringwald
5993deb3ec6SMatthias Ringwald // parameters:
6006c927b22SMatthias Ringwald // Service_search_pattern - DES (min 1 UUID, max 12)
601f20b4214SMatthias Ringwald uint16_t service_search_pattern_len = de_get_len(sdp_client_service_search_pattern);
602f20b4214SMatthias Ringwald (void)memcpy(data + offset, sdp_client_service_search_pattern,
6036535961aSMatthias Ringwald service_search_pattern_len);
6046c927b22SMatthias Ringwald offset += service_search_pattern_len;
6053deb3ec6SMatthias Ringwald
6063deb3ec6SMatthias Ringwald // MaximumAttributeByteCount - uint16_t 0x0007 - 0xffff -> mtu
607f20b4214SMatthias Ringwald big_endian_store_16(data, offset, sdp_client_mtu);
6083deb3ec6SMatthias Ringwald offset += 2;
6093deb3ec6SMatthias Ringwald
6103deb3ec6SMatthias Ringwald // ContinuationState - uint8_t number of cont. bytes N<=16
611f20b4214SMatthias Ringwald data[offset++] = sdp_client_continuation_state_len;
6123deb3ec6SMatthias Ringwald // - N-bytes previous response from server
613f20b4214SMatthias Ringwald (void)memcpy(data + offset, sdp_client_continuation_state, sdp_client_continuation_state_len);
614f20b4214SMatthias Ringwald offset += sdp_client_continuation_state_len;
6153deb3ec6SMatthias Ringwald
6163deb3ec6SMatthias Ringwald // uint16_t paramLength
617f8fbdce0SMatthias Ringwald big_endian_store_16(data, 3, offset - 5);
6183deb3ec6SMatthias Ringwald
6193deb3ec6SMatthias Ringwald return offset;
6203deb3ec6SMatthias Ringwald }
6213deb3ec6SMatthias Ringwald
6223deb3ec6SMatthias Ringwald
sdp_client_setup_service_attribute_request(uint8_t * data)623dbbeec25SMatthias Ringwald static uint16_t sdp_client_setup_service_attribute_request(uint8_t * data){
62423cb683aSMatthias Ringwald
6253deb3ec6SMatthias Ringwald uint16_t offset = 0;
626f20b4214SMatthias Ringwald sdp_client_transaction_id++;
6273deb3ec6SMatthias Ringwald // uint8_t SDP_PDU_ID_t.SDP_ServiceSearchRequest;
6283deb3ec6SMatthias Ringwald data[offset++] = SDP_ServiceAttributeRequest;
6293deb3ec6SMatthias Ringwald // uint16_t transactionID
630f20b4214SMatthias Ringwald big_endian_store_16(data, offset, sdp_client_transaction_id);
6313deb3ec6SMatthias Ringwald offset += 2;
6323deb3ec6SMatthias Ringwald
6333deb3ec6SMatthias Ringwald // param legnth
6343deb3ec6SMatthias Ringwald offset += 2;
6353deb3ec6SMatthias Ringwald
6363deb3ec6SMatthias Ringwald // parameters:
6373deb3ec6SMatthias Ringwald // ServiceRecordHandle
638f20b4214SMatthias Ringwald big_endian_store_32(data, offset, sdp_client_service_record_handle);
6393deb3ec6SMatthias Ringwald offset += 4;
6403deb3ec6SMatthias Ringwald
6413deb3ec6SMatthias Ringwald // MaximumAttributeByteCount - uint16_t 0x0007 - 0xffff -> mtu
642f20b4214SMatthias Ringwald big_endian_store_16(data, offset, sdp_client_mtu);
6433deb3ec6SMatthias Ringwald offset += 2;
6443deb3ec6SMatthias Ringwald
6453deb3ec6SMatthias Ringwald // AttibuteIDList
646f20b4214SMatthias Ringwald uint16_t attribute_id_list_len = de_get_len(sdp_client_attribute_id_list);
647f20b4214SMatthias Ringwald (void)memcpy(data + offset, sdp_client_attribute_id_list, attribute_id_list_len);
6486c927b22SMatthias Ringwald offset += attribute_id_list_len;
6493deb3ec6SMatthias Ringwald
650f20b4214SMatthias Ringwald // sdp_client_continuation_state - uint8_t number of cont. bytes N<=16
651f20b4214SMatthias Ringwald data[offset++] = sdp_client_continuation_state_len;
6523deb3ec6SMatthias Ringwald // - N-bytes previous response from server
653f20b4214SMatthias Ringwald (void)memcpy(data + offset, sdp_client_continuation_state, sdp_client_continuation_state_len);
654f20b4214SMatthias Ringwald offset += sdp_client_continuation_state_len;
6553deb3ec6SMatthias Ringwald
6563deb3ec6SMatthias Ringwald // uint16_t paramLength
657f8fbdce0SMatthias Ringwald big_endian_store_16(data, 3, offset - 5);
6583deb3ec6SMatthias Ringwald
6593deb3ec6SMatthias Ringwald return offset;
6603deb3ec6SMatthias Ringwald }
6613deb3ec6SMatthias Ringwald
sdp_client_parse_service_search_response(uint8_t * packet,uint16_t size)66223cb683aSMatthias Ringwald static void sdp_client_parse_service_search_response(uint8_t* packet, uint16_t size){
66323cb683aSMatthias Ringwald
6643deb3ec6SMatthias Ringwald uint16_t offset = 3;
6655fce6058SMatthias Ringwald if (offset + 2 + 2 + 2 > size) return; // parameterLength, totalServiceRecordCount, currentServiceRecordCount
6665fce6058SMatthias Ringwald
667f8fbdce0SMatthias Ringwald uint16_t parameterLength = big_endian_read_16(packet,offset);
6683deb3ec6SMatthias Ringwald offset+=2;
6695fce6058SMatthias Ringwald if (offset + parameterLength > size) return;
6703deb3ec6SMatthias Ringwald
671f8fbdce0SMatthias Ringwald uint16_t totalServiceRecordCount = big_endian_read_16(packet,offset);
6723deb3ec6SMatthias Ringwald offset+=2;
6733deb3ec6SMatthias Ringwald
674f8fbdce0SMatthias Ringwald uint16_t currentServiceRecordCount = big_endian_read_16(packet,offset);
6753deb3ec6SMatthias Ringwald offset+=2;
6763deb3ec6SMatthias Ringwald if (currentServiceRecordCount > totalServiceRecordCount){
6773deb3ec6SMatthias Ringwald log_error("CurrentServiceRecordCount is larger then TotalServiceRecordCount.");
6783deb3ec6SMatthias Ringwald return;
6793deb3ec6SMatthias Ringwald }
6803deb3ec6SMatthias Ringwald
6815fce6058SMatthias Ringwald if (offset + currentServiceRecordCount * 4 > size) return;
6826c927b22SMatthias Ringwald sdp_client_parse_service_record_handle_list(packet+offset, totalServiceRecordCount, currentServiceRecordCount);
6835fce6058SMatthias Ringwald offset+= currentServiceRecordCount * 4;
6843deb3ec6SMatthias Ringwald
6855fce6058SMatthias Ringwald if (offset + 1 > size) return;
686f20b4214SMatthias Ringwald sdp_client_continuation_state_len = packet[offset];
6873deb3ec6SMatthias Ringwald offset++;
688f20b4214SMatthias Ringwald if (sdp_client_continuation_state_len > 16){
689f20b4214SMatthias Ringwald sdp_client_continuation_state_len = 0;
6903deb3ec6SMatthias Ringwald log_error("Error parsing ServiceSearchResponse: Number of bytes in continuation state exceedes 16.");
6913deb3ec6SMatthias Ringwald return;
6923deb3ec6SMatthias Ringwald }
693f20b4214SMatthias Ringwald if (offset + sdp_client_continuation_state_len > size) return;
694f20b4214SMatthias Ringwald (void)memcpy(sdp_client_continuation_state, packet + offset, sdp_client_continuation_state_len);
695f20b4214SMatthias Ringwald // offset+=sdp_client_continuation_state_len;
6963deb3ec6SMatthias Ringwald }
6973deb3ec6SMatthias Ringwald
sdp_client_parse_service_attribute_response(uint8_t * packet,uint16_t size)69823cb683aSMatthias Ringwald static void sdp_client_parse_service_attribute_response(uint8_t* packet, uint16_t size){
69923cb683aSMatthias Ringwald
7003deb3ec6SMatthias Ringwald uint16_t offset = 3;
7015fce6058SMatthias Ringwald if (offset + 2 + 2 > size) return; // parameterLength, attributeListByteCount
702f8fbdce0SMatthias Ringwald uint16_t parameterLength = big_endian_read_16(packet,offset);
7033deb3ec6SMatthias Ringwald offset+=2;
7045fce6058SMatthias Ringwald if (offset+parameterLength > size) return;
7053deb3ec6SMatthias Ringwald
7063deb3ec6SMatthias Ringwald // AttributeListByteCount <= mtu
707f8fbdce0SMatthias Ringwald uint16_t attributeListByteCount = big_endian_read_16(packet,offset);
7083deb3ec6SMatthias Ringwald offset+=2;
709f20b4214SMatthias Ringwald if (attributeListByteCount > sdp_client_mtu){
7103deb3ec6SMatthias Ringwald log_error("Error parsing ServiceSearchAttributeResponse: Number of bytes in found attribute list is larger then the MaximumAttributeByteCount.");
7113deb3ec6SMatthias Ringwald return;
7123deb3ec6SMatthias Ringwald }
7133deb3ec6SMatthias Ringwald
7143deb3ec6SMatthias Ringwald // AttributeLists
7155fce6058SMatthias Ringwald if (offset+attributeListByteCount > size) return;
7166c927b22SMatthias Ringwald sdp_client_parse_attribute_lists(packet+offset, attributeListByteCount);
7173deb3ec6SMatthias Ringwald offset+=attributeListByteCount;
7183deb3ec6SMatthias Ringwald
719f20b4214SMatthias Ringwald // sdp_client_continuation_state_len
7205fce6058SMatthias Ringwald if (offset + 1 > size) return;
721f20b4214SMatthias Ringwald sdp_client_continuation_state_len = packet[offset];
7223deb3ec6SMatthias Ringwald offset++;
723f20b4214SMatthias Ringwald if (sdp_client_continuation_state_len > 16){
724f20b4214SMatthias Ringwald sdp_client_continuation_state_len = 0;
7253deb3ec6SMatthias Ringwald log_error("Error parsing ServiceAttributeResponse: Number of bytes in continuation state exceedes 16.");
7263deb3ec6SMatthias Ringwald return;
7273deb3ec6SMatthias Ringwald }
728f20b4214SMatthias Ringwald if (offset + sdp_client_continuation_state_len > size) return;
729f20b4214SMatthias Ringwald (void)memcpy(sdp_client_continuation_state, packet + offset, sdp_client_continuation_state_len);
730f20b4214SMatthias Ringwald // offset+=sdp_client_continuation_state_len;
7313deb3ec6SMatthias Ringwald }
7326c927b22SMatthias Ringwald #endif
7333deb3ec6SMatthias Ringwald
7346c927b22SMatthias Ringwald // Public API
7356c927b22SMatthias Ringwald
sdp_client_ready(void)736b443d25dSMatthias Ringwald bool sdp_client_ready(void){
7376c927b22SMatthias Ringwald return sdp_client_state == INIT;
7386c927b22SMatthias Ringwald }
7396c927b22SMatthias Ringwald
sdp_client_register_query_callback(btstack_context_callback_registration_t * callback_registration)740e094740eSMatthias Ringwald uint8_t sdp_client_register_query_callback(btstack_context_callback_registration_t * callback_registration){
741e094740eSMatthias Ringwald bool added = btstack_linked_list_add_tail(&sdp_client_query_requests, (btstack_linked_item_t*) callback_registration);
742e094740eSMatthias Ringwald if (!added) return ERROR_CODE_COMMAND_DISALLOWED;
743e094740eSMatthias Ringwald sdp_client_notify_callbacks();
744e094740eSMatthias Ringwald return ERROR_CODE_SUCCESS;
745e094740eSMatthias Ringwald }
746e094740eSMatthias Ringwald
sdp_client_query(btstack_packet_handler_t callback,bd_addr_t remote,const uint8_t * des_service_search_pattern,const uint8_t * des_attribute_id_list)747282ceebcSMatthias Ringwald uint8_t sdp_client_query(btstack_packet_handler_t callback, bd_addr_t remote, const uint8_t * des_service_search_pattern, const uint8_t * des_attribute_id_list){
748282ceebcSMatthias Ringwald if (!sdp_client_ready()) return SDP_QUERY_BUSY;
749282ceebcSMatthias Ringwald
7506c927b22SMatthias Ringwald sdp_parser_init(callback);
751f20b4214SMatthias Ringwald sdp_client_service_search_pattern = des_service_search_pattern;
752f20b4214SMatthias Ringwald sdp_client_attribute_id_list = des_attribute_id_list;
753f20b4214SMatthias Ringwald sdp_client_continuation_state_len = 0;
754f20b4214SMatthias Ringwald sdp_client_pdu_id = SDP_ServiceSearchAttributeResponse;
7556c927b22SMatthias Ringwald
7566c927b22SMatthias Ringwald sdp_client_state = W4_CONNECT;
75784e3541eSMilanka Ringwald return l2cap_create_channel(sdp_client_packet_handler, remote, BLUETOOTH_PSM_SDP, l2cap_max_mtu(), NULL);
7586c927b22SMatthias Ringwald }
7596c927b22SMatthias Ringwald
sdp_client_query_uuid16(btstack_packet_handler_t callback,bd_addr_t remote,uint16_t uuid)760282ceebcSMatthias Ringwald uint8_t sdp_client_query_uuid16(btstack_packet_handler_t callback, bd_addr_t remote, uint16_t uuid){
761282ceebcSMatthias Ringwald if (!sdp_client_ready()) return SDP_QUERY_BUSY;
762f20b4214SMatthias Ringwald return sdp_client_query(callback, remote, sdp_service_search_pattern_for_uuid16(uuid), sdp_client_des_attribute_id_list);
763023f2764SMatthias Ringwald }
764023f2764SMatthias Ringwald
sdp_client_query_uuid128(btstack_packet_handler_t callback,bd_addr_t remote,const uint8_t * uuid)765282ceebcSMatthias Ringwald uint8_t sdp_client_query_uuid128(btstack_packet_handler_t callback, bd_addr_t remote, const uint8_t* uuid){
766282ceebcSMatthias Ringwald if (!sdp_client_ready()) return SDP_QUERY_BUSY;
767f20b4214SMatthias Ringwald return sdp_client_query(callback, remote, sdp_service_search_pattern_for_uuid128(uuid), sdp_client_des_attribute_id_list);
768023f2764SMatthias Ringwald }
769023f2764SMatthias Ringwald
7706c927b22SMatthias Ringwald #ifdef ENABLE_SDP_EXTRA_QUERIES
sdp_client_service_attribute_search(btstack_packet_handler_t callback,bd_addr_t remote,uint32_t search_service_record_handle,const uint8_t * des_attribute_id_list)7718eaf1b42SMilanka Ringwald uint8_t sdp_client_service_attribute_search(btstack_packet_handler_t callback, bd_addr_t remote, uint32_t search_service_record_handle, const uint8_t * des_attribute_id_list){
772282ceebcSMatthias Ringwald if (!sdp_client_ready()) return SDP_QUERY_BUSY;
773282ceebcSMatthias Ringwald
7746c927b22SMatthias Ringwald sdp_parser_init(callback);
775f20b4214SMatthias Ringwald sdp_client_service_record_handle = search_service_record_handle;
776f20b4214SMatthias Ringwald sdp_client_attribute_id_list = des_attribute_id_list;
777f20b4214SMatthias Ringwald sdp_client_continuation_state_len = 0;
778f20b4214SMatthias Ringwald sdp_client_pdu_id = SDP_ServiceAttributeResponse;
7793deb3ec6SMatthias Ringwald
7803deb3ec6SMatthias Ringwald sdp_client_state = W4_CONNECT;
78184e3541eSMilanka Ringwald l2cap_create_channel(sdp_client_packet_handler, remote, BLUETOOTH_PSM_SDP, l2cap_max_mtu(), NULL);
782282ceebcSMatthias Ringwald return 0;
7833deb3ec6SMatthias Ringwald }
7843deb3ec6SMatthias Ringwald
sdp_client_service_search(btstack_packet_handler_t callback,bd_addr_t remote,const uint8_t * des_service_search_pattern)7858eaf1b42SMilanka Ringwald uint8_t sdp_client_service_search(btstack_packet_handler_t callback, bd_addr_t remote, const uint8_t * des_service_search_pattern){
786282ceebcSMatthias Ringwald
787282ceebcSMatthias Ringwald if (!sdp_client_ready()) return SDP_QUERY_BUSY;
788282ceebcSMatthias Ringwald
7896c927b22SMatthias Ringwald sdp_parser_init(callback);
790f20b4214SMatthias Ringwald sdp_client_service_search_pattern = des_service_search_pattern;
791f20b4214SMatthias Ringwald sdp_client_continuation_state_len = 0;
792f20b4214SMatthias Ringwald sdp_client_pdu_id = SDP_ServiceSearchResponse;
7933deb3ec6SMatthias Ringwald
7943deb3ec6SMatthias Ringwald sdp_client_state = W4_CONNECT;
79584e3541eSMilanka Ringwald l2cap_create_channel(sdp_client_packet_handler, remote, BLUETOOTH_PSM_SDP, l2cap_max_mtu(), NULL);
796282ceebcSMatthias Ringwald return 0;
7973deb3ec6SMatthias Ringwald }
7983deb3ec6SMatthias Ringwald #endif
7993deb3ec6SMatthias Ringwald
800