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