• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *    Copyright (c) 2017, The OpenThread Authors.
3  *    All rights reserved.
4  *
5  *    Redistribution and use in source and binary forms, with or without
6  *    modification, are permitted provided that the following conditions are met:
7  *    1. Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *    2. Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *    3. Neither the name of the copyright holder nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17  *    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  *    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  *    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20  *    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  *    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  *    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  *    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  *    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  *    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 /**
29  * @file
30  *   This file contains the definitions of a spinel decoder.
31  */
32 
33 #ifndef SPINEL_DECODER_HPP_
34 #define SPINEL_DECODER_HPP_
35 
36 #include "openthread-spinel-config.h"
37 
38 #include <openthread/ip6.h>
39 #include <openthread/ncp.h>
40 
41 #include "spinel.h"
42 
43 namespace ot {
44 namespace Spinel {
45 
46 /**
47  * Defines a spinel decoder.
48  */
49 class Decoder
50 {
51 public:
52     enum
53     {
54         kMaxNestedStructs = 4, ///< Maximum number of nested structs.
55     };
56 
57     /**
58      * Initializes a `Decoder` object.
59      */
60     Decoder(void);
61 
62     /**
63      * Initializes the decoder to start decoding a new frame.
64      *
65      * It sets the read position to the start of the frame and also erases/voids any saved positions (see
66      * `SavePosition()` and `ResetToSaved()` methods).
67      *
68      * @param[in] aFrame                Pointer to the buffer containing the frame to be decoded.
69      * @param[in] aLength               Length (number of bytes) of the frame.
70      */
71     void Init(const uint8_t *aFrame, uint16_t aLength);
72 
73     /**
74      * Returns the pointer to the start of the frame.
75      *
76      * @returns A pointer to buffer containing current frame being decoded.
77      */
GetFrame(void) const78     const uint8_t *GetFrame(void) const { return mFrame; }
79 
80     /**
81      * Returns the total length of current frame being decoded.
82      *
83      * @returns The length of current frame being decoded.
84      */
GetLength(void) const85     uint16_t GetLength(void) const { return mLength; }
86 
87     /**
88      * Returns the number of bytes that are already read/decoded from the frame.
89      *
90      * @returns The number of bytes already read from frame.
91      */
GetReadLength(void) const92     uint16_t GetReadLength(void) const { return mIndex; }
93 
94     /**
95      * Returns the number of remaining (not yet read/decoded) bytes in the frame.
96      *
97      * @returns The number of remaining unread bytes in the frame.
98      */
GetRemainingLength(void) const99     uint16_t GetRemainingLength(void) const { return mLength - mIndex; }
100 
101     /**
102      * Indicates whether or not all the bytes in the frame are read.
103      *
104      * @returns TRUE if all the bytes in the buffer are read, FALSE otherwise.
105      */
IsAllRead(void) const106     bool IsAllRead(void) const { return (mIndex == mLength); }
107 
108     /**
109      * Resets the read position to beginning of frame. It will also void/erase any previously saved
110      * position using `SavePosition()` method.
111      */
112     void Reset(void);
113 
114     /**
115      * Decodes and reads a boolean value form the frame.
116      *
117      * On success, the read position gets updated.
118      *
119      * @param[out] aBool                Reference to variable to output the read value.
120      *
121      * @retval OT_ERROR_NONE            Successfully read the value.
122      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `aBool` is untouched.
123      */
124     otError ReadBool(bool &aBool);
125 
126     /**
127      * Decodes and reads an `int8_t` value form the frame.
128      *
129      * On success, the read position get updated.
130      *
131      * @param[out] aInt8                Reference to variable to output the read value.
132      *
133      * @retval OT_ERROR_NONE            Successfully read the value.
134      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `aInt8` is untouched.
135      */
136     otError ReadInt8(int8_t &aInt8);
137 
138     /**
139      * Decodes and reads an `uint8_t` value form the frame.
140      *
141      * On success, the read position gets updated.
142      *
143      * @param[out] aUint8               Reference to variable to output the read value.
144      *
145      * @retval OT_ERROR_NONE            Successfully read the value.
146      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `aUint8` is untouched.
147      */
148     otError ReadUint8(uint8_t &aUint8);
149 
150     /**
151      * Decodes and reads an `int16_t` value form the frame.
152      *
153      * On success, the read position gets updated.
154      *
155      * @param[out] aInt16               Reference to variable to output the read value.
156      *
157      * @retval OT_ERROR_NONE            Successfully read the value.
158      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `aInt16` is untouched.
159      */
160     otError ReadInt16(int16_t &aInt16);
161 
162     /**
163      * Decodes and reads an `uint16_t` value form the frame.
164      *
165      * On success, the read position gets updated.
166      *
167      * @param[out] aUint16              Reference to variable to output the read value.
168      *
169      * @retval OT_ERROR_NONE            Successfully read the value.
170      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `aUint16` is untouched.
171      */
172     otError ReadUint16(uint16_t &aUint16);
173 
174     /**
175      * Decodes and reads an `int32_t` value form the frame.
176      *
177      * On success, the read position gets updated.
178      *
179      * @param[out] aInt32               Reference to variable to output the read value.
180      *
181      * @retval OT_ERROR_NONE            Successfully read the value.
182      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `Int32` is untouched.
183      */
184     otError ReadInt32(int32_t &aInt32);
185 
186     /**
187      * Decodes and reads an `uint32_t` value form the frame.
188      *
189      * On success, the read position gets updated.
190      *
191      * @param[out] aUint32              Reference to variable to output the read value.
192      *
193      * @retval OT_ERROR_NONE            Successfully read the value.
194      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `aUint32` is untouched.
195      */
196     otError ReadUint32(uint32_t &aUint32);
197 
198     /**
199      * Decodes and reads an `int64_t` value form the frame.
200      *
201      * On success, the read position gets updated.
202      *
203      * @param[out] aInt64               Reference to variable to output the read value.
204      *
205      * @retval OT_ERROR_NONE            Successfully read the value.
206      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `aInt64` is untouched.
207      */
208     otError ReadInt64(int64_t &aInt64);
209 
210     /**
211      * Decodes and reads an `uint64_t` value form the frame.
212      *
213      * On success, the read position gets updated.
214      *
215      * @param[out] aUint64              Reference to variable to output the read value.
216      *
217      * @retval OT_ERROR_NONE            Successfully read the value.
218      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `aUint64` is untouched.
219      */
220     otError ReadUint64(uint64_t &aUint64);
221 
222     /**
223      * Decodes (using spinel packed integer format) and reads an unsigned integer value form the frame.
224      *
225      * On success, the read position gets updated.
226      *
227      * @param[out] aUint                Reference to variable to output the read value.
228      *
229      * @retval OT_ERROR_NONE            Successfully read the value.
230      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `aUint` is untouched.
231      */
232     otError ReadUintPacked(unsigned int &aUint);
233 
234     /**
235      * Decodes and reads an IPv6 address form the frame.
236      *
237      * On success, the read position gets updated.
238      *
239      * @param[out] aIp6AddrPtr          Reference to IPv6 address pointer to output the value (as `spinel_ipv6addr_t`).
240      *                                  On success, the pointer variable is updated.
241      *
242      * @retval OT_ERROR_NONE            Successfully read the value.
243      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `aIp6AddrPtr` is untouched.
244      */
ReadIp6Address(const spinel_ipv6addr_t * & aIp6AddrPtr)245     otError ReadIp6Address(const spinel_ipv6addr_t *&aIp6AddrPtr)
246     {
247         return ReadItem(reinterpret_cast<const uint8_t **>(&aIp6AddrPtr), sizeof(spinel_ipv6addr_t));
248     }
249 
250     /**
251      * Decodes and reads an IPv6 address form the frame.
252      *
253      * On success, the read position gets updated.
254      *
255      * @param[out] aIp6AddrPtr          Reference to IPv6 address pointer to output the value (as `otIp6Address`).
256      *                                  On success, the pointer variable is updated.
257      *
258      * @retval OT_ERROR_NONE            Successfully read the value.
259      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `aIp6AddrPtr` is untouched.
260      */
ReadIp6Address(const otIp6Address * & aIp6AddrPtr)261     otError ReadIp6Address(const otIp6Address *&aIp6AddrPtr)
262     {
263         return ReadItem(reinterpret_cast<const uint8_t **>(&aIp6AddrPtr), sizeof(spinel_ipv6addr_t));
264     }
265 
266     /**
267      * Decodes and reads an IPv6 address form the frame.
268      *
269      * On success, the read position gets updated.
270      *
271      * @param[out] aIp6AddrBufPtr       Reference to a buffer pointer to output the value.
272      *                                  On success, the pointer variable is updated.
273      *
274      * @retval OT_ERROR_NONE            Successfully read the value.
275      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `aIp6AddrBufPtr` is untouched.
276      */
ReadIp6Address(const uint8_t * & aIp6AddrBufPtr)277     otError ReadIp6Address(const uint8_t *&aIp6AddrBufPtr)
278     {
279         return ReadItem(&aIp6AddrBufPtr, sizeof(spinel_ipv6addr_t));
280     }
281 
282     /**
283      * Decodes and reads an IPv6 address form the frame.
284      *
285      * On success, the read position gets updated and the IP address is copied into the given output variable.
286      *
287      * @param[out] aIp6Addr             Reference to IPv6 address variable to output the value (as `spinel_ipv6addr_t`).
288      *                                  On success, the address is copied into the output variable.
289      *
290      * @retval OT_ERROR_NONE            Successfully read the value.
291      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `aIp6Addr` is untouched.
292      */
293     otError ReadIp6Address(spinel_ipv6addr_t &aIp6Addr);
294 
295     /**
296      * Decodes and reads an IPv6 address form the frame.
297      *
298      * On success, the read position gets updated and the IP address is copied into the given output variable.
299      *
300      * @param[out] aIp6Addr             Reference to IPv6 address variable to output the value (as `otIp6Address`).
301      *                                  On success, the address is copied into the output variable.
302      *
303      * @retval OT_ERROR_NONE            Successfully read the value.
304      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `aIp6Addr` is untouched.
305      */
306     otError ReadIp6Address(otIp6Address &aIp6Addr);
307 
308     /**
309      * Decodes and reads an EUI64 value form the frame.
310      *
311      * On success, the read position gets updated.
312      *
313      * @param[out] aEui64Ptr            Reference to an EUI64 pointer to output the value (as `spinel_eui64_t`).
314      *                                  On success, the pointer variable is updated.
315      *
316      * @retval OT_ERROR_NONE            Successfully read the value.
317      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `aEui64Ptr` is untouched.
318      */
ReadEui64(const spinel_eui64_t * & aEui64Ptr)319     otError ReadEui64(const spinel_eui64_t *&aEui64Ptr)
320     {
321         return ReadItem(reinterpret_cast<const uint8_t **>(&aEui64Ptr), sizeof(spinel_eui64_t));
322     }
323 
324     /**
325      * Decodes and reads an EUI64 value form the frame.
326      *
327      * On success, the read position gets updated.
328      *
329      * @param[out] aEui64Ptr            Reference to an EUI64 pointer to output the value (as `otExtAddress`).
330      *                                  On success, the pointer variable is updated.
331      *
332      * @retval OT_ERROR_NONE            Successfully read the value.
333      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `aEui64Ptr` is untouched.
334      */
ReadEui64(const otExtAddress * & aEui64Ptr)335     otError ReadEui64(const otExtAddress *&aEui64Ptr)
336     {
337         return ReadItem(reinterpret_cast<const uint8_t **>(&aEui64Ptr), sizeof(spinel_eui64_t));
338     }
339 
340     /**
341      * Decodes and reads an EUI64 value form the frame.
342      *
343      * On success, the read position gets updated.
344      *
345      * @param[out] aEui64BufPtr         Reference to a buffer pointer to output the value.
346      *                                  On success, the pointer variable is updated.
347      *
348      * @retval OT_ERROR_NONE            Successfully read the value.
349      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `aEui64BufPtr` is untouched.
350      */
ReadEui64(const uint8_t * & aEui64BufPtr)351     otError ReadEui64(const uint8_t *&aEui64BufPtr) { return ReadItem(&aEui64BufPtr, sizeof(spinel_eui64_t)); }
352 
353     /**
354      * Decodes and reads an EUI64 value form the frame.
355      *
356      * On success, the read position gets updated and the EUI64 value is copied into the given output variable.
357      *
358      * @param[out] aEui64               Reference to EUI64 variable to output the value (as `spinel_eui64_t`).
359      *                                  On success, the address is copied into the output variable.
360      *
361      * @retval OT_ERROR_NONE            Successfully read the value.
362      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `aEui64` is untouched.
363      */
364     otError ReadEui64(spinel_eui64_t &aEui64);
365 
366     /**
367      * Decodes and reads an EUI64 value form the frame.
368      *
369      * On success, the read position gets updated and the EUI64 value is copied into the given output variable.
370      *
371      * @param[out] aEui64               Reference to EUI64 variable to output the value (as `otExtAddress`).
372      *                                  On success, the address is copied into the output variable.
373      *
374      * @retval OT_ERROR_NONE            Successfully read the value.
375      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `aEui64` is untouched.
376      */
377     otError ReadEui64(otExtAddress &aEui64);
378 
379     /**
380      * Decodes and reads an EUI48 value form the frame.
381      *
382      * On success, the read position gets updated.
383      *
384      * @param[out] aEui48Ptr            Reference to an EUI48 pointer to output the value (as `spinel_eui48_t`).
385      *                                  On success, the pointer variable is updated.
386      *
387      * @retval OT_ERROR_NONE            Successfully read the value.
388      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `aEui48Ptr` is untouched.
389      */
ReadEui48(const spinel_eui48_t * & aEui48Ptr)390     otError ReadEui48(const spinel_eui48_t *&aEui48Ptr)
391     {
392         return ReadItem(reinterpret_cast<const uint8_t **>(&aEui48Ptr), sizeof(spinel_eui48_t));
393     }
394 
395     /**
396      * Decodes and reads an EUI48 value form the frame.
397      *
398      * On success, the read position gets updated.
399      *
400      * @param[out] aEui48BufPtr         Reference to a buffer pointer to output the value.
401      *                                  On success, the pointer variable is updated.
402      *
403      * @retval OT_ERROR_NONE            Successfully read the value.
404      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `aEui48BufPtr` is untouched..
405      */
ReadEui48(const uint8_t * & aEui48BufPtr)406     otError ReadEui48(const uint8_t *&aEui48BufPtr) { return ReadItem(&aEui48BufPtr, sizeof(spinel_eui48_t)); }
407 
408     /**
409      * Decodes and reads an EUI48 value form the frame.
410      *
411      * On success, the read position gets updated and the EUI48 value is copied into the given output variable.
412      *
413      * @param[out] aEui48               Reference to EUI48 variable to output the value (as `spinel_eui48_t`).
414      *                                  On success, value is copied into the output variable.
415      *
416      * @retval OT_ERROR_NONE            Successfully read the value.
417      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `aEui48` is untouched.
418      */
419     otError ReadEui48(spinel_eui48_t &aEui48);
420 
421     /**
422      * Decodes and reads a UTF8 string form the frame.
423      *
424      * On success, the read position gets updated.
425      *
426      * @param[out] aUtf8                Reference to a `char` pointer to output the string.
427      *                                  On success, the pointer variable is updated.
428      *
429      * @retval OT_ERROR_NONE            Successfully read the value.
430      * @retval OT_ERROR_PARSE           Failed to parse/decode the value and `aUtf8` is untouched.
431      */
432     otError ReadUtf8(const char *&aUtf8);
433 
434     /**
435      * Decodes and reads a data blob (sequence of bytes) form the frame.
436      *
437      * On success, the read position gets updated.
438      *
439      * @param[out] aData                Reference to pointer variable to output the data.
440      *                                  On success, the pointer variable is updated.
441      * @param[out] aDataLen             Reference to variable to output the data length (number of bytes).
442      *
443      * @retval OT_ERROR_NONE            Successfully read the value.
444      * @retval OT_ERROR_PARSE           Failed to parse/decode the value. `aData` and `aDataLen` are untouched.
445      */
446     otError ReadData(const uint8_t *&aData, uint16_t &aDataLen);
447 
448     /**
449      * Decodes and reads a data blob (sequence of bytes) with data length.
450      *
451      * The data length is assumed to be prepended before the data content (encoded as a `uint16_t`). The size of the
452      * length field should not be included in the length value. This method corresponds to `SPINEL_DATATYPE_DATA_WLEN`
453      * type.
454      *
455      * @param[out] aData                Reference to pointer variable to output the data.
456      *                                  On success, the pointer variable is updated.
457      * @param[out] aDataLen             Reference to variable to out the data length (number of bytes).
458      *
459      * @retval OT_ERROR_NONE            Successfully read the value.
460      * @retval OT_ERROR_PARSE           Failed to parse/decode the value. `aDataLen` may be updated and `aData` is
461      *                                  untouched.
462      */
463     otError ReadDataWithLen(const uint8_t *&aData, uint16_t &aDataLen);
464 
465     /**
466      * Opens a struct in the frame.
467      *
468      * After a successful call to this method, all the subsequent `Read{SomeType}()` methods decode and read the
469      * field/value from the current open struct until the struct is closed using `CloseStruct()` method. Structures can
470      * be nested. Up to `kMaxNestedStructs` nested structs can be opened at the same time.
471      *
472      * @retval OT_ERROR_NONE            Successfully opened a struct.
473      * @retval OT_ERROR_PARSE           Failed to parse/open a struct.
474      * @retval OT_ERROR_INVALID_STATE   Already at the maximum number of nested open structures.
475      */
476     otError OpenStruct(void);
477 
478     /**
479      * Closes the most recently opened struct (using `OpenStruct()`) in the frame.
480      *
481      * On success, the read position is moved to end of the struct skipping any unread bytes within the struct.
482      *
483      * @retval OT_ERROR_NONE            Successfully closed the struct.
484      * @retval OT_ERROR_INVALID_STATE   There is no current open struct to close.
485      */
486     otError CloseStruct(void);
487 
488     /**
489      * Returns the number of remaining/unread bytes in the current inner-most open structure.
490      *
491      * If there is no currently open structure the number of remaining bytes in whole frame is returned instead.
492      *
493      * @returns The number of remaining unread bytes in the inner-most open structure.
494      */
GetRemainingLengthInStruct(void) const495     uint16_t GetRemainingLengthInStruct(void) const { return mEnd - mIndex; }
496 
497     /**
498      * Indicates whether or not all the bytes in inner-most open structure are read.
499      *
500      * If there is no currently open structure, the whole frame is considered instead.
501      *
502      * @returns TRUE if all the bytes are read, FALSE otherwise.
503      */
IsAllReadInStruct(void) const504     bool IsAllReadInStruct(void) const { return (mIndex == mEnd); }
505 
506     /**
507      * Saves the current read position in the frame.
508      *
509      * A subsequent call to `SavePosition()` will overwrite the previously saved position. The saved position can be
510      * used to move the read position back (using `ResetToSaved()`) and re-read the same content.
511      *
512      * Saved position can be within an open struct, and it remembers its enclosing struct. When the enclosing struct is
513      * closed, the saved position will be voided and can no longer be used. This ensures that we cannot jump back to
514      * middle an already fully decoded/read and closed struct.
515      */
516     void SavePosition(void);
517 
518     /**
519      * Resets/moves the read position to a previously saved position.
520      *
521      * The saved position remembers its enclosing structure. When `ResetToSaved()` is called, the current open
522      * structure will be the same as when position was saved.
523      *
524      * @retval OT_ERROR_NONE            Successfully reset the read position.
525      * @retval OT_ERROR_INVALID_STATE   The saved position is not valid (there is no saved position or the saved
526      *                                  position was voided since its enclosing struct was closed).
527      */
528     otError ResetToSaved(void);
529 
530 private:
531     otError ReadItem(const uint8_t **aPtr, uint16_t aSize);
ClearSavedPosition(void)532     void    ClearSavedPosition(void) { mSavedIndex = mLength; }
IsSavedPositionValid(void) const533     bool    IsSavedPositionValid(void) const { return (mSavedIndex < mLength); }
534 
535     const uint8_t *mFrame;          // Frame buffer.
536     uint16_t       mLength;         // Frame length (number of bytes).
537     uint16_t       mIndex;          // Current read index.
538     uint16_t       mEnd;            // Current end index (end of struct if in a struct, or end of buffer otherwise).
539     uint8_t        mNumOpenStructs; // Number of open structs.
540 
541     uint8_t  mSavedNumOpenStructs; // Number of open structs when read position was saved.
542     uint16_t mSavedIndex;          // Read index when position was saved.
543     uint16_t mSavedEnd;            // End index when position was saved.
544 
545     uint16_t mPrevEnd[kMaxNestedStructs];
546 };
547 
548 } // namespace Spinel
549 } // namespace ot
550 
551 #endif // SPINEL_DECODER_HPP_
552