Summary
When a fragmentation (FUOTA) session completes — either successfully or with failure — the
multicast sessions (Class B or Class C) that were serving it are not stopped. They continue
running until their server-assigned timeout expires, wasting battery and RF resources.
Affected components
lbm_lib/smtc_modem_core/lorawan_packages/fragmented_data_block_transport/v2.0.0/lorawan_fragmentation_package_v2.0.0.c
lbm_lib/smtc_modem_core/lorawan_packages/fragmented_data_block_transport/v1.0.0/lorawan_fragmentation_package_v1.0.0.c
Root cause
The fragmentation package fires SMTC_MODEM_EVENT_LORAWAN_FUOTA_DONE when all fragments are
received (or when decoding fails), but it makes no attempt to stop the multicast sessions that
delivered those fragments.
The Remote Multicast Setup package manages multicast session lifetime using a timer-only approach:
sessions are stopped when session_time + time_out expires
(lorawan_remote_multicast_setup_package_service_on_update, line 644 in v2.0.0). There is no
mechanism for the fragmentation package to trigger an early stop.
The fragmentation session data structure does contain mc_group_bit_mask (set during
FragSessionSetup, line 647 in v2.0.0), which identifies which multicast groups (0–3) were used.
This information is available at completion time but is never used for cleanup — it is only used
to validate incoming fragment frames (lines 795–822 in v2.0.0).
The problem exists symmetrically for both Class B and Class C multicast sessions, and in both
package versions (v1.0.0 and v2.0.0).
Impact
- Class B: beacon search and ping slots remain active after FUOTA completes, consuming battery
until the server-programmed session_time + time_out expires (can be minutes to hours).
- Class C: the device stays in continuous receive mode after FUOTA completes instead of returning
to Class A, increasing power consumption.
- The
SMTC_MODEM_EVENT_NO_MORE_MULTICAST_SESSION_CLASS_B /
SMTC_MODEM_EVENT_NO_MORE_MULTICAST_SESSION_CLASS_C events are not fired at FUOTA completion,
only at timer expiry, so the application cannot rely on them as a FUOTA-done signal.
Steps to reproduce
- Configure a multicast Class B or Class C session via Remote Multicast Setup package commands.
- Start a fragmentation session over that multicast session.
- Successfully receive all fragments (or exhaust the session with failures).
- Observe:
SMTC_MODEM_EVENT_LORAWAN_FUOTA_DONE fires, but the multicast session and the
associated radio activity (ping slots / Class C window) continue until the timer expires.
Fix
Design
Two new public functions are added to the Remote Multicast Setup package:
void lorawan_remote_multicast_setup_force_stop_class_b( uint8_t mc_group_id, uint8_t stack_id );
void lorawan_remote_multicast_setup_force_stop_class_c( uint8_t mc_group_id, uint8_t stack_id );
Each function:
- Guards on whether the given group actually has an active session of the respective class
(stop_class_b[] or launch_class_b[] flag set); if not, returns immediately.
- Calls
lorawan_api_multicast_b/c_stop_session() to stop the radio session.
- Clears the internal
stop_class_b/c[] and launch_class_b/c[] flags to prevent a redundant
timer-based stop later.
- Clears the corresponding
STOP_CLASS_B/C_TASK and LAUNCH_CLASS_B/C_TASK bits from
task_ctx_mask to neutralise any already-scheduled supervisor task for that group.
The task will still fire at the original timer expiry but will find nothing to do — a harmless
single extra wakeup (there is no task cancellation API in the supervisor).
- When all groups of that class are idle (
tmp == 0), disables the transport mode
(lorawan_class_b_management_enable(false) / lorawan_api_class_c_enabled(false)) and fires
the NO_MORE_MULTICAST_SESSION_CLASS_B/C event.
The guard on step 1 is essential: the fragmentation package does not track which class was used
for delivery, so it calls both force_stop_class_b and force_stop_class_c for every group bit
set in mc_group_bit_mask. The guard ensures only the actually-active class takes effect.
Changes
lorawan_remote_multicast_setup_package.h — declarations added:
void lorawan_remote_multicast_setup_force_stop_class_b( uint8_t mc_group_id, uint8_t stack_id );
void lorawan_remote_multicast_setup_force_stop_class_c( uint8_t mc_group_id, uint8_t stack_id );
lorawan_remote_multicast_setup_package_v2.0.0.c and
lorawan_remote_multicast_setup_package_v1.0.0.c — implementations added at end of file.
lorawan_fragmentation_package_v2.0.0.c and
lorawan_fragmentation_package_v1.0.0.c — two changes each:
-
Added #include "lorawan_remote_multicast_setup_package.h".
-
At the fragmentation completion block (both FRAG_SESSION_FINISHED_SUCCESSFULLY and
FRAG_SESSION_FAILED paths), before increment_asynchronous_msgnumber(FUOTA_DONE):
// Stop multicast sessions that were serving this fragmentation session.
// Both Class B and Class C are attempted for each group bit: the fragmentation
// package does not track which class was used, so each force_stop function
// silently skips groups that were not active for that class.
for( uint8_t i = 0; i < 4; i++ )
{
if( ( frag_session_data[frag_index].frag_group_data.frag_session.mc_group_bit_mask &
( 1 << i ) ) != 0 )
{
lorawan_remote_multicast_setup_force_stop_class_b( i, stack_id );
lorawan_remote_multicast_setup_force_stop_class_c( i, stack_id );
}
}
FUOTA_DONE is fired after the teardown, so the application receives it with sessions already
stopped.
Notes
- The new
force_stop functions are also useful independently (e.g., application-initiated
abort) and are intentionally exposed in the public header.
- This fix is independent of this issue (transport mode not disabled on timer-based session stop),
though both should be applied together for complete correctness.
Summary
When a fragmentation (FUOTA) session completes — either successfully or with failure — the
multicast sessions (Class B or Class C) that were serving it are not stopped. They continue
running until their server-assigned timeout expires, wasting battery and RF resources.
Affected components
lbm_lib/smtc_modem_core/lorawan_packages/fragmented_data_block_transport/v2.0.0/lorawan_fragmentation_package_v2.0.0.clbm_lib/smtc_modem_core/lorawan_packages/fragmented_data_block_transport/v1.0.0/lorawan_fragmentation_package_v1.0.0.cRoot cause
The fragmentation package fires
SMTC_MODEM_EVENT_LORAWAN_FUOTA_DONEwhen all fragments arereceived (or when decoding fails), but it makes no attempt to stop the multicast sessions that
delivered those fragments.
The Remote Multicast Setup package manages multicast session lifetime using a timer-only approach:
sessions are stopped when
session_time + time_outexpires(
lorawan_remote_multicast_setup_package_service_on_update, line 644 in v2.0.0). There is nomechanism for the fragmentation package to trigger an early stop.
The fragmentation session data structure does contain
mc_group_bit_mask(set duringFragSessionSetup, line 647 in v2.0.0), which identifies which multicast groups (0–3) were used.This information is available at completion time but is never used for cleanup — it is only used
to validate incoming fragment frames (lines 795–822 in v2.0.0).
The problem exists symmetrically for both Class B and Class C multicast sessions, and in both
package versions (v1.0.0 and v2.0.0).
Impact
until the server-programmed
session_time + time_outexpires (can be minutes to hours).to Class A, increasing power consumption.
SMTC_MODEM_EVENT_NO_MORE_MULTICAST_SESSION_CLASS_B/SMTC_MODEM_EVENT_NO_MORE_MULTICAST_SESSION_CLASS_Cevents are not fired at FUOTA completion,only at timer expiry, so the application cannot rely on them as a FUOTA-done signal.
Steps to reproduce
SMTC_MODEM_EVENT_LORAWAN_FUOTA_DONEfires, but the multicast session and theassociated radio activity (ping slots / Class C window) continue until the timer expires.
Fix
Design
Two new public functions are added to the Remote Multicast Setup package:
Each function:
(
stop_class_b[]orlaunch_class_b[]flag set); if not, returns immediately.lorawan_api_multicast_b/c_stop_session()to stop the radio session.stop_class_b/c[]andlaunch_class_b/c[]flags to prevent a redundanttimer-based stop later.
STOP_CLASS_B/C_TASKandLAUNCH_CLASS_B/C_TASKbits fromtask_ctx_maskto neutralise any already-scheduled supervisor task for that group.The task will still fire at the original timer expiry but will find nothing to do — a harmless
single extra wakeup (there is no task cancellation API in the supervisor).
tmp == 0), disables the transport mode(
lorawan_class_b_management_enable(false)/lorawan_api_class_c_enabled(false)) and firesthe
NO_MORE_MULTICAST_SESSION_CLASS_B/Cevent.The guard on step 1 is essential: the fragmentation package does not track which class was used
for delivery, so it calls both
force_stop_class_bandforce_stop_class_cfor every group bitset in
mc_group_bit_mask. The guard ensures only the actually-active class takes effect.Changes
lorawan_remote_multicast_setup_package.h— declarations added:lorawan_remote_multicast_setup_package_v2.0.0.candlorawan_remote_multicast_setup_package_v1.0.0.c— implementations added at end of file.lorawan_fragmentation_package_v2.0.0.candlorawan_fragmentation_package_v1.0.0.c— two changes each:Added
#include "lorawan_remote_multicast_setup_package.h".At the fragmentation completion block (both
FRAG_SESSION_FINISHED_SUCCESSFULLYandFRAG_SESSION_FAILEDpaths), beforeincrement_asynchronous_msgnumber(FUOTA_DONE):FUOTA_DONEis fired after the teardown, so the application receives it with sessions alreadystopped.
Notes
force_stopfunctions are also useful independently (e.g., application-initiatedabort) and are intentionally exposed in the public header.
though both should be applied together for complete correctness.