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