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