Commit graph zephyr/subsys/lorawan
Author SHA1 Message Date
Cesar Vandevelde
72aa7742b3 lorawan: use K_MSGQ_DEFINE_STATIC_TYPE
This macro eliminates manual size/alignment management and prevents
namespace collisions by moving internal queues to file-private scope.

Signed-off-by: Cesar Vandevelde <cesar.vandevelde@gmail.com>
2026-08-04 18:46:53 +01:00
Carlo Caione
c447cc9cd5 lorawan: native: report FPending on payload-less downlinks
A downlink carrying only the FPending bit (no ACK, no FRMPayload and
no pending MAC answer) was dropped without notifying the application,
losing the queued-downlink hint. Dispatch a payload-less notification
whenever the frame carries an ACK or any flag worth reporting.

Assisted-by: claude-opus 4.8
Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-07-09 07:58:44 +02:00
Carlo Caione
97c87b04e3 lorawan: native: reject application uplinks on FPort 0
FPort 0 is reserved for MAC commands; an application payload sent on port 0
would be encrypted with the network session key and parsed as MAC commands
by the server.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-07-09 07:58:44 +02:00
Carlo Caione
2323d502fa lorawan: native: route FPort 0 downlink payload to MAC parser
Per spec FPort 0 carries MAC commands only (encrypted with FNwkSIntKey)
and cannot be combined with FOpts MAC commands in the same frame: feed the
decrypted payload to the MAC command parser before any session state is
committed, reject frames mixing the two forms, and never deliver port-0
payload to the application downlink callbacks.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-07-09 07:58:44 +02:00
Carlo Caione
83183cd555 lorawan: native: implement lorawan_request_link_check
Queue the LinkCheckReq via the engine so it rides the next uplink; with
force_request mac_do_link_check() triggers the empty unconfirmed uplink
itself.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-07-09 07:58:44 +02:00
Carlo Caione
0899bb403b lorawan: native: account for pending FOpts in the payload budget
MAC commands in FOpts eat into the maximum application payload for the
datarate. Subtract the pending FOpts length when validating an uplink and
in lorawan_get_payload_sizes(), which now returns distinct values for the
next payload and the no-FOpts maximum.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-07-09 07:58:44 +02:00
Carlo Caione
2a81f7f573 lorawan: native: parse downlink FOpts MAC commands
Walk the downlink FOpts with a CID/length table so known-but-unhandled
commands are skipped and a trailing LinkCheckAns is still reached;
unknown CIDs terminate parsing since their length is unknown. Commands are
processed only after MIC verification and replay checks.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-07-09 07:58:44 +02:00
Carlo Caione
9d17a5853b lorawan: native: queue and emit LinkCheckReq in uplink FOpts
Add the LWAN_REQ_LINK_CHECK engine request: the handler queues a
LinkCheckReq that the FOpts builder emits on the next uplink.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-07-09 07:58:44 +02:00
Carlo Caione
292d48ad3a lorawan: native: do not use -EAGAIN as retry sentinel
Use a positive sentinel for the confirmed-uplink retry loop so a real
-EAGAIN propagated from the TX/RX path cannot be mistaken for a retry
request.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-07-09 07:58:44 +02:00
Carlo Caione
f8bdf18bcf lorawan: native: split join and send helpers
No functional changes in this commit.

mac_do_join() and mac_do_send() had grown into long monolithic functions.
Split frame building, downlink parsing and the retry loop into small
single-purpose helpers and group the per-transaction variables into
join_state / send_state structs.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-07-09 07:58:44 +02:00
Etienne Carriere
b9c806ece5 lorawan: use diamond include for non-local header files
Use #include <> instead of #include "" to include a header file which path
is not relative to the directory path of the file emitting the #include
directive.

This change was made running scripts/check_quoted_includes.py script
proposed in https://github.com/zephyrproject-rtos/zephyr/pull/112135
with the Linux shell command below and manually selecting the applicable
changes:
$ find subsys/lorawan/ -type f -exec \
    ./scripts/check_quoted_includes.py -w {} \;

Signed-off-by: Etienne Carriere <etienne.carriere@st.com>
2026-06-30 18:23:17 -04:00
Michael Zimmermann
e10af22991 tree-wide: replace usages of k_work_q thread with thread_id
The `thread` field is not initialized, if it's being animated via
k_work_queue_run instead of k_work_queue_start.

