|  | /* | 
|  | * Copyright (c) 2023 Florian Grandel, Zephyr Project. | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | /** | 
|  | * @file | 
|  | * @brief IEEE 802.15.4 MAC information element (IE) related types and helpers | 
|  | * | 
|  | * This is not to be included by the application. This file contains only those | 
|  | * parts of the types required for IE support that need to be visible to IEEE | 
|  | * 802.15.4 drivers and L2 at the same time, i.e. everything related to header | 
|  | * IE representation, parsing and generation. | 
|  | * | 
|  | * All specification references in this file refer to IEEE 802.15.4-2020. | 
|  | * | 
|  | * @note All structs and attributes in this file that directly represent parts | 
|  | * of IEEE 802.15.4 frames are in LITTLE ENDIAN, see section 4, especially | 
|  | * section 4.3. | 
|  | */ | 
|  |  | 
|  | #ifndef ZEPHYR_INCLUDE_NET_IEEE802154_IE_H_ | 
|  | #define ZEPHYR_INCLUDE_NET_IEEE802154_IE_H_ | 
|  |  | 
|  | #include <zephyr/net_buf.h> | 
|  | #include <zephyr/sys/byteorder.h> | 
|  |  | 
|  | /** | 
|  | * @addtogroup ieee802154_driver | 
|  | * @{ | 
|  | * | 
|  | * @name IEEE 802.15.4, section 7.4.2: MAC header information elements | 
|  | * @{ | 
|  | */ | 
|  |  | 
|  | /** | 
|  | * @brief Information Element Types. | 
|  | * | 
|  | * @details See sections 7.4.2.1 and 7.4.3.1. | 
|  | */ | 
|  | enum ieee802154_ie_type { | 
|  | IEEE802154_IE_TYPE_HEADER = 0x0, /**< Header type */ | 
|  | IEEE802154_IE_TYPE_PAYLOAD,      /**< Payload type */ | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * @brief Header Information Element IDs. | 
|  | * | 
|  | * @details See section 7.4.2.1, table 7-7, partial list, only IEs actually used | 
|  | * are implemented. | 
|  | */ | 
|  | enum ieee802154_header_ie_element_id { | 
|  | IEEE802154_HEADER_IE_ELEMENT_ID_VENDOR_SPECIFIC_IE = 0x00,   /**< Vendor specific IE */ | 
|  | IEEE802154_HEADER_IE_ELEMENT_ID_CSL_IE = 0x1a,	             /**< CSL IE */ | 
|  | IEEE802154_HEADER_IE_ELEMENT_ID_RIT_IE = 0x1b,               /**< RIT IE */ | 
|  | IEEE802154_HEADER_IE_ELEMENT_ID_RENDEZVOUS_TIME_IE = 0x1d,   /**< Rendezvous time IE */ | 
|  | IEEE802154_HEADER_IE_ELEMENT_ID_TIME_CORRECTION_IE = 0x1e,   /**< Time correction IE */ | 
|  | IEEE802154_HEADER_IE_ELEMENT_ID_HEADER_TERMINATION_1 = 0x7e, /**< Header termination 1 */ | 
|  | IEEE802154_HEADER_IE_ELEMENT_ID_HEADER_TERMINATION_2 = 0x7f, /**< Header termination 2 */ | 
|  | /* partial list, add additional ids as needed */ | 
|  | }; | 
|  |  | 
|  | /** @cond INTERNAL_HIDDEN */ | 
|  | #define IEEE802154_VENDOR_SPECIFIC_IE_OUI_LEN 3 | 
|  | /** INTERNAL_HIDDEN @endcond */ | 
|  |  | 
|  | /** @brief Vendor Specific Header IE, see section 7.4.2.3. */ | 
|  | struct ieee802154_header_ie_vendor_specific { | 
|  | /** Vendor OUI */ | 
|  | uint8_t vendor_oui[IEEE802154_VENDOR_SPECIFIC_IE_OUI_LEN]; | 
|  | /** Vendor specific information */ | 
|  | uint8_t *vendor_specific_info; | 
|  | } __packed; | 
|  |  | 
|  | /** @brief Full CSL IE, see section 7.4.2.3. */ | 
|  | struct ieee802154_header_ie_csl_full { | 
|  | uint16_t csl_phase;           /**< CSL phase */ | 
|  | uint16_t csl_period;          /**< CSL period */ | 
|  | uint16_t csl_rendezvous_time; /**< Rendezvous time */ | 
|  | } __packed; | 
|  |  | 
|  | /** @brief Reduced CSL IE, see section 7.4.2.3. */ | 
|  | struct ieee802154_header_ie_csl_reduced { | 
|  | uint16_t csl_phase;  /**< CSL phase */ | 
|  | uint16_t csl_period; /**< CSL period */ | 
|  | } __packed; | 
|  |  | 
|  | /** @brief Generic CSL IE, see section 7.4.2.3. */ | 
|  | struct ieee802154_header_ie_csl { | 
|  | union { | 
|  | /** CSL full information */ | 
|  | struct ieee802154_header_ie_csl_full full; | 
|  | /** CSL reduced information */ | 
|  | struct ieee802154_header_ie_csl_reduced reduced; | 
|  | }; | 
|  | } __packed; | 
|  |  | 
|  | /** @brief RIT IE, see section 7.4.2.4. */ | 
|  | struct ieee802154_header_ie_rit { | 
|  | uint8_t time_to_first_listen;    /**< Time to First Listen */ | 
|  | uint8_t number_of_repeat_listen; /**< Number of Repeat Listen */ | 
|  | uint16_t repeat_listen_interval; /**< Repeat listen interval */ | 
|  | } __packed; | 
|  |  | 
|  | /** | 
|  | * @brief Full Rendezvous Time IE, see section 7.4.2.6 | 
|  | * (macCslInterval is nonzero). | 
|  | */ | 
|  | struct ieee802154_header_ie_rendezvous_time_full { | 
|  | uint16_t rendezvous_time; /**< Rendezvous time */ | 
|  | uint16_t wakeup_interval; /**< Wakeup interval */ | 
|  | } __packed; | 
|  |  | 
|  | /** | 
|  | * @brief Reduced Rendezvous Time IE, see section 7.4.2.6 | 
|  | * (macCslInterval is zero). | 
|  | */ | 
|  | struct ieee802154_header_ie_rendezvous_time_reduced { | 
|  | uint16_t rendezvous_time; /**< Rendezvous time */ | 
|  | } __packed; | 
|  |  | 
|  | /** @brief Rendezvous Time IE, see section 7.4.2.6. */ | 
|  | struct ieee802154_header_ie_rendezvous_time { | 
|  | union { | 
|  | /** Rendezvous time full information */ | 
|  | struct ieee802154_header_ie_rendezvous_time_full full; | 
|  | /** Rendezvous time reduced information */ | 
|  | struct ieee802154_header_ie_rendezvous_time_reduced reduced; | 
|  | }; | 
|  | } __packed; | 
|  |  | 
|  | /** @brief Time Correction IE, see section 7.4.2.7. */ | 
|  | struct ieee802154_header_ie_time_correction { | 
|  | uint16_t time_sync_info;  /**< Time synchronization information */ | 
|  | } __packed; | 
|  |  | 
|  | /** @cond INTERNAL_HIDDEN */ | 
|  |  | 
|  | /* @brief Generic Header IE, see section 7.4.2.1. */ | 
|  | struct ieee802154_header_ie { | 
|  | #if CONFIG_LITTLE_ENDIAN | 
|  | uint16_t length : 7; | 
|  | uint16_t element_id_low : 1; /* see enum ieee802154_header_ie_element_id */ | 
|  | uint16_t element_id_high : 7; | 
|  | uint16_t type : 1; /* always 0 */ | 
|  | #else | 
|  | uint16_t element_id_low : 1; /* see enum ieee802154_header_ie_element_id */ | 
|  | uint16_t length : 7; | 
|  | uint16_t type : 1; /* always 0 */ | 
|  | uint16_t element_id_high : 7; | 
|  | #endif | 
|  | union { | 
|  | struct ieee802154_header_ie_vendor_specific vendor_specific; | 
|  | struct ieee802154_header_ie_csl csl; | 
|  | struct ieee802154_header_ie_rit rit; | 
|  | struct ieee802154_header_ie_rendezvous_time rendezvous_time; | 
|  | struct ieee802154_header_ie_time_correction time_correction; | 
|  | /* add additional supported header IEs here */ | 
|  | } content; | 
|  | } __packed; | 
|  |  | 
|  | /** INTERNAL_HIDDEN @endcond */ | 
|  |  | 
|  | /** @brief The header IE's header length (2 bytes). */ | 
|  | #define IEEE802154_HEADER_IE_HEADER_LENGTH sizeof(uint16_t) | 
|  |  | 
|  |  | 
|  | /** @cond INTERNAL_HIDDEN */ | 
|  | #define IEEE802154_DEFINE_HEADER_IE(_element_id, _length, _content, _content_type)                 \ | 
|  | (struct ieee802154_header_ie) {                                                            \ | 
|  | .length = (_length),                                                               \ | 
|  | .element_id_high = (_element_id) >> 1U, .element_id_low = (_element_id) & 0x01,    \ | 
|  | .type = IEEE802154_IE_TYPE_HEADER,                                                 \ | 
|  | .content._content_type = _content,                                                 \ | 
|  | } | 
|  |  | 
|  | #define IEEE802154_DEFINE_HEADER_IE_VENDOR_SPECIFIC_CONTENT_LEN(_vendor_specific_info_len)         \ | 
|  | (IEEE802154_VENDOR_SPECIFIC_IE_OUI_LEN + (_vendor_specific_info_len)) | 
|  |  | 
|  | #define IEEE802154_DEFINE_HEADER_IE_VENDOR_SPECIFIC_CONTENT(_vendor_oui, _vendor_specific_info)    \ | 
|  | (struct ieee802154_header_ie_vendor_specific) {                                            \ | 
|  | .vendor_oui = _vendor_oui, .vendor_specific_info = (_vendor_specific_info),        \ | 
|  | } | 
|  |  | 
|  | #define IEEE802154_DEFINE_HEADER_IE_CSL_REDUCED_CONTENT(_csl_phase, _csl_period)                   \ | 
|  | (struct ieee802154_header_ie_csl_reduced) {                                                \ | 
|  | .csl_phase = sys_cpu_to_le16(_csl_phase),                                          \ | 
|  | .csl_period = sys_cpu_to_le16(_csl_period),                                        \ | 
|  | } | 
|  |  | 
|  | #define IEEE802154_DEFINE_HEADER_IE_CSL_FULL_CONTENT(_csl_phase, _csl_period,                      \ | 
|  | _csl_rendezvous_time)                         \ | 
|  | (struct ieee802154_header_ie_csl_full) {                                                   \ | 
|  | .csl_phase = sys_cpu_to_le16(_csl_phase),                                          \ | 
|  | .csl_period = sys_cpu_to_le16(_csl_period),                                        \ | 
|  | .csl_rendezvous_time = sys_cpu_to_le16(_csl_rendezvous_time),                      \ | 
|  | } | 
|  |  | 
|  | #define IEEE802154_HEADER_IE_TIME_CORRECTION_NACK          0x8000 | 
|  | #define IEEE802154_HEADER_IE_TIME_CORRECTION_MASK          0x0fff | 
|  | #define IEEE802154_HEADER_IE_TIME_CORRECTION_SIGN_BIT_MASK 0x0800 | 
|  |  | 
|  | #define IEEE802154_DEFINE_HEADER_IE_TIME_CORRECTION_CONTENT(_ack, _time_correction_us)             \ | 
|  | (struct ieee802154_header_ie_time_correction) {                                            \ | 
|  | .time_sync_info = sys_cpu_to_le16(                                                 \ | 
|  | (!(_ack) * IEEE802154_HEADER_IE_TIME_CORRECTION_NACK) |                    \ | 
|  | ((_time_correction_us) & IEEE802154_HEADER_IE_TIME_CORRECTION_MASK)),      \ | 
|  | } | 
|  | /** INTERNAL_HIDDEN @endcond */ | 
|  |  | 
|  | /** | 
|  | * @brief Define a vendor specific header IE, see section 7.4.2.3. | 
|  | * | 
|  | * @details Example usage (all parameters in little endian): | 
|  | * | 
|  | * @code{.c} | 
|  | *   uint8_t vendor_specific_info[] = {...some vendor specific IE content...}; | 
|  | *   struct ieee802154_header_ie header_ie = IEEE802154_DEFINE_HEADER_IE_VENDOR_SPECIFIC( | 
|  | *       {0x9b, 0xb8, 0xea}, vendor_specific_info, sizeof(vendor_specific_info)); | 
|  | * @endcode | 
|  | * | 
|  | * @param _vendor_oui an initializer for a 3 byte vendor oui array in little | 
|  | * endian | 
|  | * @param _vendor_specific_info pointer to a variable length uint8_t array with | 
|  | * the vendor specific IE content | 
|  | * @param _vendor_specific_info_len the length of the vendor specific IE content | 
|  | * (in bytes) | 
|  | */ | 
|  | #define IEEE802154_DEFINE_HEADER_IE_VENDOR_SPECIFIC(_vendor_oui, _vendor_specific_info,            \ | 
|  | _vendor_specific_info_len)                     \ | 
|  | IEEE802154_DEFINE_HEADER_IE(IEEE802154_HEADER_IE_ELEMENT_ID_VENDOR_SPECIFIC_IE,            \ | 
|  | IEEE802154_DEFINE_HEADER_IE_VENDOR_SPECIFIC_CONTENT_LEN(       \ | 
|  | _vendor_specific_info_len),                            \ | 
|  | IEEE802154_DEFINE_HEADER_IE_VENDOR_SPECIFIC_CONTENT(           \ | 
|  | _vendor_oui, _vendor_specific_info),                   \ | 
|  | vendor_specific) | 
|  |  | 
|  | /** | 
|  | * @brief Define a reduced CSL IE, see section 7.4.2.3. | 
|  | * | 
|  | * @details Example usage (all parameters in CPU byte order): | 
|  | * | 
|  | * @code{.c} | 
|  | *   uint16_t csl_phase = ...; | 
|  | *   uint16_t csl_period = ...; | 
|  | *   struct ieee802154_header_ie header_ie = | 
|  | *       IEEE802154_DEFINE_HEADER_IE_CSL_REDUCED(csl_phase, csl_period); | 
|  | * @endcode | 
|  | * | 
|  | * @param _csl_phase CSL phase in CPU byte order | 
|  | * @param _csl_period CSL period in CPU byte order | 
|  | */ | 
|  | #define IEEE802154_DEFINE_HEADER_IE_CSL_REDUCED(_csl_phase, _csl_period)                           \ | 
|  | IEEE802154_DEFINE_HEADER_IE(                                                               \ | 
|  | IEEE802154_HEADER_IE_ELEMENT_ID_CSL_IE,                                            \ | 
|  | sizeof(struct ieee802154_header_ie_csl_reduced),                                   \ | 
|  | IEEE802154_DEFINE_HEADER_IE_CSL_REDUCED_CONTENT(_csl_phase, _csl_period),          \ | 
|  | csl.reduced) | 
|  |  | 
|  | /** | 
|  | * @brief Define a full CSL IE, see section 7.4.2.3. | 
|  | * | 
|  | * @details Example usage (all parameters in CPU byte order): | 
|  | * | 
|  | * @code{.c} | 
|  | *   uint16_t csl_phase = ...; | 
|  | *   uint16_t csl_period = ...; | 
|  | *   uint16_t csl_rendezvous_time = ...; | 
|  | *   struct ieee802154_header_ie header_ie = | 
|  | *       IEEE802154_DEFINE_HEADER_IE_CSL_REDUCED(csl_phase, csl_period, csl_rendezvous_time); | 
|  | * @endcode | 
|  | * | 
|  | * @param _csl_phase CSL phase in CPU byte order | 
|  | * @param _csl_period CSL period in CPU byte order | 
|  | * @param _csl_rendezvous_time CSL rendezvous time in CPU byte order | 
|  | */ | 
|  | #define IEEE802154_DEFINE_HEADER_IE_CSL_FULL(_csl_phase, _csl_period, _csl_rendezvous_time)        \ | 
|  | IEEE802154_DEFINE_HEADER_IE(IEEE802154_HEADER_IE_ELEMENT_ID_CSL_IE,                        \ | 
|  | sizeof(struct ieee802154_header_ie_csl_full),                  \ | 
|  | IEEE802154_DEFINE_HEADER_IE_CSL_FULL_CONTENT(                  \ | 
|  | _csl_phase, _csl_period, _csl_rendezvous_time),        \ | 
|  | csl.full) | 
|  |  | 
|  | /** | 
|  | * @brief Define a Time Correction IE, see section 7.4.2.7. | 
|  | * | 
|  | * @details Example usage (parameter in CPU byte order): | 
|  | * | 
|  | * @code{.c} | 
|  | *   uint16_t time_sync_info = ...; | 
|  | *   struct ieee802154_header_ie header_ie = | 
|  | *       IEEE802154_DEFINE_HEADER_IE_TIME_CORRECTION(true, time_sync_info); | 
|  | * @endcode | 
|  | * | 
|  | * @param _ack whether or not the enhanced ACK frame that receives this IE is an | 
|  | * ACK (true) or NACK (false) | 
|  | * @param _time_correction_us the positive or negative deviation from expected | 
|  | * RX time in microseconds | 
|  | */ | 
|  | #define IEEE802154_DEFINE_HEADER_IE_TIME_CORRECTION(_ack, _time_correction_us)                     \ | 
|  | IEEE802154_DEFINE_HEADER_IE(                                                               \ | 
|  | IEEE802154_HEADER_IE_ELEMENT_ID_TIME_CORRECTION_IE,                                \ | 
|  | sizeof(struct ieee802154_header_ie_time_correction),                               \ | 
|  | IEEE802154_DEFINE_HEADER_IE_TIME_CORRECTION_CONTENT(_ack, _time_correction_us),    \ | 
|  | time_correction) | 
|  |  | 
|  | /** | 
|  | * @brief Retrieve the time correction value in microseconds from a Time Correction IE, | 
|  | * see section 7.4.2.7. | 
|  | * | 
|  | * @param[in] ie pointer to the Time Correction IE structure | 
|  | * | 
|  | * @return The time correction value in microseconds. | 
|  | */ | 
|  | static inline int16_t | 
|  | ieee802154_header_ie_get_time_correction_us(struct ieee802154_header_ie_time_correction *ie) | 
|  | { | 
|  | if (ie->time_sync_info & IEEE802154_HEADER_IE_TIME_CORRECTION_SIGN_BIT_MASK) { | 
|  | /* Negative integer */ | 
|  | return (int16_t)ie->time_sync_info | ~IEEE802154_HEADER_IE_TIME_CORRECTION_MASK; | 
|  | } | 
|  |  | 
|  | /* Positive integer */ | 
|  | return (int16_t)ie->time_sync_info & IEEE802154_HEADER_IE_TIME_CORRECTION_MASK; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @brief Set the element ID of a header IE. | 
|  | * | 
|  | * @param[in] ie pointer to a header IE | 
|  | * @param[in] element_id IE element id in CPU byte order | 
|  | */ | 
|  | static inline void ieee802154_header_ie_set_element_id(struct ieee802154_header_ie *ie, | 
|  | uint8_t element_id) | 
|  | { | 
|  | ie->element_id_high = element_id >> 1U; | 
|  | ie->element_id_low = element_id & 0x01; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @brief Get the element ID of a header IE. | 
|  | * | 
|  | * @param[in] ie pointer to a header IE | 
|  | * | 
|  | * @return header IE element id in CPU byte order | 
|  | */ | 
|  | static inline uint8_t ieee802154_header_ie_get_element_id(struct ieee802154_header_ie *ie) | 
|  | { | 
|  | return (ie->element_id_high << 1U) | ie->element_id_low; | 
|  | } | 
|  |  | 
|  | /** @brief The length in bytes of a "Time Correction" header IE. */ | 
|  | #define IEEE802154_TIME_CORRECTION_HEADER_IE_LEN                                                   \ | 
|  | (IEEE802154_HEADER_IE_HEADER_LENGTH + sizeof(struct ieee802154_header_ie_time_correction)) | 
|  |  | 
|  | /** @brief The length in bytes of a "Header Termination 1" header IE. */ | 
|  | #define IEEE802154_HEADER_TERMINATION_1_HEADER_IE_LEN IEEE802154_HEADER_IE_HEADER_LENGTH | 
|  |  | 
|  | /** | 
|  | * @} | 
|  | * | 
|  | * @} | 
|  | */ | 
|  |  | 
|  | #endif /* ZEPHYR_INCLUDE_NET_IEEE802154_IE_H_ */ |