1 /*
2  * Copyright (c) 2018, 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 procedures to set pending bit and 802.15.4-2015 information
38  *   elements in nRF 802.15.4 radio driver.
39  *
40  */
41 
42 #include "nrf_802154_ack_data.h"
43 
44 #include "nrf_802154_assert.h"
45 #include <string.h>
46 
47 #include "mac_features/nrf_802154_frame_parser.h"
48 #include "nrf_802154_config.h"
49 #include "nrf_802154_const.h"
50 
51 /// Maximum number of Short Addresses of nodes for which there is ACK data to set.
52 #define NUM_SHORT_ADDRESSES    NRF_802154_PENDING_SHORT_ADDRESSES
53 /// Maximum number of Extended Addresses of nodes for which there is ACK data to set.
54 #define NUM_EXTENDED_ADDRESSES NRF_802154_PENDING_EXTENDED_ADDRESSES
55 
56 /// Structure representing pending bit setting variables.
57 typedef struct
58 {
59     bool     enabled;                                                      /// If setting pending bit is enabled.
60     uint8_t  short_addr[NUM_SHORT_ADDRESSES][SHORT_ADDRESS_SIZE];          /// Array of short addresses of nodes for which there is pending data in the buffer.
61     uint8_t  extended_addr[NUM_EXTENDED_ADDRESSES][EXTENDED_ADDRESS_SIZE]; /// Array of extended addresses of nodes for which there is pending data in the buffer.
62     uint32_t num_of_short_addr;                                            /// Current number of short addresses of nodes for which there is pending data in the buffer.
63     uint32_t num_of_ext_addr;                                              /// Current number of extended addresses of nodes for which there is pending data in the buffer.
64 } pending_bit_arrays_t;
65 
66 // Structure representing a single IE record.
67 typedef struct
68 {
69     uint8_t p_data[NRF_802154_MAX_ACK_IE_SIZE]; /// Pointer to IE data buffer.
70     uint8_t len;                                /// Length of the buffer.
71 } ie_data_t;
72 
73 // Structure representing IE records sent in an ACK message to a given short address.
74 typedef struct
75 {
76     uint8_t   addr[SHORT_ADDRESS_SIZE]; /// Short address of peer node.
77     ie_data_t ie_data;                  /// Pointer to IE records.
78 } ack_short_ie_data_t;
79 
80 // Structure representing IE records sent in an ACK message to a given extended address.
81 typedef struct
82 {
83     uint8_t   addr[EXTENDED_ADDRESS_SIZE]; /// Extended address of peer node.
84     ie_data_t ie_data;                     /// Pointer to IE records.
85 } ack_ext_ie_data_t;
86 
87 // Structure representing IE data setting variables.
88 typedef struct
89 {
90     ack_short_ie_data_t short_data[NUM_SHORT_ADDRESSES];  /// Array of short addresses and IE records sent to these addresses.
91     ack_ext_ie_data_t   ext_data[NUM_EXTENDED_ADDRESSES]; /// Array of extended addresses and IE records sent to these addresses.
92     uint32_t            num_of_short_data;                /// Current number of short addresses stored in @p short_data.
93     uint32_t            num_of_ext_data;                  /// Current number of extended addresses stored in @p ext_data.
94 } ie_arrays_t;
95 
96 // TODO: Combine below arrays to perform binary search only once per Ack generation.
97 static pending_bit_arrays_t        m_pending_bit;
98 static ie_arrays_t                 m_ie;
99 static nrf_802154_src_addr_match_t m_src_matching_method;
100 
101 /***************************************************************************************************
102  * @section Array handling helper functions
103  **************************************************************************************************/
104 
105 /**
106  * @brief Compare two extended addresses.
107  *
108  * @param[in]  p_first_addr     Pointer to a first address that should be compared.
109  * @param[in]  p_second_addr    Pointer to a second address that should be compared.
110  *
111  * @retval -1  First address is less than the second address.
112  * @retval  0  First address is equal to the second address.
113  * @retval  1  First address is greater than the second address.
114  */
extended_addr_compare(const uint8_t * p_first_addr,const uint8_t * p_second_addr)115 static int8_t extended_addr_compare(const uint8_t * p_first_addr, const uint8_t * p_second_addr)
116 {
117     uint32_t first_addr;
118     uint32_t second_addr;
119 
120     // Compare extended address in two steps to prevent unaligned access error.
121     for (uint32_t i = 0; i < EXTENDED_ADDRESS_SIZE / sizeof(uint32_t); i++)
122     {
123         first_addr  = *(uint32_t *)(p_first_addr + (i * sizeof(uint32_t)));
124         second_addr = *(uint32_t *)(p_second_addr + (i * sizeof(uint32_t)));
125 
126         if (first_addr < second_addr)
127         {
128             return -1;
129         }
130         else if (first_addr > second_addr)
131         {
132             return 1;
133         }
134     }
135 
136     return 0;
137 }
138 
139 /**
140  * @brief Compare two short addresses.
141  *
142  * @param[in]  p_first_addr     Pointer to a first address that should be compared.
143  * @param[in]  p_second_addr    Pointer to a second address that should be compared.
144  *
145  * @retval -1  First address is less than the second address.
146  * @retval  0  First address is equal to the second address.
147  * @retval  1  First address is greater than the second address.
148  */
short_addr_compare(const uint8_t * p_first_addr,const uint8_t * p_second_addr)149 static int8_t short_addr_compare(const uint8_t * p_first_addr, const uint8_t * p_second_addr)
150 {
151     uint16_t first_addr  = *(uint16_t *)(p_first_addr);
152     uint16_t second_addr = *(uint16_t *)(p_second_addr);
153 
154     if (first_addr < second_addr)
155     {
156         return -1;
157     }
158     else if (first_addr > second_addr)
159     {
160         return 1;
161     }
162     else
163     {
164         return 0;
165     }
166 }
167 
168 /**
169  * @brief Compare two addresses.
170  *
171  * @param[in]  p_first_addr     Pointer to a first address that should be compared.
172  * @param[in]  p_second_addr    Pointer to a second address that should be compared.
173  * @param[in]  extended         Indication if @p p_first_addr and @p p_second_addr are extended or short addresses.
174  *
175  * @retval -1  First address is less than the second address.
176  * @retval  0  First address is equal to the second address.
177  * @retval  1  First address is greater than the second address.
178  */
addr_compare(const uint8_t * p_first_addr,const uint8_t * p_second_addr,bool extended)179 static int8_t addr_compare(const uint8_t * p_first_addr,
180                            const uint8_t * p_second_addr,
181                            bool            extended)
182 {
183     if (extended)
184     {
185         return extended_addr_compare(p_first_addr, p_second_addr);
186     }
187     else
188     {
189         return short_addr_compare(p_first_addr, p_second_addr);
190     }
191 }
192 
193 /**
194  * @brief Perform a binary search for an address in a list of addresses.
195  *
196  * @param[in]  p_addr           Pointer to an address that is searched for.
197  * @param[in]  p_addr_array     Pointer to a list of addresses to be searched.
198  * @param[out] p_location       If the address @p p_addr appears in the list, this is its index in the address list.
199  *                              Otherwise, it is the index which @p p_addr would have if it was placed in the list
200  *                              (ascending order assumed).
201  * @param[in]  extended         Indication if @p p_addr is an extended or a short addresses.
202  *
203  * @retval true   Address @p p_addr is in the list.
204  * @retval false  Address @p p_addr is not in the list.
205  */
addr_binary_search(const uint8_t * p_addr,const uint8_t * p_addr_array,uint32_t * p_location,nrf_802154_ack_data_t data_type,bool extended)206 static bool addr_binary_search(const uint8_t       * p_addr,
207                                const uint8_t       * p_addr_array,
208                                uint32_t            * p_location,
209                                nrf_802154_ack_data_t data_type,
210                                bool                  extended)
211 {
212     uint32_t addr_array_len = 0;
213     uint8_t  entry_size     = 0;
214 
215     switch (data_type)
216     {
217         case NRF_802154_ACK_DATA_PENDING_BIT:
218             entry_size     = extended ? EXTENDED_ADDRESS_SIZE : SHORT_ADDRESS_SIZE;
219             addr_array_len = extended ?
220                              m_pending_bit.num_of_ext_addr : m_pending_bit.num_of_short_addr;
221             break;
222 
223         case NRF_802154_ACK_DATA_IE:
224             entry_size     = extended ? sizeof(ack_ext_ie_data_t) : sizeof(ack_short_ie_data_t);
225             addr_array_len = extended ? m_ie.num_of_ext_data : m_ie.num_of_short_data;
226             break;
227 
228         default:
229             NRF_802154_ASSERT(false);
230             break;
231     }
232 
233     // The actual algorithm
234     int32_t  low      = 0;
235     uint32_t midpoint = 0;
236     int32_t  high     = addr_array_len;
237 
238     while (high >= low)
239     {
240         midpoint = (uint32_t)(low + (high - low) / 2);
241 
242         if (midpoint >= addr_array_len)
243         {
244             break;
245         }
246 
247         switch (addr_compare(p_addr, p_addr_array + entry_size * midpoint, extended))
248         {
249             case -1:
250                 high = (int32_t)(midpoint - 1);
251                 break;
252 
253             case 0:
254                 *p_location = midpoint;
255                 return true;
256 
257             case 1:
258                 low = (int32_t)(midpoint + 1);
259                 break;
260 
261             default:
262                 break;
263         }
264     }
265 
266     /* If in the last iteration of the loop the last case was utilized, it means that the midpoint
267      * found by the algorithm is less than the address to be added. The midpoint should be therefore
268      * shifted to the next position. As a simplified example, a { 1, 3, 4 } array can be considered.
269      * Suppose that a number equal to 2 is about to be added to the array. At the beginning of the
270      * last iteration, midpoint is equal to 1 and low and high are equal to 0. Midpoint is then set
271      * to 0 and with last case being utilized, low is set to 1. However, midpoint equal to 0 is
272      * incorrect, as in the last iteration first element of the array proves to be less than the
273      * element to be added to the array. With the below code, midpoint is then shifted to 1. */
274     if ((uint32_t)low == midpoint + 1)
275     {
276         midpoint++;
277     }
278 
279     *p_location = midpoint;
280     return false;
281 }
282 
283 /**
284  * @brief Find an address in a list of addresses.
285  *
286  * @param[in]  p_addr           Pointer to an address that is searched for.
287  * @param[out] p_location       If the address @p p_addr appears in the list, this is its index in the address list.
288  *                              Otherwise, it is the index which @p p_addr would have if it was placed in the list
289  *                              (ascending order assumed).
290  * @param[in]  extended         Indication if @p p_addr is an extended or a short addresses.
291  *
292  * @retval true   Address @p p_addr is in the list.
293  * @retval false  Address @p p_addr is not in the list.
294  */
addr_index_find(const uint8_t * p_addr,uint32_t * p_location,nrf_802154_ack_data_t data_type,bool extended)295 static bool addr_index_find(const uint8_t       * p_addr,
296                             uint32_t            * p_location,
297                             nrf_802154_ack_data_t data_type,
298                             bool                  extended)
299 {
300     uint8_t * p_addr_array;
301     bool      valid_data_type = true;
302 
303     switch (data_type)
304     {
305         case NRF_802154_ACK_DATA_PENDING_BIT:
306             p_addr_array = extended ? (uint8_t *)m_pending_bit.extended_addr :
307                            (uint8_t *)m_pending_bit.short_addr;
308             break;
309 
310         case NRF_802154_ACK_DATA_IE:
311             p_addr_array = extended ? (uint8_t *)m_ie.ext_data : (uint8_t *)m_ie.short_data;
312             break;
313 
314         default:
315             valid_data_type = false;
316             NRF_802154_ASSERT(false);
317             break;
318     }
319 
320     if (!valid_data_type)
321     {
322         return false;
323     }
324 
325     return addr_binary_search(p_addr, p_addr_array, p_location, data_type, extended);
326 }
327 
328 /**
329  * @brief Thread implementation of the address matching algorithm.
330  *
331  * @param[in]  p_frame_data  Pointer to the frame parser data for which the ACK frame is being prepared.
332  *
333  * @retval true   Pending bit is to be set.
334  * @retval false  Pending bit is to be cleared.
335  */
addr_match_thread(const nrf_802154_frame_parser_data_t * p_frame_data)336 static bool addr_match_thread(const nrf_802154_frame_parser_data_t * p_frame_data)
337 {
338     uint32_t        location;
339     bool            extended   = nrf_802154_frame_parser_src_addr_is_extended(p_frame_data);
340     const uint8_t * p_src_addr = nrf_802154_frame_parser_src_addr_get(p_frame_data);
341 
342     // The pending bit is set by default.
343     if (!m_pending_bit.enabled || (NULL == p_src_addr))
344     {
345         return true;
346     }
347 
348     return addr_index_find(p_src_addr, &location, NRF_802154_ACK_DATA_PENDING_BIT, extended);
349 }
350 
351 /**
352  * @brief Zigbee implementation of the address matching algorithm.
353  *
354  * @param[in]  p_frame_data  Pointer to the frame parser data for which the ACK frame is being prepared.
355  *
356  * @retval true   Pending bit is to be set.
357  * @retval false  Pending bit is to be cleared.
358  */
addr_match_zigbee(const nrf_802154_frame_parser_data_t * p_frame_data)359 static bool addr_match_zigbee(const nrf_802154_frame_parser_data_t * p_frame_data)
360 {
361     uint8_t         src_addr_type;
362     uint32_t        location;
363     const uint8_t * p_cmd;
364     const uint8_t * p_src_addr;
365     bool            ret = false;
366 
367     // If ack data generator module is disabled do not perform check, return true by default.
368     if (!m_pending_bit.enabled)
369     {
370         return true;
371     }
372 
373     // Check the frame type.
374     p_src_addr    = nrf_802154_frame_parser_src_addr_get(p_frame_data);
375     src_addr_type = nrf_802154_frame_parser_src_addr_type_get(p_frame_data);
376 
377     p_cmd = nrf_802154_frame_parser_mac_command_id_get(p_frame_data);
378 
379     // Check frame type and command type.
380     if ((p_cmd != NULL) && (*p_cmd == MAC_CMD_DATA_REQ))
381     {
382         // Check addressing type - in long case address, pb should always be 1.
383         if (src_addr_type == SRC_ADDR_TYPE_SHORT)
384         {
385             // Return true if address is not found on the m_pending_bits list.
386             ret = !addr_index_find(p_src_addr,
387                                    &location,
388                                    NRF_802154_ACK_DATA_PENDING_BIT,
389                                    false);
390         }
391         else
392         {
393             ret = true;
394         }
395     }
396 
397     return ret;
398 }
399 
400 /**
401  * @brief Standard-compliant implementation of the address matching algorithm.
402  *
403  * Function always returns true. It is IEEE 802.15.4 compliant, as per 6.7.3.
404  * Higher layer should ensure empty data frame with no AR is sent afterwards.
405  *
406  * @param[in]  p_frame_data  Pointer to the frame parser data for which the ACK frame is being prepared.
407  *
408  * @retval true   Pending bit is to be set.
409  */
addr_match_standard_compliant(const nrf_802154_frame_parser_data_t * p_frame_data)410 static bool addr_match_standard_compliant(const nrf_802154_frame_parser_data_t * p_frame_data)
411 {
412     (void)p_frame_data;
413     return true;
414 }
415 
416 /**
417  * @brief Add an address to the address list in ascending order.
418  *
419  * @param[in]  p_addr           Pointer to the address to be added.
420  * @param[in]  location         Index of the location where @p p_addr should be added.
421  * @param[in]  extended         Indication if @p p_addr is an extended or a short addresses.
422  *
423  * @retval true   Address @p p_addr has been added to the list successfully.
424  * @retval false  Address @p p_addr could not be added to the list.
425  */
addr_add(const uint8_t * p_addr,uint32_t location,nrf_802154_ack_data_t data_type,bool extended)426 static bool addr_add(const uint8_t       * p_addr,
427                      uint32_t              location,
428                      nrf_802154_ack_data_t data_type,
429                      bool                  extended)
430 {
431     uint32_t * p_addr_array_len;
432     uint32_t   max_addr_array_len;
433     uint8_t  * p_addr_array;
434     uint8_t    entry_size;
435     bool       valid_data_type = true;
436 
437     switch (data_type)
438     {
439         case NRF_802154_ACK_DATA_PENDING_BIT:
440             if (extended)
441             {
442                 p_addr_array       = (uint8_t *)m_pending_bit.extended_addr;
443                 max_addr_array_len = NUM_EXTENDED_ADDRESSES;
444                 p_addr_array_len   = &m_pending_bit.num_of_ext_addr;
445                 entry_size         = EXTENDED_ADDRESS_SIZE;
446             }
447             else
448             {
449                 p_addr_array       = (uint8_t *)m_pending_bit.short_addr;
450                 max_addr_array_len = NUM_SHORT_ADDRESSES;
451                 p_addr_array_len   = &m_pending_bit.num_of_short_addr;
452                 entry_size         = SHORT_ADDRESS_SIZE;
453             }
454             break;
455 
456         case NRF_802154_ACK_DATA_IE:
457             if (extended)
458             {
459                 p_addr_array       = (uint8_t *)m_ie.ext_data;
460                 max_addr_array_len = NUM_EXTENDED_ADDRESSES;
461                 p_addr_array_len   = &m_ie.num_of_ext_data;
462                 entry_size         = sizeof(ack_ext_ie_data_t);
463             }
464             else
465             {
466                 p_addr_array       = (uint8_t *)m_ie.short_data;
467                 max_addr_array_len = NUM_SHORT_ADDRESSES;
468                 p_addr_array_len   = &m_ie.num_of_short_data;
469                 entry_size         = sizeof(ack_short_ie_data_t);
470             }
471             break;
472 
473         default:
474             valid_data_type = false;
475             NRF_802154_ASSERT(false);
476             break;
477     }
478 
479     if (!valid_data_type || (*p_addr_array_len == max_addr_array_len))
480     {
481         return false;
482     }
483 
484     uint8_t * p_entry_at_location = p_addr_array + entry_size * location;
485 
486     memmove(p_entry_at_location + entry_size,
487             p_entry_at_location,
488             (*p_addr_array_len - location) * entry_size);
489 
490     memcpy(p_entry_at_location,
491            p_addr,
492            extended ? EXTENDED_ADDRESS_SIZE : SHORT_ADDRESS_SIZE);
493 
494     if (data_type == NRF_802154_ACK_DATA_IE)
495     {
496         /* The content of ie_data_t in the structure indexed by location
497          * is uninitialized (can have old content). Let's initialize it. */
498         ie_data_t * p_ie_data = extended ?
499                                 &(((ack_ext_ie_data_t *)p_entry_at_location)->ie_data) :
500                                 &(((ack_short_ie_data_t *)p_entry_at_location)->ie_data);
501 
502         p_ie_data->len = 0U;
503         /* p_ie_data->p_data does not need initialization when len is set to zero. */
504     }
505 
506     (*p_addr_array_len)++;
507 
508     return true;
509 }
510 
511 /**
512  * @brief Remove an address from the address list keeping it in ascending order.
513  *
514  * @param[in]  location     Index of the element to be removed from the list.
515  * @param[in]  extended     Indication if address to remove is an extended or a short address.
516  *
517  * @retval true   Address @p p_addr has been removed from the list successfully.
518  * @retval false  Address @p p_addr could not removed from the list.
519  */
addr_remove(uint32_t location,nrf_802154_ack_data_t data_type,bool extended)520 static bool addr_remove(uint32_t location, nrf_802154_ack_data_t data_type, bool extended)
521 {
522     uint32_t * p_addr_array_len;
523     uint8_t  * p_addr_array;
524     uint8_t    entry_size;
525     bool       valid_data_type = true;
526 
527     switch (data_type)
528     {
529         case NRF_802154_ACK_DATA_PENDING_BIT:
530             if (extended)
531             {
532                 p_addr_array     = (uint8_t *)m_pending_bit.extended_addr;
533                 p_addr_array_len = &m_pending_bit.num_of_ext_addr;
534                 entry_size       = EXTENDED_ADDRESS_SIZE;
535             }
536             else
537             {
538                 p_addr_array     = (uint8_t *)m_pending_bit.short_addr;
539                 p_addr_array_len = &m_pending_bit.num_of_short_addr;
540                 entry_size       = SHORT_ADDRESS_SIZE;
541             }
542             break;
543 
544         case NRF_802154_ACK_DATA_IE:
545             if (extended)
546             {
547                 p_addr_array     = (uint8_t *)m_ie.ext_data;
548                 p_addr_array_len = &m_ie.num_of_ext_data;
549                 entry_size       = sizeof(ack_ext_ie_data_t);
550             }
551             else
552             {
553                 p_addr_array     = (uint8_t *)m_ie.short_data;
554                 p_addr_array_len = &m_ie.num_of_short_data;
555                 entry_size       = sizeof(ack_short_ie_data_t);
556             }
557             break;
558 
559         default:
560             valid_data_type = false;
561             NRF_802154_ASSERT(false);
562             break;
563     }
564 
565     if (!valid_data_type || (*p_addr_array_len == 0))
566     {
567         return false;
568     }
569 
570     memmove(p_addr_array + entry_size * location,
571             p_addr_array + entry_size * (location + 1),
572             (*p_addr_array_len - location - 1) * entry_size);
573 
574     (*p_addr_array_len)--;
575 
576     return true;
577 }
578 
579 /**
580  * @brief Replace or append an Information Element to the ACK data.
581  *
582  * If the target ACK data already contains an Information Element with the same
583  * ID as the new Information Element, the existing IE is replaced with the new
584  * one. Otherwise, the new IE is appended to the target ACK data.
585  *
586  * @param[in]  location     Index of the ACK data buffer to be modified.
587  * @param[in]  extended     Indication whether the ACK data buffer for
588  *                          an extended or a short address is to be modified.
589  * @param[in]  p_data       New Information Element data.
590  * @param[in]  data_len     New Information Element data length.
591  *
592  * @retval true     The new Information Element has been added successfully.
593  * @retval false    The new Information Element has not fitted in the buffer.
594  */
ie_data_set(uint32_t location,bool extended,const uint8_t * p_data,uint8_t data_len)595 static bool ie_data_set(uint32_t location, bool extended, const uint8_t * p_data, uint8_t data_len)
596 {
597     ie_data_t * ie_data =
598         extended ? &m_ie.ext_data[location].ie_data : &m_ie.short_data[location].ie_data;
599 
600     const uint8_t new_ie_id = nrf_802154_frame_parser_ie_id_get(p_data);
601 
602     for (const uint8_t * ie = nrf_802154_frame_parser_header_ie_iterator_begin(ie_data->p_data);
603          nrf_802154_frame_parser_ie_iterator_end(ie, ie_data->p_data + ie_data->len) == false;
604          ie = nrf_802154_frame_parser_ie_iterator_next(ie))
605     {
606         if (nrf_802154_frame_parser_ie_id_get(ie) != new_ie_id)
607         {
608             continue;
609         }
610 
611         if (IE_DATA_OFFSET + nrf_802154_frame_parser_ie_length_get(ie) != data_len)
612         {
613             /* Overwriting an existing IE with a different size is not supported. */
614             return false;
615         }
616 
617         memcpy((uint8_t *)ie, p_data, data_len);
618         return true;
619     }
620 
621     /* Append IE data with the new IE. */
622 
623     if (ie_data->len + data_len > NRF_802154_MAX_ACK_IE_SIZE)
624     {
625         /* No space to fit it the new IE. */
626         return false;
627     }
628 
629     memcpy(ie_data->p_data + ie_data->len, p_data, data_len);
630     ie_data->len += data_len;
631 
632     return true;
633 }
634 
635 /***************************************************************************************************
636  * @section Public API
637  **************************************************************************************************/
638 
nrf_802154_ack_data_init(void)639 void nrf_802154_ack_data_init(void)
640 {
641     memset(&m_pending_bit, 0, sizeof(m_pending_bit));
642     memset(&m_ie, 0, sizeof(m_ie));
643 
644     m_pending_bit.enabled = true;
645     m_src_matching_method = NRF_802154_SRC_ADDR_MATCH_THREAD;
646 }
647 
nrf_802154_ack_data_enable(bool enabled)648 void nrf_802154_ack_data_enable(bool enabled)
649 {
650     m_pending_bit.enabled = enabled;
651 }
652 
nrf_802154_ack_data_for_addr_set(const uint8_t * p_addr,bool extended,nrf_802154_ack_data_t data_type,const void * p_data,uint8_t data_len)653 bool nrf_802154_ack_data_for_addr_set(const uint8_t       * p_addr,
654                                       bool                  extended,
655                                       nrf_802154_ack_data_t data_type,
656                                       const void          * p_data,
657                                       uint8_t               data_len)
658 {
659     uint32_t location = 0;
660 
661     if (addr_index_find(p_addr, &location, data_type, extended) ||
662         addr_add(p_addr, location, data_type, extended))
663     {
664         if (data_type == NRF_802154_ACK_DATA_IE)
665         {
666             return ie_data_set(location, extended, p_data, data_len);
667         }
668 
669         return true;
670     }
671     else
672     {
673         return false;
674     }
675 }
676 
nrf_802154_ack_data_for_addr_clear(const uint8_t * p_addr,bool extended,nrf_802154_ack_data_t data_type)677 bool nrf_802154_ack_data_for_addr_clear(const uint8_t       * p_addr,
678                                         bool                  extended,
679                                         nrf_802154_ack_data_t data_type)
680 {
681     uint32_t location = 0;
682 
683     if (addr_index_find(p_addr, &location, data_type, extended))
684     {
685         return addr_remove(location, data_type, extended);
686     }
687     else
688     {
689         return false;
690     }
691 }
692 
nrf_802154_ack_data_reset(bool extended,nrf_802154_ack_data_t data_type)693 void nrf_802154_ack_data_reset(bool extended, nrf_802154_ack_data_t data_type)
694 {
695     switch (data_type)
696     {
697         case NRF_802154_ACK_DATA_PENDING_BIT:
698             if (extended)
699             {
700                 m_pending_bit.num_of_ext_addr = 0;
701             }
702             else
703             {
704                 m_pending_bit.num_of_short_addr = 0;
705             }
706             break;
707 
708         case NRF_802154_ACK_DATA_IE:
709             if (extended)
710             {
711                 m_ie.num_of_ext_data = 0;
712             }
713             else
714             {
715                 m_ie.num_of_short_data = 0;
716             }
717             break;
718 
719         default:
720             break;
721     }
722 }
723 
nrf_802154_ack_data_src_addr_matching_method_set(nrf_802154_src_addr_match_t match_method)724 void nrf_802154_ack_data_src_addr_matching_method_set(nrf_802154_src_addr_match_t match_method)
725 {
726     switch (match_method)
727     {
728         case NRF_802154_SRC_ADDR_MATCH_THREAD:
729         case NRF_802154_SRC_ADDR_MATCH_ZIGBEE:
730         case NRF_802154_SRC_ADDR_MATCH_ALWAYS_1:
731             m_src_matching_method = match_method;
732             break;
733 
734         default:
735             NRF_802154_ASSERT(false);
736     }
737 
738 }
739 
nrf_802154_ack_data_pending_bit_should_be_set(const nrf_802154_frame_parser_data_t * p_frame_data)740 bool nrf_802154_ack_data_pending_bit_should_be_set(
741     const nrf_802154_frame_parser_data_t * p_frame_data)
742 {
743     bool ret;
744 
745     switch (m_src_matching_method)
746     {
747         case NRF_802154_SRC_ADDR_MATCH_THREAD:
748             ret = addr_match_thread(p_frame_data);
749             break;
750 
751         case NRF_802154_SRC_ADDR_MATCH_ZIGBEE:
752             ret = addr_match_zigbee(p_frame_data);
753             break;
754 
755         case NRF_802154_SRC_ADDR_MATCH_ALWAYS_1:
756             ret = addr_match_standard_compliant(p_frame_data);
757             break;
758 
759         default:
760             ret = false;
761             NRF_802154_ASSERT(false);
762     }
763 
764     return ret;
765 }
766 
nrf_802154_ack_data_ie_get(const uint8_t * p_src_addr,bool src_addr_extended,uint8_t * p_ie_length)767 const uint8_t * nrf_802154_ack_data_ie_get(const uint8_t * p_src_addr,
768                                            bool            src_addr_extended,
769                                            uint8_t       * p_ie_length)
770 {
771     uint32_t location;
772 
773     if (NULL == p_src_addr)
774     {
775         return NULL;
776     }
777 
778     if (addr_index_find(p_src_addr, &location, NRF_802154_ACK_DATA_IE, src_addr_extended))
779     {
780         if (src_addr_extended)
781         {
782             *p_ie_length = m_ie.ext_data[location].ie_data.len;
783             return m_ie.ext_data[location].ie_data.p_data;
784         }
785         else
786         {
787             *p_ie_length = m_ie.short_data[location].ie_data.len;
788             return m_ie.short_data[location].ie_data.p_data;
789         }
790     }
791     else
792     {
793         *p_ie_length = 0;
794         return NULL;
795     }
796 }
797