Signed-off-by: Michael Zimmermann <michael.zimmermann@sevenlab.de>
2026-06-29 22:17:45 -04:00
Anas Nashif
0d2d7ae32a lorawan: multicast: validate McGroupSetupReq payload length
The MC_GROUP_SETUP handler read 29 bytes (1 id + 4 McAddr + 16 McKeyE +
4 FCountMin + 4 FCountMax) from the downlink buffer without checking
that at least 29 bytes remained after the command byte.

Assisted-by: Claude Code:claude-opus-4.8
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-27 00:45:04 +02:00
Anas Nashif
237309ea7c lorawan: frag_transport: validate downlink length before struct cast
Two gaps in frag_transport_service_handler():
1. The FRAG_SESSION_SETUP case cast rx_buf + rx_pos to struct
   frag_transport_setup_req (10 bytes) without checking remaining bytes.
2. The DATA_FRAGMENT case passed rx_buf[rx_pos] to the decoder without
   confirming that len - rx_pos >= ctx.frag_size.

Add remaining-length guards before each access.

Assisted-by: Claude Code:claude-opus-4.8
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-27 00:45:04 +02:00
Anas Nashif
3d57806765 lorawan: clock_sync: validate AppTimeAns payload length
The APP_TIME handler read 5 bytes (4-byte time correction + 1-byte token)
without checking that at least 5 bytes remained in the receive buffer,
allowing a short or crafted downlink to read past the end.

Assisted-by: Claude Code:claude-opus-4.8
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-27 00:45:04 +02:00
Anas Nashif
452c704a28 lorawan: frag_transport: reject fragment index 0
DataFragment fragments are 1-indexed. A frag_counter of 0 underflows
(frag_counter - 1) in the decoder, producing a wild frame index and
flash offset. Reject it at the transport layer.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-15 18:37:10 -04:00
Flavio Ceolin
8394a0b0e4 lorawan: clock_sync: avoid left shift signed UB
cast uint8_t to uint32_t before << 24 to avoid signed UB in
clock_sync_package_callback.

By undefined behavior sanitizer:
runtime error: left shift of 128 by 24 places cannot be
represented in type 'int'

Signed-off-by: Flavio Ceolin <flavio@hubblenetwork.com>
2026-06-10 20:11:25 -04:00
Carlo Caione
1f43e153e9 lorawan: native: reject user datarate overrides while ADR is enabled
When ADR is enabled the network controls the datarate through LinkADRReq
so a user-issued lorawan_set_datarate() at that point should not have any
effect.

Applications that want to manually control the datarate must call
lorawan_enable_adr(false) first.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-05-25 13:39:11 +02:00
Carlo Caione
ff8f596f82 lorawan: native: serialize API state through engine
Make Engine Great Again (MEGA), that is route synchronous native LoRaWAN
API work through the engine thread so the engine remains the single writer
of runtime MAC state.

Replace the shared join/send result queues with caller-owned completion
state carried by each engine request. The API caller posts a request and
waits on its own semaphore, while the MAC handler stores the result and
signals that specific request. This removes result matching from shared
queues and lets join/send wait without holding api_mutex.

Move also runtime configuration updates onto the engine thread allowing us
to drop api_mutex once runtime mutations are engine-owned.

