1 /*
2 * Copyright (c) 2018 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * This file implements the OpenThread platform abstraction
10 * for radio communication.
11 *
12 */
13
14 #include <openthread/error.h>
15 #define LOG_MODULE_NAME net_otPlat_radio
16
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_OPENTHREAD_L2_LOG_LEVEL);
19
20 #include <stdbool.h>
21 #include <stddef.h>
22 #include <stdint.h>
23 #include <string.h>
24
25 #include <zephyr/kernel.h>
26 #include <zephyr/device.h>
27 #include <zephyr/net/ieee802154_radio.h>
28 #include <zephyr/net/net_pkt.h>
29 #include <zephyr/net/net_time.h>
30 #include <zephyr/sys/__assert.h>
31
32 #include <openthread/ip6.h>
33 #include <openthread-system.h>
34 #include <openthread/instance.h>
35 #include <openthread/platform/radio.h>
36 #include <openthread/platform/diag.h>
37 #include <openthread/platform/time.h>
38 #include <openthread/message.h>
39
40 #include "platform-zephyr.h"
41
42 #if defined(CONFIG_OPENTHREAD_NAT64_TRANSLATOR)
43 #include <openthread/nat64.h>
44 #endif
45
46 #define PKT_IS_IPv6(_p) ((NET_IPV6_HDR(_p)->vtc & 0xf0) == 0x60)
47
48 #define SHORT_ADDRESS_SIZE 2
49
50 #define FCS_SIZE 2
51 #if defined(CONFIG_OPENTHREAD_THREAD_VERSION_1_1)
52 #define ACK_PKT_LENGTH 5
53 #else
54 #define ACK_PKT_LENGTH 127
55 #endif
56
57 #define FRAME_TYPE_MASK 0x07
58 #define FRAME_TYPE_ACK 0x02
59
60 #if defined(CONFIG_NET_TC_THREAD_COOPERATIVE)
61 #define OT_WORKER_PRIORITY K_PRIO_COOP(CONFIG_OPENTHREAD_THREAD_PRIORITY)
62 #else
63 #define OT_WORKER_PRIORITY K_PRIO_PREEMPT(CONFIG_OPENTHREAD_THREAD_PRIORITY)
64 #endif
65
66 #define CHANNEL_COUNT OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX - OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN + 1
67
68 /* PHY header duration in us (i.e. 2 symbol periods @ 62.5k symbol rate), see
69 * IEEE 802.15.4, sections 12.1.3.1, 12.2.5 and 12.3.3.
70 */
71 #define PHR_DURATION_US 32U
72
73 enum pending_events {
74 PENDING_EVENT_FRAME_TO_SEND, /* There is a tx frame to send */
75 PENDING_EVENT_FRAME_RECEIVED, /* Radio has received new frame */
76 PENDING_EVENT_RX_FAILED, /* The RX failed */
77 PENDING_EVENT_TX_STARTED, /* Radio has started transmitting */
78 PENDING_EVENT_TX_DONE, /* Radio transmission finished */
79 PENDING_EVENT_DETECT_ENERGY, /* Requested to start Energy Detection procedure */
80 PENDING_EVENT_DETECT_ENERGY_DONE, /* Energy Detection finished */
81 PENDING_EVENT_SLEEP, /* Sleep if idle */
82 PENDING_EVENT_COUNT /* Keep last */
83 };
84
85 K_SEM_DEFINE(radio_sem, 0, 1);
86
87 static otRadioState sState = OT_RADIO_STATE_DISABLED;
88
89 static otRadioFrame sTransmitFrame;
90 static otRadioFrame ack_frame;
91 static uint8_t ack_psdu[ACK_PKT_LENGTH];
92
93 #if defined(CONFIG_OPENTHREAD_TIME_SYNC)
94 static otRadioIeInfo tx_ie_info;
95 #endif
96
97 static struct net_pkt *tx_pkt;
98 static struct net_buf *tx_payload;
99
100 static const struct device *const radio_dev =
101 DEVICE_DT_GET(DT_CHOSEN(zephyr_ieee802154));
102 static struct ieee802154_radio_api *radio_api;
103
104 /* Get the default tx output power from Kconfig */
105 static int8_t tx_power = CONFIG_OPENTHREAD_DEFAULT_TX_POWER;
106 static uint16_t channel;
107 static bool promiscuous;
108
109 static uint16_t energy_detection_time;
110 static uint8_t energy_detection_channel;
111 static int16_t energy_detected_value;
112
113 static int8_t max_tx_power_table[CHANNEL_COUNT];
114
115 ATOMIC_DEFINE(pending_events, PENDING_EVENT_COUNT);
116 K_KERNEL_STACK_DEFINE(ot_task_stack,
117 CONFIG_OPENTHREAD_RADIO_WORKQUEUE_STACK_SIZE);
118 static struct k_work_q ot_work_q;
119 static otError rx_result;
120 static otError tx_result;
121
122 K_FIFO_DEFINE(rx_pkt_fifo);
123 K_FIFO_DEFINE(tx_pkt_fifo);
124
get_transmit_power_for_channel(uint8_t aChannel)125 static int8_t get_transmit_power_for_channel(uint8_t aChannel)
126 {
127 int8_t channel_max_power = OT_RADIO_POWER_INVALID;
128 int8_t power = 0; /* 0 dbm as default value */
129
130 if (aChannel >= OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN &&
131 aChannel <= OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX) {
132 channel_max_power =
133 max_tx_power_table[aChannel - OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN];
134 }
135
136 if (tx_power != OT_RADIO_POWER_INVALID) {
137 power = (channel_max_power < tx_power) ? channel_max_power : tx_power;
138 } else if (channel_max_power != OT_RADIO_POWER_INVALID) {
139 power = channel_max_power;
140 }
141
142 return power;
143 }
144
is_pending_event_set(enum pending_events event)145 static inline bool is_pending_event_set(enum pending_events event)
146 {
147 return atomic_test_bit(pending_events, event);
148 }
149
set_pending_event(enum pending_events event)150 static void set_pending_event(enum pending_events event)
151 {
152 atomic_set_bit(pending_events, event);
153 otSysEventSignalPending();
154 }
155
reset_pending_event(enum pending_events event)156 static void reset_pending_event(enum pending_events event)
157 {
158 atomic_clear_bit(pending_events, event);
159 }
160
clear_pending_events(void)161 static inline void clear_pending_events(void)
162 {
163 atomic_clear(pending_events);
164 }
165
energy_detected(const struct device * dev,int16_t max_ed)166 void energy_detected(const struct device *dev, int16_t max_ed)
167 {
168 if (dev == radio_dev) {
169 energy_detected_value = max_ed;
170 set_pending_event(PENDING_EVENT_DETECT_ENERGY_DONE);
171 }
172 }
173
ieee802154_handle_ack(struct net_if * iface,struct net_pkt * pkt)174 enum net_verdict ieee802154_handle_ack(struct net_if *iface, struct net_pkt *pkt)
175 {
176 ARG_UNUSED(iface);
177
178 size_t ack_len = net_pkt_get_len(pkt);
179
180 if (ack_len > ACK_PKT_LENGTH) {
181 return NET_CONTINUE;
182 }
183
184 if ((*net_pkt_data(pkt) & FRAME_TYPE_MASK) != FRAME_TYPE_ACK) {
185 return NET_CONTINUE;
186 }
187
188 if (ack_frame.mLength != 0) {
189 LOG_ERR("Overwriting unhandled ACK frame.");
190 }
191
192 if (net_pkt_read(pkt, ack_psdu, ack_len) < 0) {
193 LOG_ERR("Failed to read ACK frame.");
194 return NET_CONTINUE;
195 }
196
197 ack_frame.mPsdu = ack_psdu;
198 ack_frame.mLength = ack_len;
199 ack_frame.mInfo.mRxInfo.mLqi = net_pkt_ieee802154_lqi(pkt);
200 ack_frame.mInfo.mRxInfo.mRssi = net_pkt_ieee802154_rssi_dbm(pkt);
201
202 #if defined(CONFIG_NET_PKT_TIMESTAMP)
203 ack_frame.mInfo.mRxInfo.mTimestamp = net_pkt_timestamp_ns(pkt) / NSEC_PER_USEC;
204 #endif
205
206 return NET_OK;
207 }
208
handle_radio_event(const struct device * dev,enum ieee802154_event evt,void * event_params)209 void handle_radio_event(const struct device *dev, enum ieee802154_event evt,
210 void *event_params)
211 {
212 ARG_UNUSED(event_params);
213
214 switch (evt) {
215 case IEEE802154_EVENT_TX_STARTED:
216 if (sState == OT_RADIO_STATE_TRANSMIT) {
217 set_pending_event(PENDING_EVENT_TX_STARTED);
218 }
219 break;
220 case IEEE802154_EVENT_RX_FAILED:
221 if (sState == OT_RADIO_STATE_RECEIVE) {
222 switch (*(enum ieee802154_rx_fail_reason *) event_params) {
223 case IEEE802154_RX_FAIL_NOT_RECEIVED:
224 rx_result = OT_ERROR_NO_FRAME_RECEIVED;
225 break;
226
227 case IEEE802154_RX_FAIL_INVALID_FCS:
228 rx_result = OT_ERROR_FCS;
229 break;
230
231 case IEEE802154_RX_FAIL_ADDR_FILTERED:
232 rx_result = OT_ERROR_DESTINATION_ADDRESS_FILTERED;
233 break;
234
235 case IEEE802154_RX_FAIL_OTHER:
236 default:
237 rx_result = OT_ERROR_FAILED;
238 break;
239 }
240 set_pending_event(PENDING_EVENT_RX_FAILED);
241 }
242 break;
243 case IEEE802154_EVENT_RX_OFF:
244 set_pending_event(PENDING_EVENT_SLEEP);
245 break;
246 default:
247 /* do nothing - ignore event */
248 break;
249 }
250 }
251
252 #if defined(CONFIG_NET_PKT_TXTIME) || defined(CONFIG_OPENTHREAD_CSL_RECEIVER)
253 /**
254 * @brief Convert 32-bit (potentially wrapped) OpenThread microsecond timestamps
255 * to 64-bit Zephyr network subsystem nanosecond timestamps.
256 *
257 * This is a workaround until OpenThread is able to schedule 64-bit RX/TX time.
258 *
259 * @param target_time_ns_wrapped time in nanoseconds referred to the radio clock
260 * modulo UINT32_MAX.
261 *
262 * @return 64-bit nanosecond timestamp
263 */
convert_32bit_us_wrapped_to_64bit_ns(uint32_t target_time_us_wrapped)264 static net_time_t convert_32bit_us_wrapped_to_64bit_ns(uint32_t target_time_us_wrapped)
265 {
266 /**
267 * OpenThread provides target time as a (potentially wrapped) 32-bit
268 * integer defining a moment in time in the microsecond domain.
269 *
270 * The target time can point to a moment in the future, but can be
271 * overdue as well. In order to determine what's the case and correctly
272 * set the absolute (non-wrapped) target time, it's necessary to compare
273 * the least significant 32 bits of the current 64-bit network subsystem
274 * time with the provided 32-bit target time. Let's assume that half of
275 * the 32-bit range can be used for specifying target times in the
276 * future, and the other half - in the past.
277 */
278 uint64_t now_us = otPlatTimeGet();
279 uint32_t now_us_wrapped = (uint32_t)now_us;
280 uint32_t time_diff = target_time_us_wrapped - now_us_wrapped;
281 uint64_t result = UINT64_C(0);
282
283 if (time_diff < 0x80000000) {
284 /**
285 * Target time is assumed to be in the future. Check if a 32-bit overflow
286 * occurs between the current time and the target time.
287 */
288 if (now_us_wrapped > target_time_us_wrapped) {
289 /**
290 * Add a 32-bit overflow and replace the least significant 32 bits
291 * with the provided target time.
292 */
293 result = now_us + UINT32_MAX + 1;
294 result &= ~(uint64_t)UINT32_MAX;
295 result |= target_time_us_wrapped;
296 } else {
297 /**
298 * Leave the most significant 32 bits and replace the least significant
299 * 32 bits with the provided target time.
300 */
301 result = (now_us & (~(uint64_t)UINT32_MAX)) | target_time_us_wrapped;
302 }
303 } else {
304 /**
305 * Target time is assumed to be in the past. Check if a 32-bit overflow
306 * occurs between the target time and the current time.
307 */
308 if (now_us_wrapped > target_time_us_wrapped) {
309 /**
310 * Leave the most significant 32 bits and replace the least significant
311 * 32 bits with the provided target time.
312 */
313 result = (now_us & (~(uint64_t)UINT32_MAX)) | target_time_us_wrapped;
314 } else {
315 /**
316 * Subtract a 32-bit overflow and replace the least significant
317 * 32 bits with the provided target time.
318 */
319 result = now_us - UINT32_MAX - 1;
320 result &= ~(uint64_t)UINT32_MAX;
321 result |= target_time_us_wrapped;
322 }
323 }
324
325 __ASSERT_NO_MSG(result <= INT64_MAX / NSEC_PER_USEC);
326 return (net_time_t)result * NSEC_PER_USEC;
327 }
328 #endif /* CONFIG_NET_PKT_TXTIME || CONFIG_OPENTHREAD_CSL_RECEIVER */
329
dataInit(void)330 static void dataInit(void)
331 {
332 tx_pkt = net_pkt_alloc(K_NO_WAIT);
333 __ASSERT_NO_MSG(tx_pkt != NULL);
334
335 tx_payload = net_pkt_get_reserve_tx_data(IEEE802154_MAX_PHY_PACKET_SIZE,
336 K_NO_WAIT);
337 __ASSERT_NO_MSG(tx_payload != NULL);
338
339 net_pkt_append_buffer(tx_pkt, tx_payload);
340
341 sTransmitFrame.mPsdu = tx_payload->data;
342
343 for (size_t i = 0; i < CHANNEL_COUNT; i++) {
344 max_tx_power_table[i] = OT_RADIO_POWER_INVALID;
345 }
346
347 #if defined(CONFIG_OPENTHREAD_TIME_SYNC)
348 sTransmitFrame.mInfo.mTxInfo.mIeInfo = &tx_ie_info;
349 #endif
350 }
351
platformRadioInit(void)352 void platformRadioInit(void)
353 {
354 struct ieee802154_config cfg;
355
356 dataInit();
357
358 __ASSERT_NO_MSG(device_is_ready(radio_dev));
359
360 radio_api = (struct ieee802154_radio_api *)radio_dev->api;
361 if (!radio_api) {
362 return;
363 }
364
365 k_work_queue_start(&ot_work_q, ot_task_stack,
366 K_KERNEL_STACK_SIZEOF(ot_task_stack),
367 OT_WORKER_PRIORITY, NULL);
368 k_thread_name_set(&ot_work_q.thread, "ot_radio_workq");
369
370 if ((radio_api->get_capabilities(radio_dev) &
371 IEEE802154_HW_TX_RX_ACK) != IEEE802154_HW_TX_RX_ACK) {
372 LOG_ERR("Only radios with automatic ack handling "
373 "are currently supported");
374 k_panic();
375 }
376
377 cfg.event_handler = handle_radio_event;
378 radio_api->configure(radio_dev, IEEE802154_CONFIG_EVENT_HANDLER, &cfg);
379 }
380
radio_set_channel(uint16_t ch)381 static void radio_set_channel(uint16_t ch)
382 {
383 channel = ch;
384 radio_api->set_channel(radio_dev, ch);
385 }
386
transmit_message(struct k_work * tx_job)387 void transmit_message(struct k_work *tx_job)
388 {
389 int tx_err;
390
391 ARG_UNUSED(tx_job);
392
393 enum ieee802154_hw_caps radio_caps = radio_api->get_capabilities(radio_dev);
394
395 /*
396 * The payload is already in tx_payload->data,
397 * but we need to set the length field
398 * according to sTransmitFrame.length.
399 * We subtract the FCS size as radio driver
400 * adds CRC and increases frame length on its own.
401 */
402 tx_payload->len = sTransmitFrame.mLength - FCS_SIZE;
403
404 radio_api->set_txpower(radio_dev, get_transmit_power_for_channel(sTransmitFrame.mChannel));
405
406 #if defined(CONFIG_OPENTHREAD_TIME_SYNC)
407 if (sTransmitFrame.mInfo.mTxInfo.mIeInfo->mTimeIeOffset != 0) {
408 uint8_t *time_ie =
409 sTransmitFrame.mPsdu + sTransmitFrame.mInfo.mTxInfo.mIeInfo->mTimeIeOffset;
410 uint64_t offset_plat_time =
411 otPlatTimeGet() + sTransmitFrame.mInfo.mTxInfo.mIeInfo->mNetworkTimeOffset;
412
413 *(time_ie++) = sTransmitFrame.mInfo.mTxInfo.mIeInfo->mTimeSyncSeq;
414 sys_put_le64(offset_plat_time, time_ie);
415 }
416 #endif
417
418 net_pkt_set_ieee802154_frame_secured(tx_pkt,
419 sTransmitFrame.mInfo.mTxInfo.mIsSecurityProcessed);
420 net_pkt_set_ieee802154_mac_hdr_rdy(tx_pkt, sTransmitFrame.mInfo.mTxInfo.mIsHeaderUpdated);
421
422 if ((radio_caps & IEEE802154_HW_TXTIME) &&
423 (sTransmitFrame.mInfo.mTxInfo.mTxDelay != 0)) {
424 #if defined(CONFIG_NET_PKT_TXTIME)
425 uint32_t tx_at = sTransmitFrame.mInfo.mTxInfo.mTxDelayBaseTime +
426 sTransmitFrame.mInfo.mTxInfo.mTxDelay;
427 net_pkt_set_timestamp_ns(tx_pkt, convert_32bit_us_wrapped_to_64bit_ns(tx_at));
428 #endif
429 #if defined(CONFIG_IEEE802154_SELECTIVE_TXCHANNEL)
430 if (radio_caps & IEEE802154_HW_SELECTIVE_TXCHANNEL) {
431 net_pkt_set_ieee802154_txchannel(tx_pkt, sTransmitFrame.mChannel);
432 } else {
433 radio_set_channel(sTransmitFrame.mChannel);
434 }
435 #else
436 radio_set_channel(sTransmitFrame.mChannel);
437 #endif
438 tx_err =
439 radio_api->tx(radio_dev, IEEE802154_TX_MODE_TXTIME_CCA, tx_pkt, tx_payload);
440 } else if (sTransmitFrame.mInfo.mTxInfo.mCsmaCaEnabled) {
441 radio_set_channel(sTransmitFrame.mChannel);
442 if (radio_caps & IEEE802154_HW_CSMA) {
443 tx_err = radio_api->tx(radio_dev, IEEE802154_TX_MODE_CSMA_CA, tx_pkt,
444 tx_payload);
445 } else {
446 tx_err = radio_api->cca(radio_dev);
447 if (tx_err == 0) {
448 tx_err = radio_api->tx(radio_dev, IEEE802154_TX_MODE_DIRECT, tx_pkt,
449 tx_payload);
450 }
451 }
452 } else {
453 radio_set_channel(sTransmitFrame.mChannel);
454 tx_err = radio_api->tx(radio_dev, IEEE802154_TX_MODE_DIRECT, tx_pkt, tx_payload);
455 }
456
457 /*
458 * OpenThread handles the following errors:
459 * - OT_ERROR_NONE
460 * - OT_ERROR_NO_ACK
461 * - OT_ERROR_CHANNEL_ACCESS_FAILURE
462 * - OT_ERROR_ABORT
463 * Any other error passed to `otPlatRadioTxDone` will result in assertion.
464 */
465 switch (tx_err) {
466 case 0:
467 tx_result = OT_ERROR_NONE;
468 break;
469 case -ENOMSG:
470 tx_result = OT_ERROR_NO_ACK;
471 break;
472 case -EBUSY:
473 tx_result = OT_ERROR_CHANNEL_ACCESS_FAILURE;
474 break;
475 case -EIO:
476 tx_result = OT_ERROR_ABORT;
477 break;
478 default:
479 tx_result = OT_ERROR_CHANNEL_ACCESS_FAILURE;
480 break;
481 }
482
483 set_pending_event(PENDING_EVENT_TX_DONE);
484 }
485
handle_tx_done(otInstance * aInstance)486 static inline void handle_tx_done(otInstance *aInstance)
487 {
488 sTransmitFrame.mInfo.mTxInfo.mIsSecurityProcessed =
489 net_pkt_ieee802154_frame_secured(tx_pkt);
490 sTransmitFrame.mInfo.mTxInfo.mIsHeaderUpdated = net_pkt_ieee802154_mac_hdr_rdy(tx_pkt);
491
492 if (IS_ENABLED(CONFIG_OPENTHREAD_DIAG) && otPlatDiagModeGet()) {
493 otPlatDiagRadioTransmitDone(aInstance, &sTransmitFrame, tx_result);
494 } else {
495 otPlatRadioTxDone(aInstance, &sTransmitFrame, ack_frame.mLength ? &ack_frame : NULL,
496 tx_result);
497 ack_frame.mLength = 0;
498 }
499 }
500
openthread_handle_received_frame(otInstance * instance,struct net_pkt * pkt)501 static void openthread_handle_received_frame(otInstance *instance,
502 struct net_pkt *pkt)
503 {
504 otRadioFrame recv_frame;
505 memset(&recv_frame, 0, sizeof(otRadioFrame));
506
507 recv_frame.mPsdu = net_buf_frag_last(pkt->buffer)->data;
508 /* Length inc. CRC. */
509 recv_frame.mLength = net_buf_frags_len(pkt->buffer);
510 recv_frame.mChannel = platformRadioChannelGet(instance);
511 recv_frame.mInfo.mRxInfo.mLqi = net_pkt_ieee802154_lqi(pkt);
512 recv_frame.mInfo.mRxInfo.mRssi = net_pkt_ieee802154_rssi_dbm(pkt);
513 recv_frame.mInfo.mRxInfo.mAckedWithFramePending = net_pkt_ieee802154_ack_fpb(pkt);
514
515 #if defined(CONFIG_NET_PKT_TIMESTAMP)
516 recv_frame.mInfo.mRxInfo.mTimestamp = net_pkt_timestamp_ns(pkt) / NSEC_PER_USEC;
517 #endif
518
519 recv_frame.mInfo.mRxInfo.mAckedWithSecEnhAck = net_pkt_ieee802154_ack_seb(pkt);
520 recv_frame.mInfo.mRxInfo.mAckFrameCounter = net_pkt_ieee802154_ack_fc(pkt);
521 recv_frame.mInfo.mRxInfo.mAckKeyId = net_pkt_ieee802154_ack_keyid(pkt);
522
523 if (IS_ENABLED(CONFIG_OPENTHREAD_DIAG) && otPlatDiagModeGet()) {
524 otPlatDiagRadioReceiveDone(instance, &recv_frame, OT_ERROR_NONE);
525 } else {
526 otPlatRadioReceiveDone(instance, &recv_frame, OT_ERROR_NONE);
527 }
528
529 net_pkt_unref(pkt);
530 }
531
532 #if defined(CONFIG_OPENTHREAD_NAT64_TRANSLATOR)
533
openthread_ip4_new_msg(otInstance * instance,otMessageSettings * settings)534 static otMessage *openthread_ip4_new_msg(otInstance *instance, otMessageSettings *settings)
535 {
536 return otIp4NewMessage(instance, settings);
537 }
538
openthread_nat64_send(otInstance * instance,otMessage * message)539 static otError openthread_nat64_send(otInstance *instance, otMessage *message)
540 {
541 return otNat64Send(instance, message);
542 }
543
544 #else /* CONFIG_OPENTHREAD_NAT64_TRANSLATOR */
545
openthread_ip4_new_msg(otInstance * instance,otMessageSettings * settings)546 static otMessage *openthread_ip4_new_msg(otInstance *instance, otMessageSettings *settings)
547 {
548 return NULL;
549 }
550
openthread_nat64_send(otInstance * instance,otMessage * message)551 static otError openthread_nat64_send(otInstance *instance, otMessage *message)
552 {
553 return OT_ERROR_DROP;
554 }
555
556 #endif /* CONFIG_OPENTHREAD_NAT64_TRANSLATOR */
557
openthread_handle_frame_to_send(otInstance * instance,struct net_pkt * pkt)558 static void openthread_handle_frame_to_send(otInstance *instance, struct net_pkt *pkt)
559 {
560 otError error;
561 struct net_buf *buf;
562 otMessage *message;
563 otMessageSettings settings;
564 bool is_ip6 = PKT_IS_IPv6(pkt);
565
566 NET_DBG("Sending %s packet to ot stack", is_ip6 ? "IPv6" : "IPv4");
567
568 settings.mPriority = OT_MESSAGE_PRIORITY_NORMAL;
569 settings.mLinkSecurityEnabled = true;
570
571 message = is_ip6 ? otIp6NewMessage(instance, &settings)
572 : openthread_ip4_new_msg(instance, &settings);
573 if (!message) {
574 NET_ERR("Cannot allocate new message buffer");
575 goto exit;
576 }
577
578 if (IS_ENABLED(CONFIG_OPENTHREAD)) {
579 /* Set multicast loop so the stack can process multicast packets for
580 * subscribed addresses.
581 */
582 otMessageSetMulticastLoopEnabled(message, true);
583 }
584
585 for (buf = pkt->buffer; buf; buf = buf->frags) {
586 if (otMessageAppend(message, buf->data, buf->len) != OT_ERROR_NONE) {
587 NET_ERR("Error while appending to otMessage");
588 otMessageFree(message);
589 goto exit;
590 }
591 }
592
593 error = is_ip6 ? otIp6Send(instance, message) : openthread_nat64_send(instance, message);
594
595 if (error != OT_ERROR_NONE) {
596 NET_ERR("Error while calling %s [error: %d]",
597 is_ip6 ? "otIp6Send" : "openthread_nat64_send", error);
598 }
599
600 exit:
601 net_pkt_unref(pkt);
602 }
603
notify_new_rx_frame(struct net_pkt * pkt)604 int notify_new_rx_frame(struct net_pkt *pkt)
605 {
606 k_fifo_put(&rx_pkt_fifo, pkt);
607 set_pending_event(PENDING_EVENT_FRAME_RECEIVED);
608
609 return 0;
610 }
611
notify_new_tx_frame(struct net_pkt * pkt)612 int notify_new_tx_frame(struct net_pkt *pkt)
613 {
614 k_fifo_put(&tx_pkt_fifo, pkt);
615 set_pending_event(PENDING_EVENT_FRAME_TO_SEND);
616
617 return 0;
618 }
619
run_tx_task(otInstance * aInstance)620 static int run_tx_task(otInstance *aInstance)
621 {
622 static K_WORK_DEFINE(tx_job, transmit_message);
623
624 ARG_UNUSED(aInstance);
625
626 if (!k_work_is_pending(&tx_job)) {
627 sState = OT_RADIO_STATE_TRANSMIT;
628
629 k_work_submit_to_queue(&ot_work_q, &tx_job);
630 return 0;
631 } else {
632 return -EBUSY;
633 }
634 }
635
platformRadioProcess(otInstance * aInstance)636 void platformRadioProcess(otInstance *aInstance)
637 {
638 bool event_pending = false;
639
640 if (is_pending_event_set(PENDING_EVENT_FRAME_TO_SEND)) {
641 struct net_pkt *evt_pkt;
642
643 reset_pending_event(PENDING_EVENT_FRAME_TO_SEND);
644 while ((evt_pkt = (struct net_pkt *) k_fifo_get(&tx_pkt_fifo, K_NO_WAIT)) != NULL) {
645 if (IS_ENABLED(CONFIG_OPENTHREAD_COPROCESSOR_RCP)) {
646 net_pkt_unref(evt_pkt);
647 } else {
648 openthread_handle_frame_to_send(aInstance, evt_pkt);
649 }
650 }
651 }
652
653 if (is_pending_event_set(PENDING_EVENT_FRAME_RECEIVED)) {
654 struct net_pkt *rx_pkt;
655
656 reset_pending_event(PENDING_EVENT_FRAME_RECEIVED);
657 while ((rx_pkt = (struct net_pkt *) k_fifo_get(&rx_pkt_fifo, K_NO_WAIT)) != NULL) {
658 openthread_handle_received_frame(aInstance, rx_pkt);
659 }
660 }
661
662 if (is_pending_event_set(PENDING_EVENT_RX_FAILED)) {
663 reset_pending_event(PENDING_EVENT_RX_FAILED);
664 if (IS_ENABLED(CONFIG_OPENTHREAD_DIAG) && otPlatDiagModeGet()) {
665 otPlatDiagRadioReceiveDone(aInstance, NULL, rx_result);
666 } else {
667 otPlatRadioReceiveDone(aInstance, NULL, rx_result);
668 }
669 }
670
671 if (is_pending_event_set(PENDING_EVENT_TX_STARTED)) {
672 reset_pending_event(PENDING_EVENT_TX_STARTED);
673 otPlatRadioTxStarted(aInstance, &sTransmitFrame);
674 }
675
676 if (is_pending_event_set(PENDING_EVENT_TX_DONE)) {
677 reset_pending_event(PENDING_EVENT_TX_DONE);
678
679 if (sState == OT_RADIO_STATE_TRANSMIT ||
680 radio_api->get_capabilities(radio_dev) & IEEE802154_HW_SLEEP_TO_TX) {
681 sState = OT_RADIO_STATE_RECEIVE;
682 handle_tx_done(aInstance);
683 }
684 }
685
686 if (is_pending_event_set(PENDING_EVENT_SLEEP)) {
687 reset_pending_event(PENDING_EVENT_SLEEP);
688 ARG_UNUSED(otPlatRadioSleep(aInstance));
689 }
690
691 /* handle events that can't run during transmission */
692 if (sState != OT_RADIO_STATE_TRANSMIT) {
693 if (is_pending_event_set(PENDING_EVENT_DETECT_ENERGY)) {
694 radio_api->set_channel(radio_dev,
695 energy_detection_channel);
696
697 if (!radio_api->ed_scan(radio_dev,
698 energy_detection_time,
699 energy_detected)) {
700 reset_pending_event(
701 PENDING_EVENT_DETECT_ENERGY);
702 } else {
703 event_pending = true;
704 }
705 }
706
707 if (is_pending_event_set(PENDING_EVENT_DETECT_ENERGY_DONE)) {
708 otPlatRadioEnergyScanDone(aInstance, (int8_t) energy_detected_value);
709 reset_pending_event(PENDING_EVENT_DETECT_ENERGY_DONE);
710 }
711 }
712
713 if (event_pending) {
714 otSysEventSignalPending();
715 }
716 }
717
platformRadioChannelGet(otInstance * aInstance)718 uint16_t platformRadioChannelGet(otInstance *aInstance)
719 {
720 ARG_UNUSED(aInstance);
721
722 return channel;
723 }
724
otPlatRadioSetPanId(otInstance * aInstance,uint16_t aPanId)725 void otPlatRadioSetPanId(otInstance *aInstance, uint16_t aPanId)
726 {
727 ARG_UNUSED(aInstance);
728
729 radio_api->filter(radio_dev, true, IEEE802154_FILTER_TYPE_PAN_ID,
730 (struct ieee802154_filter *) &aPanId);
731 }
732
otPlatRadioSetExtendedAddress(otInstance * aInstance,const otExtAddress * aExtAddress)733 void otPlatRadioSetExtendedAddress(otInstance *aInstance,
734 const otExtAddress *aExtAddress)
735 {
736 ARG_UNUSED(aInstance);
737
738 radio_api->filter(radio_dev, true, IEEE802154_FILTER_TYPE_IEEE_ADDR,
739 (struct ieee802154_filter *) &aExtAddress);
740 }
741
otPlatRadioSetShortAddress(otInstance * aInstance,uint16_t aShortAddress)742 void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aShortAddress)
743 {
744 ARG_UNUSED(aInstance);
745
746 radio_api->filter(radio_dev, true, IEEE802154_FILTER_TYPE_SHORT_ADDR,
747 (struct ieee802154_filter *) &aShortAddress);
748 }
749
otPlatRadioIsEnabled(otInstance * aInstance)750 bool otPlatRadioIsEnabled(otInstance *aInstance)
751 {
752 ARG_UNUSED(aInstance);
753
754 return (sState != OT_RADIO_STATE_DISABLED) ? true : false;
755 }
756
otPlatRadioEnable(otInstance * aInstance)757 otError otPlatRadioEnable(otInstance *aInstance)
758 {
759 if (!otPlatRadioIsEnabled(aInstance)) {
760 sState = OT_RADIO_STATE_SLEEP;
761 }
762
763 return OT_ERROR_NONE;
764 }
765
otPlatRadioDisable(otInstance * aInstance)766 otError otPlatRadioDisable(otInstance *aInstance)
767 {
768 if (otPlatRadioIsEnabled(aInstance)) {
769 sState = OT_RADIO_STATE_DISABLED;
770 }
771
772 return OT_ERROR_NONE;
773 }
774
otPlatRadioSleep(otInstance * aInstance)775 otError otPlatRadioSleep(otInstance *aInstance)
776 {
777 ARG_UNUSED(aInstance);
778
779 otError error = OT_ERROR_INVALID_STATE;
780
781 if (sState == OT_RADIO_STATE_SLEEP ||
782 sState == OT_RADIO_STATE_RECEIVE ||
783 sState == OT_RADIO_STATE_TRANSMIT) {
784 error = OT_ERROR_NONE;
785 radio_api->stop(radio_dev);
786 sState = OT_RADIO_STATE_SLEEP;
787 }
788
789 return error;
790 }
791
otPlatRadioReceive(otInstance * aInstance,uint8_t aChannel)792 otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
793 {
794 ARG_UNUSED(aInstance);
795
796 channel = aChannel;
797
798 radio_api->set_channel(radio_dev, aChannel);
799 radio_api->set_txpower(radio_dev, get_transmit_power_for_channel(channel));
800 radio_api->start(radio_dev);
801 sState = OT_RADIO_STATE_RECEIVE;
802
803 return OT_ERROR_NONE;
804 }
805
806 #if defined(CONFIG_OPENTHREAD_CSL_RECEIVER) || defined(CONFIG_OPENTHREAD_WAKEUP_END_DEVICE)
otPlatRadioReceiveAt(otInstance * aInstance,uint8_t aChannel,uint32_t aStart,uint32_t aDuration)807 otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel,
808 uint32_t aStart, uint32_t aDuration)
809 {
810 int result;
811
812 ARG_UNUSED(aInstance);
813
814 struct ieee802154_config config = {
815 .rx_slot.channel = aChannel,
816 .rx_slot.start = convert_32bit_us_wrapped_to_64bit_ns(aStart),
817 .rx_slot.duration = (net_time_t)aDuration * NSEC_PER_USEC,
818 };
819
820 result = radio_api->configure(radio_dev, IEEE802154_CONFIG_RX_SLOT,
821 &config);
822
823 return result ? OT_ERROR_FAILED : OT_ERROR_NONE;
824 }
825 #endif
826
827 #if defined(CONFIG_IEEE802154_CARRIER_FUNCTIONS)
platformRadioTransmitCarrier(otInstance * aInstance,bool aEnable)828 otError platformRadioTransmitCarrier(otInstance *aInstance, bool aEnable)
829 {
830 if (radio_api->continuous_carrier == NULL) {
831 return OT_ERROR_NOT_IMPLEMENTED;
832 }
833
834 if ((aEnable) && (sState == OT_RADIO_STATE_RECEIVE)) {
835 radio_api->set_txpower(radio_dev, get_transmit_power_for_channel(channel));
836
837 if (radio_api->continuous_carrier(radio_dev) != 0) {
838 return OT_ERROR_FAILED;
839 }
840
841 sState = OT_RADIO_STATE_TRANSMIT;
842 } else if ((!aEnable) && (sState == OT_RADIO_STATE_TRANSMIT)) {
843 return otPlatRadioReceive(aInstance, channel);
844 } else {
845 return OT_ERROR_INVALID_STATE;
846 }
847
848 return OT_ERROR_NONE;
849 }
850
platformRadioTransmitModulatedCarrier(otInstance * aInstance,bool aEnable,const uint8_t * aData)851 otError platformRadioTransmitModulatedCarrier(otInstance *aInstance, bool aEnable,
852 const uint8_t *aData)
853 {
854 if (radio_api->modulated_carrier == NULL) {
855 return OT_ERROR_NOT_IMPLEMENTED;
856 }
857
858 if (aEnable && sState == OT_RADIO_STATE_RECEIVE) {
859 if (aData == NULL) {
860 return OT_ERROR_INVALID_ARGS;
861 }
862
863 radio_api->set_txpower(radio_dev, get_transmit_power_for_channel(channel));
864
865 if (radio_api->modulated_carrier(radio_dev, aData) != 0) {
866 return OT_ERROR_FAILED;
867 }
868 sState = OT_RADIO_STATE_TRANSMIT;
869 } else if ((!aEnable) && sState == OT_RADIO_STATE_TRANSMIT) {
870 return otPlatRadioReceive(aInstance, channel);
871 } else {
872 return OT_ERROR_INVALID_STATE;
873 }
874
875 return OT_ERROR_NONE;
876 }
877
878 #endif /* CONFIG_IEEE802154_CARRIER_FUNCTIONS */
879
otPlatRadioGetState(otInstance * aInstance)880 otRadioState otPlatRadioGetState(otInstance *aInstance)
881 {
882 ARG_UNUSED(aInstance);
883
884 return sState;
885 }
886
otPlatRadioTransmit(otInstance * aInstance,otRadioFrame * aPacket)887 otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aPacket)
888 {
889 otError error = OT_ERROR_INVALID_STATE;
890
891 ARG_UNUSED(aInstance);
892 ARG_UNUSED(aPacket);
893
894 __ASSERT_NO_MSG(aPacket == &sTransmitFrame);
895
896 enum ieee802154_hw_caps radio_caps;
897
898 radio_caps = radio_api->get_capabilities(radio_dev);
899
900 if ((sState == OT_RADIO_STATE_RECEIVE) || (radio_caps & IEEE802154_HW_SLEEP_TO_TX)) {
901 if (run_tx_task(aInstance) == 0) {
902 error = OT_ERROR_NONE;
903 }
904 }
905
906 return error;
907 }
908
otPlatRadioGetTransmitBuffer(otInstance * aInstance)909 otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance)
910 {
911 ARG_UNUSED(aInstance);
912
913 return &sTransmitFrame;
914 }
915
get_rssi_energy_detected(const struct device * dev,int16_t max_ed)916 static void get_rssi_energy_detected(const struct device *dev, int16_t max_ed)
917 {
918 ARG_UNUSED(dev);
919 energy_detected_value = max_ed;
920 k_sem_give(&radio_sem);
921 }
922
otPlatRadioGetRssi(otInstance * aInstance)923 int8_t otPlatRadioGetRssi(otInstance *aInstance)
924 {
925 int8_t ret_rssi = INT8_MAX;
926 int error = 0;
927 const uint16_t detection_time = 1;
928 enum ieee802154_hw_caps radio_caps;
929 ARG_UNUSED(aInstance);
930
931 radio_caps = radio_api->get_capabilities(radio_dev);
932
933 if (!(radio_caps & IEEE802154_HW_ENERGY_SCAN)) {
934 /*
935 * TODO: No API in Zephyr to get the RSSI
936 * when IEEE802154_HW_ENERGY_SCAN is not available
937 */
938 ret_rssi = 0;
939 } else {
940 /*
941 * Blocking implementation of get RSSI
942 * using no-blocking ed_scan
943 */
944 error = radio_api->ed_scan(radio_dev, detection_time,
945 get_rssi_energy_detected);
946
947 if (error == 0) {
948 k_sem_take(&radio_sem, K_FOREVER);
949
950 ret_rssi = (int8_t)energy_detected_value;
951 }
952 }
953
954 return ret_rssi;
955 }
956
otPlatRadioGetCaps(otInstance * aInstance)957 otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
958 {
959 otRadioCaps caps = OT_RADIO_CAPS_NONE;
960
961 enum ieee802154_hw_caps radio_caps;
962 ARG_UNUSED(aInstance);
963 __ASSERT(radio_api,
964 "platformRadioInit needs to be called prior to otPlatRadioGetCaps");
965
966 radio_caps = radio_api->get_capabilities(radio_dev);
967
968 if (radio_caps & IEEE802154_HW_ENERGY_SCAN) {
969 caps |= OT_RADIO_CAPS_ENERGY_SCAN;
970 }
971
972 if (radio_caps & IEEE802154_HW_CSMA) {
973 caps |= OT_RADIO_CAPS_CSMA_BACKOFF;
974 }
975
976 if (radio_caps & IEEE802154_HW_TX_RX_ACK) {
977 caps |= OT_RADIO_CAPS_ACK_TIMEOUT;
978 }
979
980 if (radio_caps & IEEE802154_HW_SLEEP_TO_TX) {
981 caps |= OT_RADIO_CAPS_SLEEP_TO_TX;
982 }
983
984 #if !defined(CONFIG_OPENTHREAD_THREAD_VERSION_1_1)
985 if (radio_caps & IEEE802154_HW_TX_SEC) {
986 caps |= OT_RADIO_CAPS_TRANSMIT_SEC;
987 }
988 #endif
989
990 #if defined(CONFIG_NET_PKT_TXTIME)
991 if (radio_caps & IEEE802154_HW_TXTIME) {
992 caps |= OT_RADIO_CAPS_TRANSMIT_TIMING;
993 }
994 #endif
995
996 if (radio_caps & IEEE802154_HW_RXTIME) {
997 caps |= OT_RADIO_CAPS_RECEIVE_TIMING;
998 }
999
1000 if (radio_caps & IEEE802154_RX_ON_WHEN_IDLE) {
1001 caps |= OT_RADIO_CAPS_RX_ON_WHEN_IDLE;
1002 }
1003
1004 return caps;
1005 }
1006
otPlatRadioSetRxOnWhenIdle(otInstance * aInstance,bool aRxOnWhenIdle)1007 void otPlatRadioSetRxOnWhenIdle(otInstance *aInstance, bool aRxOnWhenIdle)
1008 {
1009 struct ieee802154_config config = {
1010 .rx_on_when_idle = aRxOnWhenIdle
1011 };
1012
1013 ARG_UNUSED(aInstance);
1014
1015 LOG_DBG("RxOnWhenIdle=%d", aRxOnWhenIdle ? 1 : 0);
1016
1017 radio_api->configure(radio_dev, IEEE802154_CONFIG_RX_ON_WHEN_IDLE, &config);
1018 }
1019
otPlatRadioGetPromiscuous(otInstance * aInstance)1020 bool otPlatRadioGetPromiscuous(otInstance *aInstance)
1021 {
1022 ARG_UNUSED(aInstance);
1023
1024 LOG_DBG("PromiscuousMode=%d", promiscuous ? 1 : 0);
1025
1026 return promiscuous;
1027 }
1028
otPlatRadioSetPromiscuous(otInstance * aInstance,bool aEnable)1029 void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable)
1030 {
1031 struct ieee802154_config config = {
1032 .promiscuous = aEnable
1033 };
1034
1035 ARG_UNUSED(aInstance);
1036
1037 LOG_DBG("PromiscuousMode=%d", aEnable ? 1 : 0);
1038
1039 promiscuous = aEnable;
1040 /* TODO: Should check whether the radio driver actually supports
1041 * promiscuous mode, see net_if_l2(iface)->get_flags() and
1042 * ieee802154_radio_get_hw_capabilities(iface).
1043 */
1044 radio_api->configure(radio_dev, IEEE802154_CONFIG_PROMISCUOUS, &config);
1045 }
1046
otPlatRadioEnergyScan(otInstance * aInstance,uint8_t aScanChannel,uint16_t aScanDuration)1047 otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel,
1048 uint16_t aScanDuration)
1049 {
1050 energy_detection_time = aScanDuration;
1051 energy_detection_channel = aScanChannel;
1052
1053 if (radio_api->ed_scan == NULL) {
1054 return OT_ERROR_NOT_IMPLEMENTED;
1055 }
1056
1057 reset_pending_event(PENDING_EVENT_DETECT_ENERGY);
1058 reset_pending_event(PENDING_EVENT_DETECT_ENERGY_DONE);
1059
1060 radio_api->set_channel(radio_dev, aScanChannel);
1061
1062 if (radio_api->ed_scan(radio_dev, energy_detection_time, energy_detected) != 0) {
1063 /*
1064 * OpenThread API does not accept failure of this function,
1065 * it can return 'No Error' or 'Not Implemented' error only.
1066 * If ed_scan start failed event is set to schedule the scan at
1067 * later time.
1068 */
1069 LOG_ERR("Failed do start energy scan, scheduling for later");
1070 set_pending_event(PENDING_EVENT_DETECT_ENERGY);
1071 }
1072
1073 return OT_ERROR_NONE;
1074 }
1075
otPlatRadioGetCcaEnergyDetectThreshold(otInstance * aInstance,int8_t * aThreshold)1076 otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *aInstance,
1077 int8_t *aThreshold)
1078 {
1079 OT_UNUSED_VARIABLE(aInstance);
1080 OT_UNUSED_VARIABLE(aThreshold);
1081
1082 return OT_ERROR_NOT_IMPLEMENTED;
1083 }
1084
otPlatRadioSetCcaEnergyDetectThreshold(otInstance * aInstance,int8_t aThreshold)1085 otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance,
1086 int8_t aThreshold)
1087 {
1088 OT_UNUSED_VARIABLE(aInstance);
1089 OT_UNUSED_VARIABLE(aThreshold);
1090
1091 return OT_ERROR_NOT_IMPLEMENTED;
1092 }
1093
otPlatRadioEnableSrcMatch(otInstance * aInstance,bool aEnable)1094 void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable)
1095 {
1096 ARG_UNUSED(aInstance);
1097
1098 struct ieee802154_config config = {
1099 .auto_ack_fpb.enabled = aEnable,
1100 .auto_ack_fpb.mode = IEEE802154_FPB_ADDR_MATCH_THREAD,
1101 };
1102
1103 (void)radio_api->configure(radio_dev, IEEE802154_CONFIG_AUTO_ACK_FPB,
1104 &config);
1105 }
1106
otPlatRadioAddSrcMatchShortEntry(otInstance * aInstance,const uint16_t aShortAddress)1107 otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance,
1108 const uint16_t aShortAddress)
1109 {
1110 ARG_UNUSED(aInstance);
1111
1112 uint8_t short_address[SHORT_ADDRESS_SIZE];
1113 struct ieee802154_config config = {
1114 .ack_fpb.enabled = true,
1115 .ack_fpb.addr = short_address,
1116 .ack_fpb.extended = false
1117 };
1118
1119 sys_put_le16(aShortAddress, short_address);
1120
1121 if (radio_api->configure(radio_dev, IEEE802154_CONFIG_ACK_FPB,
1122 &config) != 0) {
1123 return OT_ERROR_NO_BUFS;
1124 }
1125
1126 return OT_ERROR_NONE;
1127 }
1128
otPlatRadioAddSrcMatchExtEntry(otInstance * aInstance,const otExtAddress * aExtAddress)1129 otError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance,
1130 const otExtAddress *aExtAddress)
1131 {
1132 ARG_UNUSED(aInstance);
1133
1134 struct ieee802154_config config = {
1135 .ack_fpb.enabled = true,
1136 .ack_fpb.addr = (uint8_t *)aExtAddress->m8,
1137 .ack_fpb.extended = true
1138 };
1139
1140 if (radio_api->configure(radio_dev, IEEE802154_CONFIG_ACK_FPB,
1141 &config) != 0) {
1142 return OT_ERROR_NO_BUFS;
1143 }
1144
1145 return OT_ERROR_NONE;
1146 }
1147
otPlatRadioClearSrcMatchShortEntry(otInstance * aInstance,const uint16_t aShortAddress)1148 otError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance,
1149 const uint16_t aShortAddress)
1150 {
1151 ARG_UNUSED(aInstance);
1152
1153 uint8_t short_address[SHORT_ADDRESS_SIZE];
1154 struct ieee802154_config config = {
1155 .ack_fpb.enabled = false,
1156 .ack_fpb.addr = short_address,
1157 .ack_fpb.extended = false
1158 };
1159
1160 sys_put_le16(aShortAddress, short_address);
1161
1162 if (radio_api->configure(radio_dev, IEEE802154_CONFIG_ACK_FPB,
1163 &config) != 0) {
1164 return OT_ERROR_NO_BUFS;
1165 }
1166
1167 return OT_ERROR_NONE;
1168 }
1169
otPlatRadioClearSrcMatchExtEntry(otInstance * aInstance,const otExtAddress * aExtAddress)1170 otError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance,
1171 const otExtAddress *aExtAddress)
1172 {
1173 ARG_UNUSED(aInstance);
1174
1175 struct ieee802154_config config = {
1176 .ack_fpb.enabled = false,
1177 .ack_fpb.addr = (uint8_t *)aExtAddress->m8,
1178 .ack_fpb.extended = true
1179 };
1180
1181 if (radio_api->configure(radio_dev, IEEE802154_CONFIG_ACK_FPB,
1182 &config) != 0) {
1183 return OT_ERROR_NO_BUFS;
1184 }
1185
1186 return OT_ERROR_NONE;
1187 }
1188
otPlatRadioClearSrcMatchShortEntries(otInstance * aInstance)1189 void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance)
1190 {
1191 ARG_UNUSED(aInstance);
1192
1193 struct ieee802154_config config = {
1194 .ack_fpb.enabled = false,
1195 .ack_fpb.addr = NULL,
1196 .ack_fpb.extended = false
1197 };
1198
1199 (void)radio_api->configure(radio_dev, IEEE802154_CONFIG_ACK_FPB,
1200 &config);
1201 }
1202
otPlatRadioClearSrcMatchExtEntries(otInstance * aInstance)1203 void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance)
1204 {
1205 ARG_UNUSED(aInstance);
1206
1207 struct ieee802154_config config = {
1208 .ack_fpb.enabled = false,
1209 .ack_fpb.addr = NULL,
1210 .ack_fpb.extended = true
1211 };
1212
1213 (void)radio_api->configure(radio_dev, IEEE802154_CONFIG_ACK_FPB,
1214 &config);
1215 }
1216
otPlatRadioGetReceiveSensitivity(otInstance * aInstance)1217 int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
1218 {
1219 ARG_UNUSED(aInstance);
1220
1221 return CONFIG_OPENTHREAD_DEFAULT_RX_SENSITIVITY;
1222 }
1223
otPlatRadioGetTransmitPower(otInstance * aInstance,int8_t * aPower)1224 otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower)
1225 {
1226 ARG_UNUSED(aInstance);
1227
1228 if (aPower == NULL) {
1229 return OT_ERROR_INVALID_ARGS;
1230 }
1231
1232 *aPower = tx_power;
1233
1234 return OT_ERROR_NONE;
1235 }
1236
otPlatRadioSetTransmitPower(otInstance * aInstance,int8_t aPower)1237 otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower)
1238 {
1239 ARG_UNUSED(aInstance);
1240
1241 tx_power = aPower;
1242
1243 return OT_ERROR_NONE;
1244 }
1245
otPlatTimeGet(void)1246 uint64_t otPlatTimeGet(void)
1247 {
1248 if (radio_api == NULL || radio_api->get_time == NULL) {
1249 return k_ticks_to_us_floor64(k_uptime_ticks());
1250 } else {
1251 return radio_api->get_time(radio_dev) / NSEC_PER_USEC;
1252 }
1253 }
1254
1255 #if defined(CONFIG_NET_PKT_TXTIME)
otPlatRadioGetNow(otInstance * aInstance)1256 uint64_t otPlatRadioGetNow(otInstance *aInstance)
1257 {
1258 ARG_UNUSED(aInstance);
1259
1260 return otPlatTimeGet();
1261 }
1262 #endif
1263
1264 #if !defined(CONFIG_OPENTHREAD_THREAD_VERSION_1_1)
otPlatRadioSetMacKey(otInstance * aInstance,uint8_t aKeyIdMode,uint8_t aKeyId,const otMacKeyMaterial * aPrevKey,const otMacKeyMaterial * aCurrKey,const otMacKeyMaterial * aNextKey,otRadioKeyType aKeyType)1265 void otPlatRadioSetMacKey(otInstance *aInstance, uint8_t aKeyIdMode, uint8_t aKeyId,
1266 const otMacKeyMaterial *aPrevKey, const otMacKeyMaterial *aCurrKey,
1267 const otMacKeyMaterial *aNextKey, otRadioKeyType aKeyType)
1268 {
1269 ARG_UNUSED(aInstance);
1270 __ASSERT_NO_MSG(aPrevKey != NULL && aCurrKey != NULL && aNextKey != NULL);
1271
1272 #if defined(CONFIG_OPENTHREAD_PLATFORM_KEYS_EXPORTABLE_ENABLE)
1273 __ASSERT_NO_MSG(aKeyType == OT_KEY_TYPE_KEY_REF);
1274 size_t keyLen;
1275 otError error;
1276
1277 error = otPlatCryptoExportKey(aPrevKey->mKeyMaterial.mKeyRef,
1278 (uint8_t *)aPrevKey->mKeyMaterial.mKey.m8, OT_MAC_KEY_SIZE,
1279 &keyLen);
1280 __ASSERT_NO_MSG(error == OT_ERROR_NONE);
1281 error = otPlatCryptoExportKey(aCurrKey->mKeyMaterial.mKeyRef,
1282 (uint8_t *)aCurrKey->mKeyMaterial.mKey.m8, OT_MAC_KEY_SIZE,
1283 &keyLen);
1284 __ASSERT_NO_MSG(error == OT_ERROR_NONE);
1285 error = otPlatCryptoExportKey(aNextKey->mKeyMaterial.mKeyRef,
1286 (uint8_t *)aNextKey->mKeyMaterial.mKey.m8, OT_MAC_KEY_SIZE,
1287 &keyLen);
1288 __ASSERT_NO_MSG(error == OT_ERROR_NONE);
1289 #else
1290 __ASSERT_NO_MSG(aKeyType == OT_KEY_TYPE_LITERAL_KEY);
1291 #endif
1292
1293 uint8_t key_id_mode = aKeyIdMode >> 3;
1294
1295 struct ieee802154_key keys[] = {
1296 {
1297 .key_id_mode = key_id_mode,
1298 .frame_counter_per_key = false,
1299 },
1300 {
1301 .key_id_mode = key_id_mode,
1302 .frame_counter_per_key = false,
1303 },
1304 {
1305 .key_id_mode = key_id_mode,
1306 .frame_counter_per_key = false,
1307 },
1308 {
1309 .key_value = NULL,
1310 },
1311 };
1312
1313 struct ieee802154_key clear_keys[] = {
1314 {
1315 .key_value = NULL,
1316 },
1317 };
1318
1319 if (key_id_mode == 1) {
1320 /* aKeyId in range: (1, 0x80) means valid keys */
1321 uint8_t prev_key_id = aKeyId == 1 ? 0x80 : aKeyId - 1;
1322 uint8_t next_key_id = aKeyId == 0x80 ? 1 : aKeyId + 1;
1323
1324 keys[0].key_id = &prev_key_id;
1325 keys[0].key_value = (uint8_t *)aPrevKey->mKeyMaterial.mKey.m8;
1326
1327 keys[1].key_id = &aKeyId;
1328 keys[1].key_value = (uint8_t *)aCurrKey->mKeyMaterial.mKey.m8;
1329
1330 keys[2].key_id = &next_key_id;
1331 keys[2].key_value = (uint8_t *)aNextKey->mKeyMaterial.mKey.m8;
1332 } else {
1333 /* aKeyId == 0 is used only to clear keys for stack reset in RCP */
1334 __ASSERT_NO_MSG((key_id_mode == 0) && (aKeyId == 0));
1335 }
1336
1337 struct ieee802154_config config = {
1338 .mac_keys = aKeyId == 0 ? clear_keys : keys,
1339 };
1340
1341 (void)radio_api->configure(radio_dev, IEEE802154_CONFIG_MAC_KEYS,
1342 &config);
1343 }
1344
otPlatRadioSetMacFrameCounter(otInstance * aInstance,uint32_t aMacFrameCounter)1345 void otPlatRadioSetMacFrameCounter(otInstance *aInstance,
1346 uint32_t aMacFrameCounter)
1347 {
1348 ARG_UNUSED(aInstance);
1349
1350 struct ieee802154_config config = { .frame_counter = aMacFrameCounter };
1351
1352 (void)radio_api->configure(radio_dev, IEEE802154_CONFIG_FRAME_COUNTER,
1353 &config);
1354 }
1355
otPlatRadioSetMacFrameCounterIfLarger(otInstance * aInstance,uint32_t aMacFrameCounter)1356 void otPlatRadioSetMacFrameCounterIfLarger(otInstance *aInstance, uint32_t aMacFrameCounter)
1357 {
1358 ARG_UNUSED(aInstance);
1359
1360 struct ieee802154_config config = { .frame_counter = aMacFrameCounter };
1361 (void)radio_api->configure(radio_dev, IEEE802154_CONFIG_FRAME_COUNTER_IF_LARGER,
1362 &config);
1363 }
1364 #endif
1365
1366 #if defined(CONFIG_OPENTHREAD_CSL_RECEIVER)
otPlatRadioEnableCsl(otInstance * aInstance,uint32_t aCslPeriod,otShortAddress aShortAddr,const otExtAddress * aExtAddr)1367 otError otPlatRadioEnableCsl(otInstance *aInstance, uint32_t aCslPeriod, otShortAddress aShortAddr,
1368 const otExtAddress *aExtAddr)
1369 {
1370 struct ieee802154_config config;
1371 /* CSL phase will be injected on-the-fly by the driver. */
1372 struct ieee802154_header_ie header_ie =
1373 IEEE802154_DEFINE_HEADER_IE_CSL_REDUCED(/* phase */ 0, aCslPeriod);
1374 int result;
1375
1376 ARG_UNUSED(aInstance);
1377
1378 /* Configure the CSL period first to give drivers a chance to validate
1379 * the IE for consistency if they wish to.
1380 */
1381 config.csl_period = aCslPeriod;
1382 result = radio_api->configure(radio_dev, IEEE802154_CONFIG_CSL_PERIOD, &config);
1383 if (result) {
1384 return OT_ERROR_FAILED;
1385 }
1386
1387 /* Configure the CSL IE. */
1388 config.ack_ie.header_ie = aCslPeriod > 0 ? &header_ie : NULL;
1389 config.ack_ie.short_addr = aShortAddr;
1390 config.ack_ie.ext_addr = aExtAddr != NULL ? aExtAddr->m8 : NULL;
1391 config.ack_ie.purge_ie = false;
1392
1393 result = radio_api->configure(radio_dev, IEEE802154_CONFIG_ENH_ACK_HEADER_IE, &config);
1394
1395 return result ? OT_ERROR_FAILED : OT_ERROR_NONE;
1396 }
1397
otPlatRadioResetCsl(otInstance * aInstance)1398 otError otPlatRadioResetCsl(otInstance *aInstance)
1399 {
1400 struct ieee802154_config config = { 0 };
1401 int result;
1402
1403 result = radio_api->configure(radio_dev, IEEE802154_CONFIG_CSL_PERIOD, &config);
1404 if (result) {
1405 return OT_ERROR_FAILED;
1406 }
1407
1408 config.ack_ie.purge_ie = true;
1409 result = radio_api->configure(radio_dev, IEEE802154_CONFIG_ENH_ACK_HEADER_IE, &config);
1410
1411 return result ? OT_ERROR_FAILED : OT_ERROR_NONE;
1412 }
1413
otPlatRadioUpdateCslSampleTime(otInstance * aInstance,uint32_t aCslSampleTime)1414 void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, uint32_t aCslSampleTime)
1415 {
1416 ARG_UNUSED(aInstance);
1417
1418 /* CSL sample time points to "start of MAC" while the expected RX time
1419 * refers to "end of SFD".
1420 */
1421 struct ieee802154_config config = {
1422 .expected_rx_time =
1423 convert_32bit_us_wrapped_to_64bit_ns(aCslSampleTime - PHR_DURATION_US),
1424 };
1425
1426 (void)radio_api->configure(radio_dev, IEEE802154_CONFIG_EXPECTED_RX_TIME, &config);
1427 }
1428 #endif /* CONFIG_OPENTHREAD_CSL_RECEIVER */
1429
1430 #if defined(CONFIG_OPENTHREAD_WAKEUP_COORDINATOR)
otPlatRadioEnableCst(otInstance * aInstance,uint32_t aCstPeriod,otShortAddress aShortAddr,const otExtAddress * aExtAddr)1431 otError otPlatRadioEnableCst(otInstance *aInstance, uint32_t aCstPeriod, otShortAddress aShortAddr,
1432 const otExtAddress *aExtAddr)
1433 {
1434 struct ieee802154_config config;
1435 int result;
1436 uint8_t header_ie[OT_IE_HEADER_SIZE + OT_THREAD_IE_SIZE + OT_CST_IE_SIZE] = { 0 };
1437 size_t index = 0;
1438
1439 ARG_UNUSED(aInstance);
1440
1441 /* Configure the CST period first to give drivers a chance to validate
1442 * the IE for consistency if they wish to.
1443 */
1444 config.cst_period = aCstPeriod;
1445 result = radio_api->configure(radio_dev, IEEE802154_OPENTHREAD_CONFIG_CST_PERIOD, &config);
1446 if (result) {
1447 return OT_ERROR_FAILED;
1448 }
1449
1450 /* Configure the CST IE. */
1451 header_ie[index++] = OT_THREAD_IE_SIZE + OT_CST_IE_SIZE;
1452 header_ie[index++] = 0;
1453 sys_put_le24(THREAD_IE_VENDOR_OUI, &header_ie[index]);
1454 index += 3;
1455 header_ie[index++] = THREAD_IE_SUBTYPE_CST;
1456 /* Leave CST Phase empty intentionally */
1457 index += 2;
1458 sys_put_le16(aCstPeriod, &header_ie[index]);
1459 index += 2;
1460
1461 config.ack_ie.header_ie = aCstPeriod > 0 ? (struct ieee802154_header_ie *)header_ie : NULL;
1462 config.ack_ie.short_addr = aShortAddr;
1463 config.ack_ie.ext_addr = aExtAddr != NULL ? aExtAddr->m8 : NULL;
1464 config.ack_ie.purge_ie = false;
1465
1466 result = radio_api->configure(radio_dev, IEEE802154_CONFIG_ENH_ACK_HEADER_IE, &config);
1467
1468 return result ? OT_ERROR_FAILED : OT_ERROR_NONE;
1469 }
1470
otPlatRadioUpdateCstSampleTime(otInstance * aInstance,uint32_t aCstSampleTime)1471 void otPlatRadioUpdateCstSampleTime(otInstance *aInstance, uint32_t aCstSampleTime)
1472 {
1473 int result;
1474
1475 ARG_UNUSED(aInstance);
1476
1477 struct ieee802154_config config = {
1478 .expected_tx_time = convert_32bit_us_wrapped_to_64bit_ns(
1479 aCstSampleTime - PHR_DURATION_US),
1480 };
1481
1482 result = radio_api->configure(radio_dev, IEEE802154_OPENTHREAD_CONFIG_EXPECTED_TX_TIME,
1483 &config);
1484 __ASSERT_NO_MSG(result == 0);
1485 (void)result;
1486 }
1487 #endif /* CONFIG_OPENTHREAD_WAKEUP_COORDINATOR */
1488
otPlatRadioGetCslAccuracy(otInstance * aInstance)1489 uint8_t otPlatRadioGetCslAccuracy(otInstance *aInstance)
1490 {
1491 ARG_UNUSED(aInstance);
1492
1493 return radio_api->get_sch_acc(radio_dev);
1494 }
1495
1496 #if defined(CONFIG_OPENTHREAD_PLATFORM_CSL_UNCERT)
otPlatRadioGetCslUncertainty(otInstance * aInstance)1497 uint8_t otPlatRadioGetCslUncertainty(otInstance *aInstance)
1498 {
1499 ARG_UNUSED(aInstance);
1500
1501 return CONFIG_OPENTHREAD_PLATFORM_CSL_UNCERT;
1502 }
1503 #endif
1504
1505 #if defined(CONFIG_OPENTHREAD_LINK_METRICS_SUBJECT)
1506 /**
1507 * Header IE format - IEEE Std. 802.15.4-2015, 7.4.2.1 && 7.4.2.2
1508 *
1509 * +---------------------------------+----------------------+
1510 * | Length | Element ID | Type=0 | Vendor OUI |
1511 * +-----------+------------+--------+----------------------+
1512 * | Bytes: 0-1 | 2-4 |
1513 * +-----------+---------------------+----------------------+
1514 * | Bits: 0-6 | 7-14 | 15 | IE_VENDOR_THREAD_OUI |
1515 * +-----------+------------+--------+----------------------|
1516 *
1517 * Thread v1.2.1 Spec., 4.11.3.4.4.6
1518 * +---------------------------------+-------------------+------------------+
1519 * | Vendor Specific Information |
1520 * +---------------------------------+-------------------+------------------+
1521 * | 5 | 6 | 7 (optional) |
1522 * +---------------------------------+-------------------+------------------+
1523 * | IE_VENDOR_THREAD_ACK_PROBING_ID | LINK_METRIC_TOKEN | LINK_METRIC_TOKEN|
1524 * |---------------------------------|-------------------|------------------|
1525 */
set_vendor_ie_header_lm(bool lqi,bool link_margin,bool rssi,uint8_t * ie_header)1526 static void set_vendor_ie_header_lm(bool lqi, bool link_margin, bool rssi, uint8_t *ie_header)
1527 {
1528 /* Vendor-specific IE identifier */
1529 const uint8_t ie_vendor_id = 0x00;
1530 /* Thread Vendor-specific ACK Probing IE subtype ID */
1531 const uint8_t ie_vendor_thread_ack_probing_id = 0x00;
1532 /* Thread Vendor-specific IE OUI */
1533 const uint32_t ie_vendor_thread_oui = 0xeab89b;
1534 /* Thread Vendor-specific ACK Probing IE RSSI value placeholder */
1535 const uint8_t ie_vendor_thread_rssi_token = 0x01;
1536 /* Thread Vendor-specific ACK Probing IE Link margin value placeholder */
1537 const uint8_t ie_vendor_thread_margin_token = 0x02;
1538 /* Thread Vendor-specific ACK Probing IE LQI value placeholder */
1539 const uint8_t ie_vendor_thread_lqi_token = 0x03;
1540 const uint8_t oui_size = 3;
1541 const uint8_t sub_type = 1;
1542 const uint8_t id_offset = 7;
1543 const uint16_t id_mask = 0x00ff << id_offset;
1544 const uint8_t type = 0x00;
1545 const uint8_t type_offset = 7;
1546 const uint8_t type_mask = 0x01 << type_offset;
1547 const uint8_t length_mask = 0x7f;
1548 uint8_t content_len;
1549 uint16_t element_id = 0x0000;
1550 uint8_t link_metrics_idx = 6;
1551 uint8_t link_metrics_data_len = (uint8_t)lqi + (uint8_t)link_margin + (uint8_t)rssi;
1552
1553 __ASSERT(link_metrics_data_len <= 2, "Thread limits to 2 metrics at most");
1554 __ASSERT(ie_header, "Invalid argument");
1555
1556 if (link_metrics_data_len == 0) {
1557 ie_header[0] = 0;
1558 return;
1559 }
1560
1561 /* Set Element ID */
1562 element_id = (((uint16_t)ie_vendor_id) << id_offset) & id_mask;
1563 sys_put_le16(element_id, &ie_header[0]);
1564
1565 /* Set Length - number of octets in content field. */
1566 content_len = oui_size + sub_type + link_metrics_data_len;
1567 ie_header[0] = (ie_header[0] & ~length_mask) | (content_len & length_mask);
1568
1569 /* Set Type */
1570 ie_header[1] = (ie_header[1] & ~type_mask) | (type & type_mask);
1571
1572 /* Set Vendor Oui */
1573 sys_put_le24(ie_vendor_thread_oui, &ie_header[2]);
1574
1575 /* Set SubType */
1576 ie_header[5] = ie_vendor_thread_ack_probing_id;
1577
1578 /* Set Link Metrics Tokens
1579 * TODO: Thread requires the order of requested metrics by the Link Metrics Initiator
1580 * to be kept by the Link Metrics Subject in the ACKs.
1581 */
1582 if (lqi) {
1583 ie_header[link_metrics_idx++] = ie_vendor_thread_lqi_token;
1584 }
1585
1586 if (link_margin) {
1587 ie_header[link_metrics_idx++] = ie_vendor_thread_margin_token;
1588 }
1589
1590 if (rssi) {
1591 ie_header[link_metrics_idx++] = ie_vendor_thread_rssi_token;
1592 }
1593 }
1594
otPlatRadioConfigureEnhAckProbing(otInstance * aInstance,otLinkMetrics aLinkMetrics,const otShortAddress aShortAddress,const otExtAddress * aExtAddress)1595 otError otPlatRadioConfigureEnhAckProbing(otInstance *aInstance, otLinkMetrics aLinkMetrics,
1596 const otShortAddress aShortAddress,
1597 const otExtAddress *aExtAddress)
1598 {
1599 struct ieee802154_config config = {
1600 .ack_ie.short_addr = aShortAddress,
1601 .ack_ie.ext_addr = aExtAddress->m8,
1602 };
1603 uint8_t header_ie_buf[OT_ACK_IE_MAX_SIZE];
1604 int result;
1605
1606 ARG_UNUSED(aInstance);
1607
1608 set_vendor_ie_header_lm(aLinkMetrics.mLqi, aLinkMetrics.mLinkMargin,
1609 aLinkMetrics.mRssi, header_ie_buf);
1610 config.ack_ie.header_ie = (struct ieee802154_header_ie *)header_ie_buf;
1611 result = radio_api->configure(radio_dev, IEEE802154_CONFIG_ENH_ACK_HEADER_IE, &config);
1612
1613 return result ? OT_ERROR_FAILED : OT_ERROR_NONE;
1614 }
1615
1616 #endif /* CONFIG_OPENTHREAD_LINK_METRICS_SUBJECT */
1617
otPlatRadioSetChannelMaxTransmitPower(otInstance * aInstance,uint8_t aChannel,int8_t aMaxPower)1618 otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance, uint8_t aChannel,
1619 int8_t aMaxPower)
1620 {
1621 ARG_UNUSED(aInstance);
1622
1623 if (aChannel < OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN ||
1624 aChannel > OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX) {
1625 return OT_ERROR_INVALID_ARGS;
1626 }
1627
1628 max_tx_power_table[aChannel - OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN] = aMaxPower;
1629
1630 if (aChannel == channel) {
1631 radio_api->set_txpower(radio_dev, get_transmit_power_for_channel(aChannel));
1632 }
1633
1634 return OT_ERROR_NONE;
1635 }
1636