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