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