From 99467cd874253166048e95bac65ff4c80ca10ed5 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 21 Feb 2021 12:59:47 +0800 Subject: [PATCH] 1.2 WIP at least doesn't crash --- docs/software/TODO.md | 10 ++-- proto | 2 +- src/mesh/DSRRouter.cpp | 95 ++++++++++++++++++----------------- src/mesh/DSRRouter.h | 2 +- src/mesh/FloodingRouter.cpp | 4 +- src/mesh/FloodingRouter.h | 2 +- src/mesh/MeshService.h | 3 +- src/mesh/ReliableRouter.cpp | 25 ++++----- src/mesh/ReliableRouter.h | 2 +- src/mesh/Router.cpp | 7 +-- src/mesh/Router.h | 2 +- src/plugins/RoutingPlugin.cpp | 11 +++- 12 files changed, 89 insertions(+), 76 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 8f1b07625..d2c4a7c97 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -4,14 +4,14 @@ You probably don't care about this section - skip to the next one. 1.2 cleanup & multichannel support: -* call RouterPlugin for *all* packets - not just Router packets -* clear priority before sending (to keep wire size small) +* DONE call RouterPlugin for *all* packets - not just Router packets * generate channel hash from the name of the channel+the psk (not just one or the other) * DONE remove deprecated * DONE fix setchannel in phoneapi.cpp * DONE set mynodeinfo.max_channels * DONE set mynodeinfo.num_bands (formerly num_channels) -* fix sniffing of non Routing packets +* DONE fix sniffing of non Routing packets +* enable remote setttings access by moving settings operations into a regular plugin (move settings ops out of PhoneAPI) * DONE move portnum up? * DONE remove region specific builds from the firmware * add gui in android app for setting region @@ -22,6 +22,9 @@ You probably don't care about this section - skip to the next one. * DONE move most parts of meshpacket into the Data packet, so that we can chain multiple Data for sending when they all have a common destination and key. * when selecting a MeshPacket for transmit, scan the TX queue for any Data packets we can merge together as a WirePayload. In the low level send/rx code expand that into multiple MeshPackets as needed (thus 'hiding' from MeshPacket that over the wire we send multiple datapackets * confirm we are still calling the plugins for messages inbound from the phone (or generated locally) +* confirm we are still multi hop routing flood broadcasts +* confirm we are still doing resends on unicast reliable packets +* add support for full DSR unicast delivery * DONE move acks into routing * DONE make all subpackets different versions of data * DONE move routing control into a data packet @@ -31,6 +34,7 @@ You probably don't care about this section - skip to the next one. * add multichannel support in python * add channel selection for sending * record recevied channel in meshpacket +* test remote settings operations (confirm it works 3 hops away) * add channel restrictions for plugins (and restrict routing plugin to the "control" channel) * make a primaryChannel global and properly maintain it when the phone sends setChannel * move setCrypto call into packet send and packet decode code diff --git a/proto b/proto index 527b0fdc3..f23417aa7 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 527b0fdc343f89843158977a1c1a7c14db854565 +Subproject commit f23417aa7dcb8f61bbb2c1ea07c7b988ae66ec38 diff --git a/src/mesh/DSRRouter.cpp b/src/mesh/DSRRouter.cpp index 04d4a2bef..0b28257f6 100644 --- a/src/mesh/DSRRouter.cpp +++ b/src/mesh/DSRRouter.cpp @@ -62,7 +62,7 @@ ErrorCode DSRRouter::send(MeshPacket *p) return ReliableRouter::send(p); } -void DSRRouter::sniffReceived(const MeshPacket *p, const Routing &c) +void DSRRouter::sniffReceived(const MeshPacket *p, const Routing *c) { // Learn 0 hop routes by just hearing any adjacent nodes // But treat broadcasts carefully, because when flood broadcasts go out they keep the same original "from". So we want to @@ -72,47 +72,49 @@ void DSRRouter::sniffReceived(const MeshPacket *p, const Routing &c) addRoute(p->from, p->from, 0); // We are adjacent with zero hops } - switch (c.which_variant) { - case Routing_route_request_tag: - // Handle route discovery packets (will be a broadcast message) - // FIXME - always start request with the senders nodenum - if (weAreInRoute(c.route_request)) { - DEBUG_MSG("Ignoring a route request that contains us\n"); - } else { - updateRoutes(c.route_request, - true); // Update our routing tables based on the route that came in so far on this request - - if (p->decoded.dest == getNodeNum()) { - // They were looking for us, send back a route reply (the sender address will be first in the list) - sendRouteReply(c.route_request); + if (c) + switch (c->which_variant) { + case Routing_route_request_tag: + // Handle route discovery packets (will be a broadcast message) + // FIXME - always start request with the senders nodenum + if (weAreInRoute(c->route_request)) { + DEBUG_MSG("Ignoring a route request that contains us\n"); } else { - // They were looking for someone else, forward it along (as a zero hop broadcast) - NodeNum nextHop = getNextHop(p->decoded.dest); - if (nextHop) { - // in our route cache, reply to the requester (the sender address will be first in the list) - sendRouteReply(c.route_request, nextHop); + updateRoutes(c->route_request, + true); // Update our routing tables based on the route that came in so far on this request + + if (p->decoded.dest == getNodeNum()) { + // They were looking for us, send back a route reply (the sender address will be first in the list) + sendRouteReply(c->route_request); } else { - // Not in our route cache, rebroadcast on their behalf (after adding ourselves to the request route) - resendRouteRequest(p); + // They were looking for someone else, forward it along (as a zero hop broadcast) + NodeNum nextHop = getNextHop(p->decoded.dest); + if (nextHop) { + // in our route cache, reply to the requester (the sender address will be first in the list) + sendRouteReply(c->route_request, nextHop); + } else { + // Not in our route cache, rebroadcast on their behalf (after adding ourselves to the request route) + resendRouteRequest(p); + } } } + break; + case Routing_route_reply_tag: + updateRoutes(c->route_reply, false); + + // FIXME, if any of our current pending packets were waiting for this route, send them (and leave them as regular + // pending packets until ack arrives) + // FIXME, if we don't get a route reply at all (or a route error), timeout and generate a routeerror TIMEOUT on our + // own... + break; + case Routing_error_reason_tag: + removeRoute(p->decoded.dest); + + // FIXME: if any pending packets were waiting on this route, delete them + break; + default: + break; } - break; - case Routing_route_reply_tag: - updateRoutes(c.route_reply, false); - - // FIXME, if any of our current pending packets were waiting for this route, send them (and leave them as regular pending - // packets until ack arrives) - // FIXME, if we don't get a route reply at all (or a route error), timeout and generate a routeerror TIMEOUT on our own... - break; - case Routing_error_reason_tag: - removeRoute(p->decoded.dest); - - // FIXME: if any pending packets were waiting on this route, delete them - break; - default: - break; - } // We simply ignore ACKs - because ReliableRouter will delete the pending packet for us @@ -137,15 +139,18 @@ void DSRRouter::sniffReceived(const MeshPacket *p, const Routing &c) // FIXME, stop local processing of this packet } - // handle naks - convert them to route error packets - // All naks are generated locally, because we failed resending the packet too many times - PacketId nakId = c.fail_id; - if (nakId) { - auto pending = findPendingPacket(p->to, nakId); - if (pending && pending->packet->decoded.source) { // if source not set, this was not a multihop packet, just ignore - removeRoute(pending->packet->decoded.dest); // We no longer have a route to the specified node + if (c) { + // handle naks - convert them to route error packets + // All naks are generated locally, because we failed resending the packet too many times + PacketId nakId = c->fail_id; + if (nakId) { + auto pending = findPendingPacket(p->to, nakId); + if (pending && + pending->packet->decoded.source) { // if source not set, this was not a multihop packet, just ignore + removeRoute(pending->packet->decoded.dest); // We no longer have a route to the specified node - sendRouteError(p, Routing_Error_GOT_NAK); + sendRouteError(p, Routing_Error_GOT_NAK); + } } } } diff --git a/src/mesh/DSRRouter.h b/src/mesh/DSRRouter.h index eef1a991c..796dc236c 100644 --- a/src/mesh/DSRRouter.h +++ b/src/mesh/DSRRouter.h @@ -8,7 +8,7 @@ class DSRRouter : public ReliableRouter * Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to * update routing tables etc... based on what we overhear (even for messages not destined to our node) */ - virtual void sniffReceived(const MeshPacket *p, const Routing &c); + virtual void sniffReceived(const MeshPacket *p, const Routing *c); /** * Send a packet on a suitable interface. This routine will diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index 777178c41..049d038c7 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -27,11 +27,11 @@ bool FloodingRouter::shouldFilterReceived(const MeshPacket *p) return Router::shouldFilterReceived(p); } -void FloodingRouter::sniffReceived(const MeshPacket *p, const Routing &c) +void FloodingRouter::sniffReceived(const MeshPacket *p, const Routing *c) { // If a broadcast, possibly _also_ send copies out into the mesh. // (FIXME, do something smarter than naive flooding here) - if (p->to == NODENUM_BROADCAST && p->hop_limit > 0) { + if (p->to == NODENUM_BROADCAST && p->hop_limit > 0 && p->from != getNodeNum()) { if (p->id != 0) { MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it diff --git a/src/mesh/FloodingRouter.h b/src/mesh/FloodingRouter.h index 3e4f5de6e..41bc898df 100644 --- a/src/mesh/FloodingRouter.h +++ b/src/mesh/FloodingRouter.h @@ -55,5 +55,5 @@ class FloodingRouter : public Router, protected PacketHistory /** * Look for broadcasts we need to rebroadcast */ - virtual void sniffReceived(const MeshPacket *p, const Routing &c); + virtual void sniffReceived(const MeshPacket *p, const Routing *c); }; diff --git a/src/mesh/MeshService.h b/src/mesh/MeshService.h index 6cf52a00e..0f2e772b3 100644 --- a/src/mesh/MeshService.h +++ b/src/mesh/MeshService.h @@ -89,9 +89,10 @@ class MeshService /// returns 0 to allow futher processing int onGPSChanged(const meshtastic::GPSStatus *arg); - /// Handle a packet that just arrived from the radio. This method does _not_ free the provided packet. If it needs + /// Handle a packet that just arrived from the radio. This method does _ReliableRouternot_ free the provided packet. If it needs /// to keep the packet around it makes a copy int handleFromRadio(const MeshPacket *p); + friend class RoutingPlugin; }; extern MeshService service; diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index 3dc07c9c9..65e1ff9f8 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -53,7 +53,7 @@ bool ReliableRouter::shouldFilterReceived(const MeshPacket *p) * * Otherwise, let superclass handle it. */ -void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing &c) +void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing *c) { NodeNum ourNode = getNodeNum(); @@ -64,18 +64,19 @@ void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing &c) } // If the payload is valid, look for ack/nak + if (c) { + PacketId ackId = c->success_id; + PacketId nakId = c->fail_id; - PacketId ackId = c.success_id; - PacketId nakId = c.fail_id; - - // We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records - if (ackId || nakId) { - if (ackId) { - DEBUG_MSG("Received a ack=%d, stopping retransmissions\n", ackId); - stopRetransmission(p->to, ackId); - } else { - DEBUG_MSG("Received a nak=%d, stopping retransmissions\n", nakId); - stopRetransmission(p->to, nakId); + // We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records + if (ackId || nakId) { + if (ackId) { + DEBUG_MSG("Received a ack=%d, stopping retransmissions\n", ackId); + stopRetransmission(p->to, ackId); + } else { + DEBUG_MSG("Received a nak=%d, stopping retransmissions\n", nakId); + stopRetransmission(p->to, nakId); + } } } } diff --git a/src/mesh/ReliableRouter.h b/src/mesh/ReliableRouter.h index bf0338f9b..e6a71f423 100644 --- a/src/mesh/ReliableRouter.h +++ b/src/mesh/ReliableRouter.h @@ -90,7 +90,7 @@ class ReliableRouter : public FloodingRouter /** * Look for acks/naks or someone retransmitting us */ - virtual void sniffReceived(const MeshPacket *p, const Routing &c); + virtual void sniffReceived(const MeshPacket *p, const Routing *c); /** * Try to find the pending packet record for this ID (or NULL if not found) diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 7876ddde4..673fafefd 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -194,7 +194,7 @@ bool Router::cancelSending(NodeNum from, PacketId id) { * Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to * update routing tables etc... based on what we overhear (even for messages not destined to our node) */ -void Router::sniffReceived(const MeshPacket *p, const Routing &c) +void Router::sniffReceived(const MeshPacket *p, const Routing *c) { DEBUG_MSG("FIXME-update-db Sniffing packet\n"); // FIXME, update nodedb here for any packet that passes through us @@ -247,11 +247,6 @@ void Router::handleReceived(MeshPacket *p) // call any promiscious plugins here, make a (non promisiocous) plugin for forwarding messages to phone api // sniffReceived(p); MeshPlugin::callPlugins(*p); - - if (p->to == NODENUM_BROADCAST || p->to == getNodeNum()) { - printPacket("Delivering rx packet", p); - meshservice.handleFromRadio(p); - } } } diff --git a/src/mesh/Router.h b/src/mesh/Router.h index 17297ba14..4b1656936 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -89,7 +89,7 @@ class Router : protected concurrency::OSThread * Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to * update routing tables etc... based on what we overhear (even for messages not destined to our node) */ - virtual void sniffReceived(const MeshPacket *p, const Routing &c); + virtual void sniffReceived(const MeshPacket *p, const Routing *c); /** * Remove any encryption and decode the protobufs inside this packet (if necessary). diff --git a/src/plugins/RoutingPlugin.cpp b/src/plugins/RoutingPlugin.cpp index d0bcaf6a9..c3709ea5a 100644 --- a/src/plugins/RoutingPlugin.cpp +++ b/src/plugins/RoutingPlugin.cpp @@ -8,9 +8,16 @@ RoutingPlugin *routingPlugin; -bool RoutingPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Routing *p) +bool RoutingPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Routing *r) { - assert(0); + router->sniffReceived(&mp, r); + + // FIXME - move this to a non promsicious PhoneAPI plugin? + if (mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum()) { + printPacket("Delivering rx packet", &mp); + service.handleFromRadio(&mp); + } + return false; // Let others look at this message also if they want }