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