xref: /btstack/src/classic/obex_message_builder.c (revision 7c006017049f293307f1ba63f1a6136a5ef8ad5b)
1*7c006017SMilanka Ringwald /*
2*7c006017SMilanka Ringwald  * Copyright (C) 2019 BlueKitchen GmbH
3*7c006017SMilanka Ringwald  *
4*7c006017SMilanka Ringwald  * Redistribution and use in source and binary forms, with or without
5*7c006017SMilanka Ringwald  * modification, are permitted provided that the following conditions
6*7c006017SMilanka Ringwald  * are met:
7*7c006017SMilanka Ringwald  *
8*7c006017SMilanka Ringwald  * 1. Redistributions of source code must retain the above copyright
9*7c006017SMilanka Ringwald  *    notice, this list of conditions and the following disclaimer.
10*7c006017SMilanka Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*7c006017SMilanka Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*7c006017SMilanka Ringwald  *    documentation and/or other materials provided with the distribution.
13*7c006017SMilanka Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*7c006017SMilanka Ringwald  *    contributors may be used to endorse or promote products derived
15*7c006017SMilanka Ringwald  *    from this software without specific prior written permission.
16*7c006017SMilanka Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*7c006017SMilanka Ringwald  *    personal benefit and not for any commercial purpose or for
18*7c006017SMilanka Ringwald  *    monetary gain.
19*7c006017SMilanka Ringwald  *
20*7c006017SMilanka Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*7c006017SMilanka Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*7c006017SMilanka Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*7c006017SMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24*7c006017SMilanka Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*7c006017SMilanka Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*7c006017SMilanka Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*7c006017SMilanka Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*7c006017SMilanka Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*7c006017SMilanka Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*7c006017SMilanka Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*7c006017SMilanka Ringwald  * SUCH DAMAGE.
32*7c006017SMilanka Ringwald  *
33*7c006017SMilanka Ringwald  * Please inquire about commercial licensing options at
34*7c006017SMilanka Ringwald  * [email protected]
35*7c006017SMilanka Ringwald  *
36*7c006017SMilanka Ringwald  */
37*7c006017SMilanka Ringwald 
38*7c006017SMilanka Ringwald #define __BTSTACK_FILE__ "obex_message_builder.c"
39*7c006017SMilanka Ringwald 
40*7c006017SMilanka Ringwald #include "btstack_config.h"
41*7c006017SMilanka Ringwald 
42*7c006017SMilanka Ringwald #include <stdint.h>
43*7c006017SMilanka Ringwald #include <stdlib.h>
44*7c006017SMilanka Ringwald 
45*7c006017SMilanka Ringwald #include "btstack_util.h"
46*7c006017SMilanka Ringwald #include "btstack_debug.h"
47*7c006017SMilanka Ringwald #include "classic/obex.h"
48*7c006017SMilanka Ringwald #include "classic/obex_message_builder.h"
49*7c006017SMilanka Ringwald 
50*7c006017SMilanka Ringwald static uint8_t obex_message_builder_packet_init(uint8_t * buffer, uint16_t buffer_len, uint8_t opcode){
51*7c006017SMilanka Ringwald     if (buffer_len < 3) return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED;
52*7c006017SMilanka Ringwald     buffer[0] = opcode;
53*7c006017SMilanka Ringwald     big_endian_store_16(buffer, 1, 3);
54*7c006017SMilanka Ringwald     return ERROR_CODE_SUCCESS;
55*7c006017SMilanka Ringwald }
56*7c006017SMilanka Ringwald 
57*7c006017SMilanka Ringwald static uint8_t obex_message_builder_packet_append(uint8_t * buffer, uint16_t buffer_len, const uint8_t * data, uint16_t len){
58*7c006017SMilanka Ringwald     uint16_t pos = big_endian_read_16(buffer, 1);
59*7c006017SMilanka Ringwald     if (buffer_len < pos + len) return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED;
60*7c006017SMilanka Ringwald     memcpy(&buffer[pos], data, len);
61*7c006017SMilanka Ringwald     pos += len;
62*7c006017SMilanka Ringwald     big_endian_store_16(buffer, 1, pos);
63*7c006017SMilanka Ringwald      return ERROR_CODE_SUCCESS;
64*7c006017SMilanka Ringwald }
65*7c006017SMilanka Ringwald 
66*7c006017SMilanka Ringwald static 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){
67*7c006017SMilanka Ringwald     uint8_t header[3];
68*7c006017SMilanka Ringwald     header[0] = header_type;
69*7c006017SMilanka Ringwald     big_endian_store_16(header, 1, sizeof(header) + header_data_length);
70*7c006017SMilanka Ringwald 
71*7c006017SMilanka Ringwald     uint8_t status = obex_message_builder_packet_append(buffer, buffer_len, &header[0], sizeof(header));
72*7c006017SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS) return status;
73*7c006017SMilanka Ringwald 
74*7c006017SMilanka Ringwald     return obex_message_builder_packet_append(buffer, buffer_len, header_data, header_data_length);
75*7c006017SMilanka Ringwald }
76*7c006017SMilanka Ringwald 
77*7c006017SMilanka Ringwald static uint8_t obex_message_builder_header_add_byte(uint8_t * buffer, uint16_t buffer_len, uint8_t header_type, uint8_t value){
78*7c006017SMilanka Ringwald     uint8_t header[2];
79*7c006017SMilanka Ringwald     header[0] = header_type;
80*7c006017SMilanka Ringwald     header[1] = value;
81*7c006017SMilanka Ringwald     return obex_message_builder_packet_append(buffer, buffer_len, &header[0], sizeof(header));
82*7c006017SMilanka Ringwald }
83*7c006017SMilanka Ringwald 
84*7c006017SMilanka Ringwald static uint8_t obex_message_builder_header_add_word(uint8_t * buffer, uint16_t buffer_len, uint8_t header_type, uint32_t value){
85*7c006017SMilanka Ringwald     uint8_t header[5];
86*7c006017SMilanka Ringwald     header[0] = header_type;
87*7c006017SMilanka Ringwald     big_endian_store_32(header, 1, value);
88*7c006017SMilanka Ringwald     return obex_message_builder_packet_append(buffer, buffer_len, &header[0], sizeof(header));
89*7c006017SMilanka Ringwald }
90*7c006017SMilanka Ringwald 
91*7c006017SMilanka Ringwald static uint8_t obex_message_builder_header_add_connection_id(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){
92*7c006017SMilanka Ringwald     // add connection_id header if set, must be first header if used
93*7c006017SMilanka Ringwald     if (obex_connection_id == OBEX_CONNECTION_ID_INVALID) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
94*7c006017SMilanka Ringwald     return obex_message_builder_header_add_word(buffer, buffer_len, OBEX_HEADER_CONNECTION_ID, obex_connection_id);
95*7c006017SMilanka Ringwald }
96*7c006017SMilanka Ringwald 
97*7c006017SMilanka 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){
98*7c006017SMilanka Ringwald     uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_CONNECT);
99*7c006017SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS) return status;
100*7c006017SMilanka Ringwald 
101*7c006017SMilanka Ringwald     uint8_t fields[4];
102*7c006017SMilanka Ringwald     fields[0] = obex_version_number;
103*7c006017SMilanka Ringwald     fields[1] = flags;
104*7c006017SMilanka Ringwald     big_endian_store_16(fields, 2, maximum_obex_packet_length);
105*7c006017SMilanka Ringwald     return obex_message_builder_packet_append(buffer, buffer_len, &fields[0], sizeof(fields));
106*7c006017SMilanka Ringwald }
107*7c006017SMilanka Ringwald 
108*7c006017SMilanka Ringwald uint8_t obex_message_builder_request_create_get(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){
109*7c006017SMilanka Ringwald     uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_GET | OBEX_OPCODE_FINAL_BIT_MASK);
110*7c006017SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS) return status;
111*7c006017SMilanka Ringwald     return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id);
112*7c006017SMilanka Ringwald }
113*7c006017SMilanka Ringwald 
114*7c006017SMilanka Ringwald uint8_t obex_message_builder_request_create_put(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){
115*7c006017SMilanka Ringwald     uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_PUT | OBEX_OPCODE_FINAL_BIT_MASK);
116*7c006017SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS) return status;
117*7c006017SMilanka Ringwald 
118*7c006017SMilanka Ringwald     return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id);
119*7c006017SMilanka Ringwald }
120*7c006017SMilanka Ringwald 
121*7c006017SMilanka 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){
122*7c006017SMilanka Ringwald     uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_SETPATH);
123*7c006017SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS) return status;
124*7c006017SMilanka Ringwald 
125*7c006017SMilanka Ringwald     uint8_t fields[2];
126*7c006017SMilanka Ringwald     fields[0] = flags;
127*7c006017SMilanka Ringwald     fields[1] = 0;  // reserved
128*7c006017SMilanka Ringwald     status = obex_message_builder_packet_append(buffer, buffer_len, &fields[0], sizeof(fields));
129*7c006017SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS) return status;
130*7c006017SMilanka Ringwald     return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id);
131*7c006017SMilanka Ringwald }
132*7c006017SMilanka Ringwald 
133*7c006017SMilanka Ringwald uint8_t obex_message_builder_request_create_abort(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){
134*7c006017SMilanka Ringwald     uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_ABORT);
135*7c006017SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS) return status;
136*7c006017SMilanka Ringwald     return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id);
137*7c006017SMilanka Ringwald }
138*7c006017SMilanka Ringwald 
139*7c006017SMilanka Ringwald uint8_t obex_message_builder_request_create_disconnect(uint8_t * buffer, uint16_t buffer_len, uint32_t obex_connection_id){
140*7c006017SMilanka Ringwald     uint8_t status = obex_message_builder_packet_init(buffer, buffer_len, OBEX_OPCODE_DISCONNECT);
141*7c006017SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS) return status;
142*7c006017SMilanka Ringwald     return obex_message_builder_header_add_connection_id(buffer, buffer_len, obex_connection_id);
143*7c006017SMilanka Ringwald }
144*7c006017SMilanka Ringwald 
145*7c006017SMilanka Ringwald uint8_t obex_message_builder_header_add_srm_enable(uint8_t * buffer, uint16_t buffer_len){
146*7c006017SMilanka Ringwald     return obex_message_builder_header_add_byte(buffer, buffer_len, OBEX_HEADER_SINGLE_RESPONSE_MODE, OBEX_SRM_ENABLE);
147*7c006017SMilanka Ringwald }
148*7c006017SMilanka Ringwald 
149*7c006017SMilanka Ringwald uint8_t obex_message_builder_header_add_target(uint8_t * buffer, uint16_t buffer_len, const uint8_t * target, uint16_t length){
150*7c006017SMilanka Ringwald     return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_TARGET, target, length);
151*7c006017SMilanka Ringwald }
152*7c006017SMilanka Ringwald 
153*7c006017SMilanka Ringwald uint8_t obex_message_builder_header_add_application_parameters(uint8_t * buffer, uint16_t buffer_len, const uint8_t * data, uint16_t length){
154*7c006017SMilanka Ringwald     return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_APPLICATION_PARAMETERS, data, length);
155*7c006017SMilanka Ringwald }
156*7c006017SMilanka Ringwald 
157*7c006017SMilanka Ringwald uint8_t obex_message_builder_add_header_challenge_response(uint8_t * buffer, uint16_t buffer_len, const uint8_t * data, uint16_t length){
158*7c006017SMilanka Ringwald     return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_AUTHENTICATION_RESPONSE, data, length);
159*7c006017SMilanka Ringwald }
160*7c006017SMilanka Ringwald 
161*7c006017SMilanka Ringwald uint8_t obex_message_builder_add_body_static(uint8_t * buffer, uint16_t buffer_len, const uint8_t * data, uint32_t length){
162*7c006017SMilanka Ringwald     return obex_message_builder_header_add_variable(buffer, buffer_len, OBEX_HEADER_END_OF_BODY, data, length);
163*7c006017SMilanka Ringwald }
164*7c006017SMilanka Ringwald 
165*7c006017SMilanka Ringwald uint8_t obex_message_builder_header_add_name(uint8_t * buffer, uint16_t buffer_len, const char * name){
166*7c006017SMilanka Ringwald     int len = strlen(name);
167*7c006017SMilanka Ringwald     if (len) {
168*7c006017SMilanka Ringwald         // empty string does not have trailing \0
169*7c006017SMilanka Ringwald         len++;
170*7c006017SMilanka Ringwald     }
171*7c006017SMilanka Ringwald     if (buffer_len <  (1 + 2 + len*2) ) return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED;
172*7c006017SMilanka Ringwald 
173*7c006017SMilanka Ringwald     uint16_t pos = big_endian_read_16(buffer, 1);
174*7c006017SMilanka Ringwald     buffer[pos++] = OBEX_HEADER_NAME;
175*7c006017SMilanka Ringwald     big_endian_store_16(buffer, pos, 1 + 2 + len*2);
176*7c006017SMilanka Ringwald     pos += 2;
177*7c006017SMilanka Ringwald     int i;
178*7c006017SMilanka Ringwald     // @note name[len] == 0
179*7c006017SMilanka Ringwald     for (i = 0 ; i < len ; i++){
180*7c006017SMilanka Ringwald         buffer[pos++] = 0;
181*7c006017SMilanka Ringwald         buffer[pos++] = *name++;
182*7c006017SMilanka Ringwald     }
183*7c006017SMilanka Ringwald     big_endian_store_16(buffer, 1, pos);
184*7c006017SMilanka Ringwald     return ERROR_CODE_SUCCESS;
185*7c006017SMilanka Ringwald }
186*7c006017SMilanka Ringwald 
187*7c006017SMilanka Ringwald uint8_t obex_message_builder_header_add_type(uint8_t * buffer, uint16_t buffer_len, const char * type){
188*7c006017SMilanka Ringwald     uint8_t header[3];
189*7c006017SMilanka Ringwald     header[0] = OBEX_HEADER_TYPE;
190*7c006017SMilanka Ringwald     int len_incl_zero = strlen(type) + 1;
191*7c006017SMilanka Ringwald     big_endian_store_16(header, 1, 1 + 2 + len_incl_zero);
192*7c006017SMilanka Ringwald 
193*7c006017SMilanka Ringwald     uint8_t status = obex_message_builder_packet_append(buffer, buffer_len, &header[0], sizeof(header));
194*7c006017SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS) return status;
195*7c006017SMilanka Ringwald     return obex_message_builder_packet_append(buffer, buffer_len, (const uint8_t*)type, len_incl_zero);
196*7c006017SMilanka Ringwald }
197