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