Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions src/mesh/MeshService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,10 @@ int MeshService::handleFromRadio(const meshtastic_MeshPacket *mp)
}

printPacket("Forwarding to phone", mp);
sendToPhone(packetPool.allocCopy(*mp));
if (auto *c = packetPool.allocCopy(*mp))
sendToPhone(c);
else
LOG_DEBUG("phone-forward dropped: packetPool exhausted");

return 0;
}
Expand Down Expand Up @@ -205,7 +208,10 @@ void MeshService::handleToRadio(meshtastic_MeshPacket &p)
DEBUG_HEAP_BEFORE;
auto a = packetPool.allocCopy(p);
DEBUG_HEAP_AFTER("MeshService::handleToRadio", a);
sendToMesh(a, RX_SRC_USER);
if (a)
sendToMesh(a, RX_SRC_USER);
else
LOG_WARN("handleToRadio: packetPool exhausted, dropping ToRadio packet");

bool loopback = false; // if true send any packet the phone sends back itself (for testing)
if (loopback) {
Expand All @@ -225,6 +231,10 @@ bool MeshService::cancelSending(PacketId id)
ErrorCode MeshService::sendQueueStatusToPhone(const meshtastic_QueueStatus &qs, ErrorCode res, uint32_t mesh_packet_id)
{
meshtastic_QueueStatus *copied = queueStatusPool.allocCopy(qs);
if (!copied) {
LOG_DEBUG("sendQueueStatusToPhone: queueStatusPool exhausted, skipping");
return ERRNO_UNKNOWN;
}

copied->res = res;
copied->mesh_packet_id = mesh_packet_id;
Expand Down Expand Up @@ -265,7 +275,12 @@ void MeshService::sendToMesh(meshtastic_MeshPacket *p, RxSource src, bool ccToPh
auto a = packetPool.allocCopy(*p);
DEBUG_HEAP_AFTER("MeshService::sendToMesh", a);

sendToPhone(a);
if (a)
sendToPhone(a);
// else: packetPool exhausted; the cc-to-phone copy is dropped here.
// The original packet is still queued to the mesh; phone visibility
// of cc'd local sends depends on whether the RX path forwards it,
// which is not guaranteed for non-broadcast / non-local-dest sends.
}

// Router may ask us to release the packet if it wasn't sent
Expand Down
17 changes: 12 additions & 5 deletions src/mesh/NextHopRouter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@ ErrorCode NextHopRouter::send(meshtastic_MeshPacket *p)

// If it's from us, ReliableRouter already handles retransmissions if want_ack is set. If a next hop is set and hop limit is
// not 0 or want_ack is set, start retransmissions
if ((!isFromUs(p) || !p->want_ack) && p->next_hop != NO_NEXT_HOP_PREFERENCE && (p->hop_limit > 0 || p->want_ack))
startRetransmission(packetPool.allocCopy(*p)); // start retransmission for relayed packet
if ((!isFromUs(p) || !p->want_ack) && p->next_hop != NO_NEXT_HOP_PREFERENCE && (p->hop_limit > 0 || p->want_ack)) {
if (auto *retxCopy = packetPool.allocCopy(*p))
startRetransmission(retxCopy); // start retransmission for relayed packet
// else: pool exhausted; relayed packet is still sent below — just no retransmission
}

return Router::send(p);
}
Expand Down Expand Up @@ -146,6 +149,10 @@ bool NextHopRouter::perhapsRebroadcast(const meshtastic_MeshPacket *p)
if (isRebroadcaster()) {
if (p->next_hop == NO_NEXT_HOP_PREFERENCE || p->next_hop == nodeDB->getLastByteOfNodeNum(getNodeNum())) {
meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it
if (!tosend) {
LOG_WARN("Rebroadcast skipped: packetPool exhausted (from=%x)", p->relay_node);
return false;
}
LOG_INFO("Rebroadcast received message coming from %x", p->relay_node);

// If exhausting hops, force hop_limit = 0 regardless of other logic
Expand Down Expand Up @@ -319,14 +326,14 @@ int32_t NextHopRouter::doRetransmissions()
LOG_INFO("Resetting next hop for packet with dest 0x%x\n", p.packet->to);
sentTo->next_hop = NO_NEXT_HOP_PREFERENCE;
}
FloodingRouter::send(packetPool.allocCopy(*p.packet));
if (auto *c = packetPool.allocCopy(*p.packet)) FloodingRouter::send(c);
} else {
NextHopRouter::send(packetPool.allocCopy(*p.packet));
if (auto *c = packetPool.allocCopy(*p.packet)) NextHopRouter::send(c);
}
} else {
// Note: we call the superclass version because we don't want to have our version of send() add a new
// retransmission record
FloodingRouter::send(packetPool.allocCopy(*p.packet));
if (auto *c = packetPool.allocCopy(*p.packet)) FloodingRouter::send(c);
}

