xref: /btstack/src/classic/obex_parser.h (revision f4a7fdb58b86de5021755e6288d669e308ddbf2c)
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 /**
1173a6b6ac9SMatthias Ringwald  * Callback to process chunked data
1183a6b6ac9SMatthias Ringwald  * @param user_data provided in obex_parser_init
1193a6b6ac9SMatthias Ringwald  * @param header_id current OBEX header ID
1203a6b6ac9SMatthias Ringwald  * @param total_len of header
1213a6b6ac9SMatthias Ringwald  * @param data_offset
1223a6b6ac9SMatthias Ringwald  * @param data_len
1233a6b6ac9SMatthias Ringwald  * @param data_buffer
1243a6b6ac9SMatthias Ringwald  */
1253a6b6ac9SMatthias 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);
1263a6b6ac9SMatthias Ringwald 
1273a6b6ac9SMatthias Ringwald typedef enum {
1283a6b6ac9SMatthias Ringwald     OBEX_APP_PARAM_PARSER_PARAMS_STATE_INCOMPLETE,
1293a6b6ac9SMatthias Ringwald     OBEX_APP_PARAM_PARSER_PARAMS_STATE_COMPLETE,
1303a6b6ac9SMatthias Ringwald     OBEX_APP_PARAM_PARSER_PARAMS_STATE_OVERRUN,
1313a6b6ac9SMatthias Ringwald     OBEX_APP_PARAM_PARSER_PARAMS_STATE_INVALID,
1323a6b6ac9SMatthias Ringwald } obex_app_param_parser_params_state_t;
1333a6b6ac9SMatthias Ringwald 
1343a6b6ac9SMatthias Ringwald typedef enum {
1353a6b6ac9SMatthias Ringwald     OBEX_APP_PARAM_PARSER_TAG_INCOMPLETE,
1363a6b6ac9SMatthias Ringwald     OBEX_APP_PARAM_PARSER_TAG_COMPLETE,
1373a6b6ac9SMatthias Ringwald     OBEX_APP_PARAM_PARSER_TAG_OVERRUN,
1383a6b6ac9SMatthias Ringwald } obex_app_param_parser_tag_state_t;
1393a6b6ac9SMatthias Ringwald 
1403a6b6ac9SMatthias Ringwald typedef enum {
1413a6b6ac9SMatthias Ringwald     OBEX_APP_PARAM_PARSER_STATE_W4_TYPE = 0,
1423a6b6ac9SMatthias Ringwald     OBEX_APP_PARAM_PARSER_STATE_W4_LEN,
1433a6b6ac9SMatthias Ringwald     OBEX_APP_PARAM_PARSER_STATE_W4_VALUE,
1443a6b6ac9SMatthias Ringwald     OBEX_APP_PARAM_PARSER_STATE_COMPLETE,
1453a6b6ac9SMatthias Ringwald     OBEX_APP_PARAM_PARSER_STATE_INVALID,
1463a6b6ac9SMatthias Ringwald     OBEX_APP_PARAM_PARSER_STATE_OVERRUN,
1473a6b6ac9SMatthias Ringwald } obex_app_param_parser_state_t;
1483a6b6ac9SMatthias Ringwald 
1493a6b6ac9SMatthias Ringwald typedef struct {
1503a6b6ac9SMatthias Ringwald     obex_app_param_parser_callback_t callback;
1513a6b6ac9SMatthias Ringwald     obex_app_param_parser_state_t state;
1523a6b6ac9SMatthias Ringwald     void * user_data;
1533a6b6ac9SMatthias Ringwald     uint16_t param_size;
1543a6b6ac9SMatthias Ringwald     uint16_t param_pos;
1553a6b6ac9SMatthias Ringwald     uint16_t tag_len;
1563a6b6ac9SMatthias Ringwald     uint16_t tag_pos;
1573a6b6ac9SMatthias Ringwald     uint8_t  tag_id;
1583a6b6ac9SMatthias Ringwald } obex_app_param_parser_t;
1593a6b6ac9SMatthias Ringwald 
1603a6b6ac9SMatthias Ringwald /**
161ac9a0d84SMatthias Ringwald  * Initialize OBEX Parser for next OBEX request
162ac9a0d84SMatthias Ringwald  * @param obex_parser
1633a6b6ac9SMatthias 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
1723a6b6ac9SMatthias 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
1983a6b6ac9SMatthias 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 
2063a6b6ac9SMatthias Ringwald /**
2073a6b6ac9SMatthias Ringwald  * Initialize OBEX Application Param Parser
2083a6b6ac9SMatthias Ringwald  * @param parser
2093a6b6ac9SMatthias Ringwald  * @param function to call for tag data
2103a6b6ac9SMatthias Ringwald  * @param param_size of OBEX_HEADER_APPLICATION_PARAMETERS header
2113a6b6ac9SMatthias Ringwald  * @param user_data provided to callback function
2123a6b6ac9SMatthias Ringwald  */
213*f4a7fdb5SMatthias Ringwald void obex_app_param_parser_init(obex_app_param_parser_t * parser, obex_app_param_parser_callback_t callback, uint16_t param_size, void * user_data);
2143a6b6ac9SMatthias Ringwald 
2153a6b6ac9SMatthias Ringwald /**
2163a6b6ac9SMatthias Ringwald  * Process OBEX App Param data
2173a6b6ac9SMatthias Ringwald  * @param parser
2183a6b6ac9SMatthias Ringwald  * @param data_len
2193a6b6ac9SMatthias Ringwald  * @param data_buffer
2203a6b6ac9SMatthias Ringwald  * @return OBEX_APP_PARAM_PARSER_PARAMS_STATE_COMPLETE if packet has been completely parsed
2213a6b6ac9SMatthias Ringwald  */
2223a6b6ac9SMatthias 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);
2233a6b6ac9SMatthias Ringwald 
2243a6b6ac9SMatthias Ringwald /**
2253a6b6ac9SMatthias Ringwald  * Helper to collect tag chunks in fixed-size data buffer
2263a6b6ac9SMatthias Ringwald  * @param tag_buffer
2273a6b6ac9SMatthias Ringwald  * @param buffer_size of data buffer
2283a6b6ac9SMatthias Ringwald  * @param total_len of tag value
2293a6b6ac9SMatthias Ringwald  * @param data_offset of chunk to store
2303a6b6ac9SMatthias Ringwald  * @param data_buffer
2313a6b6ac9SMatthias Ringwald  * @param data_len chunk length
2323a6b6ac9SMatthias Ringwald  * @return OBEX_APP_PARAM_PARSER_TAG_COMPLETE when tag complete
2333a6b6ac9SMatthias Ringwald  */
2343a6b6ac9SMatthias Ringwald 
2353a6b6ac9SMatthias 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,
2363a6b6ac9SMatthias Ringwald                                                                   uint8_t data_offset, const uint8_t * data_buffer, uint8_t data_len);
2373a6b6ac9SMatthias Ringwald 
238ac9a0d84SMatthias Ringwald 
239ac9a0d84SMatthias Ringwald /* API_END */
240ac9a0d84SMatthias Ringwald 
241ac9a0d84SMatthias Ringwald #if defined __cplusplus
242ac9a0d84SMatthias Ringwald }
243ac9a0d84SMatthias Ringwald #endif
244ac9a0d84SMatthias Ringwald #endif
245