1 /*
2 * Copyright (c) 2016 Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * @brief IEEE 802.15.4 MAC frame related functions implementation
10 *
11 * All references to the spec refer to IEEE 802.15.4-2020.
12 */
13
14 #include <zephyr/logging/log.h>
15 LOG_MODULE_REGISTER(net_ieee802154_frame, CONFIG_NET_L2_IEEE802154_LOG_LEVEL);
16
17 #include "ieee802154_frame.h"
18 #include "ieee802154_security.h"
19
20 #include <zephyr/net/net_core.h>
21 #include <zephyr/net/net_if.h>
22
23 #include <ipv6.h>
24 #include <nbr.h>
25
26 #define dbg_print_fs(fs) \
27 NET_DBG("fs(1): %u/%u/%u/%u/%u/%u", fs->fc.frame_type, fs->fc.security_enabled, \
28 fs->fc.frame_pending, fs->fc.ar, fs->fc.pan_id_comp, fs->fc.reserved); \
29 NET_DBG("fs(2): %u/%u/%u/%u/%u - %u", fs->fc.seq_num_suppr, fs->fc.ie_list, \
30 fs->fc.dst_addr_mode, fs->fc.frame_version, fs->fc.src_addr_mode, fs->sequence)
31
32 #define BUF_TIMEOUT K_MSEC(50)
33
34 #ifdef CONFIG_NET_L2_IEEE802154_SECURITY
35 const uint8_t level_2_authtag_len[4] = {0, IEEE802154_AUTH_TAG_LENGTH_32,
36 IEEE802154_AUTH_TAG_LENGTH_64,
37 IEEE802154_AUTH_TAG_LENGTH_128};
38 #endif
39
ieee802154_validate_fc_seq(uint8_t * buf,uint8_t ** p_buf,uint8_t * length)40 struct ieee802154_fcf_seq *ieee802154_validate_fc_seq(uint8_t *buf, uint8_t **p_buf,
41 uint8_t *length)
42 {
43 struct ieee802154_fcf_seq *fs = (struct ieee802154_fcf_seq *)buf;
44
45 dbg_print_fs(fs);
46
47 /** Basic FC checks */
48 if (fs->fc.frame_type == IEEE802154_FRAME_TYPE_RESERVED ||
49 fs->fc.frame_version >= IEEE802154_VERSION_RESERVED) {
50 return NULL;
51 }
52
53 if (fs->fc.frame_type == IEEE802154_FRAME_TYPE_MULTIPURPOSE) {
54 if (fs->fc.frame_version != 0) {
55 return NULL;
56 }
57 } else {
58 /** Only for versions 2003/2006 */
59 if (fs->fc.frame_version < IEEE802154_VERSION_802154 &&
60 (fs->fc.dst_addr_mode == IEEE802154_ADDR_MODE_RESERVED ||
61 fs->fc.src_addr_mode == IEEE802154_ADDR_MODE_RESERVED ||
62 fs->fc.frame_type >= IEEE802154_FRAME_TYPE_RESERVED)) {
63 return NULL;
64 }
65 }
66
67 if (fs->fc.frame_type == IEEE802154_FRAME_TYPE_BEACON &&
68 (fs->fc.dst_addr_mode != IEEE802154_ADDR_MODE_NONE ||
69 fs->fc.src_addr_mode == IEEE802154_ADDR_MODE_NONE || fs->fc.pan_id_comp)) {
70 /** See section 7.2.2.1.1 */
71 return NULL;
72 } else if (fs->fc.frame_type == IEEE802154_FRAME_TYPE_DATA &&
73 fs->fc.dst_addr_mode == IEEE802154_ADDR_MODE_NONE &&
74 fs->fc.src_addr_mode == IEEE802154_ADDR_MODE_NONE) {
75 /** See section 7.2.2.2.1 */
76 return NULL;
77 } else if (fs->fc.frame_type == IEEE802154_FRAME_TYPE_MAC_COMMAND && fs->fc.frame_pending) {
78 /** See section 7.3 */
79 return NULL;
80 }
81
82 #ifndef CONFIG_NET_L2_IEEE802154_SECURITY
83 if (fs->fc.security_enabled) {
84 return NULL;
85 }
86 #endif
87
88 if (p_buf) {
89 *length -= IEEE802154_FCF_SEQ_LENGTH;
90 *p_buf = buf + IEEE802154_FCF_SEQ_LENGTH;
91 }
92
93 return fs;
94 }
95
validate_addr(uint8_t * buf,uint8_t ** p_buf,uint8_t * length,enum ieee802154_addressing_mode mode,bool pan_id_compression,struct ieee802154_address_field ** addr)96 static inline bool validate_addr(uint8_t *buf, uint8_t **p_buf, uint8_t *length,
97 enum ieee802154_addressing_mode mode, bool pan_id_compression,
98 struct ieee802154_address_field **addr)
99 {
100 uint8_t len = 0;
101
102 *p_buf = buf;
103
104 NET_DBG("Buf %p - mode %d - pan id comp %d", (void *)buf, mode, pan_id_compression);
105
106 if (mode == IEEE802154_ADDR_MODE_NONE) {
107 *addr = NULL;
108 return true;
109 }
110
111 if (!pan_id_compression) {
112 len = IEEE802154_PAN_ID_LENGTH;
113 }
114
115 if (mode == IEEE802154_ADDR_MODE_SHORT) {
116 len += IEEE802154_SHORT_ADDR_LENGTH;
117 } else {
118 /* IEEE802154_ADDR_MODE_EXTENDED */
119 len += IEEE802154_EXT_ADDR_LENGTH;
120 }
121
122 if (len > *length) {
123 return false;
124 }
125
126 *p_buf += len;
127 *length -= len;
128
129 *addr = (struct ieee802154_address_field *)buf;
130
131 return true;
132 }
133
134 #ifdef CONFIG_NET_L2_IEEE802154_SECURITY
135 struct ieee802154_aux_security_hdr *
ieee802154_validate_aux_security_hdr(uint8_t * buf,uint8_t ** p_buf,uint8_t * length)136 ieee802154_validate_aux_security_hdr(uint8_t *buf, uint8_t **p_buf, uint8_t *length)
137 {
138 struct ieee802154_aux_security_hdr *ash = (struct ieee802154_aux_security_hdr *)buf;
139 uint8_t len = IEEE802154_SECURITY_CF_LENGTH + IEEE802154_SECURITY_FRAME_COUNTER_LENGTH;
140
141 /* At least the asf is sized of: control field + frame counter */
142 if (*length < len) {
143 return NULL;
144 }
145
146 /* Only implicit key mode is supported for now */
147 if (ash->control.key_id_mode != IEEE802154_KEY_ID_MODE_IMPLICIT) {
148 return NULL;
149 }
150
151 /* Explicit key must have a key index != 0x00, see section 9.4.2.3 */
152 switch (ash->control.key_id_mode) {
153 case IEEE802154_KEY_ID_MODE_IMPLICIT:
154 break;
155 case IEEE802154_KEY_ID_MODE_INDEX:
156 len += IEEE802154_KEY_ID_FIELD_INDEX_LENGTH;
157 if (*length < len) {
158 return NULL;
159 }
160
161 if (!ash->kif.mode_1.key_index) {
162 return NULL;
163 }
164
165 break;
166 case IEEE802154_KEY_ID_MODE_SRC_4_INDEX:
167 len += IEEE802154_KEY_ID_FIELD_SRC_4_INDEX_LENGTH;
168 if (*length < len) {
169 return NULL;
170 }
171
172 if (!ash->kif.mode_2.key_index) {
173 return NULL;
174 }
175
176 break;
177 case IEEE802154_KEY_ID_MODE_SRC_8_INDEX:
178 len += IEEE802154_KEY_ID_FIELD_SRC_8_INDEX_LENGTH;
179 if (*length < len) {
180 return NULL;
181 }
182
183 if (!ash->kif.mode_3.key_index) {
184 return NULL;
185 }
186
187 break;
188 }
189
190 *p_buf = buf + len;
191 *length -= len;
192
193 return ash;
194 }
195 #endif /* CONFIG_NET_L2_IEEE802154_SECURITY */
196
ieee802514_beacon_header_length(uint8_t * buf,uint8_t length)197 int ieee802514_beacon_header_length(uint8_t *buf, uint8_t length)
198 {
199 struct ieee802154_beacon *beacon = (struct ieee802154_beacon *)buf;
200 struct ieee802154_pas_spec *pas;
201 uint8_t len = IEEE802154_BEACON_SF_SIZE + IEEE802154_BEACON_GTS_SPEC_SIZE;
202
203 if (length < len) {
204 return -EINVAL;
205 }
206
207 /* see section 7.3.1.5 on how to calculate GTS length */
208 if (beacon->gts.desc_count) {
209 len += IEEE802154_BEACON_GTS_DIR_SIZE +
210 beacon->gts.desc_count * IEEE802154_BEACON_GTS_SIZE;
211 }
212
213 if (length < len) {
214 return -EINVAL;
215 }
216
217 /* see section 7.3.1.6 on how to calculate pending address length */
218 pas = (struct ieee802154_pas_spec *)buf + len;
219
220 len += IEEE802154_BEACON_PAS_SPEC_SIZE;
221 if (length < len) {
222 return -EINVAL;
223 }
224
225 if (pas->nb_sap || pas->nb_eap) {
226 len += (pas->nb_sap * IEEE802154_SHORT_ADDR_LENGTH) +
227 (pas->nb_eap * IEEE802154_EXT_ADDR_LENGTH);
228 }
229
230 if (length < len) {
231 return -EINVAL;
232 }
233
234 return len;
235 }
236
validate_mac_command_cfi_to_mhr(struct ieee802154_mhr * mhr,bool ack_requested,bool has_pan_id,uint8_t src_bf,bool src_pan_brdcst_chk,uint8_t dst_bf,bool dst_brdcst_chk)237 static inline bool validate_mac_command_cfi_to_mhr(struct ieee802154_mhr *mhr,
238 bool ack_requested, bool has_pan_id,
239 uint8_t src_bf, bool src_pan_brdcst_chk,
240 uint8_t dst_bf, bool dst_brdcst_chk)
241 {
242 if (mhr->fs->fc.ar != ack_requested || mhr->fs->fc.pan_id_comp == has_pan_id) {
243 return false;
244 }
245
246 if (!(BIT(mhr->fs->fc.src_addr_mode) & src_bf) ||
247 !(BIT(mhr->fs->fc.dst_addr_mode) & dst_bf)) {
248 return false;
249 }
250
251 if (src_pan_brdcst_chk) {
252 if (mhr->src_addr->plain.pan_id != IEEE802154_BROADCAST_PAN_ID) {
253 return false;
254 }
255 }
256
257 if (dst_brdcst_chk) {
258 /* broadcast address is symmetric so no need to swap byte order */
259 if (mhr->dst_addr->plain.addr.short_addr != IEEE802154_BROADCAST_ADDRESS) {
260 return false;
261 }
262 }
263
264 return true;
265 }
266
validate_mac_command(struct ieee802154_mpdu * mpdu,uint8_t * buf,uint8_t length)267 static inline bool validate_mac_command(struct ieee802154_mpdu *mpdu, uint8_t *buf, uint8_t length)
268 {
269 struct ieee802154_command *command = (struct ieee802154_command *)buf;
270 uint8_t len = IEEE802154_CMD_CFI_LENGTH;
271 bool src_pan_brdcst_chk = false;
272 uint8_t src_bf = 0, dst_bf = 0;
273 bool dst_brdcst_chk = false;
274 bool ack_requested = false;
275 bool has_pan_id = true;
276
277 if (length < len) {
278 return false;
279 }
280
281 switch (command->cfi) {
282 case IEEE802154_CFI_UNKNOWN:
283 return false;
284 case IEEE802154_CFI_ASSOCIATION_REQUEST:
285 len += IEEE802154_CMD_ASSOC_REQ_LENGTH;
286 ack_requested = true;
287 src_bf = BIT(IEEE802154_ADDR_MODE_EXTENDED);
288 src_pan_brdcst_chk = true;
289 dst_bf = BIT(IEEE802154_ADDR_MODE_SHORT) | BIT(IEEE802154_ADDR_MODE_EXTENDED);
290
291 break;
292 case IEEE802154_CFI_ASSOCIATION_RESPONSE:
293 len += IEEE802154_CMD_ASSOC_RES_LENGTH;
294 __fallthrough;
295 case IEEE802154_CFI_DISASSOCIATION_NOTIFICATION:
296 if (command->cfi == IEEE802154_CFI_DISASSOCIATION_NOTIFICATION) {
297 len += IEEE802154_CMD_DISASSOC_NOTE_LENGTH;
298 dst_bf = BIT(IEEE802154_ADDR_MODE_SHORT);
299 }
300 __fallthrough;
301 case IEEE802154_CFI_PAN_ID_CONFLICT_NOTIFICATION:
302 ack_requested = true;
303 has_pan_id = false;
304 src_bf = BIT(IEEE802154_ADDR_MODE_EXTENDED);
305 dst_bf |= BIT(IEEE802154_ADDR_MODE_EXTENDED);
306
307 break;
308 case IEEE802154_CFI_DATA_REQUEST:
309 ack_requested = true;
310 src_bf = BIT(IEEE802154_ADDR_MODE_SHORT) | BIT(IEEE802154_ADDR_MODE_EXTENDED);
311
312 if (mpdu->mhr.fs->fc.dst_addr_mode == IEEE802154_ADDR_MODE_NONE) {
313 dst_bf = BIT(IEEE802154_ADDR_MODE_NONE);
314 } else {
315 has_pan_id = false;
316 dst_bf = BIT(IEEE802154_ADDR_MODE_SHORT) |
317 BIT(IEEE802154_ADDR_MODE_EXTENDED);
318 }
319
320 break;
321 case IEEE802154_CFI_ORPHAN_NOTIFICATION:
322 has_pan_id = false;
323 src_bf = BIT(IEEE802154_ADDR_MODE_EXTENDED);
324 dst_bf = BIT(IEEE802154_ADDR_MODE_SHORT);
325
326 break;
327 case IEEE802154_CFI_BEACON_REQUEST:
328 src_bf = BIT(IEEE802154_ADDR_MODE_NONE);
329 dst_bf = BIT(IEEE802154_ADDR_MODE_SHORT);
330 dst_brdcst_chk = true;
331
332 break;
333 case IEEE802154_CFI_COORDINATOR_REALIGNEMENT:
334 len += IEEE802154_CMD_COORD_REALIGN_LENGTH;
335 src_bf = BIT(IEEE802154_ADDR_MODE_EXTENDED);
336
337 if (mpdu->mhr.fs->fc.dst_addr_mode == IEEE802154_ADDR_MODE_SHORT) {
338 dst_bf = BIT(IEEE802154_ADDR_MODE_SHORT);
339 dst_brdcst_chk = true;
340 } else {
341 dst_bf = BIT(IEEE802154_ADDR_MODE_EXTENDED);
342 }
343
344 break;
345 case IEEE802154_CFI_GTS_REQUEST:
346 len += IEEE802154_GTS_REQUEST_LENGTH;
347 ack_requested = true;
348 src_bf = BIT(IEEE802154_ADDR_MODE_SHORT);
349 dst_bf = BIT(IEEE802154_ADDR_MODE_NONE);
350
351 break;
352 default:
353 return false;
354 }
355
356 if (length < len) {
357 return false;
358 }
359
360 if (!validate_mac_command_cfi_to_mhr(&mpdu->mhr, ack_requested, has_pan_id, src_bf,
361 src_pan_brdcst_chk, dst_bf,
362 dst_brdcst_chk)) {
363 return false;
364 }
365
366 mpdu->command = command;
367
368 return true;
369 }
370
validate_payload_and_mfr(struct ieee802154_mpdu * mpdu,uint8_t * buf,uint8_t * p_buf,uint8_t length)371 static inline bool validate_payload_and_mfr(struct ieee802154_mpdu *mpdu, uint8_t *buf,
372 uint8_t *p_buf, uint8_t length)
373 {
374 uint8_t type = mpdu->mhr.fs->fc.frame_type;
375
376 NET_DBG("Header size: %u, payload size %u", (uint32_t)(p_buf - buf), length);
377
378 if (type == IEEE802154_FRAME_TYPE_BEACON) {
379 if (ieee802514_beacon_header_length(p_buf, length) < 0) {
380 return false;
381 }
382 } else if (type == IEEE802154_FRAME_TYPE_DATA) {
383 /** A data frame embeds a payload */
384 if (length == 0U) {
385 return false;
386 }
387 } else if (type == IEEE802154_FRAME_TYPE_ACK) {
388 /** An ACK frame has no payload */
389 if (length) {
390 return false;
391 }
392 } else {
393 if (!validate_mac_command(mpdu, p_buf, length)) {
394 return false;
395 }
396 }
397
398 mpdu->payload_length = length;
399
400 if (length) {
401 mpdu->payload = (void *)p_buf;
402 } else {
403 mpdu->payload = NULL;
404 }
405
406 return true;
407 }
408
ieee802154_validate_frame(uint8_t * buf,uint8_t length,struct ieee802154_mpdu * mpdu)409 bool ieee802154_validate_frame(uint8_t *buf, uint8_t length, struct ieee802154_mpdu *mpdu)
410 {
411 uint8_t *p_buf = NULL;
412
413 if (length > IEEE802154_MTU || length < IEEE802154_MIN_LENGTH) {
414 NET_DBG("Wrong packet length: %d", length);
415 return false;
416 }
417
418 mpdu->mhr.fs = ieee802154_validate_fc_seq(buf, &p_buf, &length);
419 if (!mpdu->mhr.fs) {
420 return false;
421 }
422
423 /* TODO: Support later version's frame types */
424 if (mpdu->mhr.fs->fc.frame_type > IEEE802154_FRAME_TYPE_MAC_COMMAND) {
425 return false;
426 }
427
428 if (!validate_addr(p_buf, &p_buf, &length, mpdu->mhr.fs->fc.dst_addr_mode, false,
429 &mpdu->mhr.dst_addr) ||
430 !validate_addr(p_buf, &p_buf, &length, mpdu->mhr.fs->fc.src_addr_mode,
431 (mpdu->mhr.fs->fc.pan_id_comp), &mpdu->mhr.src_addr)) {
432 return false;
433 }
434
435 #ifdef CONFIG_NET_L2_IEEE802154_SECURITY
436 if (mpdu->mhr.fs->fc.security_enabled) {
437 mpdu->mhr.aux_sec = ieee802154_validate_aux_security_hdr(p_buf, &p_buf, &length);
438 if (!mpdu->mhr.aux_sec) {
439 return false;
440 }
441 }
442 #endif
443
444 return validate_payload_and_mfr(mpdu, buf, p_buf, length);
445 }
446
ieee802154_compute_header_and_authtag_len(struct net_if * iface,struct net_linkaddr * dst,struct net_linkaddr * src,uint8_t * ll_hdr_len,uint8_t * authtag_len)447 void ieee802154_compute_header_and_authtag_len(struct net_if *iface, struct net_linkaddr *dst,
448 struct net_linkaddr *src, uint8_t *ll_hdr_len,
449 uint8_t *authtag_len)
450 {
451 uint8_t hdr_len = sizeof(struct ieee802154_fcf_seq), tag_len = 0;
452 bool broadcast = !dst->addr;
453
454 /* PAN ID */
455 hdr_len += IEEE802154_PAN_ID_LENGTH;
456
457 /* Destination Address - see get_dst_addr_mode() */
458 hdr_len += broadcast ? IEEE802154_SHORT_ADDR_LENGTH : dst->len;
459
460 /* Source Address - see data_addr_to_fs_settings() */
461 hdr_len += src->addr ? src->len : dst->len;
462
463 #ifdef CONFIG_NET_L2_IEEE802154_SECURITY
464 if (broadcast) {
465 NET_DBG("Broadcast packets are not being encrypted.");
466 goto done;
467 }
468
469 struct ieee802154_context *ctx = (struct ieee802154_context *)net_if_l2_data(iface);
470
471 k_sem_take(&ctx->ctx_lock, K_FOREVER);
472
473 struct ieee802154_security_ctx *sec_ctx = &ctx->sec_ctx;
474 if (sec_ctx->level == IEEE802154_SECURITY_LEVEL_NONE) {
475 goto release;
476 }
477
478 /* Compute aux-sec hdr size and add it to hdr_len */
479 hdr_len += IEEE802154_SECURITY_CF_LENGTH + IEEE802154_SECURITY_FRAME_COUNTER_LENGTH;
480
481 switch (sec_ctx->key_mode) {
482 case IEEE802154_KEY_ID_MODE_IMPLICIT:
483 /* The only mode supported for now,
484 * generate_aux_securiy_hdr() will fail on other modes
485 */
486 break;
487 case IEEE802154_KEY_ID_MODE_INDEX:
488 hdr_len += IEEE802154_KEY_ID_FIELD_INDEX_LENGTH;
489 break;
490 case IEEE802154_KEY_ID_MODE_SRC_4_INDEX:
491 hdr_len += IEEE802154_KEY_ID_FIELD_SRC_4_INDEX_LENGTH;
492 break;
493 case IEEE802154_KEY_ID_MODE_SRC_8_INDEX:
494 hdr_len += IEEE802154_KEY_ID_FIELD_SRC_8_INDEX_LENGTH;
495 }
496
497 if (sec_ctx->level < IEEE802154_SECURITY_LEVEL_ENC) {
498 tag_len = level_2_authtag_len[sec_ctx->level];
499 } else {
500 tag_len = level_2_authtag_len[sec_ctx->level - 4U];
501 }
502
503 release:
504 k_sem_give(&ctx->ctx_lock);
505 done:
506 #endif /* CONFIG_NET_L2_IEEE802154_SECURITY */
507
508 NET_DBG("Computed header size %u", hdr_len);
509 NET_DBG("Computed authtag size: %u", tag_len);
510
511 *ll_hdr_len = hdr_len;
512 *authtag_len = tag_len;
513 }
514
generate_fcf_grounds(uint8_t ** p_buf,bool ack_requested)515 static inline struct ieee802154_fcf_seq *generate_fcf_grounds(uint8_t **p_buf, bool ack_requested)
516 {
517 struct ieee802154_fcf_seq *fs;
518
519 fs = (struct ieee802154_fcf_seq *)*p_buf;
520
521 fs->fc.security_enabled = 0U;
522 fs->fc.frame_pending = 0U;
523 fs->fc.ar = ack_requested;
524 fs->fc.pan_id_comp = 0U;
525 fs->fc.reserved = 0U;
526 /* We support version 2006 only for now */
527 fs->fc.seq_num_suppr = 0U;
528 fs->fc.ie_list = 0U;
529 fs->fc.frame_version = IEEE802154_VERSION_802154_2006;
530
531 *p_buf += sizeof(struct ieee802154_fcf_seq);
532
533 return fs;
534 }
535
get_dst_addr_mode(struct net_linkaddr * dst,bool * broadcast)536 static inline enum ieee802154_addressing_mode get_dst_addr_mode(struct net_linkaddr *dst,
537 bool *broadcast)
538 {
539 if (!dst->addr) {
540 NET_DBG("Broadcast destination");
541 *broadcast = true;
542 return IEEE802154_ADDR_MODE_SHORT;
543 }
544
545 if (dst->len == IEEE802154_SHORT_ADDR_LENGTH) {
546 uint16_t short_addr = ntohs(*(uint16_t *)(dst->addr));
547 *broadcast = (short_addr == IEEE802154_BROADCAST_ADDRESS);
548 return IEEE802154_ADDR_MODE_SHORT;
549 } else {
550 *broadcast = false;
551 }
552
553 if (dst->len == IEEE802154_EXT_ADDR_LENGTH) {
554 return IEEE802154_ADDR_MODE_EXTENDED;
555 }
556
557 return IEEE802154_ADDR_MODE_NONE;
558 }
559
data_addr_to_fs_settings(struct net_linkaddr * dst,struct ieee802154_fcf_seq * fs,struct ieee802154_frame_params * params)560 static inline bool data_addr_to_fs_settings(struct net_linkaddr *dst, struct ieee802154_fcf_seq *fs,
561 struct ieee802154_frame_params *params)
562 {
563 bool broadcast;
564
565 fs->fc.dst_addr_mode = get_dst_addr_mode(dst, &broadcast);
566 if (fs->fc.dst_addr_mode != IEEE802154_ADDR_MODE_NONE) {
567 fs->fc.pan_id_comp = 1U;
568
569 if (broadcast) {
570 params->dst.short_addr = IEEE802154_BROADCAST_ADDRESS;
571 params->dst.len = IEEE802154_SHORT_ADDR_LENGTH;
572 fs->fc.ar = 0U;
573 } else if (dst->len == IEEE802154_SHORT_ADDR_LENGTH) {
574 params->dst.short_addr = ntohs(*(uint16_t *)(dst->addr));
575 params->dst.len = IEEE802154_SHORT_ADDR_LENGTH;
576 } else {
577 __ASSERT_NO_MSG(dst->len == IEEE802154_EXT_ADDR_LENGTH);
578 memcpy(params->dst.ext_addr, dst->addr, sizeof(params->dst.ext_addr));
579 params->dst.len = IEEE802154_EXT_ADDR_LENGTH;
580 }
581 }
582
583 if (params->short_addr) {
584 fs->fc.src_addr_mode = IEEE802154_ADDR_MODE_SHORT;
585 } else {
586 fs->fc.src_addr_mode = IEEE802154_ADDR_MODE_EXTENDED;
587 }
588
589 return broadcast;
590 }
591
generate_addressing_fields(struct ieee802154_context * ctx,struct ieee802154_fcf_seq * fs,struct ieee802154_frame_params * params,uint8_t * p_buf)592 static uint8_t *generate_addressing_fields(struct ieee802154_context *ctx,
593 struct ieee802154_fcf_seq *fs,
594 struct ieee802154_frame_params *params, uint8_t *p_buf)
595 {
596 struct ieee802154_address_field *address_field;
597
598 /* destination address */
599 if (fs->fc.dst_addr_mode != IEEE802154_ADDR_MODE_NONE) {
600 address_field = (struct ieee802154_address_field *)p_buf;
601
602 address_field->plain.pan_id = sys_cpu_to_le16(params->dst.pan_id);
603 p_buf += IEEE802154_PAN_ID_LENGTH;
604
605 if (fs->fc.dst_addr_mode == IEEE802154_ADDR_MODE_SHORT) {
606 address_field->plain.addr.short_addr =
607 sys_cpu_to_le16(params->dst.short_addr);
608 p_buf += IEEE802154_SHORT_ADDR_LENGTH;
609 } else {
610 sys_memcpy_swap(address_field->plain.addr.ext_addr, params->dst.ext_addr,
611 IEEE802154_EXT_ADDR_LENGTH);
612 p_buf += IEEE802154_EXT_ADDR_LENGTH;
613 }
614 }
615
616 /* source address */
617 if (fs->fc.src_addr_mode == IEEE802154_ADDR_MODE_NONE) {
618 return p_buf;
619 }
620
621 address_field = (struct ieee802154_address_field *)p_buf;
622 struct ieee802154_address *src_addr;
623
624 if (fs->fc.pan_id_comp) {
625 src_addr = &address_field->comp.addr;
626 } else {
627 address_field->plain.pan_id = sys_cpu_to_le16(params->pan_id);
628 src_addr = &address_field->plain.addr;
629 p_buf += IEEE802154_PAN_ID_LENGTH;
630 }
631
632 if (fs->fc.src_addr_mode == IEEE802154_ADDR_MODE_SHORT) {
633 src_addr->short_addr = sys_cpu_to_le16(params->short_addr);
634 p_buf += IEEE802154_SHORT_ADDR_LENGTH;
635 } else {
636 memcpy(src_addr->ext_addr, ctx->ext_addr, IEEE802154_EXT_ADDR_LENGTH);
637 p_buf += IEEE802154_EXT_ADDR_LENGTH;
638 }
639
640 return p_buf;
641 }
642
643 #ifdef CONFIG_NET_L2_IEEE802154_SECURITY
generate_aux_security_hdr(struct ieee802154_security_ctx * sec_ctx,uint8_t * p_buf)644 static uint8_t *generate_aux_security_hdr(struct ieee802154_security_ctx *sec_ctx, uint8_t *p_buf)
645 {
646 struct ieee802154_aux_security_hdr *aux_sec;
647
648 if (sec_ctx->level == IEEE802154_SECURITY_LEVEL_NONE) {
649 return p_buf;
650 }
651
652 if (sec_ctx->key_mode != IEEE802154_KEY_ID_MODE_IMPLICIT) {
653 /* TODO: Support other key ID modes. */
654 return NULL;
655 }
656
657 aux_sec = (struct ieee802154_aux_security_hdr *)p_buf;
658
659 aux_sec->control.security_level = sec_ctx->level;
660 aux_sec->control.key_id_mode = sec_ctx->key_mode;
661 aux_sec->control.reserved = 0U;
662
663 aux_sec->frame_counter = sys_cpu_to_le32(sec_ctx->frame_counter);
664
665 return p_buf + IEEE802154_SECURITY_CF_LENGTH + IEEE802154_SECURITY_FRAME_COUNTER_LENGTH;
666 }
667 #endif /* CONFIG_NET_L2_IEEE802154_SECURITY */
668
ieee802154_create_data_frame(struct ieee802154_context * ctx,struct net_linkaddr * dst,struct net_linkaddr * src,struct net_buf * buf,uint8_t ll_hdr_len)669 bool ieee802154_create_data_frame(struct ieee802154_context *ctx, struct net_linkaddr *dst,
670 struct net_linkaddr *src, struct net_buf *buf, uint8_t ll_hdr_len)
671 {
672 struct ieee802154_frame_params params = {0};
673 struct ieee802154_fcf_seq *fs;
674 uint8_t *p_buf = buf->data;
675 uint8_t *buf_start = p_buf;
676 bool ret = false;
677 bool broadcast;
678
679 k_sem_take(&ctx->ctx_lock, K_FOREVER);
680
681 fs = generate_fcf_grounds(&p_buf, ctx->ack_requested);
682
683 fs->fc.frame_type = IEEE802154_FRAME_TYPE_DATA;
684 fs->sequence = ctx->sequence++;
685
686 params.dst.pan_id = ctx->pan_id;
687 params.pan_id = ctx->pan_id;
688 if (src->addr && src->len == IEEE802154_SHORT_ADDR_LENGTH) {
689 params.short_addr = ntohs(*(uint16_t *)(src->addr));
690 if (ctx->short_addr != params.short_addr) {
691 goto out;
692 }
693 } else {
694 if (src->len != IEEE802154_EXT_ADDR_LENGTH) {
695 goto out;
696 }
697
698 uint8_t ext_addr_le[IEEE802154_EXT_ADDR_LENGTH];
699
700 sys_memcpy_swap(ext_addr_le, src->addr, IEEE802154_EXT_ADDR_LENGTH);
701 if (memcmp(ctx->ext_addr, ext_addr_le, src->len)) {
702 goto out;
703 }
704 }
705
706 broadcast = data_addr_to_fs_settings(dst, fs, ¶ms);
707
708 p_buf = generate_addressing_fields(ctx, fs, ¶ms, p_buf);
709
710 #ifdef CONFIG_NET_L2_IEEE802154_SECURITY
711 if (broadcast) {
712 /* TODO: This may not always be correct. */
713 NET_DBG("No security hdr needed: broadcasting");
714 goto no_security_hdr;
715 }
716
717 if (ctx->sec_ctx.level == IEEE802154_SECURITY_LEVEL_NONE) {
718 NET_WARN("IEEE 802.15.4 security is enabled but has not been configured.");
719 goto no_security_hdr;
720 }
721
722 fs->fc.security_enabled = 1U;
723
724 p_buf = generate_aux_security_hdr(&ctx->sec_ctx, p_buf);
725 if (!p_buf) {
726 NET_ERR("Unsupported key mode.");
727 goto out;
728 }
729
730 uint8_t level = ctx->sec_ctx.level;
731
732 if (level >= IEEE802154_SECURITY_LEVEL_ENC) {
733 level -= 4U;
734 }
735
736 uint8_t authtag_len = level_2_authtag_len[level];
737 uint8_t payload_len = buf->len - ll_hdr_len - authtag_len;
738
739 /* Let's encrypt/auth only in the end, if needed */
740 if (!ieee802154_encrypt_auth(&ctx->sec_ctx, buf_start, ll_hdr_len,
741 payload_len, authtag_len, ctx->ext_addr)) {
742 goto out;
743 };
744
745 no_security_hdr:
746 #endif /* CONFIG_NET_L2_IEEE802154_SECURITY */
747 if ((p_buf - buf_start) != ll_hdr_len) {
748 /* ll_hdr_len was too small? We probably overwrote payload bytes */
749 NET_ERR("Could not generate data frame %zu vs %u", (p_buf - buf_start), ll_hdr_len);
750 goto out;
751 }
752
753 dbg_print_fs(fs);
754
755 ret = true;
756
757 out:
758 k_sem_give(&ctx->ctx_lock);
759 return ret;
760 }
761
762 #ifdef CONFIG_NET_L2_IEEE802154_RFD
763
cfi_to_fs_settings(enum ieee802154_cfi cfi,struct ieee802154_fcf_seq * fs,struct ieee802154_frame_params * params)764 static inline bool cfi_to_fs_settings(enum ieee802154_cfi cfi, struct ieee802154_fcf_seq *fs,
765 struct ieee802154_frame_params *params)
766 {
767 switch (cfi) {
768 case IEEE802154_CFI_DISASSOCIATION_NOTIFICATION:
769 fs->fc.pan_id_comp = 1U;
770
771 __fallthrough;
772 case IEEE802154_CFI_ASSOCIATION_REQUEST:
773 fs->fc.ar = 1U;
774 fs->fc.src_addr_mode = IEEE802154_ADDR_MODE_EXTENDED;
775
776 if (params->dst.len == IEEE802154_SHORT_ADDR_LENGTH) {
777 fs->fc.dst_addr_mode = IEEE802154_ADDR_MODE_SHORT;
778 } else {
779 fs->fc.dst_addr_mode = IEEE802154_ADDR_MODE_EXTENDED;
780 }
781
782 break;
783 case IEEE802154_CFI_ASSOCIATION_RESPONSE:
784 case IEEE802154_CFI_PAN_ID_CONFLICT_NOTIFICATION:
785 fs->fc.ar = 1U;
786 fs->fc.pan_id_comp = 1U;
787 fs->fc.src_addr_mode = IEEE802154_ADDR_MODE_EXTENDED;
788 fs->fc.dst_addr_mode = IEEE802154_ADDR_MODE_EXTENDED;
789
790 break;
791 case IEEE802154_CFI_DATA_REQUEST:
792 fs->fc.ar = 1U;
793 /* TODO: src/dst addr mode: see section 7.5.5 */
794
795 break;
796 case IEEE802154_CFI_ORPHAN_NOTIFICATION:
797 fs->fc.pan_id_comp = 1U;
798 fs->fc.src_addr_mode = IEEE802154_ADDR_MODE_EXTENDED;
799 fs->fc.dst_addr_mode = IEEE802154_ADDR_MODE_SHORT;
800
801 break;
802 case IEEE802154_CFI_BEACON_REQUEST:
803 fs->fc.src_addr_mode = IEEE802154_ADDR_MODE_NONE;
804 fs->fc.dst_addr_mode = IEEE802154_ADDR_MODE_SHORT;
805 break;
806 case IEEE802154_CFI_COORDINATOR_REALIGNEMENT:
807 fs->fc.src_addr_mode = IEEE802154_ADDR_MODE_EXTENDED;
808 /* TODO: ack_requested and dst addr mode: see section 7.5.10 */
809
810 break;
811 case IEEE802154_CFI_GTS_REQUEST:
812 fs->fc.ar = 1U;
813 fs->fc.src_addr_mode = IEEE802154_ADDR_MODE_SHORT;
814 fs->fc.dst_addr_mode = IEEE802154_ADDR_MODE_NONE;
815
816 break;
817 default:
818 return false;
819 }
820
821 return true;
822 }
823
mac_command_length(enum ieee802154_cfi cfi)824 static inline uint8_t mac_command_length(enum ieee802154_cfi cfi)
825 {
826 uint8_t length = 1U; /* cfi is at least present */
827
828 switch (cfi) {
829 case IEEE802154_CFI_ASSOCIATION_REQUEST:
830 case IEEE802154_CFI_DISASSOCIATION_NOTIFICATION:
831 case IEEE802154_CFI_GTS_REQUEST:
832 length += 1U;
833 break;
834 case IEEE802154_CFI_ASSOCIATION_RESPONSE:
835 length += 3U;
836 break;
837 case IEEE802154_CFI_COORDINATOR_REALIGNEMENT:
838 length += 8U;
839 break;
840 default:
841 break;
842 }
843
844 return length;
845 }
846
ieee802154_create_mac_cmd_frame(struct net_if * iface,enum ieee802154_cfi type,struct ieee802154_frame_params * params)847 struct net_pkt *ieee802154_create_mac_cmd_frame(struct net_if *iface, enum ieee802154_cfi type,
848 struct ieee802154_frame_params *params)
849 {
850 struct ieee802154_context *ctx = net_if_l2_data(iface);
851 struct ieee802154_fcf_seq *fs;
852 struct net_pkt *pkt = NULL;
853 uint8_t *p_buf, *p_start;
854
855 k_sem_take(&ctx->ctx_lock, K_FOREVER);
856
857 /* It would be costly to compute the size when actual frames are never
858 * bigger than IEEE802154_MTU bytes less the FCS size, so let's allocate that
859 * size as buffer.
860 */
861 pkt = net_pkt_alloc_with_buffer(iface, IEEE802154_MTU, AF_UNSPEC, 0, BUF_TIMEOUT);
862 if (!pkt) {
863 goto out;
864 }
865
866 p_buf = net_pkt_data(pkt);
867 p_start = p_buf;
868
869 fs = generate_fcf_grounds(
870 &p_buf, type == IEEE802154_CFI_BEACON_REQUEST ? false : ctx->ack_requested);
871
872 fs->fc.frame_type = IEEE802154_FRAME_TYPE_MAC_COMMAND;
873 fs->sequence = ctx->sequence++;
874
875 if (!cfi_to_fs_settings(type, fs, params)) {
876 goto error;
877 }
878
879 p_buf = generate_addressing_fields(ctx, fs, params, p_buf);
880
881 net_buf_add(pkt->buffer, p_buf - p_start);
882
883 /* Let's insert the cfi */
884 ((struct ieee802154_command *)p_buf)->cfi = type;
885
886 dbg_print_fs(fs);
887
888 goto out;
889
890 error:
891 net_pkt_unref(pkt);
892 pkt = NULL;
893
894 out:
895 k_sem_give(&ctx->ctx_lock);
896 return pkt;
897 }
898
ieee802154_mac_cmd_finalize(struct net_pkt * pkt,enum ieee802154_cfi type)899 void ieee802154_mac_cmd_finalize(struct net_pkt *pkt, enum ieee802154_cfi type)
900 {
901 net_buf_add(pkt->buffer, mac_command_length(type));
902 }
903
904 #endif /* CONFIG_NET_L2_IEEE802154_RFD */
905
ieee802154_create_ack_frame(struct net_if * iface,struct net_pkt * pkt,uint8_t seq)906 bool ieee802154_create_ack_frame(struct net_if *iface, struct net_pkt *pkt, uint8_t seq)
907 {
908 uint8_t *p_buf = net_pkt_data(pkt);
909 struct ieee802154_fcf_seq *fs;
910
911 if (!p_buf) {
912 return false;
913 }
914
915 fs = generate_fcf_grounds(&p_buf, false);
916
917 fs->fc.dst_addr_mode = IEEE802154_ADDR_MODE_NONE;
918 fs->fc.src_addr_mode = IEEE802154_ADDR_MODE_NONE;
919
920 fs->fc.frame_type = IEEE802154_FRAME_TYPE_ACK;
921 fs->sequence = seq;
922
923 net_buf_add(pkt->buffer, IEEE802154_ACK_PKT_LENGTH);
924
925 return true;
926 }
927
928 #ifdef CONFIG_NET_L2_IEEE802154_SECURITY
ieee802154_decipher_data_frame(struct net_if * iface,struct net_pkt * pkt,struct ieee802154_mpdu * mpdu)929 bool ieee802154_decipher_data_frame(struct net_if *iface, struct net_pkt *pkt,
930 struct ieee802154_mpdu *mpdu)
931 {
932 struct ieee802154_context *ctx = net_if_l2_data(iface);
933 bool ret = false;
934
935 k_sem_take(&ctx->ctx_lock, K_FOREVER);
936
937 uint8_t level = ctx->sec_ctx.level;
938
939 if (!mpdu->mhr.fs->fc.security_enabled) {
940 ret = true;
941 goto out;
942 }
943
944 /* Section 9.2.4: Incoming frame security procedure, Security Enabled field is set to one
945 *
946 * [...]
947 *
948 * a) Legacy security. If the Frame Version field of the frame to be unsecured is set to
949 * zero, the procedure shall return with a Status of UNSUPPORTED_LEGACY.
950 */
951 if (mpdu->mhr.aux_sec->control.security_level != level) {
952 goto out;
953 }
954
955 if (level >= IEEE802154_SECURITY_LEVEL_ENC) {
956 level -= 4U;
957 }
958
959 uint8_t authtag_len = level_2_authtag_len[level];
960 uint8_t ll_hdr_len = (uint8_t *)mpdu->payload - net_pkt_data(pkt);
961 uint8_t payload_len = net_pkt_get_len(pkt) - ll_hdr_len - authtag_len;
962 uint8_t ext_addr_le[IEEE802154_EXT_ADDR_LENGTH];
963
964 /* TODO: Handle src short address.
965 * This will require to look up in nbr cache with short addr
966 * in order to get the extended address related to it.
967 */
968 if (net_pkt_lladdr_src(pkt)->len != IEEE802154_EXT_ADDR_LENGTH) {
969 NET_ERR("Decrypting packages with short source addresses is not supported.");
970 goto out;
971 }
972
973 sys_memcpy_swap(ext_addr_le, net_pkt_lladdr_src(pkt)->addr, net_pkt_lladdr_src(pkt)->len);
974 if (!ieee802154_decrypt_auth(&ctx->sec_ctx, net_pkt_data(pkt), ll_hdr_len, payload_len,
975 authtag_len, ext_addr_le,
976 sys_le32_to_cpu(mpdu->mhr.aux_sec->frame_counter))) {
977 NET_ERR("Could not decipher the frame");
978 goto out;
979 }
980
981 /* We remove tag size from buf's length, it is now useless. */
982 pkt->buffer->len -= authtag_len;
983
984 ret = true;
985
986 out:
987 k_sem_give(&ctx->ctx_lock);
988 return ret;
989 }
990 #endif /* CONFIG_NET_L2_IEEE802154_SECURITY */
991