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