diff --git a/docs/software/mesh-alg.md b/docs/software/mesh-alg.md index 19e7e506c..b809692a4 100644 --- a/docs/software/mesh-alg.md +++ b/docs/software/mesh-alg.md @@ -4,11 +4,13 @@ great source of papers and class notes: http://www.cs.jhu.edu/~cs647/ reliable messaging tasks (stage one for DSR): -- fix FIXME - should snoop packet not sent to us -- add a 'messagePeek' hook for all messages that pass through our node. +- DONE generalize naive flooding +- DONE add a max hops parameter, use it for broadcast as well (0 means adjacent only, 1 is one forward etc...). Store as three bits in the header. +- DONE add a 'snoopReceived' hook for all messages that pass through our node. - DONE use the same 'recentmessages' array used for broadcast msgs to detect duplicate retransmitted messages. - keep possible retries in the list with to be rebroadcast messages? -- for each message keep a count of # retries (max of three) +- for each message keep a count of # retries (max of three). allow this to _also_ work for broadcasts. +- Don't use broadcasts for the network pings (close open github issue) - delay some random time for each retry (large enough to allow for acks to come in) - once an ack comes in, remove the packet from the retry list and deliver the ack to the original sender - after three retries, deliver a no-ack packet to the original sender (i.e. the phone app or mesh router service) @@ -60,8 +62,6 @@ TODO: - DONE reread the disaster radio protocol docs - seems based on Babel (which is AODVish) - REJECTED - seems dying - possibly dash7? https://www.slideshare.net/MaartenWeyn1/dash7-alliance-protocol-technical-presentation https://github.com/MOSAIC-LoPoW/dash7-ap-open-source-stack - does the opensource stack implement multihop routing? flooding? their discussion mailing list looks dead-dead - update duty cycle spreadsheet for our typical usecase -- DONE generalize naive flooding -- DONE add a max hops parameter, use it for broadcast as well (0 means adjacent only, 1 is one forward etc...). Store as three bits in the header. a description of DSR: https://tools.ietf.org/html/rfc4728 good slides here: https://www.slideshare.net/ashrafmath/dynamic-source-routing good description of batman protocol: https://www.open-mesh.org/projects/open-mesh/wiki/BATMANConcept diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index e9941fb12..c40211a8f 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -29,6 +29,7 @@ void FloodingRouter::handleReceived(MeshPacket *p) DEBUG_MSG("Ignoring incoming msg, because we've already seen it\n"); packetPool.release(p); } else { + // 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->id != 0) { MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 28aba7fe7..986deb3fd 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -285,7 +285,7 @@ MeshPacket *MeshService::allocForSending() p->which_payload = MeshPacket_decoded_tag; // Assume payload is decoded at start. p->from = nodeDB.getNodeNum(); p->to = NODENUM_BROADCAST; - p->hop_limit = HOP_MAX; + p->hop_limit = HOP_RELIABLE; p->id = generatePacketId(); p->rx_time = getValidTime(); // Just in case we process the packet locally - make sure it has a valid timestamp diff --git a/src/mesh/MeshTypes.h b/src/mesh/MeshTypes.h index 04bb13ad6..f491ce508 100644 --- a/src/mesh/MeshTypes.h +++ b/src/mesh/MeshTypes.h @@ -21,7 +21,10 @@ typedef uint8_t PacketId; // A packet sequence number * maxhops to 3 should be fine for a while. This also serves to prevent routing/flooding attempts to be attempted for * too long. **/ -#define HOP_MAX 3 +#define HOP_MAX 7 + +/// We normally just use max 3 hops for sending reliable messages +#define HOP_RELIABLE 3 typedef int ErrorCode; diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 78b9f661c..ba0c32f05 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -2,7 +2,6 @@ #include "MeshTypes.h" #include "OSTimer.h" #include "mesh-pb-constants.h" -#include // FIXME, this class shouldn't need to look into nodedb #include #include #include @@ -284,31 +283,30 @@ void RadioLibInterface::handleReceiveInterrupt() rxBad++; } else { const PacketHeader *h = (PacketHeader *)radiobuf; - uint8_t ourAddr = nodeDB.getNodeNum(); rxGood++; - if (h->to != 255 && h->to != ourAddr) { - DEBUG_MSG("FIXME - should snoop packet not sent to us\n"); - } else { - MeshPacket *mp = packetPool.allocZeroed(); - mp->from = h->from; - mp->to = h->to; - mp->id = h->id; - assert(HOP_MAX <= 0x07); // If hopmax changes, carefully check this code - mp->hop_limit = h->flags & 0x07; + // Note: we deliver _all_ packets to our router (i.e. our interface is intentionally promiscuous). + // This allows the router and other apps on our node to sniff packets (usually routing) between other + // nodes. + MeshPacket *mp = packetPool.allocZeroed(); - addReceiveMetadata(mp); + mp->from = h->from; + mp->to = h->to; + mp->id = h->id; + assert(HOP_MAX <= 0x07); // If hopmax changes, carefully check this code + mp->hop_limit = h->flags & 0x07; - mp->which_payload = MeshPacket_encrypted_tag; // Mark that the payload is still encrypted at this point - assert(payloadLen <= sizeof(mp->encrypted.bytes)); - memcpy(mp->encrypted.bytes, payload, payloadLen); - mp->encrypted.size = payloadLen; + addReceiveMetadata(mp); - DEBUG_MSG("Lora RX interrupt from=0x%x, id=%u\n", mp->from, mp->id); + mp->which_payload = MeshPacket_encrypted_tag; // Mark that the payload is still encrypted at this point + assert(payloadLen <= sizeof(mp->encrypted.bytes)); + memcpy(mp->encrypted.bytes, payload, payloadLen); + mp->encrypted.size = payloadLen; - deliverToReceiver(mp); - } + DEBUG_MSG("Lora RX interrupt from=0x%x, id=%u\n", mp->from, mp->id); + + deliverToReceiver(mp); } } } diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 3752a2fbd..21b928f22 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -3,6 +3,7 @@ #include "GPS.h" #include "configuration.h" #include "mesh-pb-constants.h" +#include /** * Router todo @@ -80,6 +81,15 @@ ErrorCode Router::send(MeshPacket *p) } } +/** + * 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(MeshPacket *p) +{ + DEBUG_MSG("Sniffing packet not sent to us fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id); +} + /** * Handle any packet that is received by an interface on this node. * Note: some packets may merely being passed through this node and will be forwarded elsewhere. @@ -93,6 +103,8 @@ void Router::handleReceived(MeshPacket *p) assert(p->which_payload == MeshPacket_encrypted_tag); // I _think_ the only thing that pushes to us is raw devices that just received packets + // FIXME - someday don't send routing packets encrypted. That would allow us to route for other channels without + // being able to decrypt their data. // Try to decrypt the packet if we can static uint8_t bytes[MAX_RHPACKETLEN]; memcpy(bytes, p->encrypted.bytes, @@ -106,8 +118,12 @@ void Router::handleReceived(MeshPacket *p) // parsing was successful, queue for our recipient p->which_payload = MeshPacket_decoded_tag; - DEBUG_MSG("Notifying observers of received packet fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id); - notifyPacketReceived.notifyObservers(p); + sniffReceived(p); + uint8_t ourAddr = nodeDB.getNodeNum(); + if (p->to == NODENUM_BROADCAST || p->to == ourAddr) { + DEBUG_MSG("Notifying observers of received packet fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id); + notifyPacketReceived.notifyObservers(p); + } } packetPool.release(p); diff --git a/src/mesh/Router.h b/src/mesh/Router.h index 77538a0bd..03d75d33d 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -63,6 +63,12 @@ class Router * Note: this method will free the provided packet. */ virtual void handleReceived(MeshPacket *p); + + /** + * 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(MeshPacket *p); }; extern Router &router; \ No newline at end of file