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