1ac9a0d84SMatthias Ringwald /* 2ac9a0d84SMatthias Ringwald * Copyright (C) 2021 BlueKitchen GmbH 3ac9a0d84SMatthias Ringwald * 4ac9a0d84SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5ac9a0d84SMatthias Ringwald * modification, are permitted provided that the following conditions 6ac9a0d84SMatthias Ringwald * are met: 7ac9a0d84SMatthias Ringwald * 8ac9a0d84SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9ac9a0d84SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10ac9a0d84SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11ac9a0d84SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12ac9a0d84SMatthias Ringwald * documentation and/or other materials provided with the distribution. 13ac9a0d84SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14ac9a0d84SMatthias Ringwald * contributors may be used to endorse or promote products derived 15ac9a0d84SMatthias Ringwald * from this software without specific prior written permission. 16ac9a0d84SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 17ac9a0d84SMatthias Ringwald * personal benefit and not for any commercial purpose or for 18ac9a0d84SMatthias Ringwald * monetary gain. 19ac9a0d84SMatthias Ringwald * 20ac9a0d84SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21ac9a0d84SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22ac9a0d84SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23ac9a0d84SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 24ac9a0d84SMatthias Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25ac9a0d84SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26ac9a0d84SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27ac9a0d84SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28ac9a0d84SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29ac9a0d84SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30ac9a0d84SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31ac9a0d84SMatthias Ringwald * SUCH DAMAGE. 32ac9a0d84SMatthias Ringwald * 33ac9a0d84SMatthias Ringwald * Please inquire about commercial licensing options at 34ac9a0d84SMatthias Ringwald * [email protected] 35ac9a0d84SMatthias Ringwald * 36ac9a0d84SMatthias Ringwald */ 37ac9a0d84SMatthias Ringwald 38ac9a0d84SMatthias Ringwald /** 39ac9a0d84SMatthias Ringwald * OBEX Parser 40ac9a0d84SMatthias Ringwald * Parser incoming arbitrarily chunked OBEX object 41ac9a0d84SMatthias Ringwald */ 42ac9a0d84SMatthias Ringwald 43ac9a0d84SMatthias Ringwald #ifndef OBEX_PARSER_H 44ac9a0d84SMatthias Ringwald #define OBEX_PARSER_H 45ac9a0d84SMatthias Ringwald 46ac9a0d84SMatthias Ringwald #if defined __cplusplus 47ac9a0d84SMatthias Ringwald extern "C" { 48ac9a0d84SMatthias Ringwald #endif 49ac9a0d84SMatthias Ringwald 50ac9a0d84SMatthias Ringwald #include <stdint.h> 51ac9a0d84SMatthias Ringwald 52ac9a0d84SMatthias Ringwald typedef enum { 53ac9a0d84SMatthias Ringwald OBEX_PARSER_STATE_W4_OPCODE, 54ac9a0d84SMatthias Ringwald OBEX_PARSER_STATE_W4_RESPONSE_CODE, 55ac9a0d84SMatthias Ringwald OBEX_PARSER_STATE_W4_PACKET_LEN, 56ac9a0d84SMatthias Ringwald OBEX_PARSER_STATE_W4_PARAMS, 57ac9a0d84SMatthias Ringwald OBEX_PARSER_STATE_W4_HEADER_ID, 58ac9a0d84SMatthias Ringwald OBEX_PARSER_STATE_W4_HEADER_LEN_FIRST, 59ac9a0d84SMatthias Ringwald OBEX_PARSER_STATE_W4_HEADER_LEN_SECOND, 60ac9a0d84SMatthias Ringwald OBEX_PARSER_STATE_W4_HEADER_VALUE, 61ac9a0d84SMatthias Ringwald OBEX_PARSER_STATE_COMPLETE, 62ac9a0d84SMatthias Ringwald OBEX_PARSER_STATE_OVERRUN, 63ac9a0d84SMatthias Ringwald OBEX_PARSER_STATE_INVALID, 64ac9a0d84SMatthias Ringwald } obex_parser_state_t; 65ac9a0d84SMatthias Ringwald 66ac9a0d84SMatthias Ringwald /* API_START */ 67ac9a0d84SMatthias Ringwald 68ac9a0d84SMatthias Ringwald /** 69ac9a0d84SMatthias Ringwald * Callback to process chunked data 70ac9a0d84SMatthias Ringwald * @param user_data provided in obex_parser_init 71ac9a0d84SMatthias Ringwald * @param header_id current OBEX header ID 72ac9a0d84SMatthias Ringwald * @param total_len of header 73ac9a0d84SMatthias Ringwald * @param data_offset 74ac9a0d84SMatthias Ringwald * @param data_len 75ac9a0d84SMatthias Ringwald * @param data_buffer 76ac9a0d84SMatthias Ringwald */ 77ac9a0d84SMatthias Ringwald typedef void (*obex_parser_callback_t)(void * user_data, uint8_t header_id, uint16_t total_len, uint16_t data_offset, const uint8_t * data_buffer, uint16_t data_len); 78ac9a0d84SMatthias Ringwald 79ac9a0d84SMatthias Ringwald typedef enum { 80ac9a0d84SMatthias Ringwald OBEX_PARSER_OBJECT_STATE_INCOMPLETE, 81ac9a0d84SMatthias Ringwald OBEX_PARSER_OBJECT_STATE_COMPLETE, 82ac9a0d84SMatthias Ringwald OBEX_PARSER_OBJECT_STATE_OVERRUN, 83ac9a0d84SMatthias Ringwald OBEX_PARSER_OBJECT_STATE_INVALID, 84ac9a0d84SMatthias Ringwald } obex_parser_object_state_t; 85ac9a0d84SMatthias Ringwald 86ac9a0d84SMatthias Ringwald typedef enum { 87ac9a0d84SMatthias Ringwald OBEX_PARSER_HEADER_INCOMPLETE, 88ac9a0d84SMatthias Ringwald OBEX_PARSER_HEADER_COMPLETE, 89ac9a0d84SMatthias Ringwald OBEX_PARSER_HEADER_OVERRUN, 90ac9a0d84SMatthias Ringwald } obex_parser_header_state_t; 91ac9a0d84SMatthias Ringwald 92ac9a0d84SMatthias Ringwald typedef struct { 93ac9a0d84SMatthias Ringwald uint8_t opcode; 94ac9a0d84SMatthias Ringwald uint8_t response_code; 95ac9a0d84SMatthias Ringwald // Connect only 96ac9a0d84SMatthias Ringwald uint8_t obex_version_number; 97ac9a0d84SMatthias Ringwald uint16_t max_packet_length; 98ac9a0d84SMatthias Ringwald // Connect + Set Path only 99ac9a0d84SMatthias Ringwald uint8_t flags; 100ac9a0d84SMatthias Ringwald } obex_parser_operation_info_t; 101ac9a0d84SMatthias Ringwald 102ac9a0d84SMatthias Ringwald typedef struct { 103ac9a0d84SMatthias Ringwald obex_parser_callback_t callback; 104ac9a0d84SMatthias Ringwald void * user_data; 105ac9a0d84SMatthias Ringwald uint16_t packet_size; 106ac9a0d84SMatthias Ringwald uint16_t packet_pos; 107ac9a0d84SMatthias Ringwald obex_parser_state_t state; 108ac9a0d84SMatthias Ringwald uint8_t opcode; 109ac9a0d84SMatthias Ringwald uint8_t response_code; 110ac9a0d84SMatthias Ringwald uint16_t item_len; 111ac9a0d84SMatthias Ringwald uint16_t item_pos; 112ac9a0d84SMatthias Ringwald uint8_t params[6]; // for connect and set path 113ac9a0d84SMatthias Ringwald uint8_t header_id; 114ac9a0d84SMatthias Ringwald } obex_parser_t; 115ac9a0d84SMatthias Ringwald 116ac9a0d84SMatthias Ringwald /** 117*3a6b6ac9SMatthias Ringwald * Callback to process chunked data 118*3a6b6ac9SMatthias Ringwald * @param user_data provided in obex_parser_init 119*3a6b6ac9SMatthias Ringwald * @param header_id current OBEX header ID 120*3a6b6ac9SMatthias Ringwald * @param total_len of header 121*3a6b6ac9SMatthias Ringwald * @param data_offset 122*3a6b6ac9SMatthias Ringwald * @param data_len 123*3a6b6ac9SMatthias Ringwald * @param data_buffer 124*3a6b6ac9SMatthias Ringwald */ 125*3a6b6ac9SMatthias Ringwald typedef void (*obex_app_param_parser_callback_t)(void * user_data, uint8_t tag_id, uint8_t total_len, uint8_t data_offset, const uint8_t * data_buffer, uint8_t data_len); 126*3a6b6ac9SMatthias Ringwald 127*3a6b6ac9SMatthias Ringwald typedef enum { 128*3a6b6ac9SMatthias Ringwald OBEX_APP_PARAM_PARSER_PARAMS_STATE_INCOMPLETE, 129*3a6b6ac9SMatthias Ringwald OBEX_APP_PARAM_PARSER_PARAMS_STATE_COMPLETE, 130*3a6b6ac9SMatthias Ringwald OBEX_APP_PARAM_PARSER_PARAMS_STATE_OVERRUN, 131*3a6b6ac9SMatthias Ringwald OBEX_APP_PARAM_PARSER_PARAMS_STATE_INVALID, 132*3a6b6ac9SMatthias Ringwald } obex_app_param_parser_params_state_t; 133*3a6b6ac9SMatthias Ringwald 134*3a6b6ac9SMatthias Ringwald typedef enum { 135*3a6b6ac9SMatthias Ringwald OBEX_APP_PARAM_PARSER_TAG_INCOMPLETE, 136*3a6b6ac9SMatthias Ringwald OBEX_APP_PARAM_PARSER_TAG_COMPLETE, 137*3a6b6ac9SMatthias Ringwald OBEX_APP_PARAM_PARSER_TAG_OVERRUN, 138*3a6b6ac9SMatthias Ringwald } obex_app_param_parser_tag_state_t; 139*3a6b6ac9SMatthias Ringwald 140*3a6b6ac9SMatthias Ringwald typedef enum { 141*3a6b6ac9SMatthias Ringwald OBEX_APP_PARAM_PARSER_STATE_W4_TYPE = 0, 142*3a6b6ac9SMatthias Ringwald OBEX_APP_PARAM_PARSER_STATE_W4_LEN, 143*3a6b6ac9SMatthias Ringwald OBEX_APP_PARAM_PARSER_STATE_W4_VALUE, 144*3a6b6ac9SMatthias Ringwald OBEX_APP_PARAM_PARSER_STATE_COMPLETE, 145*3a6b6ac9SMatthias Ringwald OBEX_APP_PARAM_PARSER_STATE_INVALID, 146*3a6b6ac9SMatthias Ringwald OBEX_APP_PARAM_PARSER_STATE_OVERRUN, 147*3a6b6ac9SMatthias Ringwald } obex_app_param_parser_state_t; 148*3a6b6ac9SMatthias Ringwald 149*3a6b6ac9SMatthias Ringwald typedef struct { 150*3a6b6ac9SMatthias Ringwald obex_app_param_parser_callback_t callback; 151*3a6b6ac9SMatthias Ringwald obex_app_param_parser_state_t state; 152*3a6b6ac9SMatthias Ringwald void * user_data; 153*3a6b6ac9SMatthias Ringwald uint16_t param_size; 154*3a6b6ac9SMatthias Ringwald uint16_t param_pos; 155*3a6b6ac9SMatthias Ringwald uint16_t tag_len; 156*3a6b6ac9SMatthias Ringwald uint16_t tag_pos; 157*3a6b6ac9SMatthias Ringwald uint8_t tag_id; 158*3a6b6ac9SMatthias Ringwald } obex_app_param_parser_t; 159*3a6b6ac9SMatthias Ringwald 160*3a6b6ac9SMatthias Ringwald /** 161ac9a0d84SMatthias Ringwald * Initialize OBEX Parser for next OBEX request 162ac9a0d84SMatthias Ringwald * @param obex_parser 163*3a6b6ac9SMatthias Ringwald * @param function to call for field data 164ac9a0d84SMatthias Ringwald * @param user_data provided to callback function 165ac9a0d84SMatthias Ringwald */ 166ac9a0d84SMatthias Ringwald void obex_parser_init_for_request(obex_parser_t * obex_parser, obex_parser_callback_t obex_parser_callback, void * user_data); 167ac9a0d84SMatthias Ringwald 168ac9a0d84SMatthias Ringwald /** 169ac9a0d84SMatthias Ringwald * Initialize OBEX Parser for next OBEX response 170ac9a0d84SMatthias Ringwald * @param obex_parser 171ac9a0d84SMatthias Ringwald * @param opcode of request - needed as responses with additional fields like connect and set path 172*3a6b6ac9SMatthias Ringwald * @param function to call for field data 173ac9a0d84SMatthias Ringwald * @param user_data provided to callback function 174ac9a0d84SMatthias Ringwald */ 175ac9a0d84SMatthias Ringwald void obex_parser_init_for_response(obex_parser_t * obex_parser, uint8_t opcode, obex_parser_callback_t obex_parser_callback, void * user_data); 176ac9a0d84SMatthias Ringwald 177ac9a0d84SMatthias Ringwald /** 178ac9a0d84SMatthias Ringwald * Process OBEX data 179ac9a0d84SMatthias Ringwald * @param obex_parser 180ac9a0d84SMatthias Ringwald * @param data_len 181ac9a0d84SMatthias Ringwald * @param data_buffer 182ac9a0d84SMatthias Ringwald * @return OBEX_PARSER_OBJECT_STATE_COMPLETE if packet has been completely parsed 183ac9a0d84SMatthias Ringwald */ 184ac9a0d84SMatthias Ringwald obex_parser_object_state_t obex_parser_process_data(obex_parser_t *obex_parser, const uint8_t *data_buffer, uint16_t data_len); 185ac9a0d84SMatthias Ringwald 186ac9a0d84SMatthias Ringwald /** 187ac9a0d84SMatthias Ringwald * Get operation info for request/response packets 188ac9a0d84SMatthias Ringwald * @param obex_parser 189ac9a0d84SMatthias Ringwald * @return 190ac9a0d84SMatthias Ringwald */ 191ac9a0d84SMatthias Ringwald void obex_parser_get_operation_info(obex_parser_t * obex_parser, obex_parser_operation_info_t * obex_operation_info); 192ac9a0d84SMatthias Ringwald 193ac9a0d84SMatthias Ringwald /** 194ac9a0d84SMatthias Ringwald * Helper to collect header chunks in fixed-size header buffer 195ac9a0d84SMatthias Ringwald * @param header_buffer 196ac9a0d84SMatthias Ringwald * @param buffer_size of header_buffer 197ac9a0d84SMatthias Ringwald * @param total_len of header value 198*3a6b6ac9SMatthias Ringwald * @param data_offset of chunk to store 199ac9a0d84SMatthias Ringwald * @param data_buffer 200ac9a0d84SMatthias Ringwald * @param data_len chunk length 201ac9a0d84SMatthias Ringwald * @return OBEX_PARSER_HEADER_COMPLETE when header value complete 202ac9a0d84SMatthias Ringwald */ 203ac9a0d84SMatthias Ringwald obex_parser_header_state_t obex_parser_header_store(uint8_t * header_buffer, uint16_t buffer_size, uint16_t total_len, 204ac9a0d84SMatthias Ringwald uint16_t data_offset, const uint8_t * data_buffer, uint16_t data_len); 205ac9a0d84SMatthias Ringwald 206*3a6b6ac9SMatthias Ringwald /** 207*3a6b6ac9SMatthias Ringwald * Initialize OBEX Application Param Parser 208*3a6b6ac9SMatthias Ringwald * @param parser 209*3a6b6ac9SMatthias Ringwald * @param function to call for tag data 210*3a6b6ac9SMatthias Ringwald * @param param_size of OBEX_HEADER_APPLICATION_PARAMETERS header 211*3a6b6ac9SMatthias Ringwald * @param user_data provided to callback function 212*3a6b6ac9SMatthias Ringwald */ 213*3a6b6ac9SMatthias Ringwald void obex_app_param_parser_init(obex_app_param_parser_t * parser, obex_app_param_parser_callback_t callback, uint8_t param_size, void * user_data); 214*3a6b6ac9SMatthias Ringwald 215*3a6b6ac9SMatthias Ringwald /** 216*3a6b6ac9SMatthias Ringwald * Process OBEX App Param data 217*3a6b6ac9SMatthias Ringwald * @param parser 218*3a6b6ac9SMatthias Ringwald * @param data_len 219*3a6b6ac9SMatthias Ringwald * @param data_buffer 220*3a6b6ac9SMatthias Ringwald * @return OBEX_APP_PARAM_PARSER_PARAMS_STATE_COMPLETE if packet has been completely parsed 221*3a6b6ac9SMatthias Ringwald */ 222*3a6b6ac9SMatthias Ringwald obex_app_param_parser_params_state_t obex_app_param_parser_process_data(obex_app_param_parser_t *parser, const uint8_t *data_buffer, uint16_t data_len); 223*3a6b6ac9SMatthias Ringwald 224*3a6b6ac9SMatthias Ringwald /** 225*3a6b6ac9SMatthias Ringwald * Helper to collect tag chunks in fixed-size data buffer 226*3a6b6ac9SMatthias Ringwald * @param tag_buffer 227*3a6b6ac9SMatthias Ringwald * @param buffer_size of data buffer 228*3a6b6ac9SMatthias Ringwald * @param total_len of tag value 229*3a6b6ac9SMatthias Ringwald * @param data_offset of chunk to store 230*3a6b6ac9SMatthias Ringwald * @param data_buffer 231*3a6b6ac9SMatthias Ringwald * @param data_len chunk length 232*3a6b6ac9SMatthias Ringwald * @return OBEX_APP_PARAM_PARSER_TAG_COMPLETE when tag complete 233*3a6b6ac9SMatthias Ringwald */ 234*3a6b6ac9SMatthias Ringwald 235*3a6b6ac9SMatthias Ringwald obex_app_param_parser_tag_state_t obex_app_param_parser_tag_store(uint8_t * tag_buffer, uint8_t buffer_size, uint8_t total_len, 236*3a6b6ac9SMatthias Ringwald uint8_t data_offset, const uint8_t * data_buffer, uint8_t data_len); 237*3a6b6ac9SMatthias Ringwald 238ac9a0d84SMatthias Ringwald 239ac9a0d84SMatthias Ringwald /* API_END */ 240ac9a0d84SMatthias Ringwald 241ac9a0d84SMatthias Ringwald #if defined __cplusplus 242ac9a0d84SMatthias Ringwald } 243ac9a0d84SMatthias Ringwald #endif 244ac9a0d84SMatthias Ringwald #endif 245