xref: /btstack/src/classic/obex_message_builder.c (revision cbf509016daa1295a6a8b22d7314db50b88c6c9a)
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_or_response_code){
51     if (buffer_len < 3) return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED;
52     buffer[0] = opcode_or_response_code;
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 uint16_t obex_message_builder_get_message_length(uint8_t * buffer){
67     return big_endian_read_16(buffer, 1);
68 }
69 
70 uint8_t obex_message_builder_header_add_byte(uint8_t * buffer, uint16_t buffer_len, uint8_t header_type, uint8_t value){
71     uint8_t header[2];
72     header[0] = header_type;
73     header[1] = value;
74     return obex_message_builder_packet_append(buffer, buffer_len, &header[0], sizeof(header));
75 }
76 
77 uint8_t obex_message_builder_header_add_word(uint8_t * buffer, uint16_t buffer_len, uint8_t header_type, uint32_t value){
78     uint8_t header[5];
79     header[0] = header_type;
80     big_endian_store_32(header, 1, value);
81     return obex_message_builder_packet_append(buffer, buffer_len, &header[0], sizeof(header));
82 }
83 
84 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){
85     uint8_t header[3];
86     header[0] = header_type;
87     big_endian_store_16(header, 1, sizeof(header) + header_data_length);
88 
89     uint8_t status = obex_message_builder_packet_append(buffer, buffer_len, &header[0], sizeof(header));
90     if (status != ERROR_CODE_SUCCESS) return status;
91 
92     return obex_message_builder_packet_append(buffer, buffer_len, header_data, header_data_length);
93 }
94 
95 static uint8_t obex_message_builder_header_add_connection_id(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){
96     // add connection_id header if set, must be first header if used
97     if (obex_connection_id == OBEX_CONNECTION_ID_INVALID) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
98     return obex_message_builder_header_add_word(buffer, buffer_len, OBEX_HEADER_CONNECTION_ID, obex_connection_id);
99 }
100 
101 static inline uint8_t obex_message_builder_create_connect(uint8_t * buffer, uint16_t buffer_len, uint8_t opcode,
102     uint8_t obex_version_number, uint8_t flags, uint16_t maximum_obex_packet_length){
103     uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, opcode);
104     if (status != ERROR_CODE_SUCCESS) return status;
105 
106     uint8_t fields[4];
107     fields[0] = obex_version_number;
108     fields[1] = flags;
109     big_endian_store_16(fields, 2, maximum_obex_packet_length);
110     return obex_message_builder_packet_append(buffer, buffer_len, &fields[0], sizeof(fields));
111 }
112 
113 uint8_t obex_message_builder_request_create_connect(uint8_t * buffer, uint16_t buffer_len,
114     uint8_t obex_version_number, uint8_t flags, uint16_t maximum_obex_packet_length){
115 
116     return obex_message_builder_create_connect(buffer, buffer_len, OBEX_OPCODE_CONNECT, obex_version_number, flags, maximum_obex_packet_length);
117 }
118 
119 uint8_t obex_message_builder_response_create_connect(uint8_t * buffer, uint16_t buffer_len, uint8_t obex_version_number,
120     uint8_t flags, uint16_t maximum_obex_packet_length, uint32_t obex_connection_id){
121 
122     uint8_t status = obex_message_builder_create_connect(buffer, buffer_len, OBEX_RESP_SUCCESS, obex_version_number, flags, maximum_obex_packet_length);
123     if (status != ERROR_CODE_SUCCESS) return status;
124     return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id);
125 }
126 
127 uint8_t obex_message_builder_response_create_general(uint8_t * buffer, uint16_t buffer_len, uint8_t response_code){
128     return obex_message_builder_packet_init(buffer, buffer_len, response_code);
129 }
130 
131 uint8_t obex_message_builder_response_update_code(uint8_t * buffer, uint16_t buffer_len, uint8_t response_code){
132     if (buffer_len < 3) return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED;
133     buffer[0] = response_code;
134     return ERROR_CODE_SUCCESS;
135 }
136 
137 uint8_t obex_message_builder_request_create_get(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){
138     uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_GET | OBEX_OPCODE_FINAL_BIT_MASK);
139     if (status != ERROR_CODE_SUCCESS) return status;
140     return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id);
141 }
142 
143 uint8_t obex_message_builder_request_create_put(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){
144     uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_PUT | OBEX_OPCODE_FINAL_BIT_MASK);
145     if (status != ERROR_CODE_SUCCESS) return status;
146 
147     return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id);
148 }
149 
150 uint8_t obex_message_builder_request_create_set_path(uint8_t * buffer, uint16_t buffer_len, uint8_t flags, uint32_t obex_connection_id){
151     uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_SETPATH);
152     if (status != ERROR_CODE_SUCCESS) return status;
153 
154     uint8_t fields[2];
155     fields[0] = flags;
156     fields[1] = 0;  // reserved
157     status = obex_message_builder_packet_append(buffer, buffer_len, &fields[0], sizeof(fields));
158     if (status != ERROR_CODE_SUCCESS) return status;
159     return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id);
160 }
161 
162 uint8_t obex_message_builder_request_create_abort(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){
163     uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_ABORT);
164     if (status != ERROR_CODE_SUCCESS) return status;
165     return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id);
166 }
167 
168 uint8_t obex_message_builder_request_create_disconnect(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){
169     uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_DISCONNECT);
170     if (status != ERROR_CODE_SUCCESS) return status;
171     return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id);
172 }
173 
174 uint8_t obex_message_builder_header_add_srm_enable(uint8_t * buffer, uint16_t buffer_len){
175     return obex_message_builder_header_add_byte(buffer, buffer_len, OBEX_HEADER_SINGLE_RESPONSE_MODE, OBEX_SRM_ENABLE);
176 }
177 
178 uint8_t obex_message_builder_header_add_target(uint8_t * buffer, uint16_t buffer_len, const uint8_t * target, uint16_t length){
179     return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_TARGET, target, length);
180 }
181 
182 uint8_t obex_message_builder_header_add_application_parameters(uint8_t * buffer, uint16_t buffer_len, const uint8_t * data, uint16_t length){
183     return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_APPLICATION_PARAMETERS, data, length);
184 }
185 
186 uint8_t obex_message_builder_header_add_challenge_response(uint8_t * buffer, uint16_t buffer_len, const uint8_t * data, uint16_t length){
187     return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_AUTHENTICATION_RESPONSE, data, length);
188 }
189 
190 uint8_t obex_message_builder_header_add_who(uint8_t * buffer, uint16_t buffer_len, const uint8_t * who){
191     return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_WHO, who, 16);
192 }
193 
194 uint8_t obex_message_builder_body_add_static(uint8_t * buffer, uint16_t buffer_len, const uint8_t * data, uint32_t length){
195     return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_END_OF_BODY, data, length);
196 }
197 
198 uint8_t obex_message_builder_header_add_name_prefix(uint8_t * buffer, uint16_t buffer_len, const char * name, uint16_t name_len){
199     // non-empty string have trailing \0
200     bool add_trailing_zero = name_len > 0;
201 
202     uint16_t header_len = 1 + 2 + (name_len * 2) + (add_trailing_zero ? 2 : 0);
203     if (buffer_len < header_len) return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED;
204 
205     uint16_t pos = big_endian_read_16(buffer, 1);
206     buffer[pos++] = OBEX_HEADER_NAME;
207     big_endian_store_16(buffer, pos, header_len);
208     pos += 2;
209     int i;
210     // @note name[len] == 0
211     for (i = 0 ; i < name_len ; i++){
212         buffer[pos++] = 0;
213         buffer[pos++] = *name++;
214     }
215     if (add_trailing_zero){
216         buffer[pos++] = 0;
217         buffer[pos++] = 0;
218     }
219     big_endian_store_16(buffer, 1, pos);
220     return ERROR_CODE_SUCCESS;
221 }
222 uint8_t obex_message_builder_header_add_name(uint8_t * buffer, uint16_t buffer_len, const char * name){
223     uint16_t name_len = (uint16_t) strlen(name);
224     return obex_message_builder_header_add_name_prefix(buffer, buffer_len, name, name_len);
225 }
226 
227 uint8_t obex_message_builder_header_add_type(uint8_t * buffer, uint16_t buffer_len, const char * type){
228     uint8_t header[3];
229     header[0] = OBEX_HEADER_TYPE;
230     int len_incl_zero = (uint16_t) strlen(type) + 1;
231     big_endian_store_16(header, 1, 1 + 2 + len_incl_zero);
232 
233     uint8_t status = obex_message_builder_packet_append(buffer, buffer_len, &header[0], sizeof(header));
234     if (status != ERROR_CODE_SUCCESS) return status;
235     return obex_message_builder_packet_append(buffer, buffer_len, (const uint8_t*)type, len_incl_zero);
236 }
237