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