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 layer 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, CONFIG_NET_L2_IEEE802154_LOG_LEVEL);
16
17 #include <errno.h>
18
19 #include <zephyr/net/capture.h>
20 #include <zephyr/net/ethernet.h>
21 #include <zephyr/net/net_core.h>
22 #include <zephyr/net/net_if.h>
23 #include <zephyr/net/net_l2.h>
24 #include <zephyr/net/net_linkaddr.h>
25 #include <zephyr/random/random.h>
26
27 #ifdef CONFIG_NET_6LO
28 #include "ieee802154_6lo.h"
29
30 #include <6lo.h>
31 #include <ipv6.h>
32
33 #ifdef CONFIG_NET_L2_IEEE802154_FRAGMENT
34 #include "ieee802154_6lo_fragment.h"
35 #endif /* CONFIG_NET_L2_IEEE802154_FRAGMENT */
36 #endif /* CONFIG_NET_6LO */
37
38 #include "ieee802154_frame.h"
39 #include "ieee802154_mgmt_priv.h"
40 #include "ieee802154_priv.h"
41 #include "ieee802154_security.h"
42 #include "ieee802154_utils.h"
43
44 #define BUF_TIMEOUT K_MSEC(50)
45
46 NET_BUF_POOL_DEFINE(tx_frame_buf_pool, 1, IEEE802154_MTU, 8, NULL);
47
48 #define PKT_TITLE "IEEE 802.15.4 packet content:"
49 #define TX_PKT_TITLE "> " PKT_TITLE
50 #define RX_PKT_TITLE "< " PKT_TITLE
51
52 #ifdef CONFIG_NET_DEBUG_L2_IEEE802154_DISPLAY_PACKET
53
54 #include "net_private.h"
55
pkt_hexdump(const char * title,struct net_pkt * pkt,bool in)56 static inline void pkt_hexdump(const char *title, struct net_pkt *pkt, bool in)
57 {
58 if (IS_ENABLED(CONFIG_NET_DEBUG_L2_IEEE802154_DISPLAY_PACKET_RX) && in) {
59 net_pkt_hexdump(pkt, title);
60 }
61
62 if (IS_ENABLED(CONFIG_NET_DEBUG_L2_IEEE802154_DISPLAY_PACKET_TX) && !in) {
63 net_pkt_hexdump(pkt, title);
64 }
65 }
66
67 #else
68 #define pkt_hexdump(...)
69 #endif /* CONFIG_NET_DEBUG_L2_IEEE802154_DISPLAY_PACKET */
70
ieee802154_acknowledge(struct net_if * iface,struct ieee802154_mpdu * mpdu)71 static inline void ieee802154_acknowledge(struct net_if *iface, struct ieee802154_mpdu *mpdu)
72 {
73 struct net_pkt *pkt;
74
75 if (ieee802154_radio_get_hw_capabilities(iface) & IEEE802154_HW_RX_TX_ACK) {
76 return;
77 }
78
79 if (!mpdu->mhr.fs->fc.ar) {
80 return;
81 }
82
83 pkt = net_pkt_alloc_with_buffer(iface, IEEE802154_ACK_PKT_LENGTH, AF_UNSPEC, 0,
84 BUF_TIMEOUT);
85 if (!pkt) {
86 return;
87 }
88
89 if (ieee802154_create_ack_frame(iface, pkt, mpdu->mhr.fs->sequence)) {
90 /* ACK frames must not use the CSMA/CA procedure, see section 6.2.5.1. */
91 ieee802154_radio_tx(iface, IEEE802154_TX_MODE_DIRECT, pkt, pkt->buffer);
92 }
93
94 net_pkt_unref(pkt);
95
96 return;
97 }
98
ieee802154_prepare_for_ack(struct net_if * iface,struct net_pkt * pkt,struct net_buf * frag)99 inline bool ieee802154_prepare_for_ack(struct net_if *iface, struct net_pkt *pkt,
100 struct net_buf *frag)
101 {
102 bool ack_required = ieee802154_is_ar_flag_set(frag);
103
104 if (ieee802154_radio_get_hw_capabilities(iface) & IEEE802154_HW_TX_RX_ACK) {
105 return ack_required;
106 }
107
108 if (ack_required) {
109 struct ieee802154_fcf_seq *fs = (struct ieee802154_fcf_seq *)frag->data;
110 struct ieee802154_context *ctx = net_if_l2_data(iface);
111
112 ctx->ack_seq = fs->sequence;
113 if (k_sem_count_get(&ctx->ack_lock) == 1U) {
114 k_sem_take(&ctx->ack_lock, K_NO_WAIT);
115 }
116
117 return true;
118 }
119
120 return false;
121 }
122
ieee802154_handle_ack(struct net_if * iface,struct net_pkt * pkt)123 enum net_verdict ieee802154_handle_ack(struct net_if *iface, struct net_pkt *pkt)
124 {
125 struct ieee802154_context *ctx = net_if_l2_data(iface);
126
127 if (ieee802154_radio_get_hw_capabilities(iface) & IEEE802154_HW_TX_RX_ACK) {
128 __ASSERT_NO_MSG(ctx->ack_seq == 0U);
129 /* TODO: Release packet in L2 as we're taking ownership. */
130 return NET_OK;
131 }
132
133 if (pkt->buffer->len == IEEE802154_ACK_PKT_LENGTH) {
134 uint8_t len = IEEE802154_ACK_PKT_LENGTH;
135 struct ieee802154_fcf_seq *fs;
136
137 fs = ieee802154_validate_fc_seq(net_pkt_data(pkt), NULL, &len);
138 if (!fs || fs->fc.frame_type != IEEE802154_FRAME_TYPE_ACK ||
139 fs->sequence != ctx->ack_seq) {
140 return NET_CONTINUE;
141 }
142
143 k_sem_give(&ctx->ack_lock);
144
145 /* TODO: Release packet in L2 as we're taking ownership. */
146 return NET_OK;
147 }
148
149 return NET_CONTINUE;
150 }
151
ieee802154_wait_for_ack(struct net_if * iface,bool ack_required)152 inline int ieee802154_wait_for_ack(struct net_if *iface, bool ack_required)
153 {
154 struct ieee802154_context *ctx = net_if_l2_data(iface);
155 int ret;
156
157 if (!ack_required ||
158 (ieee802154_radio_get_hw_capabilities(iface) & IEEE802154_HW_TX_RX_ACK)) {
159 __ASSERT_NO_MSG(ctx->ack_seq == 0U);
160 return 0;
161 }
162
163 ret = k_sem_take(&ctx->ack_lock, K_MSEC(10));
164 if (ret == 0) {
165 /* no-op */
166 } else if (ret == -EAGAIN) {
167 ret = -ETIME;
168 } else {
169 NET_ERR("Error while waiting for ACK.");
170 ret = -EFAULT;
171 }
172
173 ctx->ack_seq = 0U;
174 return ret;
175 }
176
ieee802154_radio_send(struct net_if * iface,struct net_pkt * pkt,struct net_buf * frag)177 int ieee802154_radio_send(struct net_if *iface, struct net_pkt *pkt, struct net_buf *frag)
178 {
179 uint8_t remaining_attempts = CONFIG_NET_L2_IEEE802154_RADIO_TX_RETRIES + 1;
180 bool hw_csma, ack_required;
181 int ret;
182
183 NET_DBG("frag %p", frag);
184
185 if (ieee802154_radio_get_hw_capabilities(iface) & IEEE802154_HW_RETRANSMISSION) {
186 /* A driver that claims retransmission capability must also be able
187 * to wait for ACK frames otherwise it could not decide whether or
188 * not retransmission is required in a standard conforming way.
189 */
190 __ASSERT_NO_MSG(ieee802154_radio_get_hw_capabilities(iface) &
191 IEEE802154_HW_TX_RX_ACK);
192 remaining_attempts = 1;
193 }
194
195 hw_csma = IS_ENABLED(CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA) &&
196 ieee802154_radio_get_hw_capabilities(iface) & IEEE802154_HW_CSMA;
197
198 /* Media access (CSMA, ALOHA, ...) and retransmission, see section 6.7.4.4. */
199 while (remaining_attempts) {
200 if (!hw_csma) {
201 ret = ieee802154_wait_for_clear_channel(iface);
202 if (ret != 0) {
203 NET_WARN("Clear channel assessment failed: dropping fragment %p on "
204 "interface %p.",
205 frag, iface);
206 return ret;
207 }
208 }
209
210 /* No-op in case the driver has IEEE802154_HW_TX_RX_ACK capability. */
211 ack_required = ieee802154_prepare_for_ack(iface, pkt, frag);
212
213 /* TX including:
214 * - CSMA/CA in case the driver has IEEE802154_HW_CSMA capability,
215 * - waiting for ACK in case the driver has IEEE802154_HW_TX_RX_ACK capability,
216 * - retransmission on ACK timeout in case the driver has
217 * IEEE802154_HW_RETRANSMISSION capability.
218 */
219 ret = ieee802154_radio_tx(
220 iface, hw_csma ? IEEE802154_TX_MODE_CSMA_CA : IEEE802154_TX_MODE_DIRECT,
221 pkt, frag);
222 if (ret) {
223 /* Transmission failure. */
224 return ret;
225 }
226
227 if (!ack_required) {
228 /* See section 6.7.4.4: "A device that sends a frame with the AR field set
229 * to indicate no acknowledgment requested may assume that the transmission
230 * was successfully received and shall not perform the retransmission
231 * procedure."
232 */
233 return 0;
234 }
235
236
237 /* No-op in case the driver has IEEE802154_HW_TX_RX_ACK capability. */
238 ret = ieee802154_wait_for_ack(iface, ack_required);
239 if (ret == 0) {
240 /* ACK received - transmission is successful. */
241 return 0;
242 }
243
244 remaining_attempts--;
245 }
246
247 return -EIO;
248 }
249
swap_and_set_pkt_ll_addr(struct net_linkaddr * addr,bool has_pan_id,enum ieee802154_addressing_mode mode,struct ieee802154_address_field * ll)250 static inline void swap_and_set_pkt_ll_addr(struct net_linkaddr *addr, bool has_pan_id,
251 enum ieee802154_addressing_mode mode,
252 struct ieee802154_address_field *ll)
253 {
254 switch (mode) {
255 case IEEE802154_ADDR_MODE_EXTENDED:
256 (void)net_linkaddr_create(
257 addr,
258 has_pan_id ? ll->plain.addr.ext_addr : ll->comp.addr.ext_addr,
259 IEEE802154_EXT_ADDR_LENGTH,
260 NET_LINK_IEEE802154);
261 break;
262
263 case IEEE802154_ADDR_MODE_SHORT:
264 (void)net_linkaddr_create(
265 addr,
266 (const uint8_t *)(has_pan_id ?
267 &ll->plain.addr.short_addr : &ll->comp.addr.short_addr),
268 IEEE802154_SHORT_ADDR_LENGTH,
269 NET_LINK_IEEE802154);
270 break;
271
272 case IEEE802154_ADDR_MODE_NONE:
273 default:
274 (void)net_linkaddr_clear(addr);
275 }
276
277 /* The net stack expects big endian link layer addresses for POSIX compliance
278 * so we must swap it. This is ok as the L2 address field points into the L2
279 * header of the frame buffer which will no longer be accessible once the
280 * packet reaches upper layers.
281 */
282 if (addr->len > 0) {
283 sys_mem_swap(addr->addr, addr->len);
284 }
285 }
286
287 /**
288 * Filters the destination address of the frame.
289 *
290 * This is done before deciphering and authenticating encrypted frames.
291 */
ieee802154_check_dst_addr(struct net_if * iface,struct ieee802154_mhr * mhr)292 static bool ieee802154_check_dst_addr(struct net_if *iface, struct ieee802154_mhr *mhr)
293 {
294 struct ieee802154_address_field_plain *dst_plain = &mhr->dst_addr->plain;
295 struct ieee802154_context *ctx = net_if_l2_data(iface);
296 bool ret = false;
297
298 /* Apply filtering requirements from section 6.7.2 c)-e). For a)-b),
299 * see ieee802154_parse_fcf_seq()
300 */
301
302 if (mhr->fs->fc.dst_addr_mode == IEEE802154_ADDR_MODE_NONE) {
303 if (mhr->fs->fc.frame_version < IEEE802154_VERSION_802154 &&
304 mhr->fs->fc.frame_type == IEEE802154_FRAME_TYPE_BEACON) {
305 /* See IEEE 802.15.4-2015, section 7.3.1.1. */
306 return true;
307 }
308
309 /* TODO: apply d.4 and d.5 when PAN coordinator is implemented */
310 /* also, macImplicitBroadcast is not implemented */
311 return false;
312 }
313
314 k_sem_take(&ctx->ctx_lock, K_FOREVER);
315
316 /* c) If a destination PAN ID is included in the frame, it shall match
317 * macPanId or shall be the broadcast PAN ID.
318 */
319 if (!(dst_plain->pan_id == IEEE802154_BROADCAST_PAN_ID ||
320 dst_plain->pan_id == sys_cpu_to_le16(ctx->pan_id))) {
321 LOG_DBG("Frame PAN ID does not match!");
322 goto out;
323 }
324
325 if (mhr->fs->fc.dst_addr_mode == IEEE802154_ADDR_MODE_SHORT) {
326 /* d.1) A short destination address is included in the frame,
327 * and it matches either macShortAddress or the broadcast
328 * address.
329 */
330 if (!(dst_plain->addr.short_addr == IEEE802154_BROADCAST_ADDRESS ||
331 dst_plain->addr.short_addr == sys_cpu_to_le16(ctx->short_addr))) {
332 LOG_DBG("Frame dst address (short) does not match!");
333 goto out;
334 }
335
336 } else if (mhr->fs->fc.dst_addr_mode == IEEE802154_ADDR_MODE_EXTENDED) {
337 /* d.2) An extended destination address is included in the frame and
338 * matches [...] macExtendedAddress [...].
339 */
340 if (memcmp(dst_plain->addr.ext_addr, ctx->ext_addr,
341 IEEE802154_EXT_ADDR_LENGTH) != 0) {
342 LOG_DBG("Frame dst address (ext) does not match!");
343 goto out;
344 }
345
346 /* TODO: d.3) The Destination Address field and the Destination PAN ID
347 * field are not included in the frame and macImplicitBroadcast is TRUE.
348 */
349
350 /* TODO: d.4) The device is the PAN coordinator, only source addressing fields
351 * are included in a Data frame or MAC command and the source PAN ID
352 * matches macPanId.
353 */
354 }
355 ret = true;
356
357 out:
358 k_sem_give(&ctx->ctx_lock);
359 return ret;
360 }
361
ieee802154_recv(struct net_if * iface,struct net_pkt * pkt)362 static enum net_verdict ieee802154_recv(struct net_if *iface, struct net_pkt *pkt)
363 {
364 const struct ieee802154_radio_api *radio = net_if_get_device(iface)->api;
365 enum net_verdict verdict = NET_CONTINUE;
366 struct ieee802154_fcf_seq *fs;
367 struct ieee802154_mpdu mpdu;
368 bool is_broadcast;
369 size_t ll_hdr_len;
370
371 /* The IEEE 802.15.4 stack assumes that drivers provide a single-fragment package. */
372 __ASSERT_NO_MSG(pkt->buffer && pkt->buffer->frags == NULL);
373
374 if (!ieee802154_validate_frame(net_pkt_data(pkt), net_pkt_get_len(pkt), &mpdu)) {
375 return NET_DROP;
376 }
377
378 /* validate LL destination address (when IEEE802154_HW_FILTER not available) */
379 if (!(radio->get_capabilities(net_if_get_device(iface)) & IEEE802154_HW_FILTER) &&
380 !ieee802154_check_dst_addr(iface, &mpdu.mhr)) {
381 return NET_DROP;
382 }
383
384 fs = mpdu.mhr.fs;
385
386 if (fs->fc.frame_type == IEEE802154_FRAME_TYPE_ACK) {
387 return NET_DROP;
388 }
389
390 if (fs->fc.frame_type == IEEE802154_FRAME_TYPE_BEACON) {
391 verdict = ieee802154_handle_beacon(iface, &mpdu, net_pkt_ieee802154_lqi(pkt));
392 if (verdict == NET_CONTINUE) {
393 net_pkt_unref(pkt);
394 return NET_OK;
395 }
396 /* Beacons must not be acknowledged, see section 6.7.4.1. */
397 return verdict;
398 }
399
400 if (ieee802154_is_scanning(iface)) {
401 return NET_DROP;
402 }
403
404 if (fs->fc.frame_type == IEEE802154_FRAME_TYPE_MAC_COMMAND) {
405 verdict = ieee802154_handle_mac_command(iface, &mpdu);
406 if (verdict == NET_DROP) {
407 return verdict;
408 }
409 }
410
411 /* At this point the frame is either a MAC command or a data frame
412 * which may have to be acknowledged, see section 6.7.4.1.
413 */
414
415 is_broadcast = false;
416
417 if (fs->fc.dst_addr_mode == IEEE802154_ADDR_MODE_SHORT) {
418 struct ieee802154_address_field *dst_addr = mpdu.mhr.dst_addr;
419 uint16_t short_dst_addr;
420
421 short_dst_addr = fs->fc.pan_id_comp ? dst_addr->comp.addr.short_addr
422 : dst_addr->plain.addr.short_addr;
423 is_broadcast = short_dst_addr == IEEE802154_BROADCAST_ADDRESS;
424 }
425
426 /* Frames that are broadcast must not be acknowledged, see section 6.7.2. */
427 if (!is_broadcast) {
428 ieee802154_acknowledge(iface, &mpdu);
429 }
430
431 if (fs->fc.frame_type == IEEE802154_FRAME_TYPE_MAC_COMMAND) {
432 net_pkt_unref(pkt);
433 return NET_OK;
434 }
435
436 if (!ieee802154_decipher_data_frame(iface, pkt, &mpdu)) {
437 return NET_DROP;
438 }
439
440 /* Setting LL addresses for upper layers must be done after L2 packet
441 * handling as it will mangle the L2 frame header to comply with upper
442 * layers' (POSIX) requirement to represent network addresses in big endian.
443 */
444 swap_and_set_pkt_ll_addr(net_pkt_lladdr_src(pkt), !fs->fc.pan_id_comp,
445 fs->fc.src_addr_mode, mpdu.mhr.src_addr);
446
447 swap_and_set_pkt_ll_addr(net_pkt_lladdr_dst(pkt), true, fs->fc.dst_addr_mode,
448 mpdu.mhr.dst_addr);
449
450 net_pkt_set_ll_proto_type(pkt, ETH_P_IEEE802154);
451
452 pkt_hexdump(RX_PKT_TITLE " (with ll)", pkt, true);
453
454 ll_hdr_len = (uint8_t *)mpdu.payload - net_pkt_data(pkt);
455 net_buf_pull(pkt->buffer, ll_hdr_len);
456
457 #ifdef CONFIG_NET_6LO
458 verdict = ieee802154_6lo_decode_pkt(iface, pkt);
459 #endif /* CONFIG_NET_6LO */
460
461 if (verdict == NET_CONTINUE) {
462 pkt_hexdump(RX_PKT_TITLE, pkt, true);
463 }
464
465 return verdict;
466
467 /* At this point the call amounts to (part of) an
468 * MCPS-DATA.indication primitive, see section 8.3.3.
469 */
470 }
471
472 /**
473 * Implements (part of) the MCPS-DATA.request/confirm primitives, see sections 8.3.2/3.
474 */
ieee802154_send(struct net_if * iface,struct net_pkt * pkt)475 static int ieee802154_send(struct net_if *iface, struct net_pkt *pkt)
476 {
477 struct ieee802154_context *ctx = net_if_l2_data(iface);
478 uint8_t ll_hdr_len = 0, authtag_len = 0;
479 static struct net_buf *frame_buf;
480 static struct net_buf *pkt_buf;
481 bool send_raw = false;
482 int len;
483 #ifdef CONFIG_NET_L2_IEEE802154_FRAGMENT
484 struct ieee802154_6lo_fragment_ctx frag_ctx;
485 int requires_fragmentation = 0;
486 #endif
487
488 if (frame_buf == NULL) {
489 frame_buf = net_buf_alloc(&tx_frame_buf_pool, K_FOREVER);
490 }
491
492 if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) && net_pkt_family(pkt) == AF_PACKET) {
493 enum net_sock_type socket_type;
494 struct net_context *context;
495
496 context = net_pkt_context(pkt);
497 if (!context) {
498 return -EINVAL;
499 }
500
501 socket_type = net_context_get_type(context);
502 if (socket_type == SOCK_RAW) {
503 send_raw = true;
504 } else if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET_DGRAM) &&
505 socket_type == SOCK_DGRAM) {
506 struct sockaddr_ll *dst_addr = (struct sockaddr_ll *)&context->remote;
507 struct sockaddr_ll_ptr *src_addr =
508 (struct sockaddr_ll_ptr *)&context->local;
509
510 (void)net_linkaddr_set(net_pkt_lladdr_dst(pkt),
511 dst_addr->sll_addr,
512 dst_addr->sll_halen);
513
514 (void)net_linkaddr_set(net_pkt_lladdr_src(pkt),
515 src_addr->sll_addr,
516 src_addr->sll_halen);
517 } else {
518 return -EINVAL;
519 }
520 }
521
522 if (!send_raw) {
523 ieee802154_compute_header_and_authtag_len(iface, net_pkt_lladdr_dst(pkt),
524 net_pkt_lladdr_src(pkt), &ll_hdr_len,
525 &authtag_len);
526
527 #ifdef CONFIG_NET_6LO
528 #ifdef CONFIG_NET_L2_IEEE802154_FRAGMENT
529 requires_fragmentation =
530 ieee802154_6lo_encode_pkt(iface, pkt, &frag_ctx, ll_hdr_len, authtag_len);
531 if (requires_fragmentation < 0) {
532 return requires_fragmentation;
533 }
534 #else
535 ieee802154_6lo_encode_pkt(iface, pkt, NULL, ll_hdr_len, authtag_len);
536 #endif /* CONFIG_NET_L2_IEEE802154_FRAGMENT */
537 #endif /* CONFIG_NET_6LO */
538 }
539
540 net_capture_pkt(iface, pkt);
541
542 len = 0;
543 pkt_buf = pkt->buffer;
544 while (pkt_buf) {
545 int ret;
546
547 /* Reinitializing frame_buf */
548 net_buf_reset(frame_buf);
549 net_buf_add(frame_buf, ll_hdr_len);
550
551 #ifdef CONFIG_NET_L2_IEEE802154_FRAGMENT
552 if (requires_fragmentation) {
553 pkt_buf = ieee802154_6lo_fragment(&frag_ctx, frame_buf, true);
554 } else {
555 net_buf_add_mem(frame_buf, pkt_buf->data, pkt_buf->len);
556 pkt_buf = pkt_buf->frags;
557 }
558 #else
559 if (ll_hdr_len + pkt_buf->len + authtag_len > IEEE802154_MTU) {
560 NET_ERR("Frame too long: %d", pkt_buf->len);
561 return -EINVAL;
562 }
563 net_buf_add_mem(frame_buf, pkt_buf->data, pkt_buf->len);
564 pkt_buf = pkt_buf->frags;
565 #endif /* CONFIG_NET_L2_IEEE802154_FRAGMENT */
566
567 __ASSERT_NO_MSG(authtag_len <= net_buf_tailroom(frame_buf));
568 net_buf_add(frame_buf, authtag_len);
569
570 if (!(send_raw || ieee802154_create_data_frame(ctx, net_pkt_lladdr_dst(pkt),
571 net_pkt_lladdr_src(pkt),
572 frame_buf, ll_hdr_len))) {
573 return -EINVAL;
574 }
575
576 ret = ieee802154_radio_send(iface, pkt, frame_buf);
577 if (ret) {
578 return ret;
579 }
580
581 len += frame_buf->len;
582 }
583
584 net_pkt_unref(pkt);
585
586 return len;
587 }
588
ieee802154_enable(struct net_if * iface,bool state)589 static int ieee802154_enable(struct net_if *iface, bool state)
590 {
591 struct ieee802154_context *ctx = net_if_l2_data(iface);
592
593 NET_DBG("iface %p %s", iface, state ? "up" : "down");
594
595 k_sem_take(&ctx->ctx_lock, K_FOREVER);
596
597 if (ctx->channel == IEEE802154_NO_CHANNEL) {
598 k_sem_give(&ctx->ctx_lock);
599 return -ENETDOWN;
600 }
601
602 k_sem_give(&ctx->ctx_lock);
603
604 if (state) {
605 return ieee802154_radio_start(iface);
606 }
607
608 return ieee802154_radio_stop(iface);
609 }
610
ieee802154_flags(struct net_if * iface)611 static enum net_l2_flags ieee802154_flags(struct net_if *iface)
612 {
613 struct ieee802154_context *ctx = net_if_l2_data(iface);
614
615 /* No need for locking as these flags are set once
616 * during L2 initialization and then never changed.
617 */
618 return ctx->flags;
619 }
620
621 NET_L2_INIT(IEEE802154_L2, ieee802154_recv, ieee802154_send, ieee802154_enable, ieee802154_flags);
622
ieee802154_init(struct net_if * iface)623 void ieee802154_init(struct net_if *iface)
624 {
625 struct ieee802154_context *ctx = net_if_l2_data(iface);
626 const uint8_t *eui64_be = net_if_get_link_addr(iface)->addr;
627 int16_t tx_power = CONFIG_NET_L2_IEEE802154_RADIO_DFLT_TX_POWER;
628
629 NET_DBG("Initializing IEEE 802.15.4 stack on iface %p", iface);
630
631 k_sem_init(&ctx->ctx_lock, 1, 1);
632 k_sem_init(&ctx->ack_lock, 0, 1);
633
634 /* no need to lock the context here as it has
635 * not been published yet.
636 */
637
638 /* See section 6.7.1 - Transmission: "Each device shall initialize its data sequence number
639 * (DSN) to a random value and store its current DSN value in the MAC PIB attribute macDsn
640 * [...]."
641 */
642 ctx->sequence = sys_rand32_get() & 0xFF;
643
644 ctx->channel = IEEE802154_NO_CHANNEL;
645 ctx->flags = NET_L2_MULTICAST;
646 if (ieee802154_radio_get_hw_capabilities(iface) & IEEE802154_HW_PROMISC) {
647 ctx->flags |= NET_L2_PROMISC_MODE;
648 }
649
650 ctx->pan_id = IEEE802154_PAN_ID_NOT_ASSOCIATED;
651 ctx->short_addr = IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED;
652 ctx->coord_short_addr = IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED;
653 sys_memcpy_swap(ctx->ext_addr, eui64_be, IEEE802154_EXT_ADDR_LENGTH);
654
655 /* We switch to a link address store that we
656 * own so that we can write user defined short
657 * or extended addresses w/o mutating internal
658 * driver storage.
659 */
660 ctx->linkaddr.type = NET_LINK_IEEE802154;
661 ctx->linkaddr.len = IEEE802154_EXT_ADDR_LENGTH;
662 memcpy(ctx->linkaddr.addr, eui64_be, IEEE802154_EXT_ADDR_LENGTH);
663 net_if_set_link_addr(iface, ctx->linkaddr.addr, ctx->linkaddr.len, ctx->linkaddr.type);
664
665 if (IS_ENABLED(CONFIG_IEEE802154_NET_IF_NO_AUTO_START) ||
666 IS_ENABLED(CONFIG_NET_CONFIG_SETTINGS)) {
667 LOG_DBG("Interface auto start disabled.");
668 net_if_flag_set(iface, NET_IF_NO_AUTO_START);
669 }
670
671 ieee802154_mgmt_init(iface);
672
673 #ifdef CONFIG_NET_L2_IEEE802154_SECURITY
674 if (ieee802154_security_init(&ctx->sec_ctx)) {
675 NET_ERR("Initializing link-layer security failed");
676 }
677 #endif
678
679 sys_memcpy_swap(ctx->ext_addr, eui64_be, IEEE802154_EXT_ADDR_LENGTH);
680 ieee802154_radio_filter_ieee_addr(iface, ctx->ext_addr);
681
682 if (!ieee802154_radio_set_tx_power(iface, tx_power)) {
683 ctx->tx_power = tx_power;
684 }
685 }
686