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