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 #ifdef ENABLE_GOEP_L2CAP 309 uint16_t l2cap_psm; 310 #endif 311 312 if (des_iterator_get_type(&des_list_it) != DE_DES) continue; 313 314 des_element = des_iterator_get_element(&des_list_it); 315 des_iterator_init(&prot_it, des_element); 316 317 // first element is UUID 318 element = des_iterator_get_element(&prot_it); 319 if (de_get_element_type(element) != DE_UUID) continue; 320 321 uuid = de_get_uuid32(element); 322 des_iterator_next(&prot_it); 323 if (!des_iterator_has_more(&prot_it)) continue; 324 325 // second element is RFCOMM server channel or L2CAP PSM 326 element = des_iterator_get_element(&prot_it); 327 switch (uuid){ 328 #ifdef ENABLE_GOEP_L2CAP 329 case BLUETOOTH_PROTOCOL_L2CAP: 330 if (de_element_get_uint16(element, &l2cap_psm)){ 331 context->l2cap_psm = l2cap_psm; 332 } 333 break; 334 #endif 335 case BLUETOOTH_PROTOCOL_RFCOMM: 336 if (context->uuid == BLUETOOTH_SERVICE_CLASS_MESSAGE_ACCESS_SERVER) { 337 context->mas_info.rfcomm_port = element[de_get_header_size(element)]; 338 } else { 339 context->rfcomm_port = element[de_get_header_size(element)]; 340 } 341 break; 342 default: 343 break; 344 } 345 } 346 break; 347 #ifdef ENABLE_GOEP_L2CAP 348 case BLUETOOTH_ATTRIBUTE_GOEP_L2CAP_PSM: 349 if (context->uuid == BLUETOOTH_SERVICE_CLASS_MESSAGE_ACCESS_SERVER){ 350 de_element_get_uint16(goep_client_sdp_query_attribute_value, &context->mas_info.l2cap_psm); 351 } else { 352 de_element_get_uint16(goep_client_sdp_query_attribute_value, &context->l2cap_psm); 353 } 354 break; 355 #endif 356 // BLUETOOTH_ATTRIBUTE_PBAP_SUPPORTED_FEATURES == BLUETOOTH_ATTRIBUTE_MAP_SUPPORTED_FEATURES == 0x0317 357 case BLUETOOTH_ATTRIBUTE_PBAP_SUPPORTED_FEATURES: 358 if (de_get_element_type(goep_client_sdp_query_attribute_value) != DE_UINT) break; 359 if (de_get_size_type(goep_client_sdp_query_attribute_value) != DE_SIZE_32) break; 360 if (context->uuid == BLUETOOTH_SERVICE_CLASS_MESSAGE_ACCESS_SERVER) { 361 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)); 362 } else { 363 context->profile_supported_features = big_endian_read_32(goep_client_sdp_query_attribute_value, de_get_header_size(goep_client_sdp_query_attribute_value)); 364 } 365 break; 366 367 case BLUETOOTH_ATTRIBUTE_MAS_INSTANCE_ID: 368 if (de_get_element_type(goep_client_sdp_query_attribute_value) != DE_UINT) break; 369 if (de_get_size_type(goep_client_sdp_query_attribute_value) != DE_SIZE_8) break; 370 context->mas_info.instance_id = goep_client_sdp_query_attribute_value[de_get_header_size(goep_client_sdp_query_attribute_value)]; 371 break; 372 373 case BLUETOOTH_ATTRIBUTE_SUPPORTED_MESSAGE_TYPES: 374 if (de_get_element_type(goep_client_sdp_query_attribute_value) != DE_UINT) break; 375 if (de_get_size_type(goep_client_sdp_query_attribute_value) != DE_SIZE_8) break; 376 context->mas_info.supported_message_types = goep_client_sdp_query_attribute_value[de_get_header_size(goep_client_sdp_query_attribute_value)]; 377 break; 378 379 default: 380 break; 381 } 382 break; 383 384 case SDP_EVENT_QUERY_COMPLETE: 385 goep_client_handle_sdp_query_end_of_record(context); 386 status = sdp_event_query_complete_get_status(packet); 387 if (status != ERROR_CODE_SUCCESS){ 388 log_info("GOEP client, SDP query failed 0x%02x", status); 389 context->state = GOEP_INIT; 390 goep_client_emit_connected_event(goep_client, status); 391 break; 392 } 393 if ((context->rfcomm_port == 0) && (context->l2cap_psm == 0)){ 394 log_info("No GOEP RFCOMM or L2CAP server found"); 395 context->state = GOEP_INIT; 396 goep_client_emit_connected_event(goep_client, SDP_SERVICE_NOT_FOUND); 397 break; 398 } 399 #ifdef ENABLE_GOEP_L2CAP 400 if (context->l2cap_psm){ 401 log_info("Remote GOEP L2CAP PSM: %u", context->l2cap_psm); 402 l2cap_ertm_create_channel(&goep_client_packet_handler, context->bd_addr, context->l2cap_psm, 403 &ertm_config, ertm_buffer, sizeof(ertm_buffer), &context->bearer_cid); 404 return; 405 } 406 #endif 407 log_info("Remote GOEP RFCOMM Server Channel: %u", context->rfcomm_port); 408 rfcomm_create_channel(&goep_client_packet_handler, context->bd_addr, context->rfcomm_port, &context->bearer_cid); 409 break; 410 411 default: 412 break; 413 } 414 } 415 416 static uint8_t * goep_client_get_outgoing_buffer(goep_client_t * context){ 417 if (context->l2cap_psm){ 418 return goep_packet_buffer; 419 } else { 420 return rfcomm_get_outgoing_buffer(); 421 } 422 } 423 424 static uint16_t goep_client_get_outgoing_buffer_len(goep_client_t * context){ 425 if (context->l2cap_psm){ 426 return sizeof(goep_packet_buffer); 427 } else { 428 return rfcomm_get_max_frame_size(context->bearer_cid); 429 } 430 } 431 432 static void goep_client_packet_init(uint16_t goep_cid, uint8_t opcode){ 433 UNUSED(goep_cid); 434 goep_client_t * context = goep_client; 435 if (context->l2cap_psm){ 436 } else { 437 rfcomm_reserve_packet_buffer(); 438 } 439 // store opcode for parsing of response 440 context->obex_opcode = opcode; 441 } 442 443 void goep_client_init(void){ 444 memset(goep_client, 0, sizeof(goep_client_t)); 445 goep_client->state = GOEP_INIT; 446 goep_client->cid = 1; 447 goep_client->obex_connection_id = OBEX_CONNECTION_ID_INVALID; 448 } 449 450 void goep_client_deinit(void){ 451 memset(goep_client, 0, sizeof(goep_client_t)); 452 memset(goep_client_sdp_query_attribute_value, 0, sizeof(goep_client_sdp_query_attribute_value)); 453 memset(goep_packet_buffer, 0, sizeof(goep_packet_buffer)); 454 } 455 456 uint8_t goep_client_create_connection(btstack_packet_handler_t handler, bd_addr_t addr, uint16_t uuid, uint16_t * out_cid){ 457 goep_client_t * context = goep_client; 458 if (context->state != GOEP_INIT) return BTSTACK_MEMORY_ALLOC_FAILED; 459 memset(context, 0, sizeof(goep_client_t)); 460 context->client_handler = handler; 461 context->state = GOEP_W4_SDP; 462 context->uuid = uuid; 463 (void)memcpy(context->bd_addr, addr, 6); 464 context->profile_supported_features = PROFILE_FEATURES_NOT_PRESENT; 465 sdp_client_query_uuid16(&goep_client_handle_sdp_query_event, context->bd_addr, uuid); 466 *out_cid = context->cid; 467 return ERROR_CODE_SUCCESS; 468 } 469 470 uint32_t goep_client_get_pbap_supported_features(uint16_t goep_cid){ 471 UNUSED(goep_cid); 472 goep_client_t * context = goep_client; 473 return context->profile_supported_features; 474 } 475 476 uint32_t goep_client_get_map_supported_features(uint16_t goep_cid){ 477 UNUSED(goep_cid); 478 goep_client_t * context = goep_client; 479 return context->profile_supported_features; 480 } 481 482 uint8_t goep_client_get_map_mas_instance_id(uint16_t goep_cid){ 483 UNUSED(goep_cid); 484 goep_client_t * context = goep_client; 485 return context->map_mas_instance_id; 486 } 487 488 uint8_t goep_client_get_map_suported_message_types(uint16_t goep_cid){ 489 UNUSED(goep_cid); 490 goep_client_t * context = goep_client; 491 return context->map_supported_message_types; 492 } 493 494 495 bool goep_client_version_20_or_higher(uint16_t goep_cid){ 496 UNUSED(goep_cid); 497 goep_client_t * context = goep_client; 498 return context->l2cap_psm != 0; 499 } 500 501 void goep_client_request_can_send_now(uint16_t goep_cid){ 502 UNUSED(goep_cid); 503 goep_client_t * context = goep_client; 504 if (context->l2cap_psm){ 505 l2cap_request_can_send_now_event(context->bearer_cid); 506 } else { 507 rfcomm_request_can_send_now_event(context->bearer_cid); 508 } 509 } 510 511 uint8_t goep_client_disconnect(uint16_t goep_cid){ 512 UNUSED(goep_cid); 513 goep_client_t * context = goep_client; 514 if (context->l2cap_psm){ 515 l2cap_disconnect(context->bearer_cid); 516 } else { 517 rfcomm_disconnect(context->bearer_cid); 518 } 519 return ERROR_CODE_SUCCESS; 520 } 521 522 void goep_client_set_connection_id(uint16_t goep_cid, uint32_t connection_id){ 523 UNUSED(goep_cid); 524 goep_client_t * context = goep_client; 525 context->obex_connection_id = connection_id; 526 } 527 528 uint8_t goep_client_get_request_opcode(uint16_t goep_cid){ 529 UNUSED(goep_cid); 530 goep_client_t * context = goep_client; 531 return context->obex_opcode; 532 } 533 534 void goep_client_request_create_connect(uint16_t goep_cid, uint8_t obex_version_number, uint8_t flags, uint16_t maximum_obex_packet_length){ 535 UNUSED(goep_cid); 536 goep_client_t * context = goep_client; 537 goep_client_packet_init(goep_cid, OBEX_OPCODE_CONNECT); 538 539 // workaround: limit OBEX packet len to L2CAP/RFCOMM MTU to avoid handling of fragemented packets 540 maximum_obex_packet_length = btstack_min(maximum_obex_packet_length, context->bearer_mtu); 541 542 uint8_t * buffer = goep_client_get_outgoing_buffer(context); 543 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context); 544 obex_message_builder_request_create_connect(buffer, buffer_len, obex_version_number, flags, maximum_obex_packet_length); 545 } 546 547 void goep_client_request_create_get(uint16_t goep_cid){ 548 UNUSED(goep_cid); 549 goep_client_t * context = goep_client; 550 goep_client_packet_init(goep_cid, OBEX_OPCODE_GET | OBEX_OPCODE_FINAL_BIT_MASK); 551 552 uint8_t * buffer = goep_client_get_outgoing_buffer(context); 553 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context); 554 obex_message_builder_request_create_get(buffer, buffer_len, context->obex_connection_id); 555 } 556 557 void goep_client_request_create_put(uint16_t goep_cid){ 558 UNUSED(goep_cid); 559 goep_client_t * context = goep_client; 560 goep_client_packet_init(goep_cid, OBEX_OPCODE_PUT | OBEX_OPCODE_FINAL_BIT_MASK); 561 562 uint8_t * buffer = goep_client_get_outgoing_buffer(context); 563 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context); 564 obex_message_builder_request_create_put(buffer, buffer_len, context->obex_connection_id); 565 } 566 567 void goep_client_request_create_set_path(uint16_t goep_cid, uint8_t flags){ 568 UNUSED(goep_cid); 569 goep_client_t * context = goep_client; 570 goep_client_packet_init(goep_cid, OBEX_OPCODE_SETPATH); 571 572 uint8_t * buffer = goep_client_get_outgoing_buffer(context); 573 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context); 574 obex_message_builder_request_create_set_path(buffer, buffer_len, flags, context->obex_connection_id); 575 } 576 577 void goep_client_request_create_abort(uint16_t goep_cid){ 578 UNUSED(goep_cid); 579 goep_client_t * context = goep_client; 580 goep_client_packet_init(goep_cid, OBEX_OPCODE_ABORT); 581 582 uint8_t * buffer = goep_client_get_outgoing_buffer(context); 583 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context); 584 obex_message_builder_request_create_abort(buffer, buffer_len, context->obex_connection_id); 585 } 586 587 void goep_client_request_create_disconnect(uint16_t goep_cid){ 588 UNUSED(goep_cid); 589 goep_client_t * context = goep_client; 590 goep_client_packet_init(goep_cid, OBEX_OPCODE_DISCONNECT); 591 592 uint8_t * buffer = goep_client_get_outgoing_buffer(context); 593 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context); 594 obex_message_builder_request_create_disconnect(buffer, buffer_len, context->obex_connection_id); 595 } 596 597 void goep_client_header_add_byte(uint16_t goep_cid, uint8_t header_type, uint8_t value){ 598 UNUSED(goep_cid); 599 goep_client_t * context = goep_client; 600 601 uint8_t * buffer = goep_client_get_outgoing_buffer(context); 602 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context); 603 obex_message_builder_header_add_byte(buffer, buffer_len, header_type, value); 604 } 605 606 void goep_client_header_add_word(uint16_t goep_cid, uint8_t header_type, uint32_t value){ 607 UNUSED(goep_cid); 608 goep_client_t * context = goep_client; 609 610 uint8_t * buffer = goep_client_get_outgoing_buffer(context); 611 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context); 612 obex_message_builder_header_add_word(buffer, buffer_len, header_type, value); 613 } 614 615 void goep_client_header_add_variable(uint16_t goep_cid, uint8_t header_type, const uint8_t * header_data, uint16_t header_data_length){ 616 UNUSED(goep_cid); 617 goep_client_t * context = goep_client; 618 619 uint8_t * buffer = goep_client_get_outgoing_buffer(context); 620 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context); 621 obex_message_builder_header_add_variable(buffer, buffer_len, header_type, header_data, header_data_length); 622 } 623 624 void goep_client_header_add_srm_enable(uint16_t goep_cid){ 625 UNUSED(goep_cid); 626 goep_client_t * context = goep_client; 627 628 uint8_t * buffer = goep_client_get_outgoing_buffer(context); 629 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context); 630 obex_message_builder_header_add_srm_enable(buffer, buffer_len); 631 } 632 633 void goep_client_header_add_target(uint16_t goep_cid, const uint8_t * target, uint16_t length){ 634 UNUSED(goep_cid); 635 goep_client_t * context = goep_client; 636 637 uint8_t * buffer = goep_client_get_outgoing_buffer(context); 638 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context); 639 obex_message_builder_header_add_target(buffer, buffer_len, target, length); 640 } 641 642 void goep_client_header_add_application_parameters(uint16_t goep_cid, const uint8_t * data, uint16_t length){ 643 UNUSED(goep_cid); 644 goep_client_t * context = goep_client; 645 646 uint8_t * buffer = goep_client_get_outgoing_buffer(context); 647 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context); 648 obex_message_builder_header_add_application_parameters(buffer, buffer_len, data, length); 649 } 650 651 void goep_client_header_add_challenge_response(uint16_t goep_cid, const uint8_t * data, uint16_t length){ 652 UNUSED(goep_cid); 653 goep_client_t * context = goep_client; 654 655 uint8_t * buffer = goep_client_get_outgoing_buffer(context); 656 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context); 657 obex_message_builder_header_add_challenge_response(buffer, buffer_len, data, length); 658 } 659 660 void goep_client_body_add_static(uint16_t goep_cid, const uint8_t * data, uint32_t length){ 661 UNUSED(goep_cid); 662 goep_client_t * context = goep_client; 663 664 uint8_t * buffer = goep_client_get_outgoing_buffer(context); 665 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context); 666 obex_message_builder_body_add_static(buffer, buffer_len, data, length); 667 } 668 669 uint16_t goep_client_body_get_outgoing_buffer_len(uint16_t goep_cid) { 670 UNUSED(goep_cid); 671 goep_client_t * context = goep_client; 672 673 return goep_client_get_outgoing_buffer_len(context); 674 }; 675 676 void goep_client_body_fillup_static(uint16_t goep_cid, const uint8_t * data, uint32_t length, uint32_t * ret_length){ 677 UNUSED(goep_cid); 678 goep_client_t * context = goep_client; 679 680 uint8_t * buffer = goep_client_get_outgoing_buffer(context); 681 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context); 682 obex_message_builder_body_fillup_static(buffer, buffer_len, data, length, ret_length); 683 } 684 685 void goep_client_header_add_name(uint16_t goep_cid, const char * name){ 686 UNUSED(goep_cid); 687 goep_client_t * context = goep_client; 688 689 uint8_t * buffer = goep_client_get_outgoing_buffer(context); 690 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context); 691 obex_message_builder_header_add_name(buffer, buffer_len, name); 692 } 693 694 void goep_client_header_add_name_prefix(uint16_t goep_cid, const char * name, uint16_t name_len){ 695 UNUSED(goep_cid); 696 goep_client_t * context = goep_client; 697 698 uint8_t * buffer = goep_client_get_outgoing_buffer(context); 699 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context); 700 obex_message_builder_header_add_name_prefix(buffer, buffer_len, name, name_len); 701 } 702 703 void goep_client_header_add_type(uint16_t goep_cid, const char * type){ 704 UNUSED(goep_cid); 705 goep_client_t * context = goep_client; 706 707 uint8_t * buffer = goep_client_get_outgoing_buffer(context); 708 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context); 709 obex_message_builder_header_add_type(buffer, buffer_len, type); 710 } 711 712 void goep_client_header_add_length(uint16_t goep_cid, uint32_t length){ 713 UNUSED(goep_cid); 714 goep_client_t * context = goep_client; 715 716 uint8_t * buffer = goep_client_get_outgoing_buffer(context); 717 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context); 718 obex_message_builder_header_add_length(buffer, buffer_len, length); 719 } 720 721 uint16_t goep_client_request_get_max_body_size(uint16_t goep_cid){ 722 UNUSED(goep_cid); 723 goep_client_t * context = goep_client; 724 725 uint8_t * buffer = goep_client_get_outgoing_buffer(context); 726 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context); 727 uint16_t pos = big_endian_read_16(buffer, 1); 728 return buffer_len - pos; 729 } 730 731 int goep_client_execute(uint16_t goep_cid){ 732 return goep_client_execute_with_final_bit (goep_cid, true); 733 } 734 735 int goep_client_execute_with_final_bit(uint16_t goep_cid, bool final){ 736 UNUSED(goep_cid); 737 goep_client_t * context = goep_client; 738 uint8_t * buffer = goep_client_get_outgoing_buffer(context); 739 uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context); 740 741 obex_message_builder_set_final_bit (buffer, buffer_len, final); 742 743 uint16_t pos = big_endian_read_16(buffer, 1); 744 if (context->l2cap_psm){ 745 return l2cap_send(context->bearer_cid, buffer, pos); 746 } else { 747 return rfcomm_send_prepared(context->bearer_cid, pos); 748 } 749 } 750 751