1 /* ieee802154_mcxw_utils.c - NXP MCXW 802.15.4 driver utils*/
2
3 /*
4 * Copyright 2025 NXP
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 *
8 */
9
10 #include <zephyr/kernel.h>
11 #include <zephyr/arch/cpu.h>
12 #include <zephyr/sys/util.h>
13 #include <zephyr/sys/byteorder.h>
14
15 #include <errno.h>
16
17 #include "ieee802154_mcxw_utils.h"
18
19 /* TODO IEEE 802.15.4 MAC Multipurpose frame format */
20 /* TODO add function checks */
21
22 enum offset_fcf_fields {
23 OffsetFrameType = 0x00,
24 OffsetSecurityEnabled = 0x03,
25 OffsetFramePending = 0x04,
26 OffsetAR = 0x05,
27 OffsetPanIdCompression = 0x06,
28 OffsetSeqNumberSuppression = 0x08,
29 OffsetIEPresent = 0x09,
30 OffsetDstAddrMode = 0x0A,
31 OffsetFrameVersion = 0x0C,
32 OffsetSrcAddrMode = 0x0E,
33 };
34
35 enum mask_fcf_fields {
36 MaskFrameType = (0x7 << OffsetFrameType),
37 MaskSecurityEnabled = (0x01 << OffsetSecurityEnabled),
38 MaskFramePending = (0x01 << OffsetFramePending),
39 MaskAR = (0x01 << OffsetAR),
40 MaskPanIdCompression = (0x01 << OffsetPanIdCompression),
41 MaskSeqNumberSuppression = (0x01 << OffsetSeqNumberSuppression),
42 MaskIEPresent = (0x01 << OffsetIEPresent),
43 MaskDstAddrMode = (0x03 << OffsetDstAddrMode),
44 MaskFrameVersion = (0x03 << OffsetFrameVersion),
45 MaskSrcAddrMode = (0x03 << OffsetSrcAddrMode),
46 };
47
48 enum modes_dst_addr {
49 ModeDstAddrNone = 0x00,
50 ModeDstAddrShort = (0x02 << OffsetDstAddrMode),
51 ModeDstAddrExt = (0x03 << OffsetDstAddrMode),
52 };
53
54 enum version_frame {
55 VersionIeee2003 = 0x00,
56 VersionIeee2006 = 0x01,
57 VersionIeee2015 = 0x02,
58 };
59
60 enum modes_src_addr {
61 ModeSrcAddrNone = 0x00,
62 ModeSrcAddrShort = (0x02 << OffsetSrcAddrMode),
63 ModeSrcAddrExt = (0x03 << OffsetSrcAddrMode),
64 };
65
66 enum offset_scf_fields {
67 OffsetSecurityLevel = 0x00,
68 OffsetKeyIdMode = 0x03,
69 OffsetFrameCntSuppression = 0x05,
70 OffsetASNinNonce = 0x06,
71 };
72
73 enum mask_scf_fields {
74 MaskSecurityLevel = (0x07 << OffsetSecurityLevel),
75 MaskKeyIdMode = (0x03 << OffsetKeyIdMode),
76 MaskFrameCntSuppression = (0x1 << OffsetFrameCntSuppression),
77 MaskASNinNonce = (0x01 << OffsetASNinNonce),
78 };
79
get_frame_control_field(uint8_t * pdu,uint16_t length)80 static uint16_t get_frame_control_field(uint8_t *pdu, uint16_t length)
81 {
82 if ((pdu == NULL) || (length < 3)) {
83 return 0x00;
84 }
85
86 return (uint16_t)(pdu[0] | (pdu[1] << 8));
87 }
88
is_security_enabled(uint16_t fcf)89 static bool is_security_enabled(uint16_t fcf)
90 {
91 if (fcf) {
92 return (bool)(fcf & MaskSecurityEnabled);
93 }
94
95 return false;
96 }
97
is_ie_present(uint16_t fcf)98 static bool is_ie_present(uint16_t fcf)
99 {
100 if (fcf) {
101 return (bool)(fcf & MaskIEPresent);
102 }
103
104 return false;
105 }
106
get_frame_version(uint16_t fcf)107 static uint8_t get_frame_version(uint16_t fcf)
108 {
109 if (fcf) {
110 return (uint8_t)((fcf & MaskFrameVersion) >> OffsetFrameVersion);
111 }
112
113 return 0xFF;
114 }
115
is_frame_version_2015_fcf(uint16_t fcf)116 static bool is_frame_version_2015_fcf(uint16_t fcf)
117 {
118 if (fcf) {
119 return get_frame_version(fcf) == VersionIeee2015;
120 }
121
122 return false;
123 }
124
is_frame_version_2015(uint8_t * pdu,uint16_t length)125 bool is_frame_version_2015(uint8_t *pdu, uint16_t length)
126 {
127 uint16_t fcf = get_frame_control_field(pdu, length);
128
129 if (fcf) {
130 return get_frame_version(fcf) == VersionIeee2015;
131 }
132
133 return false;
134 }
135
is_sequence_number_suppression(uint16_t fcf)136 static bool is_sequence_number_suppression(uint16_t fcf)
137 {
138 if (fcf) {
139 return (bool)(fcf & MaskSeqNumberSuppression);
140 }
141
142 return false;
143 }
144
is_dst_panid_present(uint16_t fcf)145 static bool is_dst_panid_present(uint16_t fcf)
146 {
147 bool present;
148
149 if (!fcf) {
150 return false;
151 }
152
153 if (is_frame_version_2015_fcf(fcf)) {
154 switch (fcf & (MaskDstAddrMode | MaskSrcAddrMode | MaskPanIdCompression)) {
155 case (ModeDstAddrNone | ModeSrcAddrNone):
156 case (ModeDstAddrShort | ModeSrcAddrNone | MaskPanIdCompression):
157 case (ModeDstAddrExt | ModeSrcAddrNone | MaskPanIdCompression):
158 case (ModeDstAddrNone | ModeSrcAddrShort):
159 case (ModeDstAddrNone | ModeSrcAddrExt):
160 case (ModeDstAddrNone | ModeSrcAddrShort | MaskPanIdCompression):
161 case (ModeDstAddrNone | ModeSrcAddrExt | MaskPanIdCompression):
162 case (ModeDstAddrExt | ModeSrcAddrExt | MaskPanIdCompression):
163 present = false;
164 break;
165 default:
166 present = true;
167 }
168 } else {
169 present = (bool)(fcf & MaskDstAddrMode);
170 }
171
172 return present;
173 }
174
is_src_panid_present(uint16_t fcf)175 static bool is_src_panid_present(uint16_t fcf)
176 {
177 bool present;
178
179 if (!fcf) {
180 return false;
181 }
182
183 if (is_frame_version_2015_fcf(fcf)) {
184 switch (fcf & (MaskDstAddrMode | MaskSrcAddrMode | MaskPanIdCompression)) {
185 case (ModeDstAddrNone | ModeSrcAddrShort):
186 case (ModeDstAddrNone | ModeSrcAddrExt):
187 case (ModeDstAddrShort | ModeSrcAddrShort):
188 case (ModeDstAddrShort | ModeSrcAddrExt):
189 case (ModeDstAddrExt | ModeSrcAddrShort):
190 present = true;
191 break;
192 default:
193 present = false;
194 }
195
196 } else {
197 present = ((fcf & MaskSrcAddrMode) != 0) && ((fcf & MaskPanIdCompression) == 0);
198 }
199
200 return present;
201 }
202
calculate_addr_field_size(uint16_t fcf)203 static uint8_t calculate_addr_field_size(uint16_t fcf)
204 {
205 uint8_t size = 2;
206
207 if (!fcf) {
208 return 0;
209 }
210
211 if (!is_sequence_number_suppression(fcf)) {
212 size += 1;
213 }
214
215 if (is_dst_panid_present(fcf)) {
216 size += 2;
217 }
218
219 /* destination addressing mode */
220 switch (fcf & MaskDstAddrMode) {
221 case ModeDstAddrShort:
222 size += 2;
223 break;
224 case ModeDstAddrExt:
225 size += 8;
226 break;
227 default:
228 break;
229 }
230
231 if (is_src_panid_present(fcf)) {
232 size += 2;
233 }
234
235 /* source addressing mode */
236 switch (fcf & MaskSrcAddrMode) {
237 case ModeSrcAddrShort:
238 size += 2;
239 break;
240 case ModeSrcAddrExt:
241 size += 8;
242 break;
243 default:
244 break;
245 }
246
247 return size;
248 }
249
get_keyid_mode(uint8_t * pdu,uint16_t length)250 static uint8_t get_keyid_mode(uint8_t *pdu, uint16_t length)
251 {
252 uint16_t fcf = get_frame_control_field(pdu, length);
253 uint8_t ash_start;
254
255 if (is_security_enabled(fcf)) {
256 ash_start = calculate_addr_field_size(fcf);
257 return (uint8_t)((pdu[ash_start] & MaskKeyIdMode) >> OffsetKeyIdMode);
258 }
259
260 return 0xFF;
261 }
262
is_keyid_mode_1(uint8_t * pdu,uint16_t length)263 bool is_keyid_mode_1(uint8_t *pdu, uint16_t length)
264 {
265 uint8_t key_mode = get_keyid_mode(pdu, length);
266
267 if (key_mode == 0x01) {
268 return true;
269 }
270
271 return false;
272 }
273
set_frame_counter(uint8_t * pdu,uint16_t length,uint32_t fc)274 void set_frame_counter(uint8_t *pdu, uint16_t length, uint32_t fc)
275 {
276 uint16_t fcf = get_frame_control_field(pdu, length);
277
278 if (is_security_enabled(fcf)) {
279 uint8_t ash_start = calculate_addr_field_size(fcf);
280 uint8_t scf = pdu[ash_start];
281
282 /* check that Frame Counter Suppression is not set */
283 if (!(scf & MaskFrameCntSuppression)) {
284 sys_put_le32(fc, &pdu[ash_start + 1]);
285 }
286 }
287 }
288
get_asn_size(uint8_t * pdu,uint16_t length)289 static uint8_t get_asn_size(uint8_t *pdu, uint16_t length)
290 {
291 uint16_t fcf = get_frame_control_field(pdu, length);
292
293 if (is_security_enabled(fcf)) {
294 uint8_t ash_start = calculate_addr_field_size(fcf);
295 uint8_t scf = pdu[ash_start];
296 uint8_t size = 1;
297
298 /* Frame Counter Suppression is not set */
299 if (!(scf & MaskFrameCntSuppression)) {
300 size += 4;
301 }
302
303 uint8_t key_mode = get_keyid_mode(pdu, length);
304
305 switch (key_mode) {
306 case 0x01:
307 size += 1;
308 break;
309 case 0x02:
310 size += 5;
311 case 0x03:
312 size += 9;
313 default:
314 break;
315 }
316
317 return size;
318 }
319 return 0;
320 }
321
get_csl_ie_content_start(uint8_t * pdu,uint16_t length)322 static uint8_t *get_csl_ie_content_start(uint8_t *pdu, uint16_t length)
323 {
324 uint16_t fcf = get_frame_control_field(pdu, length);
325
326 if (is_ie_present(fcf)) {
327 uint8_t ie_start_idx = calculate_addr_field_size(fcf) + get_asn_size(pdu, length);
328 uint8_t *cur_ie = &pdu[ie_start_idx];
329
330 uint8_t ie_header = (uint16_t)(cur_ie[0] | (cur_ie[1] << 8));
331 uint8_t ie_length = ie_header & 0x7F;
332 uint8_t ie_el_id = ie_header & 0x7F80;
333
334 while ((ie_el_id != 0x7e) && (ie_el_id != 0x7f)) {
335 if (ie_el_id == 0x1a) {
336 return (cur_ie + 2);
337 }
338 cur_ie += (2 + ie_length);
339 ie_header = (uint16_t)(cur_ie[0] | (cur_ie[1] << 8));
340 ie_length = ie_header & 0x7F;
341 ie_el_id = ie_header & 0x7F80;
342 }
343 }
344
345 return NULL;
346 }
347
set_csl_ie(uint8_t * pdu,uint16_t length,uint16_t period,uint16_t phase)348 void set_csl_ie(uint8_t *pdu, uint16_t length, uint16_t period, uint16_t phase)
349 {
350 uint8_t *csl_ie_content = get_csl_ie_content_start(pdu, length);
351
352 if (csl_ie_content) {
353 sys_put_le16(phase, csl_ie_content);
354 sys_put_le16(period, csl_ie_content + 2);
355 }
356 }
357