How is frame count (FCnt) desyncronisation managed? (1.0.4+)

Answering here by question number:

  1. The maximum gap of the 32-bit FCnt between consecutive frames is 65K. That gap comes from one 16-bit roll-over that The Things Stack applies if the 16 least significant bits (LSB) are lower than the last. Just for full clarification, in LoRaWAN, only the 16 LSB fly over the air so the NS may need to infer the 32-bit FCnt by applying a roll-over.
  2. The primary purpose is replay attacks. Secondary is numbering frames which is used to calculate packet error rate (missed frames) and in ADR algorithms.
  3. Yes, the 16-bit roll-over is the same in all LoRaWAN 1.x
  4. I think you mean a potential 32-bit roll-over, i.e. the FCnt reaching its max. Unlike roll-overs of 16-bit FCnts (supported in older versions but hardly user), in 1.0.4 and 1.1 the FCnt does not roll-over after reaching its max. The end-device will have to join the network again once the counter reaching its max. ABP end-devices are “done” by this time.
1 Like

Thank you for your answers. Having read both your replies, I have a few more questions I would really appreciate answers to:

In LoRaWAN 1.0, 1.0.1, 1.0.2 and 1.0.3, frame counters can be 16 or 32-bit.

  1. Does The Things Stack keep track of the FCnt of devices using LoRaWAN 1.0 to 1.0.3 as a 16-bit or 32-bit value?

  2. If the FCnt is 16-bit (1.0 to 1.0.3) and there is one roll-over permitted, does that mean that the highest frame counter of a device operating on The Things Stack using these versions is 131,070 (65,535 * 2)?

  3. If the frame counter is tracked on The Things Stack as a 32-bit value (optional for 1.0 to 1.0.3, mandatory for 1.0.4 and 1.1), the device will transmit only the 16 least significant bits (LSB), even though neither the network server (NS) or device are tracking it as a 16-bit value (it’s just a 32 bit value being chopped off)? In other words, is the LoRaWAN device enforced to track the FCnt as a 32-bit value or does it assume the NS will?

  1. It knows the LW version of the device, and subsequently tracks <1.0.4 as 16-bit, and 1.0.4+ as 32-bit.
  2. 16-bit FCnts are fully cyclical, i.e. they can continuously roll-over. As per @johan, “Unlike roll-overs of 16-bit FCnts, in 1.0.4 and 1.1 the FCnt does not roll-over after reaching its max” - implying that the 16-bit counter can always roll-over, not just once. Plenty of devices out there on FCnt = hundreds of thousands on 1.0.3.
  3. Both the device and NS must keep track of the 32-bit FCnt, otherwise the encryption/decryption will not match as it is calculated using the full 32-bit counter.
2 Likes

Awesome, thanks @stevencellist!

In regards to your reply to question #2:

Now, how many times the NS rolls over is actually not specified. The Things Stack does it once.

What is the “one roll-over max” referring to in @johan’s comment if FCnts roll over continuously in LoRaWAN 1.0 to 1.0.3?

@stevencellist, regarding your search within the code, how did you know where to look?

That roll-over is the number of times the 16-bit LSB is rolled over for 32-bit frame counters. Example:

  • Device and NS both have last-known 32-bit frame counter = 0xFFFF (65535).
  • Device goes unheard for 0x10009 (65545) uplinks (more than one 16-bit value).
  • Device now has FCnt32 = 0x20008 (131080) and transmits FCnt16 = 0x0008 (8). This uplink is heard by NS again.
  • NS attempts a single roll-over to FCnt32 = 0x10008 (thinking it must’ve missed just the 8 uplinks in between), but decryption fails because the actual FCnt32 value used by the device for encryption is different. NS does not attempt a second roll-over to 0x20008 even though it would have resulted in a valid decryption.

I used the search bar to search for max_fcnt_gap (no useful results) and maxfcntgap; the latter exposes a reference in the symbol panel on the right that continues to grpc_gsns.go, where I scrolled up a bit to the if-statement leading up to that piece of the code. But the key idea is the search bar.

2 Likes

You’re a legend, thank you very much! That now makes sense :slight_smile:

You’re welcome.
As a funny trivia fact: the Helium blockchain only ever allows FCnt32 up to 8*65535, but they do always attempt up to all 8 decryption values.

1 Like

And I’ve checked for you: Chirpstack does the same

Whilst I’m at it, and I appreciate it is off-topic, how did you determine this?

max_fcnt_gap nor maxfcntgap yields any results on the Chirpstack repository, so then I tried gap which led me straight to

With a bit of inference and a clarification on wrapping_sub() and wrapping_add(), it is clear that the gap has a max value of (1 << 16) which is added to the FCnt value.

One small correction here is that for 1.0, 1.0.1, 1.0.2 and 1.0.3 devices, The Things Stack keeps track of whether the end-device supports 32-bit FCnt. We buried this setting somewhere in the Network Layer and then you need to expand to advanced settings. By default, this is set to true. The reason it is buried and true by default for new end-devices, is that we are not aware of a LoRaWAN end-device (stack) that uses 16-bit FCnt.

4 Likes

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.