TheThingsNetwork / lorawan-stack

The Things Stack, an Open Source LoRaWAN Network Server
https://www.thethingsindustries.com/stack/
Apache License 2.0
976 stars 307 forks source link

Device address not updated immediately #6008

Closed wm-eisos closed 1 year ago

wm-eisos commented 1 year ago

Summary

i believe there is an issue with handling the device address. i am using OTAA to connect an end node to the network server and when i switched to class c i cant send a downlink before i send an uplink. after i send the first uplink form the end node then i can send downlinks whenever and it is received on the end node. i noticed that the scheduled downlinks have the wrong device address assigned and not the latest one after the join request. this address is updated after the first uplink which should not be the case and which explains why i only have this problem with class c and not a since in class a you always have to do an uplink before the receive windows open. i havent tested class b but i believe it would have the same problem.

Steps to Reproduce

End Node joins the notework via OTAA End Node switch to class C Send Downlink from NS to End node

Current Result

Due to the downlink frame having the wrong device address it is being discarded at the end node

Expected Result

after the join accept frame is issued by the NS the NS should immediately update the device address and all upcoming downlinks should have the right device address

Relevant Logs

No response

URL

https://www.thethingsnetwork.org/forum/t/problem-with-sending-downlinks-before-the-first-uplink/60840/7

Deployment

The Things Stack Community Edition

The Things Stack Version

3.23.1

Client Name and Version

Gateway RAK7268
End node RAK3172

Other Information

No response

Proposed Fix

No response

Contributing

Code of Conduct

adriansmares commented 1 year ago

References https://github.com/TheThingsNetwork/lorawan-stack/issues/5200

The problem that you are encountering here is that the Network Server is not using the latest session (and device address) after a join-request -> join-accept dance because it has not received an uplink from the end device.

To put it a bit in perspective on why this happens, consider an end device which stores its session in the NVRAM. It joins and sends uplinks and receives class C downlinks and all is well. At some point it wants to join again, so it sends a join-request, the server receives it and generates a join-accept and transmits over the air, but because radio is a cruel mistress, the join accept never reaches the end device.

As things work right now, if the end device would use the 'old session', everything would still work with The Things Stack - that session is considered the current session. The one that was generated by the join-request whose join-accept never reached the end device is considered the pending session.

The pending session becomes the current session when the server believes that the end device actually is using that session - i.e. it receives an uplink from this new session.

What happens is that you schedule the class C downlink while the session is still pending - the server does not know clearly which session to use, and so it tries the old session (because it cannot know for sure that the pending session is valid - you don't know if the join accept has actually reached the end device).

The solution is to send a (confirmed) uplink after you have joined, in order to ensure that the server knows that the join accept has reached you. This will ensure that only the latest session is used for your class C downlinks, and also allows your application to know that the end device has successfully received the join accept.

TLDR: Use a three-way handshake.