blob: 0be4c1576e5c07029f31d04d18fa9090ed73abc4 [file] [log] [blame]
/*
* 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,
IEEE802154_IE_TYPE_PAYLOAD,
};
/**
* @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,
IEEE802154_HEADER_IE_ELEMENT_ID_CSL_IE = 0x1a,
IEEE802154_HEADER_IE_ELEMENT_ID_RIT_IE = 0x1b,
IEEE802154_HEADER_IE_ELEMENT_ID_RENDEZVOUS_TIME_IE = 0x1d,
IEEE802154_HEADER_IE_ELEMENT_ID_TIME_CORRECTION_IE = 0x1e,
IEEE802154_HEADER_IE_ELEMENT_ID_HEADER_TERMINATION_1 = 0x7e,
IEEE802154_HEADER_IE_ELEMENT_ID_HEADER_TERMINATION_2 = 0x7f,
/* 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 {
uint8_t vendor_oui[IEEE802154_VENDOR_SPECIFIC_IE_OUI_LEN];
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;
uint16_t csl_period;
uint16_t csl_rendezvous_time;
} __packed;
/** @brief Reduced CSL IE, see section 7.4.2.3. */
struct ieee802154_header_ie_csl_reduced {
uint16_t csl_phase;
uint16_t csl_period;
} __packed;
/** @brief Generic CSL IE, see section 7.4.2.3. */
struct ieee802154_header_ie_csl {
union {
struct ieee802154_header_ie_csl_full full;
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;
uint8_t number_of_repeat_listen;
uint16_t 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;
uint16_t 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;
} __packed;
/** @brief Rendezvous Time IE, see section 7.4.2.6. */
struct ieee802154_header_ie_rendezvous_time {
union {
struct ieee802154_header_ie_rendezvous_time_full full;
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;
} __packed;
/* @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;
/** @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_ */