xref: /btstack/src/classic/pbap_client.c (revision 8201da882231bee1019f0a84a70494b65e0d959a)
1 /*
2  * Copyright (C) 2014 BlueKitchen GmbH
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holders nor the names of
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  * 4. Any redistribution, use, or modification is done solely for
17  *    personal benefit and not for any commercial purpose or for
18  *    monetary gain.
19  *
20  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * Please inquire about commercial licensing options at
34  * [email protected]
35  *
36  */
37 
38 #define BTSTACK_FILE__ "pbap_client.c"
39 
40 #include "btstack_config.h"
41 
42 #include <stdint.h>
43 #include <string.h>
44 
45 #include "hci_cmd.h"
46 #include "btstack_run_loop.h"
47 #include "btstack_debug.h"
48 #include "hci.h"
49 #include "btstack_memory.h"
50 #include "hci_dump.h"
51 #include "l2cap.h"
52 #include "bluetooth_sdp.h"
53 #include "classic/sdp_client_rfcomm.h"
54 #include "btstack_event.h"
55 #include "md5.h"
56 
57 #include "classic/obex.h"
58 #include "classic/obex_parser.h"
59 #include "classic/goep_client.h"
60 #include "classic/pbap.h"
61 #include "classic/pbap_client.h"
62 #include "sdp_util.h"
63 
64 // 796135f0-f0c5-11d8-0966- 0800200c9a66
65 static const uint8_t pbap_uuid[] = { 0x79, 0x61, 0x35, 0xf0, 0xf0, 0xc5, 0x11, 0xd8, 0x09, 0x66, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66};
66 
67 const char * pbap_phonebook_type     = "x-bt/phonebook";
68 const char * pbap_vcard_listing_type = "x-bt/vcard-listing";
69 const char * pbap_vcard_entry_type   = "x-bt/vcard";
70 
71 const char * pbap_vcard_listing_name = "pb";
72 
73 // used for MD5
74 static const uint8_t colon = (uint8_t) ':';
75 
76 static uint32_t pbap_client_supported_features;
77 
78 static bool pbap_client_singleton_used;
79 
80 static btstack_linked_list_t pbap_clients;
81 
82 // emit events
83 static void pbap_client_emit_connected_event(pbap_client_t * context, uint8_t status){
84     uint8_t event[15];
85     int pos = 0;
86     event[pos++] = HCI_EVENT_PBAP_META;
87     pos++;  // skip len
88     event[pos++] = PBAP_SUBEVENT_CONNECTION_OPENED;
89     little_endian_store_16(event,pos,context->goep_cid);
90     pos+=2;
91     event[pos++] = status;
92     (void)memcpy(&event[pos], context->bd_addr, 6);
93     pos += 6;
94     little_endian_store_16(event,pos,context->con_handle);
95     pos += 2;
96     event[pos++] = 0;
97     event[1] = pos - 2;
98     if (pos != sizeof(event)) log_error("goep_client_emit_connected_event size %u", pos);
99     context->client_handler(HCI_EVENT_PACKET, context->goep_cid, &event[0], pos);
100 }
101 
102 static void pbap_client_emit_connection_closed_event(pbap_client_t * context){
103     uint8_t event[5];
104     int pos = 0;
105     event[pos++] = HCI_EVENT_PBAP_META;
106     pos++;  // skip len
107     event[pos++] = PBAP_SUBEVENT_CONNECTION_CLOSED;
108     little_endian_store_16(event,pos,context->goep_cid);
109     pos+=2;
110     event[1] = pos - 2;
111     if (pos != sizeof(event)) log_error("pbap_client_emit_connection_closed_event size %u", pos);
112     context->client_handler(HCI_EVENT_PACKET, context->goep_cid, &event[0], pos);
113 }
114 
115 static void pbap_client_emit_operation_complete_event(pbap_client_t * context, uint8_t status){
116     uint8_t event[6];
117     int pos = 0;
118     event[pos++] = HCI_EVENT_PBAP_META;
119     pos++;  // skip len
120     event[pos++] = PBAP_SUBEVENT_OPERATION_COMPLETED;
121     little_endian_store_16(event,pos,context->goep_cid);
122     pos+=2;
123     event[pos++]= status;
124     event[1] = pos - 2;
125     if (pos != sizeof(event)) log_error("pbap_client_emit_can_send_now_event size %u", pos);
126     context->client_handler(HCI_EVENT_PACKET, context->goep_cid, &event[0], pos);
127 }
128 
129 static void pbap_client_emit_phonebook_size_event(pbap_client_t * context, uint8_t status, uint16_t phonebook_size){
130     uint8_t event[8];
131     int pos = 0;
132     event[pos++] = HCI_EVENT_PBAP_META;
133     pos++;  // skip len
134     event[pos++] = PBAP_SUBEVENT_PHONEBOOK_SIZE;
135     little_endian_store_16(event,pos,context->goep_cid);
136     pos+=2;
137     event[pos++] = status;
138     little_endian_store_16(event,pos, phonebook_size);
139     pos+=2;
140     event[1] = pos - 2;
141     if (pos != sizeof(event)) log_error("pbap_client_emit_phonebook_size_event size %u", pos);
142     context->client_handler(HCI_EVENT_PACKET, context->goep_cid, &event[0], pos);
143 }
144 
145 static void pbap_client_emit_authentication_event(pbap_client_t * context, uint8_t options){
146     // split options
147     uint8_t user_id_required = (options & 1) ? 1 : 0;
148     uint8_t full_access      = (options & 2) ? 1 : 0;
149 
150     uint8_t event[7];
151     int pos = 0;
152     event[pos++] = HCI_EVENT_PBAP_META;
153     pos++;  // skip len
154     event[pos++] = PBAP_SUBEVENT_AUTHENTICATION_REQUEST;
155     little_endian_store_16(event,pos,context->goep_cid);
156     pos+=2;
157     event[pos++] = user_id_required;
158     event[pos++] = full_access;
159     if (pos != sizeof(event)) log_error("pbap_client_emit_authentication_event size %u", pos);
160     context->client_handler(HCI_EVENT_PACKET, context->goep_cid, &event[0], pos);
161 }
162 
163 static void pbap_client_emit_card_result_event(pbap_client_t * context, const char * name, const char * handle){
164     uint8_t event[5 + PBAP_MAX_NAME_LEN + PBAP_MAX_HANDLE_LEN];
165     int pos = 0;
166     event[pos++] = HCI_EVENT_PBAP_META;
167     pos++;  // skip len
168     event[pos++] = PBAP_SUBEVENT_CARD_RESULT;
169     little_endian_store_16(event,pos,context->goep_cid);
170     pos+=2;
171     int name_len = btstack_min(PBAP_MAX_NAME_LEN, (uint16_t) strlen(name));
172     event[pos++] = name_len;
173     (void)memcpy(&event[pos], name, name_len);
174     pos += name_len;
175     int handle_len = btstack_min(PBAP_MAX_HANDLE_LEN, (uint16_t) strlen(handle));
176     event[pos++] = handle_len;
177     (void)memcpy(&event[pos], handle, handle_len);
178     pos += handle_len;
179     event[1] = pos - 2;
180     context->client_handler(HCI_EVENT_PACKET, context->goep_cid, &event[0], pos);
181 }
182 
183 static pbap_client_t * pbap_client_for_cid(uint16_t cid){
184     btstack_linked_list_iterator_t it;
185     btstack_linked_list_iterator_init(&it, &pbap_clients);
186     while (btstack_linked_list_iterator_has_next(&it)){
187         pbap_client_t * client = (pbap_client_t *) btstack_linked_list_iterator_next(&it);
188         if (client->goep_cid == cid){
189             return client;
190         }
191     }
192     return NULL;
193 }
194 
195 static void pbap_client_finalize(pbap_client_t *client) {
196     client->state = PBAP_CLIENT_INIT;
197     btstack_linked_list_remove(&pbap_clients, (btstack_linked_item_t*) client);
198 }
199 
200 static void pbap_client_vcard_listing_init_parser(pbap_client_t * client){
201     yxml_init(&client->xml_parser, client->xml_buffer, sizeof(client->xml_buffer));
202     client->parser_card_found = false;
203     client->parser_name_found = false;
204     client->parser_handle_found = false;
205 }
206 
207 static void pbap_client_phonebook_size_parser_init(pbap_client_phonebook_size_parser_t * phonebook_size_parer){
208     memset(phonebook_size_parer, 0, sizeof(pbap_client_phonebook_size_parser_t));
209 }
210 
211 static void pbap_client_phonebook_size_parser_process_data(pbap_client_phonebook_size_parser_t * phonebook_size_parser, const uint8_t * data_buffer, uint16_t data_len){
212     while (data_len){
213         uint16_t bytes_to_consume = 1;
214         switch(phonebook_size_parser->state){
215             case PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_INVALID:
216                 return;
217             case PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_W4_TYPE:
218                 phonebook_size_parser->type = *data_buffer;
219                 phonebook_size_parser->state = PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_W4_LEN;
220                 break;
221             case PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_W4_LEN:
222                 phonebook_size_parser->len = *data_buffer;
223                 phonebook_size_parser->state = PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_W4_VALUE;
224                 switch (phonebook_size_parser->type){
225                     case PBAP_APPLICATION_PARAMETER_PHONEBOOK_SIZE:
226                         if (phonebook_size_parser->len != 2){
227                             phonebook_size_parser->state = PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_INVALID;
228                             return;
229                         }
230                         break;
231                     default:
232                         break;
233                     }
234                 break;
235             case PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_W4_VALUE:
236                 bytes_to_consume = btstack_min(phonebook_size_parser->len - phonebook_size_parser->pos, data_len);
237                 switch (phonebook_size_parser->type){
238                     case PBAP_APPLICATION_PARAMETER_PHONEBOOK_SIZE:
239                         memcpy(&phonebook_size_parser->size_buffer[phonebook_size_parser->pos], data_buffer, bytes_to_consume);
240                         break;
241                     default:
242                         // ignore data
243                         break;
244                 }
245                 phonebook_size_parser->pos += bytes_to_consume;
246                 if (phonebook_size_parser->pos == phonebook_size_parser->len){
247                     phonebook_size_parser->state = PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_W4_TYPE;
248                     switch (phonebook_size_parser->type){
249                         case PBAP_APPLICATION_PARAMETER_PHONEBOOK_SIZE:
250                             phonebook_size_parser->have_size = true;
251                             break;
252                         default:
253                             break;
254                     }
255                 }
256                 break;
257             default:
258                 break;
259         }
260         data_buffer += bytes_to_consume;
261         data_len    -= bytes_to_consume;
262     }
263 }
264 
265 static void obex_auth_parser_init(pbap_client_obex_auth_parser_t * auth_parser){
266     memset(auth_parser, 0, sizeof(pbap_client_obex_auth_parser_t));
267 }
268 
269 static void obex_auth_parser_process_data(pbap_client_obex_auth_parser_t * auth_parser, const uint8_t * data_buffer, uint16_t data_len){
270     while (data_len){
271         uint16_t bytes_to_consume = 1;
272         switch(auth_parser->state){
273             case OBEX_AUTH_PARSER_STATE_INVALID:
274                 return;
275             case OBEX_AUTH_PARSER_STATE_W4_TYPE:
276                 auth_parser->type = *data_buffer;
277                 auth_parser->state = OBEX_AUTH_PARSER_STATE_W4_LEN;
278                 break;
279             case OBEX_AUTH_PARSER_STATE_W4_LEN:
280                 auth_parser->len = *data_buffer;
281                 switch (auth_parser->type){
282                     case 0:
283                         if (auth_parser->len != 0x10){
284                             auth_parser->state = OBEX_AUTH_PARSER_STATE_INVALID;
285                             return;
286                         }
287                         break;
288                     case 1:
289                         if (auth_parser->len != 0x01){
290                             auth_parser->state = OBEX_AUTH_PARSER_STATE_INVALID;
291                             return;
292                         }
293                         break;
294                     case 2:
295                         // TODO: handle charset
296                         // charset_code = challenge_data[i];
297                         break;
298                     default:
299                         break;
300                 }
301                 auth_parser->state = OBEX_AUTH_PARSER_STATE_W4_VALUE;
302                 break;
303             case OBEX_AUTH_PARSER_STATE_W4_VALUE:
304                 bytes_to_consume = btstack_min(auth_parser->len - auth_parser->pos, data_len);
305                 switch (auth_parser->type){
306                     case 0:
307                         memcpy(&auth_parser->authentication_nonce[auth_parser->pos], data_buffer, bytes_to_consume);
308                         break;
309                     case 1:
310                         auth_parser->authentication_options = *data_buffer;
311                         break;
312                     default:
313                         // ignore
314                         break;
315                 }
316                 auth_parser->pos += bytes_to_consume;
317                 if (auth_parser->pos == auth_parser->len){
318                     auth_parser->state = OBEX_AUTH_PARSER_STATE_W4_TYPE;
319                 }
320                 break;
321             default:
322                 btstack_unreachable();
323                 break;
324         }
325         data_buffer += bytes_to_consume;
326         data_len    -= bytes_to_consume;
327     }
328 }
329 
330 static void pbap_client_yml_append_character(yxml_t * xml_parser, char * buffer, uint16_t buffer_size){
331     // "In UTF-8, characters from the U+0000..U+10FFFF range (the UTF-16 accessible range) are encoded using sequences of 1 to 4 octets."
332     uint16_t char_len = (uint16_t) strlen(xml_parser->data);
333     btstack_assert(char_len <= 4);
334     uint16_t dest_len = (uint16_t) strlen(buffer);
335     uint16_t zero_pos = dest_len + char_len;
336     if (zero_pos >= buffer_size) return;
337     memcpy(&buffer[dest_len], xml_parser->data, char_len);
338     buffer[zero_pos] = '\0';
339 }
340 
341 static void pbap_client_process_vcard_list_body(pbap_client_t *client, const uint8_t *data, uint16_t data_len) {
342 
343     while (data_len--) {
344         yxml_ret_t r = yxml_parse(&client->xml_parser, *data++);
345         switch (r) {
346             case YXML_ELEMSTART:
347                 client->parser_card_found = strcmp("card", client->xml_parser.elem) == 0;
348                 break;
349             case YXML_ELEMEND:
350                 if (client->parser_card_found) {
351                     pbap_client_emit_card_result_event(client, client->parser_name,
352                                                        client->parser_handle);
353                 }
354                 client->parser_card_found = false;
355                 break;
356             case YXML_ATTRSTART:
357                 if (!client->parser_card_found) break;
358                 if (strcmp("name", client->xml_parser.attr) == 0) {
359                     client->parser_name_found = true;
360                     client->parser_name[0] = 0;
361                     break;
362                 }
363                 if (strcmp("handle", client->xml_parser.attr) == 0) {
364                     client->parser_handle_found = true;
365                     client->parser_handle[0] = 0;
366                     break;
367                 }
368                 break;
369             case YXML_ATTRVAL:
370                 if (client->parser_name_found) {
371                     pbap_client_yml_append_character(&client->xml_parser,
372                                                      client->parser_name,
373                                                      sizeof(client->parser_name));
374                     break;
375                 }
376                 if (client->parser_handle_found) {
377                     pbap_client_yml_append_character(&client->xml_parser,
378                                                      client->parser_handle,
379                                                      sizeof(client->parser_handle));
380                     break;
381                 }
382                 break;
383             case YXML_ATTREND:
384                 client->parser_name_found = false;
385                 client->parser_handle_found = false;
386                 break;
387             default:
388                 break;
389         }
390     }
391 }
392 
393 static void pbap_client_parser_callback_connect(void * user_data, uint8_t header_id, uint16_t total_len, uint16_t data_offset, const uint8_t * data_buffer, uint16_t data_len){
394     pbap_client_t * client = (pbap_client_t *) user_data;
395     switch (header_id){
396         case OBEX_HEADER_CONNECTION_ID:
397             if (obex_parser_header_store(client->obex_header_buffer, sizeof(client->obex_header_buffer), total_len, data_offset, data_buffer, data_len) == OBEX_PARSER_HEADER_COMPLETE){
398                 goep_client_set_connection_id(client->goep_cid, big_endian_read_32(client->obex_header_buffer, 0));
399             }
400             break;
401         case OBEX_HEADER_AUTHENTICATION_CHALLENGE:
402             obex_auth_parser_process_data(&client->obex_auth_parser, data_buffer, data_len);
403             break;
404         default:
405             break;
406     }
407 }
408 
409 static void pbap_client_parser_callback_get_phonebook_size(void * user_data, uint8_t header_id, uint16_t total_len, uint16_t data_offset, const uint8_t * data_buffer, uint16_t data_len){
410     UNUSED(total_len);
411     UNUSED(data_offset);
412     pbap_client_t *client = (pbap_client_t *) user_data;
413     switch (header_id) {
414         case OBEX_HEADER_APPLICATION_PARAMETERS:
415             pbap_client_phonebook_size_parser_process_data(&client->phonebook_size_parser, data_buffer, data_len);
416             break;
417         default:
418             break;
419     }
420 }
421 
422 static void pbap_client_parser_callback_get_operation(void * user_data, uint8_t header_id, uint16_t total_len, uint16_t data_offset, const uint8_t * data_buffer, uint16_t data_len){
423     pbap_client_t *client = (pbap_client_t *) user_data;
424     switch (header_id) {
425         case OBEX_HEADER_SINGLE_RESPONSE_MODE:
426             obex_parser_header_store(&client->obex_srm.srm_value, 1, total_len, data_offset, data_buffer, data_len);
427             break;
428         case OBEX_HEADER_SINGLE_RESPONSE_MODE_PARAMETER:
429             obex_parser_header_store(&client->obex_srm.srmp_value, 1, total_len, data_offset, data_buffer, data_len);
430             break;
431         case OBEX_HEADER_BODY:
432         case OBEX_HEADER_END_OF_BODY:
433             switch(client->state){
434                 case PBAP_CLIENT_W4_PHONEBOOK:
435                 case PBAP_CLIENT_W4_GET_CARD_ENTRY_COMPLETE:
436                     if (data_offset + data_len == total_len){
437                         client->flow_wait_for_user = true;
438                     }
439                     client->client_handler(PBAP_DATA_PACKET, client->goep_cid, (uint8_t *) data_buffer, data_len);
440                     break;
441                 case PBAP_CLIENT_W4_GET_CARD_LIST_COMPLETE:
442                     pbap_client_process_vcard_list_body(client, data_buffer, data_len);
443                     break;
444                 default:
445                     btstack_unreachable();
446                     break;
447             }
448             break;
449         default:
450             // ignore other headers
451             break;
452     }
453 }
454 
455 static uint16_t pbap_client_application_params_add_vcard_selector(const pbap_client_t * client, uint8_t * application_parameters){
456     uint16_t pos = 0;
457     if (client->vcard_selector_supported){
458         // vCard Selector
459         if (client->vcard_selector){
460             application_parameters[pos++] = PBAP_APPLICATION_PARAMETER_VCARD_SELECTOR;
461             application_parameters[pos++] = 8;
462             memset(&application_parameters[pos], 0, 4);
463             pos += 4;
464             big_endian_store_32(application_parameters, pos, client->vcard_selector);
465             pos += 4;
466         }
467         // vCard Selector Operator
468         if (client->vcard_selector_operator != PBAP_VCARD_SELECTOR_OPERATOR_OR){
469             application_parameters[pos++] = PBAP_APPLICATION_PARAMETER_VCARD_SELECTOR_OPERATOR;
470             application_parameters[pos++] = 1;
471             application_parameters[pos++] = client->vcard_selector_operator;
472         }
473     }
474     return pos;
475 }
476 
477 static uint16_t pbap_client_application_params_add_max_list_count(const pbap_client_t * client, uint8_t * application_parameters, uint16_t max_count){
478     UNUSED(client);
479     uint16_t pos = 0;
480     application_parameters[pos++] = PBAP_APPLICATION_PARAMETER_MAX_LIST_COUNT;
481     application_parameters[pos++] = 2;
482     big_endian_store_16(application_parameters, 2, max_count);
483     pos += 2;
484     return pos;
485 }
486 
487 static uint16_t pbap_client_application_params_add_list_start_offset(const pbap_client_t * client, uint8_t * application_parameters, uint16_t list_start_offset){
488     uint16_t pos = 0;
489     if (client->list_start_offset != 0){
490         application_parameters[pos++] = PBAP_APPLICATION_PARAMETER_LIST_START_OFFSET;
491         application_parameters[pos++] = 2;
492         big_endian_store_16(application_parameters, 2, list_start_offset);
493         pos += 2;
494     }
495     return pos;
496 }
497 
498 static uint16_t pbap_client_application_params_add_order(const pbap_client_t * client, uint8_t * application_parameters, uint8_t order){
499     uint16_t pos = 0;
500     if (client->order != 0){
501         application_parameters[pos++] = PBAP_APPLICATION_PARAMETER_ORDER;
502         application_parameters[pos++] = 1;
503         application_parameters[pos++] = order;
504     }
505     return pos;
506 }
507 
508 static uint16_t pbap_client_application_params_add_search_property(const pbap_client_t * client, uint8_t * application_parameters, uint8_t search_property){
509     uint16_t pos = 0;
510     if (client->search_property != 0){
511         application_parameters[pos++] = PBAP_APPLICATION_PARAMETER_SEARCH_PROPERTY;
512         application_parameters[pos++] = 1;
513         application_parameters[pos++] = search_property;
514     }
515     return pos;
516 }
517 
518 static uint16_t pbap_client_application_params_add_search_value(const pbap_client_t * client, uint8_t * application_parameters, const char* search_value){
519     uint16_t pos = 0;
520     if (client->search_value != 0){
521         uint32_t length = (uint32_t) strlen(search_value);
522         application_parameters[pos++] = PBAP_APPLICATION_PARAMETER_SEARCH_VALUE;
523         application_parameters[pos++] = length;
524         memcpy (&application_parameters[pos], search_value, length);
525         pos += length;
526     }
527     return pos;
528 }
529 
530 // max size: PBAP_MAX_PHONE_NUMBER_LEN + 5
531 static uint16_t pbap_client_application_params_add_phone_number(const pbap_client_t * client, uint8_t * application_parameters){
532     uint16_t pos = 0;
533     if (client->phone_number){
534         // Search by phone number
535         uint16_t phone_number_len = btstack_min(PBAP_MAX_PHONE_NUMBER_LEN, (uint16_t) strlen(client->phone_number));
536         application_parameters[pos++] = PBAP_APPLICATION_PARAMETER_SEARCH_VALUE;
537 		btstack_assert(phone_number_len <= 255);
538         application_parameters[pos++] = (uint8_t) phone_number_len;
539         (void)memcpy(&application_parameters[pos],
540                      client->phone_number, phone_number_len);
541         pos += phone_number_len;
542         application_parameters[pos++] = PBAP_APPLICATION_PARAMETER_SEARCH_PROPERTY;
543         application_parameters[pos++] = 1;
544         application_parameters[pos++] = 0x01; // Number
545     }
546     return pos;
547 }
548 
549 static uint16_t pbap_client_application_params_add_property_selector(const pbap_client_t * client, uint8_t * application_parameters){
550     // TODO: support format
551     uint16_t pos = 0;
552     uint32_t property_selector_lower = client->property_selector;
553     if (client->vcard_name != NULL){
554         if (strncmp(client->vcard_name, "X-BT-UID:", 9) == 0) {
555             property_selector_lower |= 1U << 31;
556         }
557         if (strncmp(client->vcard_name, "X-BT-UCI:", 9) == 0) {
558             property_selector_lower |= 1U << 30;
559         }
560     }
561     if (property_selector_lower != 0){
562         application_parameters[pos++] = PBAP_APPLICATION_PARAMETER_PROPERTY_SELECTOR;
563         application_parameters[pos++] = 8;
564         big_endian_store_32(application_parameters, pos, 0);    // upper 32-bits are reserved/unused so far
565         pos += 4;
566         big_endian_store_32(application_parameters, pos, property_selector_lower);
567         pos += 4;
568     }
569     return pos;
570 }
571 
572 // Mandatory if the PSE advertises a PbapSupportedFeatures attribute in its SDP record, else excluded.
573 static uint16_t pbap_client_application_parameters_add_supported_features(const pbap_client_t * client, uint8_t *application_parameters) {
574     uint16_t pos = 0;
575     if (goep_client_get_pbap_supported_features(client->goep_cid) != PBAP_FEATURES_NOT_PRESENT){
576         application_parameters[pos++] = PBAP_APPLICATION_PARAMETER_PBAP_SUPPORTED_FEATURES;
577         application_parameters[pos++] = 4;
578         big_endian_store_32(application_parameters, 2, pbap_client_supported_features);
579         pos += 4;
580     }
581     return pos;
582 }
583 
584 static void pbap_client_add_application_parameters(const pbap_client_t * client, uint8_t * application_parameters, uint16_t len){
585     if (len > 0){
586         goep_client_header_add_application_parameters(client->goep_cid, &application_parameters[0], len);
587     }
588 }
589 
590 static void pbap_client_prepare_srm_header(pbap_client_t * client){
591     obex_srm_client_set_waiting(&client->obex_srm, client->flow_control_enabled);
592     obex_srm_client_prepare_header(&client->obex_srm, client->goep_cid);
593 }
594 
595 static void pbap_client_prepare_get_operation(pbap_client_t * client){
596     obex_parser_init_for_response(&client->obex_parser, OBEX_OPCODE_GET, pbap_client_parser_callback_get_operation, client);
597     obex_srm_client_reset_fields(&client->obex_srm);
598     client->obex_parser_waiting_for_response = true;
599 }
600 
601 static void pbap_handle_can_send_now(pbap_client_t *pbap_client) {
602     uint16_t path_element_start;
603     uint16_t path_element_len;
604     const char * path_element;
605     uint8_t  application_parameters[PBAP_MAX_PHONE_NUMBER_LEN + 10];
606     uint8_t  challenge_response[36];
607     uint16_t pos;
608 
609     MD5_CTX md5_ctx;
610 
611     if (pbap_client->abort_operation){
612         pbap_client->abort_operation = 0;
613         // prepare request
614         goep_client_request_create_abort(pbap_client->goep_cid);
615         // state
616         pbap_client->state = PBAP_CLIENT_W4_ABORT_COMPLETE;
617         // prepare response
618         obex_parser_init_for_response(&pbap_client->obex_parser, OBEX_OPCODE_ABORT, NULL, pbap_client);
619         obex_srm_client_init(&pbap_client->obex_srm);
620         pbap_client->obex_parser_waiting_for_response = true;
621         // send packet
622         goep_client_execute(pbap_client->goep_cid);
623         return;
624     }
625 
626     switch (pbap_client->state){
627         case PBAP_CLIENT_W2_SEND_CONNECT_REQUEST:
628             // prepare request
629             goep_client_request_create_connect(pbap_client->goep_cid, OBEX_VERSION, 0, OBEX_MAX_PACKETLEN_DEFAULT);
630             goep_client_header_add_target(pbap_client->goep_cid, pbap_uuid, 16);
631             pos = 0;
632             pos += pbap_client_application_parameters_add_supported_features(pbap_client, &application_parameters[pos]);
633             pbap_client_add_application_parameters(pbap_client, application_parameters, pos);
634             // state
635             pbap_client->state = PBAP_CLIENT_W4_CONNECT_RESPONSE;
636             // prepare response
637             obex_parser_init_for_response(&pbap_client->obex_parser, OBEX_OPCODE_CONNECT, pbap_client_parser_callback_connect, pbap_client);
638             obex_auth_parser_init(&pbap_client->obex_auth_parser);
639             obex_srm_client_init(&pbap_client->obex_srm);
640             pbap_client->obex_parser_waiting_for_response = true;
641             // send packet
642             goep_client_execute(pbap_client->goep_cid);
643             break;
644         case PBAP_CLIENT_W2_SEND_AUTHENTICATED_CONNECT:
645             // prepare request
646             goep_client_request_create_connect(pbap_client->goep_cid, OBEX_VERSION, 0, OBEX_MAX_PACKETLEN_DEFAULT);
647             goep_client_header_add_target(pbap_client->goep_cid, pbap_uuid, 16);
648             // setup authentication challenge response
649             pos = 0;
650             challenge_response[pos++] = 0;  // Tag Digest
651             challenge_response[pos++] = 16; // Len
652             // calculate md5
653             MD5_Init(&md5_ctx);
654             MD5_Update(&md5_ctx, pbap_client->obex_auth_parser.authentication_nonce, 16);
655             MD5_Update(&md5_ctx, &colon, 1);
656             MD5_Update(&md5_ctx, pbap_client->authentication_password, (uint16_t) strlen(pbap_client->authentication_password));
657             MD5_Final(&challenge_response[pos], &md5_ctx);
658             pos += 16;
659             challenge_response[pos++] = 2;  // Tag Nonce
660             challenge_response[pos++] = 16; // Len
661             (void)memcpy(&challenge_response[pos], pbap_client->obex_auth_parser.authentication_nonce, 16);
662             pos += 16;
663             goep_client_header_add_challenge_response(pbap_client->goep_cid, challenge_response, pos);
664             // state
665             pbap_client->state = PBAP_CLIENT_W4_CONNECT_RESPONSE;
666             // prepare response
667             obex_parser_init_for_response(&pbap_client->obex_parser, OBEX_OPCODE_CONNECT, pbap_client_parser_callback_connect, pbap_client);
668             obex_srm_client_init(&pbap_client->obex_srm);
669             pbap_client->obex_parser_waiting_for_response = true;
670             // send packet
671             goep_client_execute(pbap_client->goep_cid);
672             break;
673         case PBAP_CLIENT_W2_SEND_DISCONNECT_REQUEST:
674             // prepare request
675             goep_client_request_create_disconnect(pbap_client->goep_cid);
676             // state
677             pbap_client->state = PBAP_CLIENT_W4_DISCONNECT_RESPONSE;
678             // prepare response
679             obex_parser_init_for_response(&pbap_client->obex_parser, OBEX_OPCODE_DISCONNECT, NULL, pbap_client);
680             obex_srm_client_init(&pbap_client->obex_srm);
681             pbap_client->obex_parser_waiting_for_response = true;
682             // send packet
683             goep_client_execute(pbap_client->goep_cid);
684             return;
685         case PBAP_CLIENT_W2_GET_PHONEBOOK_SIZE:
686             // prepare request
687             goep_client_request_create_get(pbap_client->goep_cid);
688             pbap_client_prepare_srm_header(pbap_client);
689             goep_client_header_add_name(pbap_client->goep_cid, pbap_client->phonebook_path);
690             goep_client_header_add_type(pbap_client->goep_cid, pbap_phonebook_type);
691 
692             pos = 0;
693             pos += pbap_client_application_params_add_vcard_selector(pbap_client, &application_parameters[pos]);
694             // just get size
695             pos += pbap_client_application_params_add_max_list_count(pbap_client, &application_parameters[pos], 0);
696             pbap_client_add_application_parameters(pbap_client, application_parameters, pos);
697 
698             // state
699             pbap_client->state = PBAP_CLIENT_W4_GET_PHONEBOOK_SIZE_COMPLETE;
700             // prepare response
701             obex_parser_init_for_response(&pbap_client->obex_parser, OBEX_OPCODE_GET, pbap_client_parser_callback_get_phonebook_size, pbap_client);
702             obex_srm_client_init(&pbap_client->obex_srm);
703             pbap_client_phonebook_size_parser_init(&pbap_client->phonebook_size_parser);
704             pbap_client->obex_parser_waiting_for_response = true;
705             // send packet
706             goep_client_execute(pbap_client->goep_cid);
707             break;
708         case PBAP_CLIENT_W2_PULL_PHONEBOOK:
709             // prepare request
710             goep_client_request_create_get(pbap_client->goep_cid);
711             if (pbap_client->request_number == 0){
712                 obex_srm_client_init(&pbap_client->obex_srm);
713                 pbap_client_prepare_srm_header(pbap_client);
714                 goep_client_header_add_name(pbap_client->goep_cid, pbap_client->phonebook_path);
715                 goep_client_header_add_type(pbap_client->goep_cid, pbap_phonebook_type);
716 
717                 pos = 0;
718                 pos += pbap_client_application_params_add_property_selector(pbap_client, &application_parameters[pos]);
719                 if (pbap_client->max_list_count){
720                     pos += pbap_client_application_params_add_max_list_count(pbap_client, &application_parameters[pos], pbap_client->max_list_count);
721                 }
722                 pos += pbap_client_application_params_add_list_start_offset (pbap_client, &application_parameters[pos], pbap_client->list_start_offset);
723                 pos += pbap_client_application_params_add_vcard_selector(pbap_client, &application_parameters[pos]);
724                 pbap_client_add_application_parameters(pbap_client, application_parameters, pos);
725             } else {
726                 pbap_client_prepare_srm_header(pbap_client);
727             }
728             // state
729             pbap_client->state = PBAP_CLIENT_W4_PHONEBOOK;
730             pbap_client->flow_next_triggered = 0;
731             pbap_client->flow_wait_for_user = false;
732             // prepare response
733             pbap_client_prepare_get_operation(pbap_client);
734             // send packet
735             pbap_client->request_number++;
736             goep_client_execute(pbap_client->goep_cid);
737             break;
738         case PBAP_CLIENT_W2_GET_CARD_LIST:
739             // prepare request
740             goep_client_request_create_get(pbap_client->goep_cid);
741             if (pbap_client->request_number == 0){
742                 obex_srm_client_init(&pbap_client->obex_srm);
743                 pbap_client_prepare_srm_header(pbap_client);
744                 goep_client_header_add_name(pbap_client->goep_cid, pbap_client->phonebook_path);
745                 goep_client_header_add_type(pbap_client->goep_cid, pbap_vcard_listing_type);
746 
747                 pos = 0;
748                 pos += pbap_client_application_params_add_vcard_selector(pbap_client, &application_parameters[pos]);
749                 pos += pbap_client_application_params_add_phone_number(pbap_client, &application_parameters[pos]);
750                 if (pbap_client->search_value != NULL){
751                     pos += pbap_client_application_params_add_search_value(pbap_client, &application_parameters[pos], pbap_client->search_value);
752                 }
753                 if (pbap_client->search_property){
754                     pos += pbap_client_application_params_add_search_property(pbap_client, &application_parameters[pos], pbap_client->search_property);
755                 }
756                 if (pbap_client->order){
757                     pos += pbap_client_application_params_add_order(pbap_client, &application_parameters[pos], pbap_client->order);
758                 }
759                 if (pbap_client->max_list_count){
760                     pos += pbap_client_application_params_add_max_list_count(pbap_client, &application_parameters[pos], pbap_client->max_list_count);
761                 }
762                 if (pbap_client->list_start_offset){
763                     pos += pbap_client_application_params_add_list_start_offset (pbap_client, &application_parameters[pos], pbap_client->list_start_offset);
764                 }
765                 pbap_client_add_application_parameters(pbap_client, application_parameters, pos);
766             } else {
767                 pbap_client_prepare_srm_header(pbap_client);
768             }
769             // state
770             pbap_client->state = PBAP_CLIENT_W4_GET_CARD_LIST_COMPLETE;
771             // prepare response
772             pbap_client_prepare_get_operation(pbap_client);
773             // send packet
774             pbap_client->request_number++;
775             goep_client_execute(pbap_client->goep_cid);
776             break;
777         case PBAP_CLIENT_W2_GET_CARD_ENTRY:
778             // prepare request
779             goep_client_request_create_get(pbap_client->goep_cid);
780             if (pbap_client->request_number == 0){
781                 obex_srm_client_init(&pbap_client->obex_srm);
782                 pbap_client_prepare_srm_header(pbap_client);
783                 goep_client_header_add_name(pbap_client->goep_cid, pbap_client->vcard_name);
784                 goep_client_header_add_type(pbap_client->goep_cid, pbap_vcard_entry_type);
785 
786                 pos = 0;
787                 pos += pbap_client_application_params_add_property_selector(pbap_client, &application_parameters[pos]);
788                 pbap_client_add_application_parameters(pbap_client, application_parameters, pos);
789             } else {
790                 pbap_client_prepare_srm_header(pbap_client);
791             }
792             // state
793             pbap_client->state = PBAP_CLIENT_W4_GET_CARD_ENTRY_COMPLETE;
794             // prepare response
795             pbap_client_prepare_get_operation(pbap_client);
796             // send packet
797             pbap_client->request_number++;
798             goep_client_execute(pbap_client->goep_cid);
799             break;
800         case PBAP_CLIENT_W2_SET_PATH_ROOT:
801             // prepare request
802             goep_client_request_create_set_path(pbap_client->goep_cid, 1 << 1); // Don’t create directory
803             goep_client_header_add_name(pbap_client->goep_cid, "");
804             // state
805             pbap_client->state = PBAP_CLIENT_W4_SET_PATH_ROOT_COMPLETE;
806             // prepare response
807             obex_parser_init_for_response(&pbap_client->obex_parser, OBEX_OPCODE_SETPATH, NULL, pbap_client);
808             obex_srm_client_init(&pbap_client->obex_srm);
809             pbap_client->obex_parser_waiting_for_response = true;
810             // send packet
811             goep_client_execute(pbap_client->goep_cid);
812             break;
813         case PBAP_CLIENT_W2_SET_PATH_ELEMENT:
814             // prepare request
815             // find '/' or '\0'
816             path_element_start = pbap_client->set_path_offset;
817             while ((pbap_client->current_folder[pbap_client->set_path_offset] != '\0') &&
818                 (pbap_client->current_folder[pbap_client->set_path_offset] != '/')){
819                 pbap_client->set_path_offset++;
820             }
821             path_element_len = pbap_client->set_path_offset-path_element_start;
822             path_element = (const char *) &pbap_client->current_folder[path_element_start];
823 
824             // skip /
825             if (pbap_client->current_folder[pbap_client->set_path_offset] == '/'){
826                 pbap_client->set_path_offset++;
827             }
828 
829             goep_client_request_create_set_path(pbap_client->goep_cid, 1 << 1); // Don’t create directory
830             goep_client_header_add_name_prefix(pbap_client->goep_cid, path_element, path_element_len); // next element
831             // state
832             pbap_client->state = PBAP_CLIENT_W4_SET_PATH_ELEMENT_COMPLETE;
833             // prepare response
834             obex_parser_init_for_response(&pbap_client->obex_parser, OBEX_OPCODE_SETPATH, NULL, pbap_client);
835             obex_srm_client_init(&pbap_client->obex_srm);
836             pbap_client->obex_parser_waiting_for_response = true;
837             // send packet
838             goep_client_execute(pbap_client->goep_cid);
839             break;
840         default:
841             break;
842     }
843 }
844 
845 static void pbap_packet_handler_hci(uint8_t *packet, uint16_t size){
846     UNUSED(size);
847     uint8_t status;
848 
849     pbap_client_t * client;
850 
851     switch (hci_event_packet_get_type(packet)) {
852         case HCI_EVENT_GOEP_META:
853             switch (hci_event_goep_meta_get_subevent_code(packet)){
854                 case GOEP_SUBEVENT_CONNECTION_OPENED:
855                     client = pbap_client_for_cid(goep_subevent_connection_opened_get_goep_cid(packet));
856                     btstack_assert(client != NULL);
857                     status = goep_subevent_connection_opened_get_status(packet);
858                     goep_subevent_connection_opened_get_bd_addr(packet, client->bd_addr);
859                     if (status){
860                         log_info("pbap: connection failed %u", status);
861                         pbap_client_finalize(client);
862                         pbap_client_emit_connected_event(client, status);
863                     } else {
864                         log_info("pbap: connection established");
865                         client->con_handle = goep_subevent_connection_opened_get_con_handle(packet);
866                         client->state = PBAP_CLIENT_W2_SEND_CONNECT_REQUEST;
867                         goep_client_request_can_send_now(client->goep_cid);
868                     }
869                     break;
870                 case GOEP_SUBEVENT_CONNECTION_CLOSED:
871                     client = pbap_client_for_cid(goep_subevent_connection_closed_get_goep_cid(packet));
872                     btstack_assert(client != NULL);
873                     if (client->state > PBAP_CLIENT_CONNECTED){
874                         pbap_client_emit_operation_complete_event(client, OBEX_DISCONNECTED);
875                     }
876                     pbap_client_finalize(client);
877                     pbap_client_emit_connection_closed_event(client);
878                     break;
879                 case GOEP_SUBEVENT_CAN_SEND_NOW:
880                     client = pbap_client_for_cid(goep_subevent_can_send_now_get_goep_cid(packet));
881                     btstack_assert(client != NULL);
882                     pbap_handle_can_send_now(client);
883                     break;
884                 default:
885                     break;
886             }
887             break;
888         default:
889             break;
890     }
891 }
892 
893 static void pbap_packet_handler_goep(pbap_client_t *client, uint8_t *packet, uint16_t size) {
894 
895     if (client->obex_parser_waiting_for_response == false) return;
896 
897     obex_parser_object_state_t parser_state;
898     parser_state = obex_parser_process_data(&client->obex_parser, packet, size);
899     if (parser_state == OBEX_PARSER_OBJECT_STATE_COMPLETE){
900         client->obex_parser_waiting_for_response = false;
901         obex_parser_operation_info_t op_info;
902         obex_parser_get_operation_info(&client->obex_parser, &op_info);
903         switch (client->state){
904             case PBAP_CLIENT_W4_CONNECT_RESPONSE:
905                 switch (op_info.response_code) {
906                     case OBEX_RESP_SUCCESS:
907                         client->state = PBAP_CLIENT_CONNECTED;
908                         client->vcard_selector_supported = pbap_client_supported_features & goep_client_get_pbap_supported_features(client->goep_cid) & PBAP_SUPPORTED_FEATURES_VCARD_SELECTING;
909                         pbap_client_emit_connected_event(client, ERROR_CODE_SUCCESS);
910                         break;
911                     case OBEX_RESP_UNAUTHORIZED:
912                         client->state = PBAP_CLIENT_W4_USER_AUTHENTICATION;
913                         pbap_client_emit_authentication_event(client, client->obex_auth_parser.authentication_options);
914                         break;
915                     default:
916                         log_info("pbap: obex connect failed, result 0x%02x", packet[0]);
917                         client->state = PBAP_CLIENT_INIT;
918                         pbap_client_emit_connected_event(client, OBEX_CONNECT_FAILED);
919                         break;
920                 }
921                 break;
922             case PBAP_CLIENT_W4_DISCONNECT_RESPONSE:
923                 client->state = PBAP_CLIENT_CONNECTED;
924                 goep_client_disconnect(client->goep_cid);
925                 break;
926             case PBAP_CLIENT_W4_SET_PATH_ROOT_COMPLETE:
927             case PBAP_CLIENT_W4_SET_PATH_ELEMENT_COMPLETE:
928                 switch (op_info.response_code) {
929                     case OBEX_RESP_SUCCESS:
930                         // more path?
931                         if (client->current_folder[client->set_path_offset]) {
932                             client->state = PBAP_CLIENT_W2_SET_PATH_ELEMENT;
933                             goep_client_request_can_send_now(client->goep_cid);
934                         } else {
935                             client->current_folder = NULL;
936                             client->state = PBAP_CLIENT_CONNECTED;
937                             pbap_client_emit_operation_complete_event(client, ERROR_CODE_SUCCESS);
938                         }
939                         break;
940                     case OBEX_RESP_NOT_FOUND:
941                         client->state = PBAP_CLIENT_CONNECTED;
942                         pbap_client_emit_operation_complete_event(client, OBEX_NOT_FOUND);
943                         break;
944                     default:
945                         client->state = PBAP_CLIENT_CONNECTED;
946                         pbap_client_emit_operation_complete_event(client, OBEX_UNKNOWN_ERROR);
947                         break;
948                 }
949                 break;
950             case PBAP_CLIENT_W4_PHONEBOOK:
951                 switch (op_info.response_code) {
952                     case OBEX_RESP_CONTINUE:
953                         obex_srm_client_handle_headers(&client->obex_srm);
954                         if (obex_srm_client_is_srm_active(&client->obex_srm)) {
955                             // prepare response
956                             pbap_client_prepare_get_operation(client);
957                             break;
958                         }
959                         client->state = PBAP_CLIENT_W2_PULL_PHONEBOOK;
960                         if (!client->flow_control_enabled || !client->flow_wait_for_user ||
961                             client->flow_next_triggered) {
962                             goep_client_request_can_send_now(client->goep_cid);
963                         }
964                         break;
965                     case OBEX_RESP_SUCCESS:
966                         client->state = PBAP_CLIENT_CONNECTED;
967                         pbap_client_emit_operation_complete_event(client, ERROR_CODE_SUCCESS);
968                         break;
969                     default:
970                         log_info("unexpected response 0x%02x", packet[0]);
971                         client->state = PBAP_CLIENT_CONNECTED;
972                         pbap_client_emit_operation_complete_event(client, OBEX_UNKNOWN_ERROR);
973                         break;
974                 }
975                 break;
976             case PBAP_CLIENT_W4_GET_PHONEBOOK_SIZE_COMPLETE:
977                 switch (op_info.response_code) {
978                     case OBEX_RESP_SUCCESS:
979                         if (client->phonebook_size_parser.have_size) {
980                             uint16_t phonebook_size = big_endian_read_16(client->phonebook_size_parser.size_buffer, 0);
981                             client->state = PBAP_CLIENT_CONNECTED;
982                             pbap_client_emit_phonebook_size_event(client, 0, phonebook_size);
983                             break;
984                         }
985                         /* fall through */
986                     default:
987                         client->state = PBAP_CLIENT_CONNECTED;
988                         pbap_client_emit_phonebook_size_event(client, OBEX_UNKNOWN_ERROR, 0);
989                         break;
990                 }
991                 break;
992             case PBAP_CLIENT_W4_GET_CARD_LIST_COMPLETE:
993                 switch (op_info.response_code) {
994                     case OBEX_RESP_CONTINUE:
995                         // handle continue
996                         obex_srm_client_handle_headers(&client->obex_srm);
997                         if (obex_srm_client_is_srm_active(&client->obex_srm)) {
998                             // prepare response
999                             pbap_client_prepare_get_operation(client);
1000                             break;
1001                         }
1002                         client->state = PBAP_CLIENT_W2_GET_CARD_LIST;
1003                         goep_client_request_can_send_now(client->goep_cid);
1004                         break;
1005                     case OBEX_RESP_SUCCESS:
1006                         // done
1007                         client->state = PBAP_CLIENT_CONNECTED;
1008                         pbap_client_emit_operation_complete_event(client, ERROR_CODE_SUCCESS);
1009                         break;
1010                     case OBEX_RESP_NOT_ACCEPTABLE:
1011                         client->state = PBAP_CLIENT_CONNECTED;
1012                         pbap_client_emit_operation_complete_event(client, OBEX_NOT_ACCEPTABLE);
1013                         break;
1014                     default:
1015                         log_info("unexpected response 0x%02x", packet[0]);
1016                         client->state = PBAP_CLIENT_CONNECTED;
1017                         pbap_client_emit_operation_complete_event(client, OBEX_UNKNOWN_ERROR);
1018                         break;
1019                 }
1020                 break;
1021             case PBAP_CLIENT_W4_GET_CARD_ENTRY_COMPLETE:
1022                 switch (op_info.response_code) {
1023                     case OBEX_RESP_CONTINUE:
1024                         obex_srm_client_handle_headers(&client->obex_srm);
1025                         if (obex_srm_client_is_srm_active(&client->obex_srm)) {
1026                             // prepare response
1027                             pbap_client_prepare_get_operation(client);
1028                             break;
1029                         }
1030                         client->state = PBAP_CLIENT_W2_GET_CARD_ENTRY;
1031                         goep_client_request_can_send_now(client->goep_cid);
1032                         break;
1033                     case OBEX_RESP_SUCCESS:
1034                         client->state = PBAP_CLIENT_CONNECTED;
1035                         pbap_client_emit_operation_complete_event(client, ERROR_CODE_SUCCESS);
1036                         break;
1037                     case OBEX_RESP_NOT_ACCEPTABLE:
1038                         client->state = PBAP_CLIENT_CONNECTED;
1039                         pbap_client_emit_operation_complete_event(client, OBEX_NOT_ACCEPTABLE);
1040                         break;
1041                     default:
1042                         log_info("unexpected response 0x%02x", packet[0]);
1043                         client->state = PBAP_CLIENT_CONNECTED;
1044                         pbap_client_emit_operation_complete_event(client, OBEX_UNKNOWN_ERROR);
1045                         break;
1046                 }
1047                 break;
1048             case PBAP_CLIENT_W4_ABORT_COMPLETE:
1049                 client->state = PBAP_CLIENT_CONNECTED;
1050                 pbap_client_emit_operation_complete_event(client, OBEX_ABORTED);
1051                 break;
1052             default:
1053                 btstack_unreachable();
1054                 break;
1055         }
1056     }
1057 }
1058 
1059 static void pbap_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
1060     UNUSED(channel); // ok: there is no channel
1061     UNUSED(size);    // ok: handling own geop events
1062 
1063     pbap_client_t * client;
1064 
1065     switch (packet_type){
1066         case HCI_EVENT_PACKET:
1067             pbap_packet_handler_hci(packet, size);
1068             break;
1069         case GOEP_DATA_PACKET:
1070             client = pbap_client_for_cid(channel);
1071             btstack_assert(client != NULL);
1072             pbap_packet_handler_goep(client, packet, size);
1073             break;
1074         default:
1075             break;
1076     }
1077 }
1078 
1079 void pbap_client_init(void){
1080     pbap_client_supported_features =
1081             PBAP_SUPPORTED_FEATURES_DOWNLOAD |
1082             PBAP_SUPPORTED_FEATURES_BROWSING |
1083             PBAP_SUPPORTED_FEATURES_DATABASE_IDENTIFIER |
1084             PBAP_SUPPORTED_FEATURES_FOLDER_VERSION_COUNTERS |
1085             PBAP_SUPPORTED_FEATURES_VCARD_SELECTING |
1086             PBAP_SUPPORTED_FEATURES_ENHANCED_MISSED_CALLS |
1087             PBAP_SUPPORTED_FEATURES_DEFAULT_CONTACT_IMAGE_FORMAT |
1088             PBAP_SUPPORTED_FEATURES_X_BT_UCI_VCARD_PROPERTY |
1089             PBAP_SUPPORTED_FEATURES_X_BT_UID_VCARD_PROPERTY |
1090             PBAP_SUPPORTED_FEATURES_CONTACT_REFERENCING;
1091 
1092     pbap_client_singleton_used = false;
1093 }
1094 
1095 void pbap_client_deinit(void){
1096 }
1097 
1098 uint8_t pbap_client_connect(pbap_client_t * client, l2cap_ertm_config_t *l2cap_ertm_config, uint8_t *l2cap_ertm_buffer,
1099                             uint16_t l2cap_ertm_buffer_size, btstack_packet_handler_t handler, bd_addr_t addr, uint16_t * out_cid) {
1100     client->state = PBAP_CLIENT_W4_GOEP_CONNECTION;
1101     client->client_handler = handler;
1102     client->vcard_selector = 0;
1103     client->vcard_selector_operator = PBAP_VCARD_SELECTOR_OPERATOR_OR;
1104 
1105     btstack_linked_list_add(&pbap_clients, (btstack_linked_item_t*) client);
1106 
1107     uint8_t status = goep_client_connect(&client->goep_client, l2cap_ertm_config, l2cap_ertm_buffer, l2cap_ertm_buffer_size,
1108                                          &pbap_packet_handler, addr, BLUETOOTH_SERVICE_CLASS_PHONEBOOK_ACCESS_PSE, 0, &client->goep_cid);
1109     *out_cid = client->goep_cid;
1110 
1111     if (status) {
1112         pbap_client_finalize(client);
1113     }
1114     return status;
1115 }
1116 
1117 uint8_t pbap_connect(btstack_packet_handler_t handler, bd_addr_t addr, uint16_t * out_cid){
1118     static pbap_client_t pbap_client_singleton;
1119 
1120     l2cap_ertm_config_t *l2cap_ertm_config = NULL;
1121     uint8_t *l2cap_ertm_buffer = NULL;
1122     uint16_t l2cap_ertm_buffer_size = 0;
1123 
1124 #ifdef ENABLE_GOEP_L2CAP
1125 // singleton instance
1126     static uint8_t pbap_client_singleton_ertm_buffer[1000];
1127     static l2cap_ertm_config_t pbap_client_singleton_ertm_config = {
1128             1,  // ertm mandatory
1129             2,  // max transmit, some tests require > 1
1130             2000,
1131             12000,
1132             512,    // l2cap ertm mtu
1133             2,
1134             2,
1135             1,      // 16-bit FCS
1136     };
1137 
1138     l2cap_ertm_config = &pbap_client_singleton_ertm_config;
1139     l2cap_ertm_buffer = pbap_client_singleton_ertm_buffer;
1140     l2cap_ertm_buffer_size = sizeof(pbap_client_singleton_ertm_buffer);
1141 #endif
1142 
1143     if (pbap_client_singleton_used && pbap_client_singleton.state != PBAP_CLIENT_INIT){
1144         return BTSTACK_MEMORY_ALLOC_FAILED;
1145     }
1146 
1147     pbap_client_singleton_used = true;
1148 
1149     memset(&pbap_client_singleton, 0, sizeof(pbap_client_t));
1150     return pbap_client_connect(&pbap_client_singleton, l2cap_ertm_config, l2cap_ertm_buffer, l2cap_ertm_buffer_size, handler, addr, out_cid);
1151 }
1152 
1153 uint8_t pbap_disconnect(uint16_t pbap_cid){
1154     pbap_client_t * pbap_client = pbap_client_for_cid(pbap_cid);
1155     if (pbap_client == NULL){
1156         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1157     }
1158     if (pbap_client->state < PBAP_CLIENT_CONNECTED){
1159         return BTSTACK_BUSY;
1160     }
1161     pbap_client->state = PBAP_CLIENT_W2_SEND_DISCONNECT_REQUEST;
1162     goep_client_request_can_send_now(pbap_client->goep_cid);
1163     return ERROR_CODE_SUCCESS;
1164 }
1165 
1166 uint8_t pbap_get_phonebook_size(uint16_t pbap_cid, const char * path){
1167     pbap_client_t * pbap_client = pbap_client_for_cid(pbap_cid);
1168     if (pbap_client == NULL){
1169         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1170     }
1171     if (pbap_client->state != PBAP_CLIENT_CONNECTED){
1172         return BTSTACK_BUSY;
1173     }
1174     pbap_client->state = PBAP_CLIENT_W2_GET_PHONEBOOK_SIZE;
1175     pbap_client->phonebook_path = path;
1176     pbap_client->request_number = 0;
1177     goep_client_request_can_send_now(pbap_client->goep_cid);
1178     return ERROR_CODE_SUCCESS;
1179 }
1180 
1181 uint8_t pbap_pull_phonebook(uint16_t pbap_cid, const char * path){
1182     pbap_client_t * pbap_client = pbap_client_for_cid(pbap_cid);
1183     if (pbap_client == NULL){
1184         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1185     }
1186     if (pbap_client->state != PBAP_CLIENT_CONNECTED){
1187         return BTSTACK_BUSY;
1188     }
1189     pbap_client->state = PBAP_CLIENT_W2_PULL_PHONEBOOK;
1190     pbap_client->phonebook_path = path;
1191     pbap_client->vcard_name = NULL;
1192     pbap_client->request_number = 0;
1193     goep_client_request_can_send_now(pbap_client->goep_cid);
1194     return ERROR_CODE_SUCCESS;
1195 }
1196 
1197 uint8_t pbap_set_phonebook(uint16_t pbap_cid, const char * path){
1198     pbap_client_t * pbap_client = pbap_client_for_cid(pbap_cid);
1199     if (pbap_client == NULL){
1200         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1201     }
1202     if (pbap_client->state != PBAP_CLIENT_CONNECTED){
1203         return BTSTACK_BUSY;
1204     }
1205     pbap_client->state = PBAP_CLIENT_W2_SET_PATH_ROOT;
1206     pbap_client->current_folder = path;
1207     pbap_client->set_path_offset = 0;
1208     goep_client_request_can_send_now(pbap_client->goep_cid);
1209     return ERROR_CODE_SUCCESS;
1210 }
1211 
1212 uint8_t pbap_authentication_password(uint16_t pbap_cid, const char * password){
1213     pbap_client_t * pbap_client = pbap_client_for_cid(pbap_cid);
1214     if (pbap_client == NULL){
1215         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1216     }
1217     if (pbap_client->state != PBAP_CLIENT_W4_USER_AUTHENTICATION){
1218         return BTSTACK_BUSY;
1219     }
1220     pbap_client->state = PBAP_CLIENT_W2_SEND_AUTHENTICATED_CONNECT;
1221     pbap_client->authentication_password = password;
1222     goep_client_request_can_send_now(pbap_client->goep_cid);
1223     return ERROR_CODE_SUCCESS;
1224 }
1225 
1226 uint8_t pbap_pull_vcard_listing(uint16_t pbap_cid, const char * path){
1227     pbap_client_t * pbap_client = pbap_client_for_cid(pbap_cid);
1228     if (pbap_client == NULL){
1229         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1230     }
1231     if (pbap_client->state != PBAP_CLIENT_CONNECTED){
1232         return BTSTACK_BUSY;
1233     }
1234     pbap_client->state = PBAP_CLIENT_W2_GET_CARD_LIST;
1235     pbap_client->phonebook_path = path;
1236     pbap_client->phone_number = NULL;
1237     pbap_client->request_number = 0;
1238     pbap_client_vcard_listing_init_parser(pbap_client);
1239     goep_client_request_can_send_now(pbap_client->goep_cid);
1240     return ERROR_CODE_SUCCESS;
1241 }
1242 
1243 uint8_t pbap_pull_vcard_entry(uint16_t pbap_cid, const char * path){
1244     pbap_client_t * pbap_client = pbap_client_for_cid(pbap_cid);
1245     if (pbap_client == NULL){
1246         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1247     }
1248     if (pbap_client->state != PBAP_CLIENT_CONNECTED){
1249         return BTSTACK_BUSY;
1250     }
1251     pbap_client->state = PBAP_CLIENT_W2_GET_CARD_ENTRY;
1252     // pbap_client->phonebook_path = NULL;
1253     // pbap_client->phone_number = NULL;
1254     pbap_client->vcard_name = path;
1255     pbap_client->request_number = 0;
1256     goep_client_request_can_send_now(pbap_client->goep_cid);
1257     return ERROR_CODE_SUCCESS;
1258 }
1259 
1260 uint8_t pbap_lookup_by_number(uint16_t pbap_cid, const char * phone_number){
1261     pbap_client_t * pbap_client = pbap_client_for_cid(pbap_cid);
1262     if (pbap_client == NULL){
1263         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1264     }
1265     if (pbap_client->state != PBAP_CLIENT_CONNECTED){
1266         return BTSTACK_BUSY;
1267     }
1268     pbap_client->state = PBAP_CLIENT_W2_GET_CARD_LIST;
1269     pbap_client->phonebook_path = pbap_vcard_listing_name;
1270     pbap_client->phone_number   = phone_number;
1271     pbap_client->request_number = 0;
1272     pbap_client_vcard_listing_init_parser(pbap_client);
1273     goep_client_request_can_send_now(pbap_client->goep_cid);
1274     return ERROR_CODE_SUCCESS;
1275 }
1276 
1277 uint8_t pbap_abort(uint16_t pbap_cid){
1278     pbap_client_t * pbap_client = pbap_client_for_cid(pbap_cid);
1279     if (pbap_client == NULL){
1280         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1281     }
1282     if ((pbap_client->state < PBAP_CLIENT_CONNECTED) || (pbap_client->abort_operation != 0)){
1283         return ERROR_CODE_COMMAND_DISALLOWED;
1284     }
1285     log_info("abort current operation, state 0x%02x", pbap_client->state);
1286     pbap_client->abort_operation = 1;
1287     return ERROR_CODE_SUCCESS;
1288 }
1289 
1290 uint8_t pbap_next_packet(uint16_t pbap_cid){
1291     pbap_client_t * pbap_client = pbap_client_for_cid(pbap_cid);
1292     if (pbap_client == NULL){
1293         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1294     }
1295     if (pbap_client->flow_wait_for_user == false){
1296         return ERROR_CODE_SUCCESS;
1297     }
1298     switch (pbap_client->state){
1299         case PBAP_CLIENT_W2_PULL_PHONEBOOK:
1300             goep_client_request_can_send_now(pbap_client->goep_cid);
1301             break;
1302         case PBAP_CLIENT_W4_PHONEBOOK:
1303             pbap_client->flow_next_triggered = 1;
1304             break;
1305         default:
1306             break;
1307     }
1308     return ERROR_CODE_SUCCESS;
1309 }
1310 
1311 uint8_t pbap_set_flow_control_mode(uint16_t pbap_cid, int enable){
1312     pbap_client_t * pbap_client = pbap_client_for_cid(pbap_cid);
1313     if (pbap_client == NULL){
1314         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1315     }
1316     switch (pbap_client->state){
1317         case PBAP_CLIENT_CONNECTED:
1318         case PBAP_CLIENT_W4_PHONEBOOK:
1319             pbap_client->flow_control_enabled = enable;
1320             return ERROR_CODE_SUCCESS;
1321         default:
1322             return BTSTACK_BUSY;
1323     }
1324 }
1325 
1326 uint8_t pbap_set_vcard_selector(uint16_t pbap_cid, uint32_t vcard_selector){
1327     pbap_client_t * pbap_client = pbap_client_for_cid(pbap_cid);
1328     if (pbap_client == NULL){
1329         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1330     }
1331     if (pbap_client->state != PBAP_CLIENT_CONNECTED){
1332         return BTSTACK_BUSY;
1333     }
1334     pbap_client->vcard_selector = vcard_selector;
1335     return ERROR_CODE_SUCCESS;
1336 }
1337 
1338 uint8_t pbap_set_vcard_selector_operator(uint16_t pbap_cid, int vcard_selector_operator){
1339     pbap_client_t * pbap_client = pbap_client_for_cid(pbap_cid);
1340     if (pbap_client == NULL){
1341         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1342     }
1343     if (pbap_client->state != PBAP_CLIENT_CONNECTED){
1344         return BTSTACK_BUSY;
1345     }
1346     pbap_client->vcard_selector_operator = vcard_selector_operator;
1347     return ERROR_CODE_SUCCESS;
1348 }
1349 
1350 uint8_t pbap_set_property_selector(uint16_t pbap_cid, uint32_t property_selector){
1351     pbap_client_t * pbap_client = pbap_client_for_cid(pbap_cid);
1352     if (pbap_client == NULL){
1353         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1354     }
1355     if (pbap_client->state != PBAP_CLIENT_CONNECTED){
1356         return BTSTACK_BUSY;
1357     }
1358     pbap_client->property_selector  = property_selector;
1359     return ERROR_CODE_SUCCESS;
1360 }
1361 
1362 uint8_t pbap_set_max_list_count(uint16_t pbap_cid, uint16_t max_list_count){
1363     pbap_client_t * pbap_client = pbap_client_for_cid(pbap_cid);
1364     if (pbap_client == NULL){
1365         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1366     }
1367     if (pbap_client->state != PBAP_CLIENT_CONNECTED){
1368         return BTSTACK_BUSY;
1369     }
1370     pbap_client->max_list_count = max_list_count;
1371     return ERROR_CODE_SUCCESS;
1372 }
1373 
1374 uint8_t pbap_set_list_start_offset(uint16_t pbap_cid, uint16_t list_start_offset){
1375     pbap_client_t * pbap_client = pbap_client_for_cid(pbap_cid);
1376     if (pbap_client == NULL){
1377         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1378     }
1379     if (pbap_client->state != PBAP_CLIENT_CONNECTED){
1380         return BTSTACK_BUSY;
1381     }
1382     pbap_client->list_start_offset = list_start_offset;
1383     return ERROR_CODE_SUCCESS;
1384 }
1385 
1386 uint8_t pbap_set_order(uint16_t pbap_cid, uint8_t order){
1387     pbap_client_t * pbap_client = pbap_client_for_cid(pbap_cid);
1388     if (pbap_client == NULL){
1389         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1390     }
1391     if (pbap_client->state != PBAP_CLIENT_CONNECTED){
1392         return BTSTACK_BUSY;
1393     }
1394     pbap_client->order = order;
1395     return ERROR_CODE_SUCCESS;
1396 }
1397 
1398 uint8_t pbap_set_search_property(uint16_t pbap_cid, uint8_t search_property){
1399     pbap_client_t * pbap_client = pbap_client_for_cid(pbap_cid);
1400     if (pbap_client == NULL){
1401         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1402     }
1403     if (pbap_client->state != PBAP_CLIENT_CONNECTED){
1404         return BTSTACK_BUSY;
1405     }
1406     pbap_client->search_property = search_property;
1407     return ERROR_CODE_SUCCESS;
1408 }
1409 
1410 uint8_t pbap_set_search_value(uint16_t pbap_cid, const char * search_value){
1411     pbap_client_t * pbap_client = pbap_client_for_cid(pbap_cid);
1412     if (pbap_client == NULL){
1413         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1414     }
1415     if (pbap_client->state != PBAP_CLIENT_CONNECTED){
1416         return BTSTACK_BUSY;
1417     }
1418     pbap_client->search_value = search_value;
1419     return ERROR_CODE_SUCCESS;
1420 }
1421 
1422 void pbap_client_create_sdp_record(uint8_t *service, uint32_t service_record_handle, const char *service_name) {
1423     uint8_t* attribute;
1424     de_create_sequence(service);
1425 
1426     // 0x0000 "Service Record Handle"
1427     de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_RECORD_HANDLE);
1428     de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle);
1429 
1430     // 0x0001 "Service Class ID List"
1431     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST);
1432     attribute = de_push_sequence(service);
1433     {
1434         de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_PHONEBOOK_ACCESS_PCE);
1435     }
1436     de_pop_sequence(service, attribute);
1437 
1438     // 0x0009 "Bluetooth Profile Descriptor List"
1439     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
1440     attribute = de_push_sequence(service);
1441     {
1442         uint8_t *pbapServerProfile = de_push_sequence(attribute);
1443         {
1444             de_add_number(pbapServerProfile,  DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_PHONEBOOK_ACCESS);
1445             de_add_number(pbapServerProfile,  DE_UINT, DE_SIZE_16, 0x0102); // Verision 1.2
1446         }
1447         de_pop_sequence(attribute, pbapServerProfile);
1448     }
1449     de_pop_sequence(service, attribute);
1450 
1451     // 0x0100 "Service Name"
1452     de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0100);
1453     de_add_data(service,  DE_STRING, (uint16_t) strlen(service_name), (uint8_t *) service_name);
1454 }