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 507c006017SMilanka Ringwald static uint8_t obex_message_builder_packet_init(uint8_t * buffer, uint16_t buffer_len, uint8_t opcode){ 517c006017SMilanka Ringwald if (buffer_len < 3) return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED; 527c006017SMilanka Ringwald buffer[0] = opcode; 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 127*09ef1e1eSMatthias Ringwald uint8_t obex_message_builder_response_create_general(uint8_t * buffer, uint16_t buffer_len, uint8_t opcode){ 128*09ef1e1eSMatthias Ringwald return obex_message_builder_packet_init(buffer, buffer_len, opcode); 129*09ef1e1eSMatthias Ringwald } 130*09ef1e1eSMatthias Ringwald 1317c006017SMilanka Ringwald uint8_t obex_message_builder_request_create_get(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){ 1327c006017SMilanka Ringwald uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_GET | OBEX_OPCODE_FINAL_BIT_MASK); 1337c006017SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 1347c006017SMilanka Ringwald return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id); 1357c006017SMilanka Ringwald } 1367c006017SMilanka Ringwald 1377c006017SMilanka Ringwald uint8_t obex_message_builder_request_create_put(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_PUT | OBEX_OPCODE_FINAL_BIT_MASK); 1397c006017SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 1407c006017SMilanka Ringwald 1417c006017SMilanka Ringwald return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id); 1427c006017SMilanka Ringwald } 1437c006017SMilanka Ringwald 1447c006017SMilanka 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){ 1457c006017SMilanka Ringwald uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_SETPATH); 1467c006017SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 1477c006017SMilanka Ringwald 1487c006017SMilanka Ringwald uint8_t fields[2]; 1497c006017SMilanka Ringwald fields[0] = flags; 1507c006017SMilanka Ringwald fields[1] = 0; // reserved 1517c006017SMilanka Ringwald status = obex_message_builder_packet_append(buffer, buffer_len, &fields[0], sizeof(fields)); 1527c006017SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 1537c006017SMilanka Ringwald return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id); 1547c006017SMilanka Ringwald } 1557c006017SMilanka Ringwald 1567c006017SMilanka Ringwald uint8_t obex_message_builder_request_create_abort(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){ 1577c006017SMilanka Ringwald uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_ABORT); 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_disconnect(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_DISCONNECT); 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_header_add_srm_enable(uint8_t * buffer, uint16_t buffer_len){ 1697c006017SMilanka Ringwald return obex_message_builder_header_add_byte(buffer, buffer_len, OBEX_HEADER_SINGLE_RESPONSE_MODE, OBEX_SRM_ENABLE); 1707c006017SMilanka Ringwald } 1717c006017SMilanka Ringwald 1727c006017SMilanka Ringwald uint8_t obex_message_builder_header_add_target(uint8_t * buffer, uint16_t buffer_len, const uint8_t * target, uint16_t length){ 1737c006017SMilanka Ringwald return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_TARGET, target, length); 1747c006017SMilanka Ringwald } 1757c006017SMilanka Ringwald 1767c006017SMilanka Ringwald uint8_t obex_message_builder_header_add_application_parameters(uint8_t * buffer, uint16_t buffer_len, const uint8_t * data, uint16_t length){ 1777c006017SMilanka Ringwald return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_APPLICATION_PARAMETERS, data, length); 1787c006017SMilanka Ringwald } 1797c006017SMilanka Ringwald 180c4466456SMilanka Ringwald uint8_t obex_message_builder_header_add_challenge_response(uint8_t * buffer, uint16_t buffer_len, const uint8_t * data, uint16_t length){ 1817c006017SMilanka Ringwald return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_AUTHENTICATION_RESPONSE, data, length); 1827c006017SMilanka Ringwald } 1837c006017SMilanka Ringwald 1841f6020d5SMilanka Ringwald uint8_t obex_message_builder_header_add_who(uint8_t * buffer, uint16_t buffer_len, const uint8_t * who){ 1851f6020d5SMilanka Ringwald return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_WHO, who, 16); 1861f6020d5SMilanka Ringwald } 1871f6020d5SMilanka Ringwald 188948b3642SMilanka Ringwald uint8_t obex_message_builder_body_add_static(uint8_t * buffer, uint16_t buffer_len, const uint8_t * data, uint32_t length){ 1897c006017SMilanka Ringwald return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_END_OF_BODY, data, length); 1907c006017SMilanka Ringwald } 1917c006017SMilanka Ringwald 1922946c1e3SMatthias Ringwald uint8_t obex_message_builder_header_add_name_prefix(uint8_t * buffer, uint16_t buffer_len, const char * name, uint16_t name_len){ 19395f75094SMatthias Ringwald // non-empty string have trailing \0 19495f75094SMatthias Ringwald bool add_trailing_zero = name_len > 0; 19595f75094SMatthias Ringwald 19695f75094SMatthias Ringwald uint16_t header_len = 1 + 2 + (name_len * 2) + (add_trailing_zero ? 2 : 0); 19795f75094SMatthias Ringwald if (buffer_len < header_len) return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED; 1987c006017SMilanka Ringwald 1997c006017SMilanka Ringwald uint16_t pos = big_endian_read_16(buffer, 1); 2007c006017SMilanka Ringwald buffer[pos++] = OBEX_HEADER_NAME; 20195f75094SMatthias Ringwald big_endian_store_16(buffer, pos, header_len); 2027c006017SMilanka Ringwald pos += 2; 2037c006017SMilanka Ringwald int i; 2047c006017SMilanka Ringwald // @note name[len] == 0 2052946c1e3SMatthias Ringwald for (i = 0 ; i < name_len ; i++){ 2067c006017SMilanka Ringwald buffer[pos++] = 0; 2077c006017SMilanka Ringwald buffer[pos++] = *name++; 2087c006017SMilanka Ringwald } 20995f75094SMatthias Ringwald if (add_trailing_zero){ 21095f75094SMatthias Ringwald buffer[pos++] = 0; 21195f75094SMatthias Ringwald buffer[pos++] = 0; 21295f75094SMatthias Ringwald } 2137c006017SMilanka Ringwald big_endian_store_16(buffer, 1, pos); 2147c006017SMilanka Ringwald return ERROR_CODE_SUCCESS; 2157c006017SMilanka Ringwald } 2162946c1e3SMatthias Ringwald uint8_t obex_message_builder_header_add_name(uint8_t * buffer, uint16_t buffer_len, const char * name){ 21795f75094SMatthias Ringwald uint16_t name_len = strlen(name); 21895f75094SMatthias Ringwald return obex_message_builder_header_add_name_prefix(buffer, buffer_len, name, name_len); 2192946c1e3SMatthias Ringwald } 2207c006017SMilanka Ringwald 2217c006017SMilanka Ringwald uint8_t obex_message_builder_header_add_type(uint8_t * buffer, uint16_t buffer_len, const char * type){ 2227c006017SMilanka Ringwald uint8_t header[3]; 2237c006017SMilanka Ringwald header[0] = OBEX_HEADER_TYPE; 2247c006017SMilanka Ringwald int len_incl_zero = strlen(type) + 1; 2257c006017SMilanka Ringwald big_endian_store_16(header, 1, 1 + 2 + len_incl_zero); 2267c006017SMilanka Ringwald 2277c006017SMilanka Ringwald uint8_t status = obex_message_builder_packet_append(buffer, buffer_len, &header[0], sizeof(header)); 2287c006017SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 2297c006017SMilanka Ringwald return obex_message_builder_packet_append(buffer, buffer_len, (const uint8_t*)type, len_incl_zero); 2307c006017SMilanka Ringwald } 231