-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Fix/call modules #11155
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix/call modules #11155
Changes from all commits
c7453c3
39bd23e
ee13115
055b52b
1a9ce55
08fe3a4
d4e83c5
4318902
92b17c2
cbbe131
a2c03e5
63eb1a2
782b5da
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -216,10 +216,10 @@ bool Router::shouldDecrementHopLimit(const meshtastic_MeshPacket *p) | |
| */ | ||
| int32_t Router::runOnce() | ||
| { | ||
| meshtastic_MeshPacket *mp; | ||
| while ((mp = fromRadioQueue.dequeuePtr(0)) != NULL) { | ||
| // printPacket("handle fromRadioQ", mp); | ||
| perhapsHandleReceived(mp); | ||
| QueuedFromRadio qp; | ||
| while (fromRadioQueue.dequeue(&qp, 0)) { | ||
| // printPacket("handle fromRadioQ", qp.packet); | ||
| perhapsHandleReceived(qp.packet, qp.src); | ||
| } | ||
|
|
||
| // LOG_DEBUG("Sleep forever!"); | ||
|
|
@@ -230,15 +230,14 @@ int32_t Router::runOnce() | |
| * RadioInterface calls this to queue up packets that have been received from the radio. The router is now responsible for | ||
| * freeing the packet | ||
| */ | ||
| void Router::enqueueReceivedMessage(meshtastic_MeshPacket *p) | ||
| void Router::enqueueReceivedMessage(meshtastic_MeshPacket *p, RxSource src) | ||
| { | ||
| // Try enqueue until successful | ||
| while (!fromRadioQueue.enqueue(p, 0)) { | ||
| meshtastic_MeshPacket *old_p; | ||
| old_p = fromRadioQueue.dequeuePtr(0); // Dequeue and discard the oldest packet | ||
| if (old_p) { | ||
| printPacket("fromRadioQ full, drop oldest!", old_p); | ||
| packetPool.release(old_p); | ||
| while (!fromRadioQueue.enqueue(QueuedFromRadio{p, src}, 0)) { | ||
| QueuedFromRadio old_qp; | ||
| if (fromRadioQueue.dequeue(&old_qp, 0)) { // Dequeue and discard the oldest packet | ||
| printPacket("fromRadioQ full, drop oldest!", old_qp.packet); | ||
| packetPool.release(old_qp.packet); | ||
| } | ||
| } | ||
| // Nasty hack because our threading is primitive. interfaces shouldn't need to know about routers FIXME | ||
|
|
@@ -327,10 +326,13 @@ ErrorCode Router::sendLocal(meshtastic_MeshPacket *p, RxSource src) | |
| // No need to deliver externally if the destination is the local node | ||
| if (isToUs(p)) { | ||
| printPacket("Enqueued local", p); | ||
| // Preserve the trusted origin explicitly. Queueing used to erase src and make a local | ||
| // phone/module packet indistinguishable from remote already-decoded ingress. | ||
| handleReceived(p, src); | ||
| return ERRNO_SHOULD_RELEASE; | ||
| // Queue rather than call handleReceived() synchronously: a reply generated from inside | ||
| // MeshModule::callModules() (e.g. an admin/module-config response) lands here via | ||
| // sendToMesh(), and calling handleReceived() in-line would re-enter callModules() from | ||
| // within itself. The queue carries src through so the packet is still replayed with its | ||
| // true origin instead of defaulting to RX_SRC_RADIO. | ||
| enqueueReceivedMessage(p, src); | ||
| return ERRNO_OK; | ||
| } else if (!iface) { | ||
| // We must be sending to remote nodes also, fail if no interface found | ||
| abortSendAndNak(meshtastic_Routing_Error_NO_INTERFACE, p); | ||
|
|
@@ -1356,7 +1358,7 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src) | |
| packetPool.release(p_encrypted); // Release the encrypted packet (release() handles nullptr) | ||
| } | ||
|
|
||
| void Router::perhapsHandleReceived(meshtastic_MeshPacket *p) | ||
| void Router::perhapsHandleReceived(meshtastic_MeshPacket *p, RxSource src) | ||
| { | ||
| #if ARCH_PORTDUINO | ||
| // Even ignored packets get logged in the trace | ||
|
|
@@ -1365,6 +1367,18 @@ void Router::perhapsHandleReceived(meshtastic_MeshPacket *p) | |
| LOG_TRACE("%s", MeshPacketSerializer::JsonSerializeEncrypted(p).c_str()); | ||
| } | ||
| #endif | ||
| // A non-radio packet (a module's reply to a phone request, or a phone/serial-originated packet | ||
| // addressed to us, queued here only to avoid re-entering callModules() synchronously) was never | ||
| // actually received over the mesh. The ignore-list, PacketHistory/dedup, MQTT and pre-hop filters | ||
| // below exist to police untrusted radio ingress, and handleReceived() already special-cases non- | ||
| // RX_SRC_RADIO sources (e.g. it only applies the routing-auth cache for RX_SRC_RADIO) - so skip | ||
| // straight there instead of risking a trusted local/user packet getting deduped or ignore-listed. | ||
| if (src != RX_SRC_RADIO) { | ||
| handleReceived(p, src); | ||
| packetPool.release(p); | ||
| return; | ||
| } | ||
|
|
||
| // assert(radioConfig.has_preferences); | ||
| if (is_in_repeated(config.lora.ignore_incoming, p->from)) { | ||
| clearRoutingAuthCache(); | ||
|
|
@@ -1425,6 +1439,6 @@ void Router::perhapsHandleReceived(meshtastic_MeshPacket *p) | |
|
|
||
| // Note: we avoid calling shouldFilterReceived if we are supposed to ignore certain nodes - because some overrides might | ||
| // cache/learn of the existence of nodes (i.e. FloodRouter) that they should not | ||
| handleReceived(p); | ||
| handleReceived(p, src); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. locally-addressed packets now traverse perhapsHandleReceived() which means they are dedup ed and checked against the ignore-list. They are also added to the PacketHistory. Confirm a module emitting rapid to-phone-only packets can't get deduped.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right, locally-generated replies were falling through the ignore-list/PacketHistory/MQTT/pre-hop checks meant for radio ingress. handleReceived() already special-cases RX_SRC_LOCAL internally (e.g. it only applies the routing-auth cache when src == RX_SRC_RADIO), so I've made perhapsHandleReceived() skip straight to handleReceived() when src == RX_SRC_LOCAL, bypassing the filter pipeline entirely for local packets, same as the pre-PR behavior, just routed through the queue instead of called inline. Pushed in a2c03e5.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Follow-up: that guard was too narrow. RX_SRC_USER (a phone/serial packet addressed to the local node, e.g. a config request) hits the same perhapsHandleReceived() path and wasn't exempted, so it still traversed the ignore-list/dedup/pre-hop/routing-auth filters meant only for radio ingress — the same risk you flagged, just on the request side instead of the reply side. In the pre-PR code RX_SRC_USER never went through perhapsHandleReceived() at all (synchronous handleReceived() call), so this was a regression from queuing it. Widened the check from src == RX_SRC_LOCAL to src != RX_SRC_RADIO to cover both trusted non-radio sources. Pushed. |
||
| packetPool.release(p); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return code changed from ERRNO_SHOULD_RELEASE to ERRNO_OK (the queue now owns/frees the packet). Every other sendLocal caller must be verified to no longer release on ERRNO_OK or else we have another double-free/leak.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checked all three sendLocal() callers:
All three only release when the result is ERRNO_SHOULD_RELEASE, never on ERRNO_OK. Since the local/queued path now returns ERRNO_OK, none of them double-release, the queue owns the packet and it's freed once in perhapsHandleReceived() after processing. No double-free/leak.