1 /*
2 * Copyright (c) 2023 Florian Grandel, Zephyr Project.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * @brief IEEE 802.15.4 MAC information element (IE) related types and helpers
10 *
11 * This is not to be included by the application. This file contains only those
12 * parts of the types required for IE support that need to be visible to IEEE
13 * 802.15.4 drivers and L2 at the same time, i.e. everything related to header
14 * IE representation, parsing and generation.
15 *
16 * All specification references in this file refer to IEEE 802.15.4-2020.
17 *
18 * @note All structs and attributes in this file that directly represent parts
19 * of IEEE 802.15.4 frames are in LITTLE ENDIAN, see section 4, especially
20 * section 4.3.
21 */
22
23 #ifndef ZEPHYR_INCLUDE_NET_IEEE802154_IE_H_
24 #define ZEPHYR_INCLUDE_NET_IEEE802154_IE_H_
25
26 #include <zephyr/net_buf.h>
27 #include <zephyr/sys/byteorder.h>
28
29 /**
30 * @addtogroup ieee802154_driver
31 * @{
32 *
33 * @name IEEE 802.15.4, section 7.4.2: MAC header information elements
34 * @{
35 */
36
37 /**
38 * @brief Information Element Types.
39 *
40 * @details See sections 7.4.2.1 and 7.4.3.1.
41 */
42 enum ieee802154_ie_type {
43 IEEE802154_IE_TYPE_HEADER = 0x0, /**< Header type */
44 IEEE802154_IE_TYPE_PAYLOAD, /**< Payload type */
45 };
46
47 /**
48 * @brief Header Information Element IDs.
49 *
50 * @details See section 7.4.2.1, table 7-7, partial list, only IEs actually used
51 * are implemented.
52 */
53 enum ieee802154_header_ie_element_id {
54 IEEE802154_HEADER_IE_ELEMENT_ID_VENDOR_SPECIFIC_IE = 0x00, /**< Vendor specific IE */
55 IEEE802154_HEADER_IE_ELEMENT_ID_CSL_IE = 0x1a, /**< CSL IE */
56 IEEE802154_HEADER_IE_ELEMENT_ID_RIT_IE = 0x1b, /**< RIT IE */
57 IEEE802154_HEADER_IE_ELEMENT_ID_RENDEZVOUS_TIME_IE = 0x1d, /**< Rendezvous time IE */
58 IEEE802154_HEADER_IE_ELEMENT_ID_TIME_CORRECTION_IE = 0x1e, /**< Time correction IE */
59 IEEE802154_HEADER_IE_ELEMENT_ID_HEADER_TERMINATION_1 = 0x7e, /**< Header termination 1 */
60 IEEE802154_HEADER_IE_ELEMENT_ID_HEADER_TERMINATION_2 = 0x7f, /**< Header termination 2 */
61 /* partial list, add additional ids as needed */
62 };
63
64 /** @cond INTERNAL_HIDDEN */
65 #define IEEE802154_VENDOR_SPECIFIC_IE_OUI_LEN 3
66 /** INTERNAL_HIDDEN @endcond */
67
68 /** @brief Vendor Specific Header IE, see section 7.4.2.3. */
69 struct ieee802154_header_ie_vendor_specific {
70 /** Vendor OUI */
71 uint8_t vendor_oui[IEEE802154_VENDOR_SPECIFIC_IE_OUI_LEN];
72 /** Vendor specific information */
73 uint8_t *vendor_specific_info;
74 } __packed;
75
76 /** @brief Full CSL IE, see section 7.4.2.3. */
77 struct ieee802154_header_ie_csl_full {
78 uint16_t csl_phase; /**< CSL phase */
79 uint16_t csl_period; /**< CSL period */
80 uint16_t csl_rendezvous_time; /**< Rendezvous time */
81 } __packed;
82
83 /** @brief Reduced CSL IE, see section 7.4.2.3. */
84 struct ieee802154_header_ie_csl_reduced {
85 uint16_t csl_phase; /**< CSL phase */
86 uint16_t csl_period; /**< CSL period */
87 } __packed;
88
89 /** @brief Generic CSL IE, see section 7.4.2.3. */
90 struct ieee802154_header_ie_csl {
91 union {
92 /** CSL full information */
93 struct ieee802154_header_ie_csl_full full;
94 /** CSL reduced information */
95 struct ieee802154_header_ie_csl_reduced reduced;
96 };
97 } __packed;
98
99 /** @brief RIT IE, see section 7.4.2.4. */
100 struct ieee802154_header_ie_rit {
101 uint8_t time_to_first_listen; /**< Time to First Listen */
102 uint8_t number_of_repeat_listen; /**< Number of Repeat Listen */
103 uint16_t repeat_listen_interval; /**< Repeat listen interval */
104 } __packed;
105
106 /**
107 * @brief Full Rendezvous Time IE, see section 7.4.2.6
108 * (macCslInterval is nonzero).
109 */
110 struct ieee802154_header_ie_rendezvous_time_full {
111 uint16_t rendezvous_time; /**< Rendezvous time */
112 uint16_t wakeup_interval; /**< Wakeup interval */
113 } __packed;
114
115 /**
116 * @brief Reduced Rendezvous Time IE, see section 7.4.2.6
117 * (macCslInterval is zero).
118 */
119 struct ieee802154_header_ie_rendezvous_time_reduced {
120 uint16_t rendezvous_time; /**< Rendezvous time */
121 } __packed;
122
123 /** @brief Rendezvous Time IE, see section 7.4.2.6. */
124 struct ieee802154_header_ie_rendezvous_time {
125 union {
126 /** Rendezvous time full information */
127 struct ieee802154_header_ie_rendezvous_time_full full;
128 /** Rendezvous time reduced information */
129 struct ieee802154_header_ie_rendezvous_time_reduced reduced;
130 };
131 } __packed;
132
133 /** @brief Time Correction IE, see section 7.4.2.7. */
134 struct ieee802154_header_ie_time_correction {
135 uint16_t time_sync_info; /**< Time synchronization information */
136 } __packed;
137
138 /** @cond INTERNAL_HIDDEN */
139
140 /* @brief Generic Header IE, see section 7.4.2.1. */
141 struct ieee802154_header_ie {
142 #if CONFIG_LITTLE_ENDIAN
143 uint16_t length : 7;
144 uint16_t element_id_low : 1; /* see enum ieee802154_header_ie_element_id */
145 uint16_t element_id_high : 7;
146 uint16_t type : 1; /* always 0 */
147 #else
148 uint16_t element_id_low : 1; /* see enum ieee802154_header_ie_element_id */
149 uint16_t length : 7;
150 uint16_t type : 1; /* always 0 */
151 uint16_t element_id_high : 7;
152 #endif
153 union {
154 struct ieee802154_header_ie_vendor_specific vendor_specific;
155 struct ieee802154_header_ie_csl csl;
156 struct ieee802154_header_ie_rit rit;
157 struct ieee802154_header_ie_rendezvous_time rendezvous_time;
158 struct ieee802154_header_ie_time_correction time_correction;
159 /* add additional supported header IEs here */
160 } content;
161 } __packed;
162
163 /** INTERNAL_HIDDEN @endcond */
164
165 /** @brief The header IE's header length (2 bytes). */
166 #define IEEE802154_HEADER_IE_HEADER_LENGTH sizeof(uint16_t)
167
168
169 /** @cond INTERNAL_HIDDEN */
170 #define IEEE802154_DEFINE_HEADER_IE(_element_id, _length, _content, _content_type) \
171 (struct ieee802154_header_ie) { \
172 .length = (_length), \
173 .element_id_high = (_element_id) >> 1U, .element_id_low = (_element_id) & 0x01, \
174 .type = IEEE802154_IE_TYPE_HEADER, \
175 .content._content_type = _content, \
176 }
177
178 #define IEEE802154_DEFINE_HEADER_IE_VENDOR_SPECIFIC_CONTENT_LEN(_vendor_specific_info_len) \
179 (IEEE802154_VENDOR_SPECIFIC_IE_OUI_LEN + (_vendor_specific_info_len))
180
181 #define IEEE802154_DEFINE_HEADER_IE_VENDOR_SPECIFIC_CONTENT(_vendor_oui, _vendor_specific_info) \
182 (struct ieee802154_header_ie_vendor_specific) { \
183 .vendor_oui = _vendor_oui, .vendor_specific_info = (_vendor_specific_info), \
184 }
185
186 #define IEEE802154_DEFINE_HEADER_IE_CSL_REDUCED_CONTENT(_csl_phase, _csl_period) \
187 (struct ieee802154_header_ie_csl_reduced) { \
188 .csl_phase = sys_cpu_to_le16(_csl_phase), \
189 .csl_period = sys_cpu_to_le16(_csl_period), \
190 }
191
192 #define IEEE802154_DEFINE_HEADER_IE_CSL_FULL_CONTENT(_csl_phase, _csl_period, \
193 _csl_rendezvous_time) \
194 (struct ieee802154_header_ie_csl_full) { \
195 .csl_phase = sys_cpu_to_le16(_csl_phase), \
196 .csl_period = sys_cpu_to_le16(_csl_period), \
197 .csl_rendezvous_time = sys_cpu_to_le16(_csl_rendezvous_time), \
198 }
199
200 #define IEEE802154_HEADER_IE_TIME_CORRECTION_NACK 0x8000
201 #define IEEE802154_HEADER_IE_TIME_CORRECTION_MASK 0x0fff
202 #define IEEE802154_HEADER_IE_TIME_CORRECTION_SIGN_BIT_MASK 0x0800
203
204 #define IEEE802154_DEFINE_HEADER_IE_TIME_CORRECTION_CONTENT(_ack, _time_correction_us) \
205 (struct ieee802154_header_ie_time_correction) { \
206 .time_sync_info = sys_cpu_to_le16( \
207 (!(_ack) * IEEE802154_HEADER_IE_TIME_CORRECTION_NACK) | \
208 ((_time_correction_us) & IEEE802154_HEADER_IE_TIME_CORRECTION_MASK)), \
209 }
210 /** INTERNAL_HIDDEN @endcond */
211
212 /**
213 * @brief Define a vendor specific header IE, see section 7.4.2.3.
214 *
215 * @details Example usage (all parameters in little endian):
216 *
217 * @code{.c}
218 * uint8_t vendor_specific_info[] = {...some vendor specific IE content...};
219 * struct ieee802154_header_ie header_ie = IEEE802154_DEFINE_HEADER_IE_VENDOR_SPECIFIC(
220 * {0x9b, 0xb8, 0xea}, vendor_specific_info, sizeof(vendor_specific_info));
221 * @endcode
222 *
223 * @param _vendor_oui an initializer for a 3 byte vendor oui array in little
224 * endian
225 * @param _vendor_specific_info pointer to a variable length uint8_t array with
226 * the vendor specific IE content
227 * @param _vendor_specific_info_len the length of the vendor specific IE content
228 * (in bytes)
229 */
230 #define IEEE802154_DEFINE_HEADER_IE_VENDOR_SPECIFIC(_vendor_oui, _vendor_specific_info, \
231 _vendor_specific_info_len) \
232 IEEE802154_DEFINE_HEADER_IE(IEEE802154_HEADER_IE_ELEMENT_ID_VENDOR_SPECIFIC_IE, \
233 IEEE802154_DEFINE_HEADER_IE_VENDOR_SPECIFIC_CONTENT_LEN( \
234 _vendor_specific_info_len), \
235 IEEE802154_DEFINE_HEADER_IE_VENDOR_SPECIFIC_CONTENT( \
236 _vendor_oui, _vendor_specific_info), \
237 vendor_specific)
238
239 /**
240 * @brief Define a reduced CSL IE, see section 7.4.2.3.
241 *
242 * @details Example usage (all parameters in CPU byte order):
243 *
244 * @code{.c}
245 * uint16_t csl_phase = ...;
246 * uint16_t csl_period = ...;
247 * struct ieee802154_header_ie header_ie =
248 * IEEE802154_DEFINE_HEADER_IE_CSL_REDUCED(csl_phase, csl_period);
249 * @endcode
250 *
251 * @param _csl_phase CSL phase in CPU byte order
252 * @param _csl_period CSL period in CPU byte order
253 */
254 #define IEEE802154_DEFINE_HEADER_IE_CSL_REDUCED(_csl_phase, _csl_period) \
255 IEEE802154_DEFINE_HEADER_IE( \
256 IEEE802154_HEADER_IE_ELEMENT_ID_CSL_IE, \
257 sizeof(struct ieee802154_header_ie_csl_reduced), \
258 IEEE802154_DEFINE_HEADER_IE_CSL_REDUCED_CONTENT(_csl_phase, _csl_period), \
259 csl.reduced)
260
261 /**
262 * @brief Define a full CSL IE, see section 7.4.2.3.
263 *
264 * @details Example usage (all parameters in CPU byte order):
265 *
266 * @code{.c}
267 * uint16_t csl_phase = ...;
268 * uint16_t csl_period = ...;
269 * uint16_t csl_rendezvous_time = ...;
270 * struct ieee802154_header_ie header_ie =
271 * IEEE802154_DEFINE_HEADER_IE_CSL_REDUCED(csl_phase, csl_period, csl_rendezvous_time);
272 * @endcode
273 *
274 * @param _csl_phase CSL phase in CPU byte order
275 * @param _csl_period CSL period in CPU byte order
276 * @param _csl_rendezvous_time CSL rendezvous time in CPU byte order
277 */
278 #define IEEE802154_DEFINE_HEADER_IE_CSL_FULL(_csl_phase, _csl_period, _csl_rendezvous_time) \
279 IEEE802154_DEFINE_HEADER_IE(IEEE802154_HEADER_IE_ELEMENT_ID_CSL_IE, \
280 sizeof(struct ieee802154_header_ie_csl_full), \
281 IEEE802154_DEFINE_HEADER_IE_CSL_FULL_CONTENT( \
282 _csl_phase, _csl_period, _csl_rendezvous_time), \
283 csl.full)
284
285 /**
286 * @brief Define a Time Correction IE, see section 7.4.2.7.
287 *
288 * @details Example usage (parameter in CPU byte order):
289 *
290 * @code{.c}
291 * uint16_t time_sync_info = ...;
292 * struct ieee802154_header_ie header_ie =
293 * IEEE802154_DEFINE_HEADER_IE_TIME_CORRECTION(true, time_sync_info);
294 * @endcode
295 *
296 * @param _ack whether or not the enhanced ACK frame that receives this IE is an
297 * ACK (true) or NACK (false)
298 * @param _time_correction_us the positive or negative deviation from expected
299 * RX time in microseconds
300 */
301 #define IEEE802154_DEFINE_HEADER_IE_TIME_CORRECTION(_ack, _time_correction_us) \
302 IEEE802154_DEFINE_HEADER_IE( \
303 IEEE802154_HEADER_IE_ELEMENT_ID_TIME_CORRECTION_IE, \
304 sizeof(struct ieee802154_header_ie_time_correction), \
305 IEEE802154_DEFINE_HEADER_IE_TIME_CORRECTION_CONTENT(_ack, _time_correction_us), \
306 time_correction)
307
308 /**
309 * @brief Retrieve the time correction value in microseconds from a Time Correction IE,
310 * see section 7.4.2.7.
311 *
312 * @param[in] ie pointer to the Time Correction IE structure
313 *
314 * @return The time correction value in microseconds.
315 */
316 static inline int16_t
ieee802154_header_ie_get_time_correction_us(struct ieee802154_header_ie_time_correction * ie)317 ieee802154_header_ie_get_time_correction_us(struct ieee802154_header_ie_time_correction *ie)
318 {
319 if (ie->time_sync_info & IEEE802154_HEADER_IE_TIME_CORRECTION_SIGN_BIT_MASK) {
320 /* Negative integer */
321 return (int16_t)ie->time_sync_info | ~IEEE802154_HEADER_IE_TIME_CORRECTION_MASK;
322 }
323
324 /* Positive integer */
325 return (int16_t)ie->time_sync_info & IEEE802154_HEADER_IE_TIME_CORRECTION_MASK;
326 }
327
328 /**
329 * @brief Set the element ID of a header IE.
330 *
331 * @param[in] ie pointer to a header IE
332 * @param[in] element_id IE element id in CPU byte order
333 */
ieee802154_header_ie_set_element_id(struct ieee802154_header_ie * ie,uint8_t element_id)334 static inline void ieee802154_header_ie_set_element_id(struct ieee802154_header_ie *ie,
335 uint8_t element_id)
336 {
337 ie->element_id_high = element_id >> 1U;
338 ie->element_id_low = element_id & 0x01;
339 }
340
341 /**
342 * @brief Get the element ID of a header IE.
343 *
344 * @param[in] ie pointer to a header IE
345 *
346 * @return header IE element id in CPU byte order
347 */
ieee802154_header_ie_get_element_id(struct ieee802154_header_ie * ie)348 static inline uint8_t ieee802154_header_ie_get_element_id(struct ieee802154_header_ie *ie)
349 {
350 return (ie->element_id_high << 1U) | ie->element_id_low;
351 }
352
353 /** @brief The length in bytes of a "Time Correction" header IE. */
354 #define IEEE802154_TIME_CORRECTION_HEADER_IE_LEN \
355 (IEEE802154_HEADER_IE_HEADER_LENGTH + sizeof(struct ieee802154_header_ie_time_correction))
356
357 /** @brief The length in bytes of a "Header Termination 1" header IE. */
358 #define IEEE802154_HEADER_TERMINATION_1_HEADER_IE_LEN IEEE802154_HEADER_IE_HEADER_LENGTH
359
360 /**
361 * @}
362 *
363 * @}
364 */
365
366 #endif /* ZEPHYR_INCLUDE_NET_IEEE802154_IE_H_ */
367