xref: /btstack/src/classic/obex_message_builder.c (revision 09ef1e1ec37886329896ced07ff5907bbe2efade)
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