1 /*
2  * Copyright (c) 2018 - 2023, Nordic Semiconductor ASA
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice, this
11  *    list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
18  *    contributors may be used to endorse or promote products derived from this
19  *    software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  */
34 
35 /**
36  * @file
37  *   This file implements frame parsing utilities for 802.15.4 radio driver.
38  *
39  * @note This module is based on following assumptions:
40  *       a. All received frames contain both source and destination address.
41  *       b. All received frames contain destination PAN ID field.
42  *       Frames that don't meet these assumptions are dropped.
43  */
44 
45 #include "nrf_802154_frame_parser.h"
46 
47 #include "nrf_802154_const.h"
48 #include "nrf_802154_utils_byteorder.h"
49 
50 /***************************************************************************************************
51  * @section Helper functions
52  **************************************************************************************************/
53 
54 // Addressing
55 
src_addr_is_present(const nrf_802154_frame_parser_data_t * p_parser_data)56 static bool src_addr_is_present(const nrf_802154_frame_parser_data_t * p_parser_data)
57 {
58     return nrf_802154_frame_parser_src_addr_type_get(p_parser_data) != SRC_ADDR_TYPE_NONE;
59 }
60 
src_addr_size_get(const nrf_802154_frame_parser_data_t * p_parser_data)61 static uint8_t src_addr_size_get(const nrf_802154_frame_parser_data_t * p_parser_data)
62 {
63     uint8_t addr_type = nrf_802154_frame_parser_src_addr_type_get(p_parser_data);
64 
65     switch (addr_type)
66     {
67         case SRC_ADDR_TYPE_EXTENDED:
68             return EXTENDED_ADDRESS_SIZE;
69 
70         case SRC_ADDR_TYPE_SHORT:
71             return SHORT_ADDRESS_SIZE;
72 
73         case SRC_ADDR_TYPE_NONE:
74             return 0;
75 
76         default:
77             return NRF_802154_FRAME_PARSER_INVALID_OFFSET;
78     }
79 }
80 
dst_addr_is_present(const nrf_802154_frame_parser_data_t * p_parser_data)81 static bool dst_addr_is_present(const nrf_802154_frame_parser_data_t * p_parser_data)
82 {
83     return nrf_802154_frame_parser_dst_addr_type_get(p_parser_data) != DEST_ADDR_TYPE_NONE;
84 }
85 
dst_addr_size_get(const nrf_802154_frame_parser_data_t * p_parser_data)86 static uint8_t dst_addr_size_get(const nrf_802154_frame_parser_data_t * p_parser_data)
87 {
88     uint8_t addr_type = nrf_802154_frame_parser_dst_addr_type_get(p_parser_data);
89 
90     switch (addr_type)
91     {
92         case DEST_ADDR_TYPE_EXTENDED:
93             return EXTENDED_ADDRESS_SIZE;
94 
95         case DEST_ADDR_TYPE_SHORT:
96             return SHORT_ADDRESS_SIZE;
97 
98         case DEST_ADDR_TYPE_NONE:
99             return 0;
100 
101         default:
102             return NRF_802154_FRAME_PARSER_INVALID_OFFSET;
103     }
104 }
105 
106 // PAN ID
dst_panid_is_present(const nrf_802154_frame_parser_data_t * p_parser_data)107 static bool dst_panid_is_present(const nrf_802154_frame_parser_data_t * p_parser_data)
108 {
109     bool panid_compression = nrf_802154_frame_parser_panid_compression_is_set(p_parser_data);
110 
111     switch (nrf_802154_frame_parser_frame_version_get(p_parser_data))
112     {
113         case FRAME_VERSION_0:
114         case FRAME_VERSION_1:
115             if (!dst_addr_is_present(p_parser_data))
116             {
117                 return false;
118             }
119 
120             return true;
121 
122         case FRAME_VERSION_2:
123         default:
124             if (nrf_802154_frame_parser_dst_addr_is_extended(p_parser_data) &&
125                 nrf_802154_frame_parser_src_addr_is_extended(p_parser_data))
126             {
127                 return panid_compression ? false : true;
128             }
129 
130             if (src_addr_is_present(p_parser_data) && dst_addr_is_present(p_parser_data))
131             {
132                 return true;
133             }
134 
135             if (src_addr_is_present(p_parser_data))
136             {
137                 return false;
138             }
139 
140             if (dst_addr_is_present(p_parser_data))
141             {
142                 return panid_compression ? false : true;
143             }
144 
145             return panid_compression ? true : false;
146     }
147 }
148 
src_panid_is_present(const nrf_802154_frame_parser_data_t * p_parser_data)149 static bool src_panid_is_present(const nrf_802154_frame_parser_data_t * p_parser_data)
150 {
151     bool panid_compression = nrf_802154_frame_parser_panid_compression_is_set(p_parser_data);
152 
153     switch (nrf_802154_frame_parser_frame_version_get(p_parser_data))
154     {
155         case FRAME_VERSION_0:
156         case FRAME_VERSION_1:
157             if (!src_addr_is_present(p_parser_data))
158             {
159                 return false;
160             }
161 
162             return panid_compression ? false : true;
163 
164         case FRAME_VERSION_2:
165         default:
166             if (nrf_802154_frame_parser_dst_addr_is_extended(p_parser_data) &&
167                 nrf_802154_frame_parser_src_addr_is_extended(p_parser_data))
168             {
169                 return false;
170             }
171 
172             if (src_addr_is_present(p_parser_data) && dst_addr_is_present(p_parser_data))
173             {
174                 return panid_compression ? false : true;
175             }
176 
177             if (src_addr_is_present(p_parser_data))
178             {
179                 return panid_compression ? false : true;
180             }
181 
182             return false;
183     }
184 }
185 
186 // Security
187 
key_source_size_get(uint8_t key_id_mode)188 uint8_t key_source_size_get(uint8_t key_id_mode)
189 {
190     switch (key_id_mode)
191     {
192         case KEY_ID_MODE_0:
193             return KEY_SRC_KEY_ID_MODE_0_SIZE;
194 
195         case KEY_ID_MODE_1:
196             return KEY_SRC_KEY_ID_MODE_1_SIZE;
197 
198         case KEY_ID_MODE_2:
199             return KEY_SRC_KEY_ID_MODE_2_SIZE;
200 
201         case KEY_ID_MODE_3:
202             return KEY_SRC_KEY_ID_MODE_3_SIZE;
203 
204         default:
205             // Unknown key identifier mode
206             return 0;
207     }
208 }
209 
mic_size_get(const nrf_802154_frame_parser_data_t * p_parser_data)210 static uint8_t mic_size_get(const nrf_802154_frame_parser_data_t * p_parser_data)
211 {
212     switch (nrf_802154_frame_parser_sec_ctrl_sec_lvl_get(p_parser_data))
213     {
214         case SECURITY_LEVEL_MIC_32:
215         case SECURITY_LEVEL_ENC_MIC_32:
216             return MIC_32_SIZE;
217 
218         case SECURITY_LEVEL_MIC_64:
219         case SECURITY_LEVEL_ENC_MIC_64:
220             return MIC_64_SIZE;
221 
222         case SECURITY_LEVEL_MIC_128:
223         case SECURITY_LEVEL_ENC_MIC_128:
224             return MIC_128_SIZE;
225 
226         default:
227             return 0;
228     }
229 }
230 
231 /***************************************************************************************************
232  * @section Parsing functions
233  **************************************************************************************************/
234 
fcf_parse(nrf_802154_frame_parser_data_t * p_parser_data)235 static bool fcf_parse(nrf_802154_frame_parser_data_t * p_parser_data)
236 {
237     uint8_t offset = PHR_SIZE + FCF_SIZE;
238     uint8_t addr_size;
239 
240     if (offset > p_parser_data->valid_data_len)
241     {
242         // Not enough valid data to parse the FCF
243         return false;
244     }
245 
246     if (nrf_802154_frame_parser_dsn_suppress_bit_is_set(p_parser_data) == false)
247     {
248         offset += DSN_SIZE;
249     }
250 
251     if (dst_panid_is_present(p_parser_data))
252     {
253         p_parser_data->mhr.dst.panid_offset = offset;
254         offset                             += PAN_ID_SIZE;
255     }
256 
257     if (dst_addr_is_present(p_parser_data))
258     {
259         p_parser_data->mhr.dst.addr_offset = offset;
260     }
261 
262     addr_size = dst_addr_size_get(p_parser_data);
263 
264     if (addr_size == NRF_802154_FRAME_PARSER_INVALID_OFFSET)
265     {
266         return false;
267     }
268 
269     p_parser_data->helper.dst_addr_size             = addr_size;
270     offset                                         += addr_size;
271     p_parser_data->helper.dst_addressing_end_offset = offset;
272 
273     if (src_panid_is_present(p_parser_data))
274     {
275         p_parser_data->mhr.src.panid_offset = offset;
276         offset                             += PAN_ID_SIZE;
277     }
278 
279     if (src_addr_is_present(p_parser_data))
280     {
281         p_parser_data->mhr.src.addr_offset = offset;
282     }
283 
284     addr_size = src_addr_size_get(p_parser_data);
285 
286     if (addr_size == NRF_802154_FRAME_PARSER_INVALID_OFFSET)
287     {
288         return false;
289     }
290 
291     p_parser_data->helper.src_addr_size = addr_size;
292     offset                             += addr_size;
293 
294     p_parser_data->helper.addressing_end_offset = offset;
295 
296     return true;
297 }
298 
sec_ctrl_parse(nrf_802154_frame_parser_data_t * p_parser_data)299 static bool sec_ctrl_parse(nrf_802154_frame_parser_data_t * p_parser_data)
300 {
301     uint8_t offset = p_parser_data->helper.addressing_end_offset;
302     uint8_t key_id_mode;
303     uint8_t key_src_size;
304 
305     if (nrf_802154_frame_parser_security_enabled_bit_is_set(p_parser_data) == false)
306     {
307         p_parser_data->helper.aux_sec_hdr_end_offset = offset;
308         return true;
309     }
310 
311     if ((offset + SECURITY_CONTROL_SIZE) > p_parser_data->valid_data_len)
312     {
313         return false;
314     }
315 
316     p_parser_data->mhr.aux_sec_hdr.sec_ctrl_offset = offset;
317     offset += SECURITY_CONTROL_SIZE;
318 
319     if (nrf_802154_frame_parser_sec_ctrl_fc_suppress_bit_is_set(p_parser_data) == false)
320     {
321         p_parser_data->mhr.aux_sec_hdr.frame_counter_offset = offset;
322         offset += FRAME_COUNTER_SIZE;
323     }
324 
325     key_id_mode  = nrf_802154_frame_parser_sec_ctrl_key_id_mode_get(p_parser_data);
326     key_src_size = key_source_size_get(key_id_mode);
327 
328     if (key_id_mode != KEY_ID_MODE_0)
329     {
330         p_parser_data->mhr.aux_sec_hdr.key_id_offset = offset;
331 
332         if (key_src_size > 0)
333         {
334             p_parser_data->mhr.aux_sec_hdr.key_src_offset = offset;
335             offset += key_src_size;
336         }
337 
338         p_parser_data->helper.key_src_size            = key_src_size;
339         p_parser_data->mhr.aux_sec_hdr.key_idx_offset = offset;
340         offset += KEY_IDX_SIZE;
341     }
342 
343     p_parser_data->helper.mic_size               = mic_size_get(p_parser_data);
344     p_parser_data->helper.aux_sec_hdr_end_offset = offset;
345 
346     return true;
347 }
348 
full_parse(nrf_802154_frame_parser_data_t * p_parser_data)349 static bool full_parse(nrf_802154_frame_parser_data_t * p_parser_data)
350 {
351     uint8_t         offset      = p_parser_data->helper.aux_sec_hdr_end_offset;
352     uint8_t         psdu_length = nrf_802154_frame_parser_frame_length_get(p_parser_data);
353     const uint8_t * p_ie_header;
354     const uint8_t * p_end_addr;
355     const uint8_t * p_iterator;
356 
357     if (((psdu_length + PHR_SIZE) != p_parser_data->valid_data_len) ||
358         (psdu_length > MAX_PACKET_SIZE))
359     {
360         return false;
361     }
362 
363     if (nrf_802154_frame_parser_ie_present_bit_is_set(p_parser_data))
364     {
365         p_parser_data->mhr.header_ie_offset = offset;
366 
367         p_ie_header = &p_parser_data->p_frame[offset];
368         p_end_addr  = nrf_802154_frame_parser_mfr_get(p_parser_data) - mic_size_get(p_parser_data);
369         p_iterator  = nrf_802154_frame_parser_header_ie_iterator_begin(p_ie_header);
370 
371         while (!nrf_802154_frame_parser_ie_iterator_end(p_iterator, p_end_addr))
372         {
373             p_iterator = nrf_802154_frame_parser_ie_iterator_next(p_iterator);
374 
375             if (p_iterator > p_end_addr)
376             {
377                 // Boundary check failed
378                 return false;
379             }
380             else if (p_iterator == p_end_addr)
381             {
382                 // End of frame; IE header has no termination.
383                 offset = p_iterator - p_parser_data->p_frame;
384                 break;
385             }
386             else if (nrf_802154_frame_parser_ie_iterator_end(p_iterator, p_end_addr))
387             {
388                 // End of IE header; termination reached.
389                 offset = nrf_802154_frame_parser_ie_content_address_get(p_iterator) -
390                          p_parser_data->p_frame;
391                 break;
392             }
393             else
394             {
395                 // Intentionally empty
396             }
397         }
398     }
399 
400     if (offset != nrf_802154_frame_parser_mfr_offset_get(p_parser_data))
401     {
402         p_parser_data->mac_payload.mac_payload_offset = offset;
403     }
404 
405     return true;
406 }
407 
level_is_elevated(nrf_802154_frame_parser_data_t * p_parser_data,nrf_802154_frame_parser_level_t requested_parse_level)408 static bool level_is_elevated(nrf_802154_frame_parser_data_t * p_parser_data,
409                               nrf_802154_frame_parser_level_t  requested_parse_level)
410 {
411     return requested_parse_level > p_parser_data->parse_level;
412 }
413 
parse_state_advance(nrf_802154_frame_parser_data_t * p_parser_data,nrf_802154_frame_parser_level_t requested_parse_level)414 static bool parse_state_advance(nrf_802154_frame_parser_data_t * p_parser_data,
415                                 nrf_802154_frame_parser_level_t  requested_parse_level)
416 {
417     bool                            result;
418     nrf_802154_frame_parser_level_t next_level;
419 
420     do
421     {
422         result = false;
423 
424         switch (p_parser_data->parse_level)
425         {
426             case PARSE_LEVEL_NONE:
427                 if (level_is_elevated(p_parser_data, requested_parse_level))
428                 {
429                     result     = fcf_parse(p_parser_data);
430                     next_level = PARSE_LEVEL_FCF_OFFSETS;
431                 }
432                 break;
433 
434             case PARSE_LEVEL_FCF_OFFSETS:
435                 if (p_parser_data->valid_data_len >=
436                     p_parser_data->helper.dst_addressing_end_offset)
437                 {
438                     result     = true;
439                     next_level = PARSE_LEVEL_DST_ADDRESSING_END;
440                 }
441                 break;
442 
443             case PARSE_LEVEL_DST_ADDRESSING_END:
444                 if (p_parser_data->valid_data_len >= p_parser_data->helper.addressing_end_offset)
445                 {
446                     result     = true;
447                     next_level = PARSE_LEVEL_ADDRESSING_END;
448                 }
449                 break;
450 
451             case PARSE_LEVEL_ADDRESSING_END:
452                 if (level_is_elevated(p_parser_data, requested_parse_level))
453                 {
454                     result     = sec_ctrl_parse(p_parser_data);
455                     next_level = PARSE_LEVEL_SEC_CTRL_OFFSETS;
456                 }
457                 break;
458 
459             case PARSE_LEVEL_SEC_CTRL_OFFSETS:
460                 if (p_parser_data->valid_data_len >= p_parser_data->helper.aux_sec_hdr_end_offset)
461                 {
462                     result     = true;
463                     next_level = PARSE_LEVEL_AUX_SEC_HDR_END;
464                 }
465                 break;
466 
467             case PARSE_LEVEL_AUX_SEC_HDR_END:
468                 if (level_is_elevated(p_parser_data, requested_parse_level))
469                 {
470                     result     = full_parse(p_parser_data);
471                     next_level = PARSE_LEVEL_FULL;
472                 }
473                 break;
474 
475             case PARSE_LEVEL_FULL:
476                 return true;
477 
478             default:
479                 assert(false);
480                 return false;
481         }
482 
483         if (result)
484         {
485             p_parser_data->parse_level = next_level;
486         }
487     }
488     while (result);
489 
490     return p_parser_data->parse_level >= requested_parse_level;
491 }
492 
nrf_802154_frame_parser_data_init(const uint8_t * p_frame,uint8_t valid_data_len,nrf_802154_frame_parser_level_t requested_parse_level,nrf_802154_frame_parser_data_t * p_parser_data)493 bool nrf_802154_frame_parser_data_init(const uint8_t                  * p_frame,
494                                        uint8_t                          valid_data_len,
495                                        nrf_802154_frame_parser_level_t  requested_parse_level,
496                                        nrf_802154_frame_parser_data_t * p_parser_data)
497 {
498     if (p_frame == NULL)
499     {
500         return false;
501     }
502 
503     p_parser_data->p_frame        = p_frame;
504     p_parser_data->valid_data_len = valid_data_len;
505     p_parser_data->parse_level    = PARSE_LEVEL_NONE;
506 
507     memset(&p_parser_data->mhr, NRF_802154_FRAME_PARSER_INVALID_OFFSET, sizeof(p_parser_data->mhr));
508     memset(&p_parser_data->mac_payload,
509            NRF_802154_FRAME_PARSER_INVALID_OFFSET,
510            sizeof(p_parser_data->mac_payload));
511     memset(&p_parser_data->helper,
512            NRF_802154_FRAME_PARSER_INVALID_OFFSET,
513            sizeof(p_parser_data->helper));
514 
515     return parse_state_advance(p_parser_data, requested_parse_level);
516 }
517 
nrf_802154_frame_parser_valid_data_extend(nrf_802154_frame_parser_data_t * p_parser_data,uint8_t valid_data_len,nrf_802154_frame_parser_level_t requested_parse_level)518 bool nrf_802154_frame_parser_valid_data_extend(nrf_802154_frame_parser_data_t * p_parser_data,
519                                                uint8_t                          valid_data_len,
520                                                nrf_802154_frame_parser_level_t  requested_parse_level)
521 {
522     if (valid_data_len > p_parser_data->valid_data_len)
523     {
524         p_parser_data->valid_data_len = valid_data_len;
525     }
526 
527     return parse_state_advance(p_parser_data, requested_parse_level);
528 }
529