Update the public API documentation, migration guide, and native backend
version to reflect a new stricter functions ordering.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-05-25 13:39:11 +02:00
Carlo Caione
db90e8b28c lorawan: native: accept downlinks with unsupported FOpts
Commit 68c95f8e8f ("lorawan: native: reject unsupported downlink
FOpts") rejects any downlink that carries FOpts bytes, ahead of MIC
verification, by returning -ENOTSUP from mac_parse_downlink().

Real networks (TTN, ChirpStack, ...) typically issue a LinkADRReq within
the first downlinks after join, so the very first confirmed uplink response
carries FOpts and gets dropped.

Keep instead a non-fatal LOG_WRN after MIC verification so an operator
still sees that the network is issuing commands the stack does not yet
act on. Moving the warning past MIC also avoids spamming on spoofed or
corrupted frames.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-05-25 13:39:11 +02:00
Dwij Patel
c0ccc2b2c1 lorawan: multicast: fix delay units (s vs ms)
The delay for multicast responses was calculated in seconds but
lorawan_services_schedule_uplink() expects milliseconds.

According to RP002-1.0.3 chapter 2.3, the intended delay is 2+-1
seconds (i.e. a random value in the range [1, 3] seconds). The fix
converts to milliseconds using MSEC_PER_SEC:

  uint32_t delay_ms = MSEC_PER_SEC +
                      (sys_rand32_get() % (2 * MSEC_PER_SEC));

The variable is also renamed from delay to delay_ms to make the unit
explicit and consistent with the fix in frag_transport.c.

Without this fix, the response is delayed by only 1-3ms instead of
1-3s, which could cause uplink collisions when multiple devices
simultaneously respond to a multicast setup command.

Signed-off-by: Dwij Patel <dwijpatel7@gmail.com>
2026-05-13 19:02:04 +01:00
Dwij Patel
87cde7e89a lorawan: frag_transport: fix BlockAckDelay units (s vs ms)
The ans_delay for FRAG_TRANSPORT_CMD_FRAG_STATUS was calculated in
seconds but lorawan_services_schedule_uplink() expects milliseconds.

According to the LoRa Alliance Fragmented Data Block Transport spec,
the actual delay SHALL be rand() * 2^(BlockAckDelay+4) seconds.
The correct fix computes the full window in milliseconds using
MSEC_PER_SEC and proper bracket ordering to avoid operator precedence
issues with the shift operator:

  ans_delay_ms = sys_rand32_get() %
                 ((1U << (ctx.block_ack_delay + 4)) * MSEC_PER_SEC);

The variable is also renamed from ans_delay to ans_delay_ms to make
the unit explicit and help avoid similar bugs in the future.

Without this fix, the delay window for e.g. BlockAckDelay=0 is 0-16ms
instead of 0-16s, causing all devices in a multicast group to respond
nearly simultaneously and defeating the collision avoidance mechanism.

Signed-off-by: Dwij Patel <dwijpatel7@gmail.com>
2026-05-13 05:14:16 +02:00
Carlo Caione
68c95f8e8f lorawan: native: reject unsupported downlink FOpts
Downlink MAC commands are not parsed yet.

Reject frames that carry FOpts before advancing FCntDown so the stack
does not silently consume network commands it cannot handle.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-05-08 11:25:50 +02:00
Carlo Caione
de3d359c0f lorawan: native: bound confirmed retry count
LoRaWAN NbTrans is encoded in the 1..15 range.

Reject zero and out-of-range values so confirmed sends cannot block for
an unexpectedly large number of attempts.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-05-08 11:25:50 +02:00
Carlo Caione
c508df15c6 lorawan: native: serialize mutable API state
Several public APIs update or consume shared MAC state while the engine
thread is processing join and send requests.

Use a single API mutex for join, send, and mutable setters so only one
public operation can touch the native LoRaWAN state at a time. Also
reject region changes after the stack has started.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-05-08 11:25:50 +02:00
Carlo Caione
755784b934 lorawan: native: validate downlink FOpts length
Do not trust FCtrl.FOptsLen until it has been checked against the actual
frame length.

Reject frames whose FOpts area would overlap the MIC or extend past the
received buffer before verifying the MIC or updating FCntDown.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-05-08 11:25:50 +02:00
Carlo Caione
ea1e48121e lorawan: native: reuse confirmed frame for retries
Confirmed uplink retries must retransmit the same LoRaWAN frame.
Rebuilding each attempt advanced FCntUp and changed the MIC, allowing a
missed ACK to turn a retry into a second application uplink.

Build the frame once, reuse it for confirmed retry attempts, and consume
FCntUp once after transmission.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-05-08 11:25:50 +02:00
Carlo Caione
e4af8f1912 lorawan: require channel mask after stack start
Channel masks apply to the region channel plan initialized by
lorawan_start(). Accepting a mask before start leaves the backend without
a concrete channel table to update.

Document the ordering requirement in the public API and have the native
backend return -EPERM until the stack has been started.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-05-08 11:25:50 +02:00
Carlo Caione
e70f8670d2 lorawan: native: derive LWAN_MAX_CHANNELS from selected region(s)
The per-session channel table size is a spec-mandated property of
the region (EU868: 16, US915/AU915: 72, CN470: 96, ...) and is
not a user preference: a region needs exactly as many slots as its
channel plan defines, no more, no less.

Replace the hardcoded #define with a hidden Kconfig in the region
subdirectory.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-04-29 16:31:27 -04:00
Carlo Caione
0b12f16657 lorawan: native: mac: insert FOpts and ADR bit in uplink data frames
Refactor mac_build_data_frame() so uplink frames can carry MAC
commands in the FOpts region between FHDR and FPort, and set the
FCtrl.ADR bit when lorawan_enable_adr() has been called.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-04-29 16:31:27 -04:00
Carlo Caione
fabba3d255 lorawan: native: region: thread tx_power_idx through get_tx_params
Widen the get_tx_params() region op to accept a TX power index and
compute the effective dBm from it.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-04-29 16:31:27 -04:00
Carlo Caione
b0299eeb16 lorawan: native: region: add helper functions for MAC commands
Add three region-ops function pointers needed by the upcoming MAC
command framework to validate and apply parameters from LinkADRReq:

  - validate_dr: is a datarate index defined in this region?
  - validate_tx_power: is a TX power index defined in this region?
  - apply_channel_mask: apply a ChMaskCntl + ChMask pair to the
    channel table, atomically (no partial mutation on failure).

Implement them for EU868.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-04-29 16:31:27 -04:00
Carlo Caione
3b6e080ea1 lorawan: native: add EU868 region support
Add the EU868 region implementation for the native LoRaWAN backend.

Gate regions not yet implemented in the native backend behind depends on
!LORA_MODULE_BACKEND_NATIVE so they cannot be selected.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-04-20 11:43:15 +02:00
Carlo Caione
90f259cd05 lorawan: native: add native LoRaWAN backend
Add a native LoRaWAN 1.0.x Class A implementation that talks directly to
the LoRa radio driver, replacing the Semtech loramac-node dependency.

The backend provides:
 - OTAA join (Join Request / Join Accept)
 - Unconfirmed and confirmed uplinks with Class A downlink reception
 - AES-128 cryptography via PSA Crypto (CMAC for MIC, ECB for payload
   and join-accept encryption)
 - Region operations interface for channel plans, datarate tables,
   RX window parameters, and duty cycle enforcement
 - Asynchronous engine thread that serializes MAC operations
 - Full downlink dispatch with deferred callbacks on the system
   workqueue to avoid deadlocking the engine thread

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-04-20 11:43:15 +02:00
Jordan Yates
c010567673 lorawan: services: LITTLE_ENDIAN dependency
Add a `LITTLE_ENDIAN` dependency to `LORAWAN_FRAG_TRANSPORT` due to the
use of bitfields and packed structures in decoding on-air payloads.

Signed-off-by: Jordan Yates <jordan@embeint.com>
2026-04-07 08:31:51 -05:00
Jordan Yates
099dd4509f lorawan: services: update fragmented transport parsing
Update the fragmented data transport parsing to always consume complete
control messages, regardless of any validation errors. Simplify the
implementation of this by defining the packets as packed structures.

Signed-off-by: Jordan Yates <jordan@embeint.com>
2026-04-07 08:31:51 -05:00
Jordan Yates
25c395b066 lorawan: services: frag_transport: define status bits
Define status bits as enumerations, instead of using `BIT` directly in
the code.

Signed-off-by: Jordan Yates <jordan@embeint.com>
2026-04-07 08:31:51 -05:00
Jamie McCrae
f22592cbc5 tree: Replace FIXED_PARTITION_* macro usage with PARTITION_*
Replaces usage of these deprecated macros with ones that support
fixed and mapped partition compatibles. Also includes an update to
hal_espressif which also (rightly or wrongly) has zephyr specific
code in it

Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
2026-03-17 18:24:52 -04:00
Carlo Caione
c4a5c5cc32 lorawan: loramac-node: Use zephyr_library_compile_definitions_ifdef
Replace zephyr_compile_definitions_ifdef with
zephyr_library_compile_definitions_ifdef to avoid setting options globally.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-01-20 14:34:44 -05:00
Carlo Caione
d6dce1ca51 lorawan: rename region Kconfig symbols to be backend-agnostic
Move and rename the region Kconfig symbols from LORAMAC_REGION_* to
LORAWAN_REGION_* to make them backend-agnostic.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-01-16 11:41:01 +00:00
Carlo Caione
5eab8eb693 lorawan: move emulator to separate backend directory
Move the LoRaWAN emulator from the loramac-node backend directory to its
own directory because the emulator currently still depends on loramac-node
for some types and functions.

Once these dependencies are removed in a follow-up, the emulator can become
a fully standalone backend.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-01-16 11:41:01 +00:00
Carlo Caione
0a45c8dc70 lorawan: make NVM header documentation backend-agnostic
Remove loramac-node specific references (LORAMAC_NVM_NOTIFY_FLAG_*)
from the NVM interface documentation, making it suitable for any
LoRaWAN backend implementation.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-01-16 11:41:01 +00:00
Carlo Caione
429d98f80d lorawan: move loramac-node backend to subdirectory
Refactor the LoRaWAN subsystem to support multiple backends by moving
the loramac-node specific implementation into a dedicated subdirectory.

This change prepares the subsystem for adding lora-basics-modem support
as an alternative backend.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2026-01-16 11:41:01 +00:00
Josuah Demangeon
9bd94fab14 style: subsys: apply coding style on CMakeLists.txt files
Apply the CMake style guidelines to CMakeList.txt files in subsys/.

Signed-off-by: Josuah Demangeon <me@josuah.net>
2025-11-17 13:48:03 -05:00
Jamie McCrae
6963092375 lorawan: Move invalid requirement of 2KiB system workqueue
The LoRaWAN subsystem does not require 2KiB of system workqueue,
testing on nrf54l15 flpr (RISCV) CPU (with custom cryptography code)
shows it uses about 700 bytes of the system workqueue, therefore it
is assumed that the real requirement for 2KiB is the software
cryptography features, not the LoRaWAN stack itself, and the
cryptography parts of LoRaWAN can be replaced with alternatives
that do not need this high of a memory requirement, so the
requirement has been moved to the specific Kconfig for software
cryptography instead

Signed-off-by: Jamie McCrae <spam@helper3000.net>
2025-11-13 23:21:49 +02:00
Jordan Yates
3b7a797d2d lorawan: services: swap select to depends on
Switch the selects on `LORAWAN_FRAG_TRANSPORT` to `depends on`. `select`
should only be used for simple symbols without dependencies themselves.
Mixing `depends on X` and `select X` on different symbols is the primary
cause of Kconfig dependency loops.

Signed-off-by: Jordan Yates <jordan@embeint.com>
2025-08-21 06:52:11 +02:00
Jamie McCrae
637082efb0 lorawan: Imply soft-se instead of selecting it
This allows the software secure enclave to be changed to a
different implementation, which currently is not possible

Signed-off-by: Jamie McCrae <spam@helper3000.net>
2025-08-12 09:56:06 +03:00
Martin Durietz
3197be97e6 lorawan: add link check support.
Add link check support, by adding:
- link check callback in response of LinkCheckAns.
- link check request function using LinkCheckReq.

Signed-off-by: Martin Durietz <martin.durietz@gmail.com>
2025-04-17 17:23:12 +02:00
Kiara Navarro
6b2a476c66 lorawan: add callback for descriptor changes
allow the application to decide whether to keep going with the fuota
process by setting a callback that exposes the descriptor field
whenever `FragSessionSetupReq` is sent to the device.

Signed-off-by: Kiara Navarro <sophiekovalevsky@fedoraproject.org>
2025-03-07 19:42:56 +01:00
Jordan Yates
bb6cb0f1dd lorawan: clock_sync: assert instead of error code
Assert that the size provided to `clock_sync_serialize_device_time` is
sufficient, instead of returning an error code. The condition is already
enforced by the calling code, and returning an error code is incorrect
when the return code is unconditionally being used to increment the
buffer offset by callers.

Fixes #84720.

Signed-off-by: Jordan Yates <jordan@embeint.com>
2025-02-03 16:59:29 +01:00