xref: /btstack/src/classic/obex_message_builder.c (revision b28dc8004dd8d4fb9020a6dcd2bc81f05d36a008)
1 /*
2  * Copyright (C) 2019 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__ "obex_message_builder.c"
39 
40 #include "btstack_config.h"
41 
42 #include <stdint.h>
43 #include <stdlib.h>
44 
45 #include "btstack_util.h"
46 #include "btstack_debug.h"
47 #include "classic/obex.h"
48 #include "classic/obex_message_builder.h"
49 
50 static uint8_t obex_message_builder_packet_init(uint8_t * buffer, uint16_t buffer_len, uint8_t opcode){
51     if (buffer_len < 3) return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED;
52     buffer[0] = opcode;
53     big_endian_store_16(buffer, 1, 3);
54     return ERROR_CODE_SUCCESS;
55 }
56 
57 static uint8_t obex_message_builder_packet_append(uint8_t * buffer, uint16_t buffer_len, const uint8_t * data, uint16_t len){
58     uint16_t pos = big_endian_read_16(buffer, 1);
59     if (buffer_len < pos + len) return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED;
60     (void)memcpy(&buffer[pos], data, len);
61     pos += len;
62     big_endian_store_16(buffer, 1, pos);
63      return ERROR_CODE_SUCCESS;
64 }
65 
66 uint8_t obex_message_builder_header_add_byte(uint8_t * buffer, uint16_t buffer_len, uint8_t header_type, uint8_t value){
67     uint8_t header[2];
68     header[0] = header_type;
69     header[1] = value;
70     return obex_message_builder_packet_append(buffer, buffer_len, &header[0], sizeof(header));
71 }
72 
73 uint8_t obex_message_builder_header_add_word(uint8_t * buffer, uint16_t buffer_len, uint8_t header_type, uint32_t value){
74     uint8_t header[5];
75     header[0] = header_type;
76     big_endian_store_32(header, 1, value);
77     return obex_message_builder_packet_append(buffer, buffer_len, &header[0], sizeof(header));
78 }
79 
80 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){
81     uint8_t header[3];
82     header[0] = header_type;
83     big_endian_store_16(header, 1, sizeof(header) + header_data_length);
84 
85     uint8_t status = obex_message_builder_packet_append(buffer, buffer_len, &header[0], sizeof(header));
86     if (status != ERROR_CODE_SUCCESS) return status;
87 
88     return obex_message_builder_packet_append(buffer, buffer_len, header_data, header_data_length);
89 }
90 
91 static uint8_t obex_message_builder_header_add_connection_id(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){
92     // add connection_id header if set, must be first header if used
93     if (obex_connection_id == OBEX_CONNECTION_ID_INVALID) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
94     return obex_message_builder_header_add_word(buffer, buffer_len, OBEX_HEADER_CONNECTION_ID, obex_connection_id);
95 }
96 
97 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){
98     uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_CONNECT);
99     if (status != ERROR_CODE_SUCCESS) return status;
100 
101     uint8_t fields[4];
102     fields[0] = obex_version_number;
103     fields[1] = flags;
104     big_endian_store_16(fields, 2, maximum_obex_packet_length);
105     return obex_message_builder_packet_append(buffer, buffer_len, &fields[0], sizeof(fields));
106 }
107 
108 uint8_t obex_message_builder_request_create_get(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){
109     uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_GET | OBEX_OPCODE_FINAL_BIT_MASK);
110     if (status != ERROR_CODE_SUCCESS) return status;
111     return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id);
112 }
113 
114 uint8_t obex_message_builder_request_create_put(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){
115     uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_PUT | OBEX_OPCODE_FINAL_BIT_MASK);
116     if (status != ERROR_CODE_SUCCESS) return status;
117 
118     return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id);
119 }
120 
121 uint8_t obex_message_builder_request_create_set_path(uint8_t * buffer, uint16_t buffer_len, uint8_t flags, uint32_t obex_connection_id){
122     uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_SETPATH);
123     if (status != ERROR_CODE_SUCCESS) return status;
124 
125     uint8_t fields[2];
126     fields[0] = flags;
127     fields[1] = 0;  // reserved
128     status = obex_message_builder_packet_append(buffer, buffer_len, &fields[0], sizeof(fields));
129     if (status != ERROR_CODE_SUCCESS) return status;
130     return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id);
131 }
132 
133 uint8_t obex_message_builder_request_create_abort(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){
134     uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_ABORT);
135     if (status != ERROR_CODE_SUCCESS) return status;
136     return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id);
137 }
138 
139 uint8_t obex_message_builder_request_create_disconnect(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){
140     uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_DISCONNECT);
141     if (status != ERROR_CODE_SUCCESS) return status;
142     return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id);
143 }
144 
145 uint8_t obex_message_builder_header_add_srm_enable(uint8_t * buffer, uint16_t buffer_len){
146     return obex_message_builder_header_add_byte(buffer, buffer_len, OBEX_HEADER_SINGLE_RESPONSE_MODE, OBEX_SRM_ENABLE);
147 }
148 
149 uint8_t obex_message_builder_header_add_target(uint8_t * buffer, uint16_t buffer_len, const uint8_t * target, uint16_t length){
150     return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_TARGET, target, length);
151 }
152 
153 uint8_t obex_message_builder_header_add_application_parameters(uint8_t * buffer, uint16_t buffer_len, const uint8_t * data, uint16_t length){
154     return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_APPLICATION_PARAMETERS, data, length);
155 }
156 
157 uint8_t obex_message_builder_header_add_challenge_response(uint8_t * buffer, uint16_t buffer_len, const uint8_t * data, uint16_t length){
158     return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_AUTHENTICATION_RESPONSE, data, length);
159 }
160 
161 uint8_t obex_message_builder_body_add_static(uint8_t * buffer, uint16_t buffer_len, const uint8_t * data, uint32_t length){
162     return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_END_OF_BODY, data, length);
163 }
164 
165 uint8_t obex_message_builder_header_add_name_prefix(uint8_t * buffer, uint16_t buffer_len, const char * name, uint16_t name_len){
166     if (buffer_len <  (1 + 2 + name_len*2) ) return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED;
167 
168     uint16_t pos = big_endian_read_16(buffer, 1);
169     buffer[pos++] = OBEX_HEADER_NAME;
170     big_endian_store_16(buffer, pos, 1 + 2 + name_len*2);
171     pos += 2;
172     int i;
173     // @note name[len] == 0
174     for (i = 0 ; i < name_len ; i++){
175         buffer[pos++] = 0;
176         buffer[pos++] = *name++;
177     }
178     big_endian_store_16(buffer, 1, pos);
179     return ERROR_CODE_SUCCESS;
180 }
181 uint8_t obex_message_builder_header_add_name(uint8_t * buffer, uint16_t buffer_len, const char * name){
182     int len = strlen(name);
183     if (len > 0) {
184         // empty string does not have trailing \0
185         len++;
186     }
187     return obex_message_builder_header_add_name_prefix(buffer, buffer_len, name, len);
188 }
189 
190 uint8_t obex_message_builder_header_add_type(uint8_t * buffer, uint16_t buffer_len, const char * type){
191     uint8_t header[3];
192     header[0] = OBEX_HEADER_TYPE;
193     int len_incl_zero = strlen(type) + 1;
194     big_endian_store_16(header, 1, 1 + 2 + len_incl_zero);
195 
196     uint8_t status = obex_message_builder_packet_append(buffer, buffer_len, &header[0], sizeof(header));
197     if (status != ERROR_CODE_SUCCESS) return status;
198     return obex_message_builder_packet_append(buffer, buffer_len, (const uint8_t*)type, len_incl_zero);
199 }
200