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