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