Skip to content

Commit

Permalink
Merge pull request meshtastic#1258 from mc-hamster/router
Browse files Browse the repository at this point in the history
Add role to generated proto
  • Loading branch information
mc-hamster authored Feb 27, 2022
2 parents 33ed947 + e5e13d7 commit 768c26b
Show file tree
Hide file tree
Showing 6 changed files with 355 additions and 5 deletions.
6 changes: 6 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
// -----------------------------------------------------------------------------
Expand Down Expand Up @@ -440,6 +443,8 @@ void setup()

fsInit();

router = new DSRRouter();

#ifdef I2C_SDA
Wire.begin(I2C_SDA, I2C_SCL);
#elif !defined(NO_WIRE)
Expand Down Expand Up @@ -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.
Expand Down
250 changes: 250 additions & 0 deletions src/mesh/DSRRouter.cpp
Original file line number Diff line number Diff line change
@@ -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");
}
80 changes: 80 additions & 0 deletions src/mesh/DSRRouter.h
Original file line number Diff line number Diff line change
@@ -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);
};
2 changes: 1 addition & 1 deletion src/mesh/generated/admin.pb.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ extern const pb_msgdesc_t AdminMessage_msg;
#define AdminMessage_fields &AdminMessage_msg

/* Maximum encoded size of messages (where known) */
#define AdminMessage_size 608
#define AdminMessage_size 611

#ifdef __cplusplus
} /* extern "C" */
Expand Down
1 change: 1 addition & 0 deletions src/mesh/generated/radioconfig.pb.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ PB_BIND(RadioConfig_UserPreferences, RadioConfig_UserPreferences, 2)




Loading

0 comments on commit 768c26b

Please sign in to comment.