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 struct ieee802154_security_ctx *sec_ctx;
465 struct ieee802154_context *ctx;
466
467 if (broadcast) {
468 NET_DBG("Broadcast packets are not being encrypted.");
469 goto done;
470 }
471
472 ctx = (struct ieee802154_context *)net_if_l2_data(iface);
473
474 k_sem_take(&ctx->ctx_lock, K_FOREVER);
475
476 sec_ctx = &ctx->sec_ctx;
477 if (sec_ctx->level == IEEE802154_SECURITY_LEVEL_NONE) {
478 goto release;
479 }
480
481 /* Compute aux-sec hdr size and add it to hdr_len */
482 hdr_len += IEEE802154_SECURITY_CF_LENGTH + IEEE802154_SECURITY_FRAME_COUNTER_LENGTH;
483
484 switch (sec_ctx->key_mode) {
485 case IEEE802154_KEY_ID_MODE_IMPLICIT:
486 /* The only mode supported for now,
487 * generate_aux_securiy_hdr() will fail on other modes
488 */
489 break;
490 case IEEE802154_KEY_ID_MODE_INDEX:
491 hdr_len += IEEE802154_KEY_ID_FIELD_INDEX_LENGTH;
492 break;
493 case IEEE802154_KEY_ID_MODE_SRC_4_INDEX:
494 hdr_len += IEEE802154_KEY_ID_FIELD_SRC_4_INDEX_LENGTH;
495 break;
496 case IEEE802154_KEY_ID_MODE_SRC_8_INDEX:
497 hdr_len += IEEE802154_KEY_ID_FIELD_SRC_8_INDEX_LENGTH;
498 }
499
500 if (sec_ctx->level < IEEE802154_SECURITY_LEVEL_ENC) {
501 tag_len = level_2_authtag_len[sec_ctx->level];
502 } else {
503 tag_len = level_2_authtag_len[sec_ctx->level - 4U];
504 }
505
506 release:
507 k_sem_give(&ctx->ctx_lock);
508 done:
509 #endif /* CONFIG_NET_L2_IEEE802154_SECURITY */
510
511 NET_DBG("Computed header size %u", hdr_len);
512 NET_DBG("Computed authtag size: %u", tag_len);
513
514 *ll_hdr_len = hdr_len;
515 *authtag_len = tag_len;
516 }
517
generate_fcf_grounds(uint8_t ** p_buf,bool ack_requested)518 static inline struct ieee802154_fcf_seq *generate_fcf_grounds(uint8_t **p_buf, bool ack_requested)
519 {
520 struct ieee802154_fcf_seq *fs;
521
522 fs = (struct ieee802154_fcf_seq *)*p_buf;
523
524 fs->fc.security_enabled = 0U;
525 fs->fc.frame_pending = 0U;
526 fs->fc.ar = ack_requested;
527 fs->fc.pan_id_comp = 0U;
528 fs->fc.reserved = 0U;
529 /* We support version 2006 only for now */
530 fs->fc.seq_num_suppr = 0U;
531 fs->fc.ie_list = 0U;
532 fs->fc.frame_version = IEEE802154_VERSION_802154_2006;
533
534 *p_buf += sizeof(struct ieee802154_fcf_seq);
535
536 return fs;
537 }
538
get_dst_addr_mode(struct net_linkaddr * dst,bool * broadcast)539 static inline enum ieee802154_addressing_mode get_dst_addr_mode(struct net_linkaddr *dst,
540 bool *broadcast)
541 {
542 if (!dst->addr) {
543 NET_DBG("Broadcast destination");
544 *broadcast = true;
545 return IEEE802154_ADDR_MODE_SHORT;
546 }
547
548 if (dst->len == IEEE802154_SHORT_ADDR_LENGTH) {
549 uint16_t short_addr = ntohs(*(uint16_t *)(dst->addr));
550 *broadcast = (short_addr == IEEE802154_BROADCAST_ADDRESS);
551 return IEEE802154_ADDR_MODE_SHORT;
552 } else {
553 *broadcast = false;
554 }
555
556 if (dst->len == IEEE802154_EXT_ADDR_LENGTH) {
557 return IEEE802154_ADDR_MODE_EXTENDED;
558 }
559
560 return IEEE802154_ADDR_MODE_NONE;
561 }
562
data_addr_to_fs_settings(struct net_linkaddr * dst,struct ieee802154_fcf_seq * fs,struct ieee802154_frame_params * params)563 static inline bool data_addr_to_fs_settings(struct net_linkaddr *dst, struct ieee802154_fcf_seq *fs,
564 struct ieee802154_frame_params *params)
565 {
566 bool broadcast;
567
568 fs->fc.dst_addr_mode = get_dst_addr_mode(dst, &broadcast);
569 if (fs->fc.dst_addr_mode != IEEE802154_ADDR_MODE_NONE) {
570 fs->fc.pan_id_comp = 1U;
571
572 if (broadcast) {
573 params->dst.short_addr = IEEE802154_BROADCAST_ADDRESS;
574 params->dst.len = IEEE802154_SHORT_ADDR_LENGTH;
575 fs->fc.ar = 0U;
576 } else if (dst->len == IEEE802154_SHORT_ADDR_LENGTH) {
577 params->dst.short_addr = ntohs(*(uint16_t *)(dst->addr));
578 params->dst.len = IEEE802154_SHORT_ADDR_LENGTH;
579 } else {
580 __ASSERT_NO_MSG(dst->len == IEEE802154_EXT_ADDR_LENGTH);
581 memcpy(params->dst.ext_addr, dst->addr, sizeof(params->dst.ext_addr));
582 params->dst.len = IEEE802154_EXT_ADDR_LENGTH;
583 }
584 }
585
586 if (params->short_addr) {
587 fs->fc.src_addr_mode = IEEE802154_ADDR_MODE_SHORT;
588 } else {
589 fs->fc.src_addr_mode = IEEE802154_ADDR_MODE_EXTENDED;
590 }
591
592 return broadcast;
593 }
594
generate_addressing_fields(struct ieee802154_context * ctx,struct ieee802154_fcf_seq * fs,struct ieee802154_frame_params * params,uint8_t * p_buf)595 static uint8_t *generate_addressing_fields(struct ieee802154_context *ctx,
596 struct ieee802154_fcf_seq *fs,
597 struct ieee802154_frame_params *params, uint8_t *p_buf)
598 {
599 struct ieee802154_address_field *address_field;
600 struct ieee802154_address *src_addr;
601
602 /* destination address */
603 if (fs->fc.dst_addr_mode != IEEE802154_ADDR_MODE_NONE) {
604 address_field = (struct ieee802154_address_field *)p_buf;
605
606 address_field->plain.pan_id = sys_cpu_to_le16(params->dst.pan_id);
607 p_buf += IEEE802154_PAN_ID_LENGTH;
608
609 if (fs->fc.dst_addr_mode == IEEE802154_ADDR_MODE_SHORT) {
610 address_field->plain.addr.short_addr =
611 sys_cpu_to_le16(params->dst.short_addr);
612 p_buf += IEEE802154_SHORT_ADDR_LENGTH;
613 } else {
614 sys_memcpy_swap(address_field->plain.addr.ext_addr, params->dst.ext_addr,
615 IEEE802154_EXT_ADDR_LENGTH);
616 p_buf += IEEE802154_EXT_ADDR_LENGTH;
617 }
618 }
619
620 /* source address */
621 if (fs->fc.src_addr_mode == IEEE802154_ADDR_MODE_NONE) {
622 return p_buf;
623 }
624
625 address_field = (struct ieee802154_address_field *)p_buf;
626
627 if (fs->fc.pan_id_comp) {
628 src_addr = &address_field->comp.addr;
629 } else {
630 address_field->plain.pan_id = sys_cpu_to_le16(params->pan_id);
631 src_addr = &address_field->plain.addr;
632 p_buf += IEEE802154_PAN_ID_LENGTH;
633 }
634
635 if (fs->fc.src_addr_mode == IEEE802154_ADDR_MODE_SHORT) {
636 src_addr->short_addr = sys_cpu_to_le16(params->short_addr);
637 p_buf += IEEE802154_SHORT_ADDR_LENGTH;
638 } else {
639 memcpy(src_addr->ext_addr, ctx->ext_addr, IEEE802154_EXT_ADDR_LENGTH);
640 p_buf += IEEE802154_EXT_ADDR_LENGTH;
641 }
642
643 return p_buf;
644 }
645
646 #ifdef CONFIG_NET_L2_IEEE802154_SECURITY
generate_aux_security_hdr(struct ieee802154_security_ctx * sec_ctx,uint8_t * p_buf)647 static uint8_t *generate_aux_security_hdr(struct ieee802154_security_ctx *sec_ctx, uint8_t *p_buf)
648 {
649 struct ieee802154_aux_security_hdr *aux_sec;
650
651 if (sec_ctx->level == IEEE802154_SECURITY_LEVEL_NONE) {
652 return p_buf;
653 }
654
655 if (sec_ctx->key_mode != IEEE802154_KEY_ID_MODE_IMPLICIT) {
656 /* TODO: Support other key ID modes. */
657 return NULL;
658 }
659
660 aux_sec = (struct ieee802154_aux_security_hdr *)p_buf;
661
662 aux_sec->control.security_level = sec_ctx->level;
663 aux_sec->control.key_id_mode = sec_ctx->key_mode;
664 aux_sec->control.reserved = 0U;
665
666 aux_sec->frame_counter = sys_cpu_to_le32(sec_ctx->frame_counter);
667
668 return p_buf + IEEE802154_SECURITY_CF_LENGTH + IEEE802154_SECURITY_FRAME_COUNTER_LENGTH;
669 }
670 #endif /* CONFIG_NET_L2_IEEE802154_SECURITY */
671
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)672 bool ieee802154_create_data_frame(struct ieee802154_context *ctx, struct net_linkaddr *dst,
673 struct net_linkaddr *src, struct net_buf *buf, uint8_t ll_hdr_len)
674 {
675 struct ieee802154_frame_params params = {0};
676 struct ieee802154_fcf_seq *fs;
677 uint8_t *p_buf = buf->data;
678 uint8_t *buf_start = p_buf;
679 bool ret = false;
680 bool broadcast;
681
682 k_sem_take(&ctx->ctx_lock, K_FOREVER);
683
684 fs = generate_fcf_grounds(&p_buf, ctx->ack_requested);
685
686 fs->fc.frame_type = IEEE802154_FRAME_TYPE_DATA;
687 fs->sequence = ctx->sequence++;
688
689 params.dst.pan_id = ctx->pan_id;
690 params.pan_id = ctx->pan_id;
691 if (src->addr && src->len == IEEE802154_SHORT_ADDR_LENGTH) {
692 params.short_addr = ntohs(*(uint16_t *)(src->addr));
693 if (ctx->short_addr != params.short_addr) {
694 goto out;
695 }
696 } else {
697 uint8_t ext_addr_le[IEEE802154_EXT_ADDR_LENGTH];
698
699 if (src->len != IEEE802154_EXT_ADDR_LENGTH) {
700 goto out;
701 }
702
703 sys_memcpy_swap(ext_addr_le, src->addr, IEEE802154_EXT_ADDR_LENGTH);
704 if (memcmp(ctx->ext_addr, ext_addr_le, src->len)) {
705 goto out;
706 }
707 }
708
709 broadcast = data_addr_to_fs_settings(dst, fs, ¶ms);
710
711 p_buf = generate_addressing_fields(ctx, fs, ¶ms, p_buf);
712
713 #ifdef CONFIG_NET_L2_IEEE802154_SECURITY
714 uint8_t level, authtag_len, payload_len;
715
716 if (broadcast) {
717 /* TODO: This may not always be correct. */
718 NET_DBG("No security hdr needed: broadcasting");
719 goto no_security_hdr;
720 }
721
722 if (ctx->sec_ctx.level == IEEE802154_SECURITY_LEVEL_NONE) {
723 NET_WARN("IEEE 802.15.4 security is enabled but has not been configured.");
724 goto no_security_hdr;
725 }
726
727 fs->fc.security_enabled = 1U;
728
729 p_buf = generate_aux_security_hdr(&ctx->sec_ctx, p_buf);
730 if (!p_buf) {
731 NET_ERR("Unsupported key mode.");
732 goto out;
733 }
734
735 level = ctx->sec_ctx.level;
736 if (level >= IEEE802154_SECURITY_LEVEL_ENC) {
737 level -= 4U;
738 }
739
740 /* Let's encrypt/auth only in the end, if needed */
741 authtag_len = level_2_authtag_len[level];
742 payload_len = buf->len - ll_hdr_len - authtag_len;
743 if (!ieee802154_encrypt_auth(&ctx->sec_ctx, buf_start, ll_hdr_len,
744 payload_len, authtag_len, ctx->ext_addr)) {
745 goto out;
746 };
747
748 no_security_hdr:
749 #endif /* CONFIG_NET_L2_IEEE802154_SECURITY */
750 if ((p_buf - buf_start) != ll_hdr_len) {
751 /* ll_hdr_len was too small? We probably overwrote payload bytes */
752 NET_ERR("Could not generate data frame %zu vs %u", (p_buf - buf_start), ll_hdr_len);
753 goto out;
754 }
755
756 dbg_print_fs(fs);
757
758 ret = true;
759
760 out:
761 k_sem_give(&ctx->ctx_lock);
762 return ret;
763 }
764
765 #ifdef CONFIG_NET_L2_IEEE802154_RFD
766
cfi_to_fs_settings(enum ieee802154_cfi cfi,struct ieee802154_fcf_seq * fs,struct ieee802154_frame_params * params)767 static inline bool cfi_to_fs_settings(enum ieee802154_cfi cfi, struct ieee802154_fcf_seq *fs,
768 struct ieee802154_frame_params *params)
769 {
770 switch (cfi) {
771 case IEEE802154_CFI_DISASSOCIATION_NOTIFICATION:
772 fs->fc.pan_id_comp = 1U;
773
774 __fallthrough;
775 case IEEE802154_CFI_ASSOCIATION_REQUEST:
776 fs->fc.ar = 1U;
777 fs->fc.src_addr_mode = IEEE802154_ADDR_MODE_EXTENDED;
778
779 if (params->dst.len == IEEE802154_SHORT_ADDR_LENGTH) {
780 fs->fc.dst_addr_mode = IEEE802154_ADDR_MODE_SHORT;
781 } else {
782 fs->fc.dst_addr_mode = IEEE802154_ADDR_MODE_EXTENDED;
783 }
784
785 break;
786 case IEEE802154_CFI_ASSOCIATION_RESPONSE:
787 case IEEE802154_CFI_PAN_ID_CONFLICT_NOTIFICATION:
788 fs->fc.ar = 1U;
789 fs->fc.pan_id_comp = 1U;
790 fs->fc.src_addr_mode = IEEE802154_ADDR_MODE_EXTENDED;
791 fs->fc.dst_addr_mode = IEEE802154_ADDR_MODE_EXTENDED;
792
793 break;
794 case IEEE802154_CFI_DATA_REQUEST:
795 fs->fc.ar = 1U;
796 /* TODO: src/dst addr mode: see section 7.5.5 */
797
798 break;
799 case IEEE802154_CFI_ORPHAN_NOTIFICATION:
800 fs->fc.pan_id_comp = 1U;
801 fs->fc.src_addr_mode = IEEE802154_ADDR_MODE_EXTENDED;
802 fs->fc.dst_addr_mode = IEEE802154_ADDR_MODE_SHORT;
803
804 break;
805 case IEEE802154_CFI_BEACON_REQUEST:
806 fs->fc.src_addr_mode = IEEE802154_ADDR_MODE_NONE;
807 fs->fc.dst_addr_mode = IEEE802154_ADDR_MODE_SHORT;
808 break;
809 case IEEE802154_CFI_COORDINATOR_REALIGNEMENT:
810 fs->fc.src_addr_mode = IEEE802154_ADDR_MODE_EXTENDED;
811 /* TODO: ack_requested and dst addr mode: see section 7.5.10 */
812
813 break;
814 case IEEE802154_CFI_GTS_REQUEST:
815 fs->fc.ar = 1U;
816 fs->fc.src_addr_mode = IEEE802154_ADDR_MODE_SHORT;
817 fs->fc.dst_addr_mode = IEEE802154_ADDR_MODE_NONE;
818
819 break;
820 default:
821 return false;
822 }
823
824 return true;
825 }
826
mac_command_length(enum ieee802154_cfi cfi)827 static inline uint8_t mac_command_length(enum ieee802154_cfi cfi)
828 {
829 uint8_t length = 1U; /* cfi is at least present */
830
831 switch (cfi) {
832 case IEEE802154_CFI_ASSOCIATION_REQUEST:
833 case IEEE802154_CFI_DISASSOCIATION_NOTIFICATION:
834 case IEEE802154_CFI_GTS_REQUEST:
835 length += 1U;
836 break;
837 case IEEE802154_CFI_ASSOCIATION_RESPONSE:
838 length += 3U;
839 break;
840 case IEEE802154_CFI_COORDINATOR_REALIGNEMENT:
841 length += 8U;
842 break;
843 default:
844 break;
845 }
846
847 return length;
848 }
849
ieee802154_create_mac_cmd_frame(struct net_if * iface,enum ieee802154_cfi type,struct ieee802154_frame_params * params)850 struct net_pkt *ieee802154_create_mac_cmd_frame(struct net_if *iface, enum ieee802154_cfi type,
851 struct ieee802154_frame_params *params)
852 {
853 struct ieee802154_context *ctx = net_if_l2_data(iface);
854 struct ieee802154_fcf_seq *fs;
855 struct net_pkt *pkt = NULL;
856 uint8_t *p_buf, *p_start;
857
858 k_sem_take(&ctx->ctx_lock, K_FOREVER);
859
860 /* It would be costly to compute the size when actual frames are never
861 * bigger than IEEE802154_MTU bytes less the FCS size, so let's allocate that
862 * size as buffer.
863 */
864 pkt = net_pkt_alloc_with_buffer(iface, IEEE802154_MTU, AF_UNSPEC, 0, BUF_TIMEOUT);
865 if (!pkt) {
866 goto out;
867 }
868
869 p_buf = net_pkt_data(pkt);
870 p_start = p_buf;
871
872 fs = generate_fcf_grounds(
873 &p_buf, type == IEEE802154_CFI_BEACON_REQUEST ? false : ctx->ack_requested);
874
875 fs->fc.frame_type = IEEE802154_FRAME_TYPE_MAC_COMMAND;
876 fs->sequence = ctx->sequence++;
877
878 if (!cfi_to_fs_settings(type, fs, params)) {
879 goto error;
880 }
881
882 p_buf = generate_addressing_fields(ctx, fs, params, p_buf);
883
884 net_buf_add(pkt->buffer, p_buf - p_start);
885
886 /* Let's insert the cfi */
887 ((struct ieee802154_command *)p_buf)->cfi = type;
888
889 dbg_print_fs(fs);
890
891 goto out;
892
893 error:
894 net_pkt_unref(pkt);
895 pkt = NULL;
896
897 out:
898 k_sem_give(&ctx->ctx_lock);
899 return pkt;
900 }
901
ieee802154_mac_cmd_finalize(struct net_pkt * pkt,enum ieee802154_cfi type)902 void ieee802154_mac_cmd_finalize(struct net_pkt *pkt, enum ieee802154_cfi type)
903 {
904 net_buf_add(pkt->buffer, mac_command_length(type));
905 }
906
907 #endif /* CONFIG_NET_L2_IEEE802154_RFD */
908
ieee802154_create_ack_frame(struct net_if * iface,struct net_pkt * pkt,uint8_t seq)909 bool ieee802154_create_ack_frame(struct net_if *iface, struct net_pkt *pkt, uint8_t seq)
910 {
911 uint8_t *p_buf = net_pkt_data(pkt);
912 struct ieee802154_fcf_seq *fs;
913
914 if (!p_buf) {
915 return false;
916 }
917
918 fs = generate_fcf_grounds(&p_buf, false);
919
920 fs->fc.dst_addr_mode = IEEE802154_ADDR_MODE_NONE;
921 fs->fc.src_addr_mode = IEEE802154_ADDR_MODE_NONE;
922
923 fs->fc.frame_type = IEEE802154_FRAME_TYPE_ACK;
924 fs->sequence = seq;
925
926 net_buf_add(pkt->buffer, IEEE802154_ACK_PKT_LENGTH);
927
928 return true;
929 }
930
931 #ifdef CONFIG_NET_L2_IEEE802154_SECURITY
ieee802154_decipher_data_frame(struct net_if * iface,struct net_pkt * pkt,struct ieee802154_mpdu * mpdu)932 bool ieee802154_decipher_data_frame(struct net_if *iface, struct net_pkt *pkt,
933 struct ieee802154_mpdu *mpdu)
934 {
935 struct ieee802154_context *ctx = net_if_l2_data(iface);
936 uint8_t level, authtag_len, ll_hdr_len, payload_len;
937 struct ieee802154_mhr *mhr = &mpdu->mhr;
938 struct ieee802154_address *src;
939 bool ret = false;
940
941 k_sem_take(&ctx->ctx_lock, K_FOREVER);
942
943 if (!mhr->fs->fc.security_enabled) {
944 ret = true;
945 goto out;
946 }
947
948 level = ctx->sec_ctx.level;
949
950 /* Section 9.2.4: Incoming frame security procedure, Security Enabled field is set to one
951 *
952 * [...]
953 *
954 * a) Legacy security. If the Frame Version field of the frame to be unsecured is set to
955 * zero, the procedure shall return with a Status of UNSUPPORTED_LEGACY.
956 */
957 if (mhr->aux_sec->control.security_level != level) {
958 goto out;
959 }
960
961 if (level >= IEEE802154_SECURITY_LEVEL_ENC) {
962 level -= 4U;
963 }
964
965 authtag_len = level_2_authtag_len[level];
966 ll_hdr_len = (uint8_t *)mpdu->payload - net_pkt_data(pkt);
967 payload_len = net_pkt_get_len(pkt) - ll_hdr_len - authtag_len;
968
969 /* TODO: Handle src short address.
970 * This will require to look up in nbr cache with short addr
971 * in order to get the extended address related to it.
972 */
973 if (mhr->fs->fc.src_addr_mode != IEEE802154_ADDR_MODE_EXTENDED) {
974 NET_ERR("Only encrypting packages with extended source addresses is supported.");
975 goto out;
976 }
977
978 src = mhr->fs->fc.pan_id_comp ? &mhr->src_addr->comp.addr : &mhr->src_addr->plain.addr;
979
980 if (!ieee802154_decrypt_auth(&ctx->sec_ctx, net_pkt_data(pkt), ll_hdr_len, payload_len,
981 authtag_len, src->ext_addr,
982 sys_le32_to_cpu(mhr->aux_sec->frame_counter))) {
983 NET_ERR("Could not decipher the frame");
984 goto out;
985 }
986
987 /* We remove tag size from buf's length, it is now useless. */
988 pkt->buffer->len -= authtag_len;
989
990 ret = true;
991
992 out:
993 k_sem_give(&ctx->ctx_lock);
994 return ret;
995 }
996 #endif /* CONFIG_NET_L2_IEEE802154_SECURITY */
997