// Queue again
Expand Down
4 changes: 3 additions & 1 deletion src/mesh/ReliableRouter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ ErrorCode ReliableRouter::send(meshtastic_MeshPacket *p)
auto copy = packetPool.allocCopy(*p);
DEBUG_HEAP_AFTER("ReliableRouter::send", copy);

startRetransmission(copy, NUM_RELIABLE_RETX);
if (copy)
startRetransmission(copy, NUM_RELIABLE_RETX);
// else: pool exhausted; the packet itself is still sent — just no retry
}

/* If we have pending retransmissions, add the airtime of this packet to it, because during that time we cannot receive an
Expand Down
9 changes: 6 additions & 3 deletions src/mesh/Router.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -384,12 +384,15 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
return encodeResult; // FIXME - this isn't a valid ErrorCode
}
#if !MESHTASTIC_EXCLUDE_MQTT
// Only publish to MQTT if we're the original transmitter of the packet
if (moduleConfig.mqtt.enabled && isFromUs(p) && mqtt) {
// Only publish to MQTT if we're the original transmitter of the packet.
// Skip on packetPool exhaustion (p_decoded == nullptr) — onSend would
// dereference the reference and crash; better to drop the MQTT publish
// for this one packet than panic the radio.
if (p_decoded && moduleConfig.mqtt.enabled && isFromUs(p) && mqtt) {
mqtt->onSend(*p, *p_decoded, chIndex);
}
#endif
packetPool.release(p_decoded);
packetPool.release(p_decoded); // release() handles nullptr
}

#if HAS_UDP_MULTICAST
Expand Down
6 changes: 5 additions & 1 deletion src/modules/AtakPluginModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,12 @@ void AtakPluginModule::alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtast
}
}
auto decompressedCopy = packetPool.allocCopy(mp);
if (!decompressedCopy) {
LOG_DEBUG("AtakPluginModule: packetPool exhausted, skipping decompressed phone forward");
return;
}
decompressedCopy->decoded.payload.size =
pb_encode_to_bytes(decompressedCopy->decoded.payload.bytes, sizeof(decompressedCopy->decoded.payload),
pb_encode_to_bytes(decompressedCopy->decoded.payload.bytes, sizeof(decompressedCopy->decoded.payload.bytes),
meshtastic_TAKPacket_fields, &uncompressed);

service->sendToPhone(decompressedCopy);
Expand Down
13 changes: 8 additions & 5 deletions src/modules/NodeInfoModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,15 @@ bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
// if user has changed while packet was not for us, inform phone
if (hasChanged && !wasBroadcast && !isToUs(&mp)) {
auto packetCopy = packetPool.allocCopy(mp); // Keep a copy of the packet for later analysis
if (packetCopy) {
// Re-encode the user protobuf, as we have stripped out the user.id
packetCopy->decoded.payload.size = pb_encode_to_bytes(
packetCopy->decoded.payload.bytes, sizeof(packetCopy->decoded.payload.bytes), &meshtastic_User_msg, &p);

// Re-encode the user protobuf, as we have stripped out the user.id
packetCopy->decoded.payload.size = pb_encode_to_bytes(
packetCopy->decoded.payload.bytes, sizeof(packetCopy->decoded.payload.bytes), &meshtastic_User_msg, &p);

service->sendToPhone(packetCopy);
service->sendToPhone(packetCopy);
} else {
LOG_DEBUG("NodeInfoModule: packetPool exhausted, skipping phone forward");
}
}

pruneLastNodeInfoCache();
Expand Down