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 6681fb6ec9SMilanka Ringwald uint8_t obex_message_builder_header_add_byte(uint8_t * buffer, uint16_t buffer_len, uint8_t header_type, uint8_t value){ 6781fb6ec9SMilanka Ringwald uint8_t header[2]; 6881fb6ec9SMilanka Ringwald header[0] = header_type; 6981fb6ec9SMilanka Ringwald header[1] = value; 7081fb6ec9SMilanka Ringwald return obex_message_builder_packet_append(buffer, buffer_len, &header[0], sizeof(header)); 7181fb6ec9SMilanka Ringwald } 7281fb6ec9SMilanka Ringwald 7381fb6ec9SMilanka Ringwald uint8_t obex_message_builder_header_add_word(uint8_t * buffer, uint16_t buffer_len, uint8_t header_type, uint32_t value){ 7481fb6ec9SMilanka Ringwald uint8_t header[5]; 7581fb6ec9SMilanka Ringwald header[0] = header_type; 7681fb6ec9SMilanka Ringwald big_endian_store_32(header, 1, value); 7781fb6ec9SMilanka Ringwald return obex_message_builder_packet_append(buffer, buffer_len, &header[0], sizeof(header)); 7881fb6ec9SMilanka Ringwald } 7981fb6ec9SMilanka Ringwald 8081fb6ec9SMilanka 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){ 817c006017SMilanka Ringwald uint8_t header[3]; 827c006017SMilanka Ringwald header[0] = header_type; 837c006017SMilanka Ringwald big_endian_store_16(header, 1, sizeof(header) + header_data_length); 847c006017SMilanka Ringwald 857c006017SMilanka Ringwald uint8_t status = obex_message_builder_packet_append(buffer, buffer_len, &header[0], sizeof(header)); 867c006017SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 877c006017SMilanka Ringwald 887c006017SMilanka Ringwald return obex_message_builder_packet_append(buffer, buffer_len, header_data, header_data_length); 897c006017SMilanka Ringwald } 907c006017SMilanka Ringwald 917c006017SMilanka Ringwald static uint8_t obex_message_builder_header_add_connection_id(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){ 927c006017SMilanka Ringwald // add connection_id header if set, must be first header if used 937c006017SMilanka Ringwald if (obex_connection_id == OBEX_CONNECTION_ID_INVALID) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 947c006017SMilanka Ringwald return obex_message_builder_header_add_word(buffer, buffer_len, OBEX_HEADER_CONNECTION_ID, obex_connection_id); 957c006017SMilanka Ringwald } 967c006017SMilanka Ringwald 977c006017SMilanka Ringwald uint8_t obex_message_builder_request_create_connect(uint8_t * buffer, uint16_t buffer_len, uint8_t obex_version_number, uint8_t flags, uint16_t maximum_obex_packet_length){ 987c006017SMilanka Ringwald uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_CONNECT); 997c006017SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 1007c006017SMilanka Ringwald 1017c006017SMilanka Ringwald uint8_t fields[4]; 1027c006017SMilanka Ringwald fields[0] = obex_version_number; 1037c006017SMilanka Ringwald fields[1] = flags; 1047c006017SMilanka Ringwald big_endian_store_16(fields, 2, maximum_obex_packet_length); 1057c006017SMilanka Ringwald return obex_message_builder_packet_append(buffer, buffer_len, &fields[0], sizeof(fields)); 1067c006017SMilanka Ringwald } 1077c006017SMilanka Ringwald 1087c006017SMilanka Ringwald uint8_t obex_message_builder_request_create_get(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){ 1097c006017SMilanka Ringwald uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_GET | OBEX_OPCODE_FINAL_BIT_MASK); 1107c006017SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 1117c006017SMilanka Ringwald return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id); 1127c006017SMilanka Ringwald } 1137c006017SMilanka Ringwald 1147c006017SMilanka Ringwald uint8_t obex_message_builder_request_create_put(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){ 1157c006017SMilanka Ringwald uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_PUT | OBEX_OPCODE_FINAL_BIT_MASK); 1167c006017SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 1177c006017SMilanka Ringwald 1187c006017SMilanka Ringwald return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id); 1197c006017SMilanka Ringwald } 1207c006017SMilanka Ringwald 1217c006017SMilanka 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){ 1227c006017SMilanka Ringwald uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_SETPATH); 1237c006017SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 1247c006017SMilanka Ringwald 1257c006017SMilanka Ringwald uint8_t fields[2]; 1267c006017SMilanka Ringwald fields[0] = flags; 1277c006017SMilanka Ringwald fields[1] = 0; // reserved 1287c006017SMilanka Ringwald status = obex_message_builder_packet_append(buffer, buffer_len, &fields[0], sizeof(fields)); 1297c006017SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 1307c006017SMilanka Ringwald return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id); 1317c006017SMilanka Ringwald } 1327c006017SMilanka Ringwald 1337c006017SMilanka Ringwald uint8_t obex_message_builder_request_create_abort(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){ 1347c006017SMilanka Ringwald uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_ABORT); 1357c006017SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 1367c006017SMilanka Ringwald return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id); 1377c006017SMilanka Ringwald } 1387c006017SMilanka Ringwald 1397c006017SMilanka Ringwald uint8_t obex_message_builder_request_create_disconnect(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){ 1407c006017SMilanka Ringwald uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_DISCONNECT); 1417c006017SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 1427c006017SMilanka Ringwald return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id); 1437c006017SMilanka Ringwald } 1447c006017SMilanka Ringwald 1457c006017SMilanka Ringwald uint8_t obex_message_builder_header_add_srm_enable(uint8_t * buffer, uint16_t buffer_len){ 1467c006017SMilanka Ringwald return obex_message_builder_header_add_byte(buffer, buffer_len, OBEX_HEADER_SINGLE_RESPONSE_MODE, OBEX_SRM_ENABLE); 1477c006017SMilanka Ringwald } 1487c006017SMilanka Ringwald 1497c006017SMilanka Ringwald uint8_t obex_message_builder_header_add_target(uint8_t * buffer, uint16_t buffer_len, const uint8_t * target, uint16_t length){ 1507c006017SMilanka Ringwald return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_TARGET, target, length); 1517c006017SMilanka Ringwald } 1527c006017SMilanka Ringwald 1537c006017SMilanka Ringwald uint8_t obex_message_builder_header_add_application_parameters(uint8_t * buffer, uint16_t buffer_len, const uint8_t * data, uint16_t length){ 1547c006017SMilanka Ringwald return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_APPLICATION_PARAMETERS, data, length); 1557c006017SMilanka Ringwald } 1567c006017SMilanka Ringwald 157c4466456SMilanka Ringwald uint8_t obex_message_builder_header_add_challenge_response(uint8_t * buffer, uint16_t buffer_len, const uint8_t * data, uint16_t length){ 1587c006017SMilanka Ringwald return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_AUTHENTICATION_RESPONSE, data, length); 1597c006017SMilanka Ringwald } 1607c006017SMilanka Ringwald 161948b3642SMilanka Ringwald uint8_t obex_message_builder_body_add_static(uint8_t * buffer, uint16_t buffer_len, const uint8_t * data, uint32_t length){ 1627c006017SMilanka Ringwald return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_END_OF_BODY, data, length); 1637c006017SMilanka Ringwald } 1647c006017SMilanka Ringwald 1652946c1e3SMatthias Ringwald uint8_t obex_message_builder_header_add_name_prefix(uint8_t * buffer, uint16_t buffer_len, const char * name, uint16_t name_len){ 166*95f75094SMatthias Ringwald // non-empty string have trailing \0 167*95f75094SMatthias Ringwald bool add_trailing_zero = name_len > 0; 168*95f75094SMatthias Ringwald 169*95f75094SMatthias Ringwald uint16_t header_len = 1 + 2 + (name_len * 2) + (add_trailing_zero ? 2 : 0); 170*95f75094SMatthias Ringwald if (buffer_len < header_len) return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED; 1717c006017SMilanka Ringwald 1727c006017SMilanka Ringwald uint16_t pos = big_endian_read_16(buffer, 1); 1737c006017SMilanka Ringwald buffer[pos++] = OBEX_HEADER_NAME; 174*95f75094SMatthias Ringwald big_endian_store_16(buffer, pos, header_len); 1757c006017SMilanka Ringwald pos += 2; 1767c006017SMilanka Ringwald int i; 1777c006017SMilanka Ringwald // @note name[len] == 0 1782946c1e3SMatthias Ringwald for (i = 0 ; i < name_len ; i++){ 1797c006017SMilanka Ringwald buffer[pos++] = 0; 1807c006017SMilanka Ringwald buffer[pos++] = *name++; 1817c006017SMilanka Ringwald } 182*95f75094SMatthias Ringwald if (add_trailing_zero){ 183*95f75094SMatthias Ringwald buffer[pos++] = 0; 184*95f75094SMatthias Ringwald buffer[pos++] = 0; 185*95f75094SMatthias Ringwald } 1867c006017SMilanka Ringwald big_endian_store_16(buffer, 1, pos); 1877c006017SMilanka Ringwald return ERROR_CODE_SUCCESS; 1887c006017SMilanka Ringwald } 1892946c1e3SMatthias Ringwald uint8_t obex_message_builder_header_add_name(uint8_t * buffer, uint16_t buffer_len, const char * name){ 190*95f75094SMatthias Ringwald uint16_t name_len = strlen(name); 191*95f75094SMatthias Ringwald return obex_message_builder_header_add_name_prefix(buffer, buffer_len, name, name_len); 1922946c1e3SMatthias Ringwald } 1937c006017SMilanka Ringwald 1947c006017SMilanka Ringwald uint8_t obex_message_builder_header_add_type(uint8_t * buffer, uint16_t buffer_len, const char * type){ 1957c006017SMilanka Ringwald uint8_t header[3]; 1967c006017SMilanka Ringwald header[0] = OBEX_HEADER_TYPE; 1977c006017SMilanka Ringwald int len_incl_zero = strlen(type) + 1; 1987c006017SMilanka Ringwald big_endian_store_16(header, 1, 1 + 2 + len_incl_zero); 1997c006017SMilanka Ringwald 2007c006017SMilanka Ringwald uint8_t status = obex_message_builder_packet_append(buffer, buffer_len, &header[0], sizeof(header)); 2017c006017SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return status; 2027c006017SMilanka Ringwald return obex_message_builder_packet_append(buffer, buffer_len, (const uint8_t*)type, len_incl_zero); 2037c006017SMilanka Ringwald } 204