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__ "goep_client.c" 39 40 #include "btstack_config.h" 41 42 #include <stdint.h> 43 #include <string.h> 44 45 #include "btstack_debug.h" 46 #include "hci_dump.h" 47 #include "bluetooth_sdp.h" 48 #include "btstack_event.h" 49 #include "classic/goep_client.h" 50 #include "classic/obex_message_builder.h" 51 #include "classic/obex.h" 52 #include "classic/obex_iterator.h" 53 #include "classic/rfcomm.h" 54 #include "classic/sdp_client.h" 55 #include "classic/sdp_util.h" 56 #include "l2cap.h" 57 58 //------------------------------------------------------------------------------------------------------------ 59 // goep_client.c 60 // 61 62 #ifdef ENABLE_GOEP_L2CAP 63 #ifndef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE 64 #error "ENABLE_GOEP_L2CAP requires ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE. Please enable ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE or disable ENABLE_GOEP_L2CAP" 65 #endif 66 #endif 67 68 static uint16_t goep_client_cid; 69 static btstack_linked_list_t goep_clients; 70 71 static goep_client_t * goep_client_sdp_active; 72 static uint8_t goep_client_sdp_query_attribute_value[30]; 73 static const unsigned int goep_client_sdp_query_attribute_value_buffer_size = sizeof(goep_client_sdp_query_attribute_value); 74 static uint8_t goep_packet_buffer[150]; 75 76 // singleton instance 77 static goep_client_t goep_client_singleton; 78 79 #ifdef ENABLE_GOEP_L2CAP 80 // singleton instance 81 static uint8_t goep_client_singleton_ertm_buffer[1000]; 82 static l2cap_ertm_config_t goep_client_singleton_ertm_config = { 83 1, // ertm mandatory 84 2, // max transmit, some tests require > 1 85 2000, 86 12000, 87 512, // l2cap ertm mtu 88 2, 89 2, 90 1, // 16-bit FCS 91 }; 92 #endif 93 94 static inline void goep_client_emit_connected_event(goep_client_t * goep_client, uint8_t status){ 95 uint8_t event[15]; 96 int pos = 0; 97 event[pos++] = HCI_EVENT_GOEP_META; 98 pos++; // skip len 99 event[pos++] = GOEP_SUBEVENT_CONNECTION_OPENED; 100 little_endian_store_16(event, pos, goep_client->cid); 101 pos+=2; 102 event[pos++] = status; 103 (void)memcpy(&event[pos], goep_client->bd_addr, 6); 104 pos += 6; 105 little_endian_store_16(event, pos, goep_client->con_handle); 106 pos += 2; 107 event[pos++] = goep_client->incoming; 108 event[1] = pos - 2; 109 if (pos != sizeof(event)) log_error("goep_client_emit_connected_event size %u", pos); 110 goep_client->client_handler(HCI_EVENT_PACKET, goep_client->cid, &event[0], pos); 111 } 112 113 static inline void goep_client_emit_connection_closed_event(goep_client_t * goep_client){ 114 uint8_t event[5]; 115 int pos = 0; 116 event[pos++] = HCI_EVENT_GOEP_META; 117 pos++; // skip len 118 event[pos++] = GOEP_SUBEVENT_CONNECTION_CLOSED; 119 little_endian_store_16(event, pos, goep_client->cid); 120 pos+=2; 121 event[1] = pos - 2; 122 if (pos != sizeof(event)) log_error("goep_client_emit_connection_closed_event size %u", pos); 123 goep_client->client_handler(HCI_EVENT_PACKET, goep_client->cid, &event[0], pos); 124 } 125 126 static inline void goep_client_emit_can_send_now_event(goep_client_t * goep_client){ 127 uint8_t event[5]; 128 int pos = 0; 129 event[pos++] = HCI_EVENT_GOEP_META; 130 pos++; // skip len 131 event[pos++] = GOEP_SUBEVENT_CAN_SEND_NOW; 132 little_endian_store_16(event, pos, goep_client->cid); 133 pos+=2; 134 event[1] = pos - 2; 135 if (pos != sizeof(event)) log_error("goep_client_emit_can_send_now_event size %u", pos); 136 goep_client->client_handler(HCI_EVENT_PACKET, goep_client->cid, &event[0], pos); 137 } 138 139 static void goep_client_handle_connection_opened(goep_client_t * goep_client, uint8_t status, uint16_t mtu){ 140 if (status) { 141 goep_client->state = GOEP_CLIENT_INIT; 142 log_info("goep_client: open failed, status %u", status); 143 } else { 144 goep_client->bearer_mtu = mtu; 145 goep_client->state = GOEP_CLIENT_CONNECTED; 146 log_info("goep_client: connection opened. cid %u, max frame size %u", goep_client->bearer_cid, goep_client->bearer_mtu); 147 } 148 goep_client_emit_connected_event(goep_client, status); 149 } 150 151 static void goep_client_handle_connection_close(goep_client_t * goep_client){ 152 goep_client->state = GOEP_CLIENT_INIT; 153 btstack_linked_list_remove(&goep_clients, (btstack_linked_item_t *) goep_client); 154 goep_client_emit_connection_closed_event(goep_client); 155 } 156 157 static goep_client_t * goep_client_for_cid(uint16_t cid){ 158 btstack_linked_list_iterator_t it; 159 btstack_linked_list_iterator_init(&it, &goep_clients); 160 while (btstack_linked_list_iterator_has_next(&it)){ 161 goep_client_t * goep_client = (goep_client_t *) btstack_linked_list_iterator_next(&it); 162 if (goep_client->cid == cid){ 163 return goep_client; 164 } 165 } 166 return NULL; 167 } 168 169 static goep_client_t * goep_client_for_bearer_cid(uint16_t bearer_cid){ 170 if (bearer_cid == goep_client_singleton.bearer_cid){ 171 return &goep_client_singleton; 172 } else { 173 return NULL; 174 } 175 } 176 177 static void goep_client_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 178 UNUSED(channel); 179 UNUSED(size); 180 goep_client_t * goep_client; 181 switch (packet_type){ 182 case HCI_EVENT_PACKET: 183 switch (hci_event_packet_get_type(packet)) { 184 #ifdef ENABLE_GOEP_L2CAP 185 case L2CAP_EVENT_CHANNEL_OPENED: 186 goep_client = goep_client_for_bearer_cid(l2cap_event_channel_opened_get_local_cid(packet)); 187 btstack_assert(goep_client != NULL); 188 goep_client_handle_connection_opened(goep_client, l2cap_event_channel_opened_get_status(packet), 189 btstack_min(l2cap_event_channel_opened_get_remote_mtu(packet), l2cap_event_channel_opened_get_local_mtu(packet))); 190 break; 191 case L2CAP_EVENT_CAN_SEND_NOW: 192 goep_client = goep_client_for_bearer_cid(l2cap_event_can_send_now_get_local_cid(packet)); 193 btstack_assert(goep_client != NULL); 194 goep_client_emit_can_send_now_event(goep_client); 195 break; 196 case L2CAP_EVENT_CHANNEL_CLOSED: 197 goep_client = goep_client_for_bearer_cid(l2cap_event_channel_closed_get_local_cid(packet)); 198 btstack_assert(goep_client != NULL); 199 goep_client_handle_connection_close(goep_client); 200 break; 201 #endif 202 case RFCOMM_EVENT_CHANNEL_OPENED: 203 goep_client = goep_client_for_bearer_cid(rfcomm_event_channel_opened_get_rfcomm_cid(packet)); 204 btstack_assert(goep_client != NULL); 205 goep_client_handle_connection_opened(goep_client, rfcomm_event_channel_opened_get_status(packet), rfcomm_event_channel_opened_get_max_frame_size(packet)); 206 return; 207 case RFCOMM_EVENT_CAN_SEND_NOW: 208 goep_client = goep_client_for_bearer_cid(rfcomm_event_can_send_now_get_rfcomm_cid(packet)); 209 btstack_assert(goep_client != NULL); 210 goep_client_emit_can_send_now_event(goep_client); 211 break; 212 case RFCOMM_EVENT_CHANNEL_CLOSED: 213 goep_client = goep_client_for_bearer_cid(rfcomm_event_channel_closed_get_rfcomm_cid(packet)); 214 btstack_assert(goep_client != NULL); 215 goep_client_handle_connection_close(goep_client); 216 break; 217 default: 218 break; 219 } 220 break; 221 case L2CAP_DATA_PACKET: 222 case RFCOMM_DATA_PACKET: 223 goep_client = goep_client_for_bearer_cid(channel); 224 btstack_assert(goep_client != NULL); 225 goep_client->client_handler(GOEP_DATA_PACKET, goep_client->cid, packet, size); 226 break; 227 default: 228 break; 229 } 230 } 231 232 static void goep_client_handle_sdp_query_end_of_record(goep_client_t * goep_client){ 233 if (goep_client->uuid == BLUETOOTH_SERVICE_CLASS_MESSAGE_ACCESS_SERVER){ 234 if (goep_client->mas_info.instance_id == goep_client->map_mas_instance_id){ 235 // Requested MAS Instance found, accept info 236 log_info("MAS Instance #%u found", goep_client->map_mas_instance_id); 237 goep_client->rfcomm_port = goep_client->mas_info.rfcomm_port; 238 goep_client->profile_supported_features = goep_client->mas_info.supported_features; 239 goep_client->map_supported_message_types = goep_client->mas_info.supported_message_types; 240 #ifdef ENABLE_GOEP_L2CAP 241 goep_client->l2cap_psm = goep_client->mas_info.l2cap_psm; 242 #endif 243 } 244 } 245 } 246 247 static void goep_client_handle_sdp_query_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 248 goep_client_t * goep_client = goep_client_sdp_active; 249 btstack_assert(goep_client != NULL); 250 251 UNUSED(packet_type); 252 UNUSED(channel); 253 UNUSED(size); 254 255 des_iterator_t des_list_it; 256 des_iterator_t prot_it; 257 uint8_t status; 258 uint16_t record_index; 259 bool goep_server_found; 260 261 switch (hci_event_packet_get_type(packet)){ 262 case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 263 264 // detect new record 265 record_index = sdp_event_query_attribute_byte_get_record_id(packet); 266 if (record_index != goep_client->record_index){ 267 goep_client->record_index = record_index; 268 goep_client_handle_sdp_query_end_of_record(goep_client); 269 memset(&goep_client->mas_info, 0, sizeof(goep_client->mas_info)); 270 } 271 272 // check if relevant attribute 273 switch(sdp_event_query_attribute_byte_get_attribute_id(packet)){ 274 case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: 275 case BLUETOOTH_ATTRIBUTE_PBAP_SUPPORTED_FEATURES: 276 case BLUETOOTH_ATTRIBUTE_MAS_INSTANCE_ID: 277 case BLUETOOTH_ATTRIBUTE_SUPPORTED_MESSAGE_TYPES: 278 #ifdef ENABLE_GOEP_L2CAP 279 case BLUETOOTH_ATTRIBUTE_GOEP_L2CAP_PSM: 280 #endif 281 break; 282 default: 283 return; 284 } 285 286 // warn if attribute too large to fit in our buffer 287 if (sdp_event_query_attribute_byte_get_attribute_length(packet) > goep_client_sdp_query_attribute_value_buffer_size) { 288 log_error("SDP attribute value size exceeded for attribute %x: available %d, required %d", sdp_event_query_attribute_byte_get_attribute_id(packet), goep_client_sdp_query_attribute_value_buffer_size, sdp_event_query_attribute_byte_get_attribute_length(packet)); 289 break; 290 } 291 292 // store single byte 293 goep_client_sdp_query_attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet); 294 295 // wait until value fully received 296 if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) != sdp_event_query_attribute_byte_get_attribute_length(packet)) break; 297 298 // process attributes 299 switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) { 300 case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: 301 for (des_iterator_init(&des_list_it, goep_client_sdp_query_attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 302 uint8_t *des_element; 303 uint8_t *element; 304 uint32_t uuid; 305 306 if (des_iterator_get_type(&des_list_it) != DE_DES) continue; 307 308 des_element = des_iterator_get_element(&des_list_it); 309 des_iterator_init(&prot_it, des_element); 310 311 // first element is UUID 312 element = des_iterator_get_element(&prot_it); 313 if (de_get_element_type(element) != DE_UUID) continue; 314 315 uuid = de_get_uuid32(element); 316 des_iterator_next(&prot_it); 317 if (!des_iterator_has_more(&prot_it)) continue; 318 319 // second element is RFCOMM server channel or L2CAP PSM 320 element = des_iterator_get_element(&prot_it); 321 if (uuid == BLUETOOTH_PROTOCOL_RFCOMM){ 322 if (goep_client->uuid == BLUETOOTH_SERVICE_CLASS_MESSAGE_ACCESS_SERVER) { 323 goep_client->mas_info.rfcomm_port = element[de_get_header_size(element)]; 324 } else { 325 goep_client->rfcomm_port = element[de_get_header_size(element)]; 326 } 327 } 328 } 329 break; 330 #ifdef ENABLE_GOEP_L2CAP 331 case BLUETOOTH_ATTRIBUTE_GOEP_L2CAP_PSM: 332 if (goep_client->uuid == BLUETOOTH_SERVICE_CLASS_MESSAGE_ACCESS_SERVER){ 333 de_element_get_uint16(goep_client_sdp_query_attribute_value, &goep_client->mas_info.l2cap_psm); 334 } else { 335 de_element_get_uint16(goep_client_sdp_query_attribute_value, &goep_client->l2cap_psm); 336 } 337 break; 338 #endif 339 // BLUETOOTH_ATTRIBUTE_PBAP_SUPPORTED_FEATURES == BLUETOOTH_ATTRIBUTE_MAP_SUPPORTED_FEATURES == 0x0317 340 case BLUETOOTH_ATTRIBUTE_PBAP_SUPPORTED_FEATURES: 341 if (de_get_element_type(goep_client_sdp_query_attribute_value) != DE_UINT) break; 342 if (de_get_size_type(goep_client_sdp_query_attribute_value) != DE_SIZE_32) break; 343 if (goep_client->uuid == BLUETOOTH_SERVICE_CLASS_MESSAGE_ACCESS_SERVER) { 344 goep_client->mas_info.supported_features = big_endian_read_32(goep_client_sdp_query_attribute_value, de_get_header_size(goep_client_sdp_query_attribute_value)); 345 } else { 346 goep_client->profile_supported_features = big_endian_read_32(goep_client_sdp_query_attribute_value, de_get_header_size(goep_client_sdp_query_attribute_value)); 347 } 348 break; 349 350 case BLUETOOTH_ATTRIBUTE_MAS_INSTANCE_ID: 351 if (de_get_element_type(goep_client_sdp_query_attribute_value) != DE_UINT) break; 352 if (de_get_size_type(goep_client_sdp_query_attribute_value) != DE_SIZE_8) break; 353 goep_client->mas_info.instance_id = goep_client_sdp_query_attribute_value[de_get_header_size(goep_client_sdp_query_attribute_value)]; 354 break; 355 356 case BLUETOOTH_ATTRIBUTE_SUPPORTED_MESSAGE_TYPES: 357 if (de_get_element_type(goep_client_sdp_query_attribute_value) != DE_UINT) break; 358 if (de_get_size_type(goep_client_sdp_query_attribute_value) != DE_SIZE_8) break; 359 goep_client->mas_info.supported_message_types = goep_client_sdp_query_attribute_value[de_get_header_size(goep_client_sdp_query_attribute_value)]; 360 break; 361 362 default: 363 break; 364 } 365 break; 366 367 case SDP_EVENT_QUERY_COMPLETE: 368 goep_client_sdp_active = NULL; 369 goep_client_handle_sdp_query_end_of_record(goep_client); 370 status = sdp_event_query_complete_get_status(packet); 371 if (status != ERROR_CODE_SUCCESS){ 372 log_info("GOEP client, SDP query failed 0x%02x", status); 373 goep_client->state = GOEP_CLIENT_INIT; 374 goep_client_emit_connected_event(goep_client, status); 375 break; 376 } 377 goep_server_found = false; 378 if (goep_client->rfcomm_port != 0){ 379 goep_server_found = true; 380 } 381 #ifdef ENABLE_GOEP_L2CAP 382 if (goep_client->l2cap_psm != 0){ 383 goep_server_found = true; 384 } 385 #endif 386 if (goep_server_found == false){ 387 log_info("No GOEP RFCOMM or L2CAP server found"); 388 goep_client->state = GOEP_CLIENT_INIT; 389 goep_client_emit_connected_event(goep_client, SDP_SERVICE_NOT_FOUND); 390 break; 391 } 392 #ifdef ENABLE_GOEP_L2CAP 393 if (goep_client->l2cap_psm){ 394 log_info("Remote GOEP L2CAP PSM: %u", goep_client->l2cap_psm); 395 l2cap_ertm_create_channel(&goep_client_packet_handler, goep_client->bd_addr, goep_client->l2cap_psm, 396 &goep_client->ertm_config, goep_client->ertm_buffer, 397 goep_client->ertm_buffer_size, &goep_client->bearer_cid); 398 return; 399 } 400 #endif 401 log_info("Remote GOEP RFCOMM Server Channel: %u", goep_client->rfcomm_port); 402 rfcomm_create_channel(&goep_client_packet_handler, goep_client->bd_addr, goep_client->rfcomm_port, &goep_client->bearer_cid); 403 break; 404 405 default: 406 break; 407 } 408 } 409 410 static uint8_t * goep_client_get_outgoing_buffer(goep_client_t * goep_client){ 411 if (goep_client->l2cap_psm){ 412 return goep_packet_buffer; 413 } else { 414 return rfcomm_get_outgoing_buffer(); 415 } 416 } 417 418 static uint16_t goep_client_get_outgoing_buffer_len(goep_client_t * goep_client){ 419 if (goep_client->l2cap_psm){ 420 return sizeof(goep_packet_buffer); 421 } else { 422 return rfcomm_get_max_frame_size(goep_client->bearer_cid); 423 } 424 } 425 426 static void goep_client_packet_init(goep_client_t *goep_client, uint8_t opcode) { 427 if (goep_client->l2cap_psm != 0){ 428 } else { 429 rfcomm_reserve_packet_buffer(); 430 } 431 // store opcode for parsing of response 432 goep_client->obex_opcode = opcode; 433 } 434 435 void goep_client_init(void){ 436 goep_client_t * goep_client = &goep_client_singleton; 437 memset(goep_client, 0, sizeof(goep_client_t)); 438 goep_client->state = GOEP_CLIENT_INIT; 439 } 440 441 void goep_client_deinit(void){ 442 goep_clients = NULL; 443 goep_client_cid = 0; 444 memset(&goep_client_singleton, 0, sizeof(goep_client_t)); 445 memset(goep_client_sdp_query_attribute_value, 0, sizeof(goep_client_sdp_query_attribute_value)); 446 memset(goep_packet_buffer, 0, sizeof(goep_packet_buffer)); 447 } 448 449 static void geop_client_sdp_query_start(void * context){ 450 uint16_t goep_cid = (uint16_t)(uintptr_t) context; 451 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 452 if (context != NULL){ 453 goep_client_sdp_active = goep_client; 454 sdp_client_query_uuid16(&goep_client_handle_sdp_query_event, goep_client->bd_addr, 455 goep_client->uuid); 456 } 457 } 458 459 uint8_t goep_client_connect(goep_client_t *goep_client, btstack_packet_handler_t handler, bd_addr_t addr, uint16_t uuid, 460 l2cap_ertm_config_t * l2cap_ertm_config, uint16_t l2cap_ertm_buffer_size, 461 uint8_t *l2cap_ertm_buffer, uint16_t *out_cid) { 462 // get new goep cid, skip 0x0000 463 goep_client_cid++; 464 if (goep_client_cid == 0) { 465 goep_client_cid = 1; 466 } 467 468 // add to list 469 memset(goep_client, 0, sizeof(goep_client_t)); 470 goep_client->state = GOEP_CLIENT_W4_SDP; 471 goep_client->cid = goep_client_cid; 472 goep_client->client_handler = handler; 473 goep_client->uuid = uuid; 474 goep_client->profile_supported_features = PROFILE_FEATURES_NOT_PRESENT; 475 (void)memcpy(goep_client->bd_addr, addr, 6); 476 goep_client->sdp_query_request.callback = geop_client_sdp_query_start; 477 goep_client->sdp_query_request.context = (void *)(uintptr_t) goep_client->cid; 478 goep_client->obex_connection_id = OBEX_CONNECTION_ID_INVALID; 479 #ifdef ENABLE_GOEP_L2CAP 480 memcpy(&goep_client->ertm_config, l2cap_ertm_config, sizeof(l2cap_ertm_config_t)); 481 goep_client->ertm_buffer_size = l2cap_ertm_buffer_size; 482 goep_client->ertm_buffer = l2cap_ertm_buffer; 483 #endif 484 btstack_linked_list_add(&goep_clients, (btstack_linked_item_t *) goep_client); 485 486 // request sdp query 487 sdp_client_register_query_callback(&goep_client->sdp_query_request); 488 489 *out_cid = goep_client->cid; 490 return ERROR_CODE_SUCCESS; 491 } 492 493 uint8_t goep_client_create_connection(btstack_packet_handler_t handler, bd_addr_t addr, uint16_t uuid, uint16_t * out_cid){ 494 goep_client_t * goep_client = &goep_client_singleton; 495 if (goep_client->state != GOEP_CLIENT_INIT) { 496 return BTSTACK_MEMORY_ALLOC_FAILED; 497 } 498 return goep_client_connect(goep_client, handler, addr, uuid, &goep_client_singleton_ertm_config, 499 sizeof(goep_client_singleton_ertm_buffer), goep_client_singleton_ertm_buffer, out_cid); 500 } 501 502 uint32_t goep_client_get_pbap_supported_features(uint16_t goep_cid){ 503 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 504 if (goep_client == NULL){ 505 return PBAP_FEATURES_NOT_PRESENT; 506 } 507 return goep_client->profile_supported_features; 508 } 509 510 uint32_t goep_client_get_map_supported_features(uint16_t goep_cid){ 511 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 512 if (goep_client == NULL){ 513 return PROFILE_FEATURES_NOT_PRESENT; 514 } 515 return goep_client->profile_supported_features; 516 } 517 518 uint8_t goep_client_get_map_mas_instance_id(uint16_t goep_cid){ 519 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 520 if (goep_client == NULL){ 521 return 0; 522 } 523 return goep_client->map_mas_instance_id; 524 } 525 526 uint8_t goep_client_get_map_suported_message_types(uint16_t goep_cid){ 527 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 528 if (goep_client == NULL){ 529 return 0; 530 } 531 return goep_client->map_supported_message_types; 532 } 533 534 535 bool goep_client_version_20_or_higher(uint16_t goep_cid){ 536 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 537 if (goep_client == NULL){ 538 return false; 539 } 540 return goep_client->l2cap_psm != 0; 541 } 542 543 void goep_client_request_can_send_now(uint16_t goep_cid){ 544 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 545 if (goep_client == NULL){ 546 return; 547 } 548 if (goep_client->l2cap_psm){ 549 l2cap_request_can_send_now_event(goep_client->bearer_cid); 550 } else { 551 rfcomm_request_can_send_now_event(goep_client->bearer_cid); 552 } 553 } 554 555 uint8_t goep_client_disconnect(uint16_t goep_cid){ 556 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 557 if (goep_client == NULL){ 558 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 559 } 560 if (goep_client->l2cap_psm){ 561 l2cap_disconnect(goep_client->bearer_cid); 562 } else { 563 rfcomm_disconnect(goep_client->bearer_cid); 564 } 565 return ERROR_CODE_SUCCESS; 566 } 567 568 void goep_client_set_connection_id(uint16_t goep_cid, uint32_t connection_id){ 569 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 570 if (goep_client == NULL){ 571 return; 572 } 573 goep_client->obex_connection_id = connection_id; 574 } 575 576 uint8_t goep_client_get_request_opcode(uint16_t goep_cid){ 577 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 578 if (goep_client == NULL){ 579 return 0; 580 } 581 return goep_client->obex_opcode; 582 } 583 584 void goep_client_request_create_connect(uint16_t goep_cid, uint8_t obex_version_number, uint8_t flags, uint16_t maximum_obex_packet_length){ 585 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 586 if (goep_client == NULL){ 587 return; 588 } 589 goep_client_packet_init(goep_client, OBEX_OPCODE_CONNECT); 590 // workaround: limit OBEX packet len to L2CAP/RFCOMM MTU to avoid handling of fragemented packets 591 maximum_obex_packet_length = btstack_min(maximum_obex_packet_length, goep_client->bearer_mtu); 592 593 uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client); 594 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client); 595 obex_message_builder_request_create_connect(buffer, buffer_len, obex_version_number, flags, maximum_obex_packet_length); 596 } 597 598 void goep_client_request_create_get(uint16_t goep_cid){ 599 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 600 if (goep_client == NULL){ 601 return; 602 } 603 goep_client_packet_init(goep_client, OBEX_OPCODE_GET | OBEX_OPCODE_FINAL_BIT_MASK); 604 uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client); 605 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client); 606 obex_message_builder_request_create_get(buffer, buffer_len, goep_client->obex_connection_id); 607 } 608 609 void goep_client_request_create_put(uint16_t goep_cid){ 610 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 611 if (goep_client == NULL){ 612 return; 613 } 614 goep_client_packet_init(goep_client, OBEX_OPCODE_PUT | OBEX_OPCODE_FINAL_BIT_MASK); 615 uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client); 616 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client); 617 obex_message_builder_request_create_put(buffer, buffer_len, goep_client->obex_connection_id); 618 } 619 620 void goep_client_request_create_set_path(uint16_t goep_cid, uint8_t flags){ 621 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 622 if (goep_client == NULL){ 623 return; 624 } 625 goep_client_packet_init(goep_client, OBEX_OPCODE_SETPATH); 626 uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client); 627 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client); 628 obex_message_builder_request_create_set_path(buffer, buffer_len, flags, goep_client->obex_connection_id); 629 } 630 631 void goep_client_request_create_abort(uint16_t goep_cid){ 632 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 633 if (goep_client == NULL){ 634 return; 635 } 636 goep_client_packet_init(goep_client, OBEX_OPCODE_ABORT); 637 638 uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client); 639 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client); 640 obex_message_builder_request_create_abort(buffer, buffer_len, goep_client->obex_connection_id); 641 } 642 643 void goep_client_request_create_disconnect(uint16_t goep_cid){ 644 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 645 if (goep_client == NULL){ 646 return; 647 } 648 goep_client_packet_init(goep_client, OBEX_OPCODE_DISCONNECT); 649 uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client); 650 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client); 651 obex_message_builder_request_create_disconnect(buffer, buffer_len, goep_client->obex_connection_id); 652 } 653 654 void goep_client_header_add_byte(uint16_t goep_cid, uint8_t header_type, uint8_t value){ 655 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 656 if (goep_client == NULL){ 657 return; 658 } 659 uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client); 660 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client); 661 obex_message_builder_header_add_byte(buffer, buffer_len, header_type, value); 662 } 663 664 void goep_client_header_add_word(uint16_t goep_cid, uint8_t header_type, uint32_t value){ 665 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 666 if (goep_client == NULL){ 667 return; 668 } 669 uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client); 670 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client); 671 obex_message_builder_header_add_word(buffer, buffer_len, header_type, value); 672 } 673 674 void goep_client_header_add_variable(uint16_t goep_cid, uint8_t header_type, const uint8_t * header_data, uint16_t header_data_length){ 675 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 676 if (goep_client == NULL){ 677 return; 678 } 679 uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client); 680 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client); 681 obex_message_builder_header_add_variable(buffer, buffer_len, header_type, header_data, header_data_length); 682 } 683 684 void goep_client_header_add_srm_enable(uint16_t goep_cid){ 685 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 686 if (goep_client == NULL){ 687 return; 688 } 689 uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client); 690 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client); 691 obex_message_builder_header_add_srm_enable(buffer, buffer_len); 692 } 693 694 void goep_client_header_add_target(uint16_t goep_cid, const uint8_t * target, uint16_t length){ 695 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 696 if (goep_client == NULL){ 697 return; 698 } 699 uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client); 700 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client); 701 obex_message_builder_header_add_target(buffer, buffer_len, target, length); 702 } 703 704 void goep_client_header_add_application_parameters(uint16_t goep_cid, const uint8_t * data, uint16_t length){ 705 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 706 if (goep_client == NULL){ 707 return; 708 } 709 uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client); 710 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client); 711 obex_message_builder_header_add_application_parameters(buffer, buffer_len, data, length); 712 } 713 714 void goep_client_header_add_challenge_response(uint16_t goep_cid, const uint8_t * data, uint16_t length){ 715 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 716 if (goep_client == NULL){ 717 return; 718 } 719 uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client); 720 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client); 721 obex_message_builder_header_add_challenge_response(buffer, buffer_len, data, length); 722 } 723 724 void goep_client_body_add_static(uint16_t goep_cid, const uint8_t * data, uint32_t length){ 725 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 726 if (goep_client == NULL){ 727 return; 728 } 729 uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client); 730 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client); 731 obex_message_builder_body_add_static(buffer, buffer_len, data, length); 732 } 733 734 uint16_t goep_client_body_get_outgoing_buffer_len(uint16_t goep_cid) { 735 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 736 if (goep_client == NULL){ 737 return 0; 738 } 739 return goep_client_get_outgoing_buffer_len(goep_client); 740 }; 741 742 void goep_client_body_fillup_static(uint16_t goep_cid, const uint8_t * data, uint32_t length, uint32_t * ret_length){ 743 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 744 if (goep_client == NULL){ 745 return; 746 } 747 uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client); 748 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client); 749 obex_message_builder_body_fillup_static(buffer, buffer_len, data, length, ret_length); 750 } 751 752 void goep_client_header_add_name(uint16_t goep_cid, const char * name){ 753 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 754 if (goep_client == NULL){ 755 return; 756 } 757 uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client); 758 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client); 759 obex_message_builder_header_add_name(buffer, buffer_len, name); 760 } 761 762 void goep_client_header_add_name_prefix(uint16_t goep_cid, const char * name, uint16_t name_len){ 763 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 764 if (goep_client == NULL){ 765 return; 766 } 767 uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client); 768 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client); 769 obex_message_builder_header_add_name_prefix(buffer, buffer_len, name, name_len); 770 } 771 772 void goep_client_header_add_type(uint16_t goep_cid, const char * type){ 773 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 774 if (goep_client == NULL){ 775 return; 776 } 777 uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client); 778 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client); 779 obex_message_builder_header_add_type(buffer, buffer_len, type); 780 } 781 782 void goep_client_header_add_length(uint16_t goep_cid, uint32_t length){ 783 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 784 if (goep_client == NULL){ 785 return; 786 } 787 uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client); 788 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client); 789 obex_message_builder_header_add_length(buffer, buffer_len, length); 790 } 791 792 uint16_t goep_client_request_get_max_body_size(uint16_t goep_cid){ 793 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 794 if (goep_client == NULL){ 795 return 0; 796 } 797 uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client); 798 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client); 799 uint16_t pos = big_endian_read_16(buffer, 1); 800 return buffer_len - pos; 801 } 802 803 int goep_client_execute(uint16_t goep_cid){ 804 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 805 if (goep_client == NULL){ 806 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 807 } 808 return goep_client_execute_with_final_bit (goep_cid, true); 809 } 810 811 int goep_client_execute_with_final_bit(uint16_t goep_cid, bool final){ 812 goep_client_t * goep_client = goep_client_for_cid(goep_cid); 813 if (goep_client == NULL){ 814 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 815 } 816 uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client); 817 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client); 818 819 obex_message_builder_set_final_bit (buffer, buffer_len, final); 820 821 uint16_t pos = big_endian_read_16(buffer, 1); 822 if (goep_client->l2cap_psm){ 823 return l2cap_send(goep_client->bearer_cid, buffer, pos); 824 } else { 825 return rfcomm_send_prepared(goep_client->bearer_cid, pos); 826 } 827 } 828 829