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