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