From a2eb148c509221d094a4841f09beb22b606e03c1 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sun, 27 Feb 2022 12:50:50 -0800 Subject: [PATCH] Revert "Merge pull request #1257 from mc-hamster/router" This reverts commit 33ed9476f8370c184b0a615219fbd290510e0544, reversing changes made to 10fefe7c7b1432922e78791432ee9e1c3dc347fd. --- src/main.cpp | 6 + src/mesh/DSRRouter.cpp | 250 +++++++++++++++++++++++++++++++++++++++++ src/mesh/DSRRouter.h | 80 +++++++++++++ 3 files changed, 336 insertions(+) create mode 100644 src/mesh/DSRRouter.cpp create mode 100644 src/mesh/DSRRouter.h diff --git a/src/main.cpp b/src/main.cpp index 5893d95a2..f025d3dd2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,6 +9,7 @@ #include "error.h" #include "power.h" // #include "rom/rtc.h" +#include "DSRRouter.h" // #include "debug.h" #include "FSCommon.h" #include "RTC.h" @@ -61,6 +62,8 @@ uint8_t screen_found; bool axp192_found; +Router *router = NULL; // Users of router don't care what sort of subclass implements that API + // ----------------------------------------------------------------------------- // Application // ----------------------------------------------------------------------------- @@ -440,6 +443,8 @@ void setup() fsInit(); + router = new DSRRouter(); + #ifdef I2C_SDA Wire.begin(I2C_SDA, I2C_SCL); #elif !defined(NO_WIRE) @@ -657,6 +662,7 @@ void setup() if (!rIf) RECORD_CRITICALERROR(CriticalErrorCode_NoRadio); else{ + router->addInterface(rIf); // Calculate and save the bit rate to myNodeInfo // TODO: This needs to be added what ever method changes the channel from the phone. diff --git a/src/mesh/DSRRouter.cpp b/src/mesh/DSRRouter.cpp new file mode 100644 index 000000000..c2a170ec7 --- /dev/null +++ b/src/mesh/DSRRouter.cpp @@ -0,0 +1,250 @@ +#include "configuration.h" +#include "DSRRouter.h" + +/* when we receive any packet + +- sniff and update tables (especially useful to find adjacent nodes). Update user, network and position info. +- if we need to route() that packet, resend it to the next_hop based on our nodedb. +- if it is broadcast or destined for our node, deliver locally +- handle routereply/routeerror/routediscovery messages as described below +- then free it + +routeDiscovery + +- if we've already passed through us (or is from us), then it ignore it +- use the nodes already mentioned in the request to update our routing table +- if they were looking for us, send back a routereply +- if max_hops is zero and they weren't looking for us, drop (FIXME, send back error - I think not though?) +- if we receive a discovery packet, we use it to populate next_hop (if needed) towards the requester (after decrementing max_hops) +- if we receive a discovery packet, and we have a next_hop in our nodedb for that destination we send a (reliable) we send a route +reply towards the requester + +when sending any reliable packet + +- if timeout doing retries, send a routeError (nak) message back towards the original requester. all nodes eavesdrop on that +packet and update their route caches. + +when we receive a routereply packet + +- update next_hop on the node, if the new reply needs fewer hops than the existing one (we prefer shorter paths). fixme, someday +use a better heuristic + +when we receive a routeError packet + +- delete the route for that failed recipient, restartRouteDiscovery() +- if we receive routeerror in response to a discovery, +- fixme, eventually keep caches of possible other routes. +*/ + +ErrorCode DSRRouter::send(MeshPacket *p) +{ + // We only consider multihop routing packets (i.e. those with dest set) + if (p->decoded.dest) { + // add an entry for this pending message + auto pending = startRetransmission(p); + // FIXME - when acks come in for this packet, we should _not_ delete the record unless the ack was from + // the final dest. We need to keep that record around until FIXME + // Also we should not retransmit multihop entries in that table at all + + // If we have an entry in our routing tables, just send it, otherwise start a route discovery + NodeNum nextHop = getNextHop(p->decoded.dest); + if (nextHop) { + sendNextHop(nextHop, p); // start a reliable single hop send + } else { + pending->wantRoute = true; + + // start discovery, but only if we don't already a discovery in progress for that node number + startDiscovery(p->decoded.dest); + } + + return ERRNO_OK; + } else + return ReliableRouter::send(p); +} + +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 + // ignore rebroadcasts. + // this will also add records for any ACKs we receive for our messages + if (p->to != NODENUM_BROADCAST || p->hop_limit != HOP_RELIABLE) { + addRoute(getFrom(p), getFrom(p), 0); // We are adjacent with zero hops + } + + 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 { + 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 { + // 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; + } + + // We simply ignore ACKs - because ReliableRouter will delete the pending packet for us + + // Handle regular packets + if (p->to == getNodeNum()) { // Destined for us (at least for this hop) + + // We need to route this packet to some other node + if (p->decoded.dest && p->decoded.dest != p->to) { + // if we have a route out, resend the packet to the next hop, otherwise return RouteError no-route available + + NodeNum nextHop = getNextHop(p->decoded.dest); + if (nextHop) { + sendNextHop(nextHop, p); // start a reliable single hop send + } else { + // We don't have a route out + assert(p->decoded.source); // I think this is guaranteed by now + + // FIXME - what if the current packet _is_ a route error packet? + sendRouteError(p, Routing_Error_NO_ROUTE); + } + + // FIXME, stop local processing of this packet + } + + 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->error_reason ? p->decoded.request_id : 0; + 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); + } + } + } + } + + ReliableRouter::sniffReceived(p, c); +} + +/** + * Does our node appear in the specified route + */ +bool DSRRouter::weAreInRoute(const RouteDiscovery &route) +{ + return true; // FIXME +} + +/** + * Given a DSR route, use that route to update our DB of possible routes + * + * Note: routes are always listed in the same order - from sender to receipient (i.e. route_replies also use this some order) + * + * @param isRequest is true if we are looking at a route request, else we are looking at a reply + **/ +void DSRRouter::updateRoutes(const RouteDiscovery &route, bool isRequest) +{ + DEBUG_MSG("FIXME not implemented updateRoutes\n"); +} + +/** + * send back a route reply (the sender address will be first in the list) + */ +void DSRRouter::sendRouteReply(const RouteDiscovery &route, NodeNum toAppend) +{ + DEBUG_MSG("FIXME not implemented sendRoute\n"); +} + +/** + * Given a nodenum return the next node we should forward to if we want to reach that node. + * + * @return 0 if no route found + */ +NodeNum DSRRouter::getNextHop(NodeNum dest) +{ + DEBUG_MSG("FIXME not implemented getNextHop\n"); + return 0; +} + +/** Not in our route cache, rebroadcast on their behalf (after adding ourselves to the request route) + * + * We will bump down hop_limit in this call. + */ +void DSRRouter::resendRouteRequest(const MeshPacket *p) +{ + DEBUG_MSG("FIXME not implemented resendRoute\n"); +} + +/** + * Record that forwarder can reach dest for us, but they will need numHops to get there. + * If our routing tables already have something that can reach that node in fewer hops we will keep the existing route + * instead. + */ +void DSRRouter::addRoute(NodeNum dest, NodeNum forwarder, uint8_t numHops) +{ + DEBUG_MSG("FIXME not implemented addRoute\n"); +} + +/** + * Record that we no longer have a route to the dest + */ +void DSRRouter::removeRoute(NodeNum dest) +{ + DEBUG_MSG("FIXME not implemented removeRoute\n"); +} + +/** + * Forward the specified packet to the specified node + */ +void DSRRouter::sendNextHop(NodeNum n, const MeshPacket *p) +{ + DEBUG_MSG("FIXME not implemented sendNextHop\n"); +} + +/** + * Send a route error packet towards whoever originally sent this message + */ +void DSRRouter::sendRouteError(const MeshPacket *p, Routing_Error err) +{ + DEBUG_MSG("FIXME not implemented sendRouteError\n"); +} + +/** make a copy of p, start discovery, but only if we don't + * already a discovery in progress for that node number. Caller has already scheduled this message for retransmission + * when the discovery is complete. + */ +void DSRRouter::startDiscovery(NodeNum dest) +{ + DEBUG_MSG("FIXME not implemented startDiscovery\n"); +} \ No newline at end of file diff --git a/src/mesh/DSRRouter.h b/src/mesh/DSRRouter.h new file mode 100644 index 000000000..0caa9310a --- /dev/null +++ b/src/mesh/DSRRouter.h @@ -0,0 +1,80 @@ +#include "ReliableRouter.h" + +class DSRRouter : public ReliableRouter +{ + + protected: + /** + * 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) override; + + /** + * Send a packet on a suitable interface. This routine will + * later free() the packet to pool. This routine is not allowed to stall. + * If the txmit queue is full it might return an error + */ + virtual ErrorCode send(MeshPacket *p) override; + + private: + /** + * Does our node appear in the specified route + */ + bool weAreInRoute(const RouteDiscovery &route); + + /** + * Given a DSR route, use that route to update our DB of possible routes + * + * Note: routes are always listed in the same order - from sender to receipient (i.e. route_replies also use this some order) + * + * @param isRequest is true if we are looking at a route request, else we are looking at a reply + **/ + void updateRoutes(const RouteDiscovery &route, bool isRequest); + + /** + * send back a route reply (the sender address will be first in the list) + */ + void sendRouteReply(const RouteDiscovery &route, NodeNum toAppend = 0); + + /** + * Given a nodenum return the next node we should forward to if we want to reach that node. + * + * @return 0 if no route found + */ + NodeNum getNextHop(NodeNum dest); + + /** Not in our route cache, rebroadcast on their behalf (after adding ourselves to the request route) + * + * We will bump down hop_limit in this call. + */ + void resendRouteRequest(const MeshPacket *p); + + /** + * Record that forwarder can reach dest for us, but they will need numHops to get there. + * If our routing tables already have something that can reach that node in fewer hops we will keep the existing route + * instead. + */ + void addRoute(NodeNum dest, NodeNum forwarder, uint8_t numHops); + + /** + * Record that we no longer have a route to the dest + */ + void removeRoute(NodeNum dest); + + /** + * Forward the specified packet to the specified node + */ + void sendNextHop(NodeNum n, const MeshPacket *p); + + /** + * Send a route error packet towards whoever originally sent this message + */ + void sendRouteError(const MeshPacket *p, Routing_Error err); + + /** make a copy of p, start discovery, but only if we don't + * already a discovery in progress for that node number. Caller has already scheduled this message for retransmission + * when the discovery is complete. + */ + void startDiscovery(NodeNum dest); +};