17c006017SMilanka Ringwald /* 27c006017SMilanka Ringwald * Copyright (C) 2019 BlueKitchen GmbH 37c006017SMilanka Ringwald * 47c006017SMilanka Ringwald * Redistribution and use in source and binary forms, with or without 57c006017SMilanka Ringwald * modification, are permitted provided that the following conditions 67c006017SMilanka Ringwald * are met: 77c006017SMilanka Ringwald * 87c006017SMilanka Ringwald * 1. Redistributions of source code must retain the above copyright 97c006017SMilanka Ringwald * notice, this list of conditions and the following disclaimer. 107c006017SMilanka Ringwald * 2. Redistributions in binary form must reproduce the above copyright 117c006017SMilanka Ringwald * notice, this list of conditions and the following disclaimer in the 127c006017SMilanka Ringwald * documentation and/or other materials provided with the distribution. 137c006017SMilanka Ringwald * 3. Neither the name of the copyright holders nor the names of 147c006017SMilanka Ringwald * contributors may be used to endorse or promote products derived 157c006017SMilanka Ringwald * from this software without specific prior written permission. 167c006017SMilanka Ringwald * 4. Any redistribution, use, or modification is done solely for 177c006017SMilanka Ringwald * personal benefit and not for any commercial purpose or for 187c006017SMilanka Ringwald * monetary gain. 197c006017SMilanka Ringwald * 207c006017SMilanka Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 217c006017SMilanka Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 227c006017SMilanka Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 242fca4dadSMilanka Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 257c006017SMilanka Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 267c006017SMilanka Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 277c006017SMilanka Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 287c006017SMilanka Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 297c006017SMilanka Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 307c006017SMilanka Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 317c006017SMilanka Ringwald * SUCH DAMAGE. 327c006017SMilanka Ringwald * 337c006017SMilanka Ringwald * Please inquire about commercial licensing options at 347c006017SMilanka Ringwald * [email protected] 357c006017SMilanka Ringwald * 367c006017SMilanka Ringwald */ 377c006017SMilanka Ringwald 38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "obex_message_builder.c" 397c006017SMilanka Ringwald 407c006017SMilanka Ringwald #include "btstack_config.h" 417c006017SMilanka Ringwald 427c006017SMilanka Ringwald #include <stdint.h> 437c006017SMilanka Ringwald #include <stdlib.h> 447c006017SMilanka Ringwald 457c006017SMilanka Ringwald #include "btstack_util.h" 467c006017SMilanka Ringwald #include "btstack_debug.h" 477c006017SMilanka Ringwald #include "classic/obex.h" 487c006017SMilanka Ringwald #include "classic/obex_message_builder.h" 497c006017SMilanka Ringwald 508460ee57SMatthias Ringwald static uint8_t obex_message_builder_packet_init(uint8_t * buffer, uint16_t buffer_len, uint8_t opcode_or_response_code){ 517c006017SMilanka Ringwald if (buffer_len < 3) return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED; 528460ee57SMatthias Ringwald buffer[0] = opcode_or_response_code; 537c006017SMilanka Ringwald big_endian_store_16(buffer, 1, 3); 547c006017SMilanka Ringwald return ERROR_CODE_SUCCESS; 557c006017SMilanka Ringwald } 567c006017SMilanka Ringwald 577c006017SMilanka Ringwald static uint8_t obex_message_builder_packet_append(uint8_t * buffer, uint16_t buffer_len, const uint8_t * data, uint16_t len){ 587c006017SMilanka Ringwald uint16_t pos = big_endian_read_16(buffer, 1); 597c006017SMilanka Ringwald if (buffer_len < pos + len) return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED; 606535961aSMatthias Ringwald (void)memcpy(&buffer[pos], data, len); 617c006017SMilanka Ringwald pos += len; 627c006017SMilanka Ringwald big_endian_store_16(buffer, 1, pos); 637c006017SMilanka Ringwald return ERROR_CODE_SUCCESS; 647c006017SMilanka Ringwald } 657c006017SMilanka Ringwald 661f6020d5SMilanka Ringwald uint16_t obex_message_builder_get_message_length(uint8_t * buffer){ 671f6020d5SMilanka Ringwald return big_endian_read_16(buffer, 1); 681f6020d5SMilanka Ringwald } 691f6020d5SMilanka Ringwald 7081fb6ec9SMilanka Ringwald uint8_t obex_message_builder_header_add_byte(uint8_t * buffer, uint16_t buffer_len, uint8_t header_type, uint8_t value){ 7181fb6ec9SMilanka Ringwald uint8_t header[2]; 7281fb6ec9SMilanka Ringwald header[0] = header_type; 7381fb6ec9SMilanka Ringwald header[1] = value; 7481fb6ec9SMilanka Ringwald return obex_message_builder_packet_append(buffer, buffer_len, &header[0], sizeof(header)); 7581fb6ec9SMilanka Ringwald } 7681fb6ec9SMilanka Ringwald 7781fb6ec9SMilanka Ringwald uint8_t obex_message_builder_header_add_word(uint8_t * buffer, uint16_t buffer_len, uint8_t header_type, uint32_t value){ 7881fb6ec9SMilanka Ringwald uint8_t header[5]; 7981fb6ec9SMilanka Ringwald header[0] = header_type; 8081fb6ec9SMilanka Ringwald big_endian_store_32(header, 1, value); 8181fb6ec9SMilanka Ringwald return obex_message_builder_packet_append(buffer, buffer_len, &header[0], sizeof(header)); 8281fb6ec9SMilanka Ringwald } 8381fb6ec9SMilanka Ringwald 8481fb6ec9SMilanka Ringwald uint8_t obex_message_builder_header_add_variable(uint8_t * buffer, uint16_t buffer_len, uint8_t header_type, const uint8_t * header_data, uint16_t header_data_length){ 857c006017SMilanka Ringwald uint8_t header[3]; 867c006017SMilanka Ringwald header[0] = header_type; 877c006017SMilanka Ringwald big_endian_store_16(header, 1, sizeof(header) + header_data_length); 887c006017SMilanka Ringwald 897c006017SMilanka Ringwald uint8_t status = obex_message_builder_packet_append(buffer, buffer_len, &header[0], sizeof(header)); 907c006017SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 917c006017SMilanka Ringwald 927c006017SMilanka Ringwald return obex_message_builder_packet_append(buffer, buffer_len, header_data, header_data_length); 937c006017SMilanka Ringwald } 947c006017SMilanka Ringwald 957c006017SMilanka Ringwald static uint8_t obex_message_builder_header_add_connection_id(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){ 967c006017SMilanka Ringwald // add connection_id header if set, must be first header if used 977c006017SMilanka Ringwald if (obex_connection_id == OBEX_CONNECTION_ID_INVALID) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 987c006017SMilanka Ringwald return obex_message_builder_header_add_word(buffer, buffer_len, OBEX_HEADER_CONNECTION_ID, obex_connection_id); 997c006017SMilanka Ringwald } 1007c006017SMilanka Ringwald 1011f6020d5SMilanka Ringwald static inline uint8_t obex_message_builder_create_connect(uint8_t * buffer, uint16_t buffer_len, uint8_t opcode, 1021f6020d5SMilanka Ringwald uint8_t obex_version_number, uint8_t flags, uint16_t maximum_obex_packet_length){ 1031f6020d5SMilanka Ringwald uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, opcode); 1047c006017SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 1057c006017SMilanka Ringwald 1067c006017SMilanka Ringwald uint8_t fields[4]; 1077c006017SMilanka Ringwald fields[0] = obex_version_number; 1087c006017SMilanka Ringwald fields[1] = flags; 1097c006017SMilanka Ringwald big_endian_store_16(fields, 2, maximum_obex_packet_length); 1107c006017SMilanka Ringwald return obex_message_builder_packet_append(buffer, buffer_len, &fields[0], sizeof(fields)); 1117c006017SMilanka Ringwald } 1127c006017SMilanka Ringwald 1131f6020d5SMilanka Ringwald uint8_t obex_message_builder_request_create_connect(uint8_t * buffer, uint16_t buffer_len, 1141f6020d5SMilanka Ringwald uint8_t obex_version_number, uint8_t flags, uint16_t maximum_obex_packet_length){ 1151f6020d5SMilanka Ringwald 1161f6020d5SMilanka Ringwald return obex_message_builder_create_connect(buffer, buffer_len, OBEX_OPCODE_CONNECT, obex_version_number, flags, maximum_obex_packet_length); 1171f6020d5SMilanka Ringwald } 1181f6020d5SMilanka Ringwald 1191f6020d5SMilanka Ringwald uint8_t obex_message_builder_response_create_connect(uint8_t * buffer, uint16_t buffer_len, uint8_t obex_version_number, 1201f6020d5SMilanka Ringwald uint8_t flags, uint16_t maximum_obex_packet_length, uint32_t obex_connection_id){ 1211f6020d5SMilanka Ringwald 1221f6020d5SMilanka Ringwald uint8_t status = obex_message_builder_create_connect(buffer, buffer_len, OBEX_RESP_SUCCESS, obex_version_number, flags, maximum_obex_packet_length); 1231f6020d5SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 1241f6020d5SMilanka Ringwald return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id); 1251f6020d5SMilanka Ringwald } 1261f6020d5SMilanka Ringwald 1278460ee57SMatthias Ringwald uint8_t obex_message_builder_response_create_general(uint8_t * buffer, uint16_t buffer_len, uint8_t response_code){ 1288460ee57SMatthias Ringwald return obex_message_builder_packet_init(buffer, buffer_len, response_code); 12909ef1e1eSMatthias Ringwald } 13009ef1e1eSMatthias Ringwald 131c2e0c88eSMatthias Ringwald uint8_t obex_message_builder_response_update_code(uint8_t * buffer, uint16_t buffer_len, uint8_t response_code){ 132c2e0c88eSMatthias Ringwald if (buffer_len < 3) return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED; 133c2e0c88eSMatthias Ringwald buffer[0] = response_code; 134c2e0c88eSMatthias Ringwald return ERROR_CODE_SUCCESS; 135c2e0c88eSMatthias Ringwald } 136c2e0c88eSMatthias Ringwald 1377c006017SMilanka Ringwald uint8_t obex_message_builder_request_create_get(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){ 1387c006017SMilanka Ringwald uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_GET | OBEX_OPCODE_FINAL_BIT_MASK); 1397c006017SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 1407c006017SMilanka Ringwald return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id); 1417c006017SMilanka Ringwald } 1427c006017SMilanka Ringwald 1437c006017SMilanka Ringwald uint8_t obex_message_builder_request_create_put(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){ 1447c006017SMilanka Ringwald uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_PUT | OBEX_OPCODE_FINAL_BIT_MASK); 1457c006017SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 1467c006017SMilanka Ringwald 1477c006017SMilanka Ringwald return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id); 1487c006017SMilanka Ringwald } 1497c006017SMilanka Ringwald 1507c006017SMilanka Ringwald uint8_t obex_message_builder_request_create_set_path(uint8_t * buffer, uint16_t buffer_len, uint8_t flags, uint32_t obex_connection_id){ 1517c006017SMilanka Ringwald uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_SETPATH); 1527c006017SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 1537c006017SMilanka Ringwald 1547c006017SMilanka Ringwald uint8_t fields[2]; 1557c006017SMilanka Ringwald fields[0] = flags; 1567c006017SMilanka Ringwald fields[1] = 0; // reserved 1577c006017SMilanka Ringwald status = obex_message_builder_packet_append(buffer, buffer_len, &fields[0], sizeof(fields)); 1587c006017SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 1597c006017SMilanka Ringwald return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id); 1607c006017SMilanka Ringwald } 1617c006017SMilanka Ringwald 1627c006017SMilanka Ringwald uint8_t obex_message_builder_request_create_abort(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){ 1637c006017SMilanka Ringwald uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_ABORT); 1647c006017SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 1657c006017SMilanka Ringwald return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id); 1667c006017SMilanka Ringwald } 1677c006017SMilanka Ringwald 1687c006017SMilanka Ringwald uint8_t obex_message_builder_request_create_disconnect(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){ 1697c006017SMilanka Ringwald uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_DISCONNECT); 1707c006017SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 1717c006017SMilanka Ringwald return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id); 1727c006017SMilanka Ringwald } 1737c006017SMilanka Ringwald 1747c006017SMilanka Ringwald uint8_t obex_message_builder_header_add_srm_enable(uint8_t * buffer, uint16_t buffer_len){ 1757c006017SMilanka Ringwald return obex_message_builder_header_add_byte(buffer, buffer_len, OBEX_HEADER_SINGLE_RESPONSE_MODE, OBEX_SRM_ENABLE); 1767c006017SMilanka Ringwald } 1777c006017SMilanka Ringwald 1787c006017SMilanka Ringwald uint8_t obex_message_builder_header_add_target(uint8_t * buffer, uint16_t buffer_len, const uint8_t * target, uint16_t length){ 1797c006017SMilanka Ringwald return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_TARGET, target, length); 1807c006017SMilanka Ringwald } 1817c006017SMilanka Ringwald 1827c006017SMilanka Ringwald uint8_t obex_message_builder_header_add_application_parameters(uint8_t * buffer, uint16_t buffer_len, const uint8_t * data, uint16_t length){ 1837c006017SMilanka Ringwald return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_APPLICATION_PARAMETERS, data, length); 1847c006017SMilanka Ringwald } 1857c006017SMilanka Ringwald 186c4466456SMilanka Ringwald uint8_t obex_message_builder_header_add_challenge_response(uint8_t * buffer, uint16_t buffer_len, const uint8_t * data, uint16_t length){ 1877c006017SMilanka Ringwald return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_AUTHENTICATION_RESPONSE, data, length); 1887c006017SMilanka Ringwald } 1897c006017SMilanka Ringwald 1901f6020d5SMilanka Ringwald uint8_t obex_message_builder_header_add_who(uint8_t * buffer, uint16_t buffer_len, const uint8_t * who){ 1911f6020d5SMilanka Ringwald return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_WHO, who, 16); 1921f6020d5SMilanka Ringwald } 1931f6020d5SMilanka Ringwald 194948b3642SMilanka Ringwald uint8_t obex_message_builder_body_add_static(uint8_t * buffer, uint16_t buffer_len, const uint8_t * data, uint32_t length){ 1957c006017SMilanka Ringwald return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_END_OF_BODY, data, length); 1967c006017SMilanka Ringwald } 1977c006017SMilanka Ringwald 1982946c1e3SMatthias Ringwald uint8_t obex_message_builder_header_add_name_prefix(uint8_t * buffer, uint16_t buffer_len, const char * name, uint16_t name_len){ 19995f75094SMatthias Ringwald // non-empty string have trailing \0 20095f75094SMatthias Ringwald bool add_trailing_zero = name_len > 0; 20195f75094SMatthias Ringwald 20295f75094SMatthias Ringwald uint16_t header_len = 1 + 2 + (name_len * 2) + (add_trailing_zero ? 2 : 0); 20395f75094SMatthias Ringwald if (buffer_len < header_len) return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED; 2047c006017SMilanka Ringwald 2057c006017SMilanka Ringwald uint16_t pos = big_endian_read_16(buffer, 1); 2067c006017SMilanka Ringwald buffer[pos++] = OBEX_HEADER_NAME; 20795f75094SMatthias Ringwald big_endian_store_16(buffer, pos, header_len); 2087c006017SMilanka Ringwald pos += 2; 2097c006017SMilanka Ringwald int i; 2107c006017SMilanka Ringwald // @note name[len] == 0 2112946c1e3SMatthias Ringwald for (i = 0 ; i < name_len ; i++){ 2127c006017SMilanka Ringwald buffer[pos++] = 0; 2137c006017SMilanka Ringwald buffer[pos++] = *name++; 2147c006017SMilanka Ringwald } 21595f75094SMatthias Ringwald if (add_trailing_zero){ 21695f75094SMatthias Ringwald buffer[pos++] = 0; 21795f75094SMatthias Ringwald buffer[pos++] = 0; 21895f75094SMatthias Ringwald } 2197c006017SMilanka Ringwald big_endian_store_16(buffer, 1, pos); 2207c006017SMilanka Ringwald return ERROR_CODE_SUCCESS; 2217c006017SMilanka Ringwald } 2222946c1e3SMatthias Ringwald uint8_t obex_message_builder_header_add_name(uint8_t * buffer, uint16_t buffer_len, const char * name){ 223*b56e8b56SMatthias Ringwald uint16_t name_len = (uint16_t) strlen(name); 22495f75094SMatthias Ringwald return obex_message_builder_header_add_name_prefix(buffer, buffer_len, name, name_len); 2252946c1e3SMatthias Ringwald } 2267c006017SMilanka Ringwald 2277c006017SMilanka Ringwald uint8_t obex_message_builder_header_add_type(uint8_t * buffer, uint16_t buffer_len, const char * type){ 2287c006017SMilanka Ringwald uint8_t header[3]; 2297c006017SMilanka Ringwald header[0] = OBEX_HEADER_TYPE; 230*b56e8b56SMatthias Ringwald int len_incl_zero = (uint16_t) strlen(type) + 1; 2317c006017SMilanka Ringwald big_endian_store_16(header, 1, 1 + 2 + len_incl_zero); 2327c006017SMilanka Ringwald 2337c006017SMilanka Ringwald uint8_t status = obex_message_builder_packet_append(buffer, buffer_len, &header[0], sizeof(header)); 2347c006017SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 2357c006017SMilanka Ringwald return obex_message_builder_packet_append(buffer, buffer_len, (const uint8_t*)type, len_incl_zero); 2367c006017SMilanka Ringwald } 237