• 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  * This class defines a spinel decoder.
48  *
49  */
50 class Decoder
51 {
52 public:
53     enum
54     {
55         kMaxNestedStructs = 4, ///< Maximum number of nested structs.
56     };
57 
58     /**
59      * This constructor initializes a `Decoder` object.
60      *
61      */
62     Decoder(void);
63 
64     /**
65      * This method initializes the decoder to start decoding a new frame.
66      *
67      * It sets the read position to the start of the frame and also erases/voids any saved positions (see
68      * `SavePosition()` and `ResetToSaved()` methods).
69      *
70      * @param[in] aFrame                Pointer to the buffer containing the frame to be decoded.
71      * @param[in] aLength               Length (number of bytes) of the frame.
72      *
73      */
74     void Init(const uint8_t *aFrame, uint16_t aLength);
75 
76     /**
77      * This method returns the pointer to the start of the frame.
78      *
79      * @returns A pointer to buffer containing current frame being decoded.
80      *
81      */
GetFrame(void) const82     const uint8_t *GetFrame(void) const { return mFrame; }
83 
84     /**
85      * This method returns the total length of current frame being decoded.
86      *
87      * @returns The length of current frame being decoded.
88      *
89      */
GetLength(void) const90     uint16_t GetLength(void) const { return mLength; }
91 
92     /**
93      * This method returns the number of bytes that are already read/decoded from the frame.
94      *
95      * @returns The number of bytes already read from frame.
96      *
97      */
GetReadLength(void) const98     uint16_t GetReadLength(void) const { return mIndex; }
99 
100     /**
101      * This method returns the number of remaining (not yet read/decoded) bytes in the frame.
102      *
103      * @returns The number of remaining unread bytes in the frame.
104      *
105      */
GetRemainingLength(void) const106     uint16_t GetRemainingLength(void) const { return mLength - mIndex; }
107 
108     /**
109      * This method indicates whether or not all the bytes in the frame are read.
110      *
111      * @returns TRUE if all the bytes in the buffer are read, FALSE otherwise.
112      *
113      */
IsAllRead(void) const114     bool IsAllRead(void) const { return (mIndex == mLength); }
115 
116     /**
117      * This method resets the read position to beginning of frame. It will also void/erase any previously saved
118      * position using `SavePosition()` method.
119      *
120      */
121     void Reset(void);
122 
123     /**
124      * This method decodes and reads a boolean value form the frame.
125      *
126      * On success, the read position gets updated.
127      *
128      * @param[out] aBool                Reference to variable to output the read value.
129      *
130      * @retval OT_ERROR_NONE            Successfully read the value.
131      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
132      *
133      */
134     otError ReadBool(bool &aBool);
135 
136     /**
137      * This method decodes and reads an `int8_t` value form the frame.
138      *
139      * On success, the read position get updated.
140      *
141      * @param[out] aInt8                Reference to variable to output the read value.
142      *
143      * @retval OT_ERROR_NONE            Successfully read the value.
144      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
145      *
146      */
147     otError ReadInt8(int8_t &aInt8);
148 
149     /**
150      * This method decodes and reads an `uint8_t` value form the frame.
151      *
152      * On success, the read position gets updated.
153      *
154      * @param[out] aUint8               Reference to variable to output the read value.
155      *
156      * @retval OT_ERROR_NONE            Successfully read the value.
157      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
158      *
159      */
160     otError ReadUint8(uint8_t &aUint8);
161 
162     /**
163      * This method decodes and reads an `int16_t` value form the frame.
164      *
165      * On success, the read position gets updated.
166      *
167      * @param[out] aInt16               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.
171      *
172      */
173     otError ReadInt16(int16_t &aInt16);
174 
175     /**
176      * This method decodes and reads an `uint16_t` value form the frame.
177      *
178      * On success, the read position gets updated.
179      *
180      * @param[out] aUint16              Reference to variable to output the read value.
181      *
182      * @retval OT_ERROR_NONE            Successfully read the value.
183      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
184      *
185      */
186     otError ReadUint16(uint16_t &aUint16);
187 
188     /**
189      * This method decodes and reads an `int32_t` value form the frame.
190      *
191      * On success, the read position gets updated.
192      *
193      * @param[out] aInt32               Reference to variable to output the read value.
194      *
195      * @retval OT_ERROR_NONE            Successfully read the value.
196      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
197      *
198      */
199     otError ReadInt32(int32_t &aInt32);
200 
201     /**
202      * This method decodes and reads an `uint32_t` value form the frame.
203      *
204      * On success, the read position gets updated.
205      *
206      * @param[out] aUint32              Reference to variable to output the read value.
207      *
208      * @retval OT_ERROR_NONE            Successfully read the value.
209      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
210      *
211      */
212     otError ReadUint32(uint32_t &aUint32);
213 
214     /**
215      * This method decodes and reads an `int64_t` value form the frame.
216      *
217      * On success, the read position gets updated.
218      *
219      * @param[out] aInt64               Reference to variable to output the read value.
220      *
221      * @retval OT_ERROR_NONE            Successfully read the value.
222      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
223      *
224      */
225     otError ReadInt64(int64_t &aInt64);
226 
227     /**
228      * This method decodes and reads an `uint64_t` value form the frame.
229      *
230      * On success, the read position gets updated.
231      *
232      * @param[out] aUint64              Reference to variable to output the read value.
233      *
234      * @retval OT_ERROR_NONE            Successfully read the value.
235      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
236      *
237      */
238     otError ReadUint64(uint64_t &aUint64);
239 
240     /**
241      * This method decodes (using spinel packed integer format) and reads an unsigned integer value form the frame.
242      *
243      * On success, the read position gets updated.
244      *
245      * @param[out] aUint                Reference to variable to output the read value.
246      *
247      * @retval OT_ERROR_NONE            Successfully read the value.
248      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
249      *
250      */
251     otError ReadUintPacked(unsigned int &aUint);
252 
253     /**
254      * This method decodes and reads an IPv6 address form the frame.
255      *
256      * On success, the read position gets updated.
257      *
258      * @param[out] aIp6AddrPtr          Reference to IPv6 address pointer to output the value (as `spinel_ipv6addr_t`).
259      *                                  On success, the pointer variable is updated.
260      *
261      * @retval OT_ERROR_NONE            Successfully read the value.
262      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
263      *
264      */
ReadIp6Address(const spinel_ipv6addr_t * & aIp6AddrPtr)265     otError ReadIp6Address(const spinel_ipv6addr_t *&aIp6AddrPtr)
266     {
267         return ReadItem(reinterpret_cast<const uint8_t **>(&aIp6AddrPtr), sizeof(spinel_ipv6addr_t));
268     }
269 
270     /**
271      * This method decodes and reads an IPv6 address form the frame.
272      *
273      * On success, the read position gets updated.
274      *
275      * @param[out] aIp6AddrPtr          Reference to IPv6 address pointer to output the value (as `otIp6Address`).
276      *                                  On success, the pointer variable is updated.
277      *
278      * @retval OT_ERROR_NONE            Successfully read the value.
279      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
280      *
281      */
ReadIp6Address(const otIp6Address * & aIp6AddrPtr)282     otError ReadIp6Address(const otIp6Address *&aIp6AddrPtr)
283     {
284         return ReadItem(reinterpret_cast<const uint8_t **>(&aIp6AddrPtr), sizeof(spinel_ipv6addr_t));
285     }
286 
287     /**
288      * This method decodes and reads an IPv6 address form the frame.
289      *
290      * On success, the read position gets updated.
291      *
292      * @param[out] aIp6AddrBufPtr       Reference to a buffer pointer to output the value.
293      *                                  On success, the pointer variable is updated.
294      *
295      * @retval OT_ERROR_NONE            Successfully read the value.
296      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
297      *
298      */
ReadIp6Address(const uint8_t * & aIp6AddrBufPtr)299     otError ReadIp6Address(const uint8_t *&aIp6AddrBufPtr)
300     {
301         return ReadItem(&aIp6AddrBufPtr, sizeof(spinel_ipv6addr_t));
302     }
303 
304     /**
305      * This method decodes and reads an IPv6 address form the frame.
306      *
307      * On success, the read position gets updated and the IP address is copied into the given output variable.
308      *
309      * @param[out] aIp6Addr             Reference to IPv6 address variable to output the value (as `spinel_ipv6addr_t`).
310      *                                  On success, the address is copied into the output variable.
311      *
312      * @retval OT_ERROR_NONE            Successfully read the value.
313      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
314      *
315      */
316     otError ReadIp6Address(spinel_ipv6addr_t &aIp6Addr);
317 
318     /**
319      * This method decodes and reads an IPv6 address form the frame.
320      *
321      * On success, the read position gets updated and the IP address is copied into the given output variable.
322      *
323      * @param[out] aIp6Addr             Reference to IPv6 address variable to output the value (as `otIp6Address`).
324      *                                  On success, the address is copied into the output variable.
325      *
326      * @retval OT_ERROR_NONE            Successfully read the value.
327      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
328      *
329      */
330     otError ReadIp6Address(otIp6Address &aIp6Addr);
331 
332     /**
333      * This method decodes and reads an EUI64 value form the frame.
334      *
335      * On success, the read position gets updated.
336      *
337      * @param[out] aEui64Ptr            Reference to an EUI64 pointer to output the value (as `spinel_eui64_t`).
338      *                                  On success, the pointer variable is updated.
339      *
340      * @retval OT_ERROR_NONE            Successfully read the value.
341      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
342      *
343      */
ReadEui64(const spinel_eui64_t * & aEui64Ptr)344     otError ReadEui64(const spinel_eui64_t *&aEui64Ptr)
345     {
346         return ReadItem(reinterpret_cast<const uint8_t **>(&aEui64Ptr), sizeof(spinel_eui64_t));
347     }
348 
349     /**
350      * This method decodes and reads an EUI64 value form the frame.
351      *
352      * On success, the read position gets updated.
353      *
354      * @param[out] aEui64Ptr            Reference to an EUI64 pointer to output the value (as `otExtAddress`).
355      *                                  On success, the pointer variable is updated.
356      *
357      * @retval OT_ERROR_NONE            Successfully read the value.
358      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
359      *
360      */
ReadEui64(const otExtAddress * & aEui64Ptr)361     otError ReadEui64(const otExtAddress *&aEui64Ptr)
362     {
363         return ReadItem(reinterpret_cast<const uint8_t **>(&aEui64Ptr), sizeof(spinel_eui64_t));
364     }
365 
366     /**
367      * This method decodes and reads an EUI64 value form the frame.
368      *
369      * On success, the read position gets updated.
370      *
371      * @param[out] aEui64BufPtr         Reference to a buffer pointer to output the value.
372      *                                  On success, the pointer variable is updated.
373      *
374      * @retval OT_ERROR_NONE            Successfully read the value.
375      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
376      *
377      */
ReadEui64(const uint8_t * & aEui64BufPtr)378     otError ReadEui64(const uint8_t *&aEui64BufPtr) { return ReadItem(&aEui64BufPtr, sizeof(spinel_eui64_t)); }
379 
380     /**
381      * This method decodes and reads an EUI64 value form the frame.
382      *
383      * On success, the read position gets updated and the EUI64 value is copied into the given output variable.
384      *
385      * @param[out] aEui64               Reference to EUI64 variable to output the value (as `spinel_eui64_t`).
386      *                                  On success, the address is copied into the output variable.
387      *
388      * @retval OT_ERROR_NONE            Successfully read the value.
389      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
390      *
391      */
392     otError ReadEui64(spinel_eui64_t &aEui64);
393 
394     /**
395      * This method decodes and reads an EUI64 value form the frame.
396      *
397      * On success, the read position gets updated and the EUI64 value is copied into the given output variable.
398      *
399      * @param[out] aEui64               Reference to EUI64 variable to output the value (as `otExtAddress`).
400      *                                  On success, the address is copied into the output variable.
401      *
402      * @retval OT_ERROR_NONE            Successfully read the value.
403      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
404      *
405      */
406     otError ReadEui64(otExtAddress &aEui64);
407 
408     /**
409      * This method decodes and reads an EUI48 value form the frame.
410      *
411      * On success, the read position gets updated.
412      *
413      * @param[out] aEui48Ptr            Reference to an EUI48 pointer to output the value (as `spinel_eui48_t`).
414      *                                  On success, the pointer variable is updated.
415      *
416      * @retval OT_ERROR_NONE            Successfully read the value.
417      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
418      *
419      */
ReadEui48(const spinel_eui48_t * & aEui48Ptr)420     otError ReadEui48(const spinel_eui48_t *&aEui48Ptr)
421     {
422         return ReadItem(reinterpret_cast<const uint8_t **>(&aEui48Ptr), sizeof(spinel_eui48_t));
423     }
424 
425     /**
426      * This method decodes and reads an EUI48 value form the frame.
427      *
428      * On success, the read position gets updated.
429      *
430      * @param[out] aEui48BufPtr         Reference to a buffer pointer to output the value.
431      *                                  On success, the pointer variable is updated.
432      *
433      * @retval OT_ERROR_NONE            Successfully read the value.
434      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
435      *
436      */
ReadEui48(const uint8_t * & aEui48BufPtr)437     otError ReadEui48(const uint8_t *&aEui48BufPtr) { return ReadItem(&aEui48BufPtr, sizeof(spinel_eui48_t)); }
438 
439     /**
440      * This method decodes and reads an EUI48 value form the frame.
441      *
442      * On success, the read position gets updated and the EUI48 value is copied into the given output variable.
443      *
444      * @param[out] aEui48               Reference to EUI48 variable to output the value (as `spinel_eui48_t`).
445      *                                  On success, value is copied into the output variable.
446      *
447      * @retval OT_ERROR_NONE            Successfully read the value.
448      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
449      *
450      */
451     otError ReadEui48(spinel_eui48_t &aEui48);
452 
453     /**
454      * This method decodes and reads a UTF8 string form the frame.
455      *
456      * On success, the read position gets updated.
457      *
458      * @param[out] aUtf8                Reference to a `char` pointer to output the string.
459      *                                  On success, the pointer variable is updated.
460      *
461      * @retval OT_ERROR_NONE            Successfully read the value.
462      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
463      *
464      */
465     otError ReadUtf8(const char *&aUtf8);
466 
467     /**
468      * This method decodes and reads a data blob (sequence of bytes) form the frame.
469      *
470      * On success, the read position gets updated.
471      *
472      * @param[out] aData                Reference to pointer variable to output the data.
473      *                                  On success, the pointer variable is updated.
474      * @param[out] aDataLen             Reference to variable to output the data length (number of bytes).
475      *
476      * @retval OT_ERROR_NONE            Successfully read the value.
477      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
478      *
479      */
480     otError ReadData(const uint8_t *&aData, uint16_t &aDataLen);
481 
482     /**
483      * This method decodes and reads a data blob (sequence of bytes) with data length.
484      *
485      * The data length is assumed to be prepended before the data content (encoded as a `uint16_t`). The size of the
486      * length field should not be included in the length value. This method corresponds to `SPINEL_DATATYPE_DATA_WLEN`
487      * type.
488      *
489      * @param[out] aData                Reference to pointer variable to output the data.
490      *                                  On success, the pointer variable is updated.
491      * @param[out] aDataLen             Reference to variable to out the data length (number of bytes).
492      *
493      * @retval OT_ERROR_NONE            Successfully read the value.
494      * @retval OT_ERROR_PARSE           Failed to parse/decode the value.
495      *
496      */
497     otError ReadDataWithLen(const uint8_t *&aData, uint16_t &aDataLen);
498 
499     /**
500      * This method opens a struct in the frame.
501      *
502      * After a successful call to this method, all the subsequent `Read{SomeType}()` methods decode and read the
503      * field/value from the current open struct until the struct is closed using `CloseStruct()` method. Structures can
504      * be nested. Up to `kMaxNestedStructs` nested structs can be opened at the same time.
505      *
506      * @retval OT_ERROR_NONE            Successfully opened a struct.
507      * @retval OT_ERROR_PARSE           Failed to parse/open a struct.
508      * @retval OT_ERROR_INVALID_STATE   Already at the maximum number of nested open structures.
509      *
510      */
511     otError OpenStruct(void);
512 
513     /**
514      * This method closes the most recently opened struct (using `OpenStruct()`) in the frame.
515      *
516      * On success, the read position is moved to end of the struct skipping any unread bytes within the struct.
517      *
518      * @retval OT_ERROR_NONE            Successfully closed the struct.
519      * @retval OT_ERROR_INVALID_STATE   There is no current open struct to close.
520      *
521      */
522     otError CloseStruct(void);
523 
524     /**
525      * This method returns the number of remaining/unread bytes in the current inner-most open structure.
526      *
527      * If there is no currently open structure the number of remaining bytes in whole frame is returned instead.
528      *
529      * @returns The number of remaining unread bytes in the inner-most open structure.
530      *
531      */
GetRemainingLengthInStruct(void) const532     uint16_t GetRemainingLengthInStruct(void) const { return mEnd - mIndex; }
533 
534     /**
535      * This method indicates whether or not all the bytes in inner-most open structure are read.
536      *
537      * If there is no currently open structure, the whole frame is considered instead.
538      *
539      * @returns TRUE if all the bytes are read, FALSE otherwise.
540      *
541      */
IsAllReadInStruct(void) const542     bool IsAllReadInStruct(void) const { return (mIndex == mEnd); }
543 
544     /**
545      * This method saves the current read position in the frame.
546      *
547      * A subsequent call to `SavePosition()` will overwrite the previously saved position. The saved position can be
548      * used to move the read position back (using `ResetToSaved()`) and re-read the same content.
549      *
550      * Saved position can be within an open struct, and it remembers its enclosing struct. When the enclosing struct is
551      * closed, the saved position will be voided and can no longer be used. This ensures that we cannot jump back to
552      * middle an already fully decoded/read and closed struct.
553      *
554      */
555     void SavePosition(void);
556 
557     /**
558      * This method resets/moves the read position to a previously saved position.
559      *
560      * The saved position remembers its enclosing structure. When `ResetToSaved()` is called, the current open
561      * structure will be the same as when position was saved.
562      *
563      * @retval OT_ERROR_NONE            Successfully reset the read position.
564      * @retval OT_ERROR_INVALID_STATE   The saved position is not valid (there is no saved position or the saved
565      *                                  position was voided since its enclosing struct was closed).
566      *
567      */
568     otError ResetToSaved(void);
569 
570 private:
571     otError ReadItem(const uint8_t **aPtr, uint16_t aSize);
ClearSavedPosition(void)572     void    ClearSavedPosition(void) { mSavedIndex = mLength; }
IsSavedPositionValid(void) const573     bool    IsSavedPositionValid(void) const { return (mSavedIndex < mLength); }
574 
575     const uint8_t *mFrame;          // Frame buffer.
576     uint16_t       mLength;         // Frame length (number of bytes).
577     uint16_t       mIndex;          // Current read index.
578     uint16_t       mEnd;            // Current end index (end of struct if in a struct, or end of buffer otherwise).
579     uint8_t        mNumOpenStructs; // Number of open structs.
580 
581     uint8_t  mSavedNumOpenStructs; // Number of open structs when read position was saved.
582     uint16_t mSavedIndex;          // Read index when position was saved.
583     uint16_t mSavedEnd;            // End index when position was saved.
584 
585     uint16_t mPrevEnd[kMaxNestedStructs];
586 };
587 
588 } // namespace Spinel
589 } // namespace ot
590 
591 #endif // SPINEL_DECODER_HPP_
592