diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index e2fcc202..d06b4f12 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -710,10 +710,6 @@ protected: } } - void onContactTraceRecv(const ContactInfo& contact, uint32_t sender_timestamp, const uint8_t hash[], int8_t snr[], uint8_t path_len) override { - // TODO: write an out_frame - } - uint32_t calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const override { return SEND_TIMEOUT_BASE_MILLIS + (FLOOD_SEND_TIMEOUT_FACTOR * pkt_airtime_millis); } diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index 04072f84..1bb42bda 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -273,8 +273,6 @@ protected: if (pkt->getPayloadType() == PAYLOAD_TYPE_PATH || pkt->getPayloadType() == PAYLOAD_TYPE_REQ || pkt->getPayloadType() == PAYLOAD_TYPE_RESPONSE || pkt->getPayloadType() == PAYLOAD_TYPE_TXT_MSG) { f.printf(" [%02X -> %02X]\n", (uint32_t)pkt->payload[1], (uint32_t)pkt->payload[0]); - } else if (pkt->getPayloadType() == PAYLOAD_TYPE_TRACE) { - f.printf(" [%02X -> %02X]\n", (uint32_t)pkt->payload[2], (uint32_t)pkt->payload[1]); } else { f.printf("\n"); } diff --git a/examples/simple_secure_chat/main.cpp b/examples/simple_secure_chat/main.cpp index ce166d78..94273a68 100644 --- a/examples/simple_secure_chat/main.cpp +++ b/examples/simple_secure_chat/main.cpp @@ -285,10 +285,6 @@ protected: // not supported } - void onContactTraceRecv(const ContactInfo& contact, uint32_t sender_timestamp, const uint8_t hash[], int8_t snr[], uint8_t path_len) override { - // TODO: write an out_frame - } - uint32_t calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const override { return SEND_TIMEOUT_BASE_MILLIS + (FLOOD_SEND_TIMEOUT_FACTOR * pkt_airtime_millis); } diff --git a/src/Dispatcher.cpp b/src/Dispatcher.cpp index 7588bcf2..65f9687f 100644 --- a/src/Dispatcher.cpp +++ b/src/Dispatcher.cpp @@ -140,8 +140,6 @@ void Dispatcher::checkRecv() { if (pkt->getPayloadType() == PAYLOAD_TYPE_PATH || pkt->getPayloadType() == PAYLOAD_TYPE_REQ || pkt->getPayloadType() == PAYLOAD_TYPE_RESPONSE || pkt->getPayloadType() == PAYLOAD_TYPE_TXT_MSG) { Serial.printf(" [%02X -> %02X]\n", (uint32_t)pkt->payload[1], (uint32_t)pkt->payload[0]); - } else if (pkt->getPayloadType() == PAYLOAD_TYPE_TRACE) { - Serial.printf(" [%02X -> %02X]\n", (uint32_t)pkt->payload[2], (uint32_t)pkt->payload[1]); } else { Serial.printf("\n"); } diff --git a/src/Mesh.cpp b/src/Mesh.cpp index 02f209c2..0a0fd769 100644 --- a/src/Mesh.cpp +++ b/src/Mesh.cpp @@ -41,6 +41,30 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) { return ACTION_RELEASE; } + if (pkt->isRouteDirect() && pkt->getPayloadType() == PAYLOAD_TYPE_TRACE) { + if (pkt->path_len < MAX_PATH_SIZE) { + uint8_t i = 0; + uint32_t trace_tag; + memcpy(&trace_tag, &pkt->payload[i], 4); i += 4; + uint32_t auth_code; + memcpy(&auth_code, &pkt->payload[i], 4); i += 4; + uint8_t flags = pkt->payload[i++]; + + uint8_t len = pkt->payload_len - i; + if (pkt->path_len >= len) { // TRACE has reached end of given path + onTraceRecv(pkt, trace_tag, auth_code, flags, pkt->path, &pkt->payload[i], len); + } else if (self_id.isHashMatch(&pkt->payload[i + pkt->path_len]) && allowPacketForward(pkt) && !_tables->hasSeen(pkt)) { + // append SNR (Not hash!) + pkt->path[pkt->path_len] = (int8_t) (pkt->getSNR()*4); + pkt->path_len += PATH_HASH_SIZE; + + uint32_t d = getDirectRetransmitDelay(pkt); + return ACTION_RETRANSMIT_DELAYED(5, d); // schedule with priority 5 (for now), maybe make configurable? + } + } + return ACTION_RELEASE; + } + if (pkt->isRouteDirect() && pkt->path_len >= PATH_HASH_SIZE) { if (self_id.isHashMatch(pkt->path) && allowPacketForward(pkt)) { if (_tables->hasSeen(pkt)) return ACTION_RELEASE; // don't retransmit! @@ -49,16 +73,6 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) { pkt->path_len -= PATH_HASH_SIZE; memcpy(pkt->path, &pkt->path[PATH_HASH_SIZE], pkt->path_len); - if (pkt->getPayloadType() == PAYLOAD_TYPE_TRACE && pkt->payload_len + PATH_HASH_SIZE+1 < MAX_PACKET_PAYLOAD) { - if ((pkt->payload[0] & 3) == 0) { - // append our hash + SNR - pkt->payload_len += self_id.copyHashTo(&pkt->payload[pkt->payload_len]); - pkt->payload[pkt->payload_len++] = (int8_t) (pkt->getSNR()*4); - } else { - // unknown flags:type, don't append any info - } - } - uint32_t d = getDirectRetransmitDelay(pkt); return ACTION_RETRANSMIT_DELAYED(0, d); // Routed traffic is HIGHEST priority } @@ -80,16 +94,11 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) { } break; } - case PAYLOAD_TYPE_TRACE: case PAYLOAD_TYPE_PATH: case PAYLOAD_TYPE_REQ: case PAYLOAD_TYPE_RESPONSE: case PAYLOAD_TYPE_TXT_MSG: { int i = 0; - if (pkt->getPayloadType() == PAYLOAD_TYPE_TRACE) { - //uint8_t flags = pkt->payload[i]; // reserved for now - i++; // skip over - } uint8_t dest_hash = pkt->payload[i++]; uint8_t src_hash = pkt->payload[i++]; @@ -112,12 +121,7 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) { // decrypt, checking MAC is valid uint8_t data[MAX_PACKET_PAYLOAD]; - int len; - if (pkt->getPayloadType() == PAYLOAD_TYPE_TRACE) { - len = Utils::MACThenDecrypt(secret, data, macAndData, CIPHER_MAC_SIZE+CIPHER_BLOCK_SIZE); // encrypted part is fixed-len - } else { - len = Utils::MACThenDecrypt(secret, data, macAndData, pkt->payload_len - i); - } + int len = Utils::MACThenDecrypt(secret, data, macAndData, pkt->payload_len - i); if (len > 0) { // success! if (pkt->getPayloadType() == PAYLOAD_TYPE_PATH) { int k = 0; @@ -133,8 +137,6 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) { if (rpath) sendDirect(rpath, path, path_len); } } - } else if (pkt->getPayloadType() == PAYLOAD_TYPE_TRACE) { - onPeerTraceRecv(pkt, j, secret, data); } else { onPeerDataRecv(pkt, pkt->getPayloadType(), j, secret, data, len); } @@ -265,16 +267,6 @@ DispatcherAction Mesh::routeRecvPacket(Packet* packet) { // append this node's hash to 'path' packet->path_len += self_id.copyHashTo(&packet->path[packet->path_len]); - if (packet->getPayloadType() == PAYLOAD_TYPE_TRACE && (packet->payload[0] & 3) != 0) { - // flags:type must be zero (otherwise, some future/unknown sub-type) - return ACTION_RELEASE; // don't forward, just discard - } - - if (packet->getPayloadType() == PAYLOAD_TYPE_TRACE && packet->payload_len + 1 < MAX_PACKET_PAYLOAD) { - // append packet SNR - packet->payload[packet->payload_len++] = (int8_t) (packet->getSNR()*4); - } - uint32_t d = getRetransmitDelay(packet); // as this propagates outwards, give it lower and lower priority return ACTION_RETRANSMIT_DELAYED(packet->path_len, d); // give priority to closer sources, than ones further away @@ -364,7 +356,7 @@ Packet* Mesh::createPathReturn(const uint8_t* dest_hash, const uint8_t* secret, } Packet* Mesh::createDatagram(uint8_t type, const Identity& dest, const uint8_t* secret, const uint8_t* data, size_t data_len) { - if (type == PAYLOAD_TYPE_TXT_MSG || type == PAYLOAD_TYPE_REQ || type == PAYLOAD_TYPE_RESPONSE || type == PAYLOAD_TYPE_TRACE) { + if (type == PAYLOAD_TYPE_TXT_MSG || type == PAYLOAD_TYPE_REQ || type == PAYLOAD_TYPE_RESPONSE) { if (data_len + CIPHER_MAC_SIZE + CIPHER_BLOCK_SIZE-1 > MAX_PACKET_PAYLOAD) return NULL; } else { return NULL; // invalid type @@ -378,9 +370,6 @@ Packet* Mesh::createDatagram(uint8_t type, const Identity& dest, const uint8_t* packet->header = (type << PH_TYPE_SHIFT); // ROUTE_TYPE_* set later int len = 0; - if (type == PAYLOAD_TYPE_TRACE) { - packet->payload[len++] = 0; // reserved: flags:type - } len += dest.copyHashTo(&packet->payload[len]); // dest hash len += self_id.copyHashTo(&packet->payload[len]); // src hash len += Utils::encryptThenMAC(secret, &packet->payload[len], data, data_len); @@ -468,7 +457,28 @@ Packet* Mesh::createRawData(const uint8_t* data, size_t len) { return packet; } +Packet* Mesh::createTrace(uint32_t tag, uint32_t auth_code, uint8_t flags) { + Packet* packet = obtainNewPacket(); + if (packet == NULL) { + MESH_DEBUG_PRINTLN("%s Mesh::createTrace(): error, packet pool empty", getLogDateTime()); + return NULL; + } + packet->header = (PAYLOAD_TYPE_TRACE << PH_TYPE_SHIFT); // ROUTE_TYPE_* set later + + memcpy(packet->payload, &tag, 4); + memcpy(&packet->payload[4], &auth_code, 4); + packet->payload[8] = flags; + packet->payload_len = 9; // NOTE: path will be appended to payload[] later + + return packet; +} + void Mesh::sendFlood(Packet* packet, uint32_t delay_millis) { + if (packet->getPayloadType() == PAYLOAD_TYPE_TRACE) { + MESH_DEBUG_PRINTLN("%s Mesh::sendFlood(): TRACE type not suspported", getLogDateTime()); + return; + } + packet->header &= ~PH_ROUTE_MASK; packet->header |= ROUTE_TYPE_FLOOD; packet->path_len = 0; @@ -490,11 +500,20 @@ void Mesh::sendDirect(Packet* packet, const uint8_t* path, uint8_t path_len, uin packet->header &= ~PH_ROUTE_MASK; packet->header |= ROUTE_TYPE_DIRECT; - memcpy(packet->path, path, packet->path_len = path_len); + uint8_t pri; + if (packet->getPayloadType() == PAYLOAD_TYPE_TRACE) { // TRACE packets are different + // for TRACE packets, path is appended to end of PAYLOAD. (path is used for SNR's) + memcpy(&packet->payload[packet->payload_len], path, path_len); + packet->payload_len += path_len; + packet->path_len = 0; + pri = 5; // maybe make this configurable + } else { + memcpy(packet->path, path, packet->path_len = path_len); + pri = 0; + } _tables->hasSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us - - sendPacket(packet, 0, delay_millis); + sendPacket(packet, pri, delay_millis); } void Mesh::sendZeroHop(Packet* packet, uint32_t delay_millis) { diff --git a/src/Mesh.h b/src/Mesh.h index aab082fa..cfacebc9 100644 --- a/src/Mesh.h +++ b/src/Mesh.h @@ -105,13 +105,16 @@ protected: virtual void onPeerDataRecv(Packet* packet, uint8_t type, int sender_idx, const uint8_t* secret, uint8_t* data, size_t len) { } /** - * \brief A (now verified) TRACE packet has been received (by a known peer). - * NOTE: these can be received multiple times (per sender/msg-id), via different routes - * \param sender_idx index of peer, [0..n) where n is what searchPeersByHash() returned - * \param secret the pre-calculated shared-secret (handy for sending response packet) - * \param data decrypted data from payload (fixed length, one CIPHER_BLOCK) + * \brief A TRACE packet has been received. (and has reached the end of its given path) + * NOTE: this may have been initiated by another node. + * \param tag a random (unique-ish) tag set by initiator + * \param auth_code a code to authenticate the packet + * \param flags zero for now + * \param path_snrs single byte SNR*4 for each hop in the path + * \param path_hashes hashes if each repeater in the path + * \param path_len length of the path_snrs[] and path_hashes[] arrays */ - virtual void onPeerTraceRecv(Packet* packet, int sender_idx, const uint8_t* secret, uint8_t* data) { } + virtual void onTraceRecv(Packet* packet, uint32_t tag, uint32_t auth_code, uint8_t flags, const uint8_t* path_snrs, const uint8_t* path_hashes, uint8_t path_len) { } /** * \brief A path TO peer (sender_idx) has been received. (also with optional 'extra' data encoded) @@ -192,6 +195,7 @@ public: Packet* createPathReturn(const uint8_t* dest_hash, const uint8_t* secret, const uint8_t* path, uint8_t path_len, uint8_t extra_type, const uint8_t*extra, size_t extra_len); Packet* createPathReturn(const Identity& dest, const uint8_t* secret, const uint8_t* path, uint8_t path_len, uint8_t extra_type, const uint8_t*extra, size_t extra_len); Packet* createRawData(const uint8_t* data, size_t len); + Packet* createTrace(uint32_t tag, uint32_t auth_code, uint8_t flags = 0); /** * \brief send a locally-generated Packet with flood routing @@ -207,6 +211,7 @@ public: * \brief send a locally-generated Packet to just neigbor nodes (zero hops) */ void sendZeroHop(Packet* packet, uint32_t delay_millis=0); + }; } diff --git a/src/Packet.cpp b/src/Packet.cpp index 82a73339..71f89c1f 100644 --- a/src/Packet.cpp +++ b/src/Packet.cpp @@ -14,11 +14,7 @@ void Packet::calculatePacketHash(uint8_t* hash) const { SHA256 sha; uint8_t t = getPayloadType(); sha.update(&t, 1); - if (t == PAYLOAD_TYPE_TRACE) { - sha.update(payload, 3+CIPHER_MAC_SIZE+CIPHER_BLOCK_SIZE); // the 'content' part of TRACE packets is just the fixed-len encrypted part - } else { - sha.update(payload, payload_len); - } + sha.update(payload, payload_len); sha.finalize(hash, MAX_HASH_SIZE); } diff --git a/src/helpers/BaseChatMesh.cpp b/src/helpers/BaseChatMesh.cpp index 813bb8e9..eb6116e7 100644 --- a/src/helpers/BaseChatMesh.cpp +++ b/src/helpers/BaseChatMesh.cpp @@ -166,50 +166,6 @@ void BaseChatMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender } } -void BaseChatMesh::onPeerTraceRecv(mesh::Packet* packet, int sender_idx, const uint8_t* secret, uint8_t* data) { - int i = matching_peer_indexes[sender_idx]; - if (i < 0 || i >= num_contacts) { - MESH_DEBUG_PRINTLN("onPeerTraceRecv: Invalid sender idx: %d", i); - return; - } - - if ((packet->payload[0] & 3) != 0) { - MESH_DEBUG_PRINTLN("onPeerTraceRecv: unknown TRACE sub-type: %u", (uint32_t)packet->payload[0]); - return; - } - - ContactInfo& from = contacts[i]; - - uint32_t timestamp; - memcpy(×tamp, data, 4); // timestamp (by sender's RTC clock - which could be wrong) - uint8_t sender_flags = data[4]; - - int j = 3 + CIPHER_MAC_SIZE + CIPHER_BLOCK_SIZE; // skip fixed-len part - - uint8_t path_hashes[64]; - int8_t path_snr[65]; - uint16_t len; - if (packet->isRouteFlood()) { - memcpy(path_hashes, packet->path, len = packet->path_len); - memset(path_snr, 0, sizeof(path_snr)); - memcpy(path_snr, &packet->payload[j], packet->payload_len - j); // 'track' should just contain SNRs - } else { - len = 0; - while (j + 1 < packet->payload_len) { - path_hashes[len] = packet->payload[j++]; // pairs of Hash + SNR - path_snr[len] = packet->payload[j++]; - len++; - } - } - path_snr[len] = (int8_t)(packet->getSNR()*4); // also include last hop (to this node) - - onContactTraceRecv(from, timestamp, path_hashes, path_snr, len); - - if (sender_flags & 1) { // the 'wants reply' flag - // TODO: send a TRACE packet back - } -} - bool BaseChatMesh::onPeerPathRecv(mesh::Packet* packet, int sender_idx, const uint8_t* secret, uint8_t* path, uint8_t path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) { int i = matching_peer_indexes[sender_idx]; if (i < 0 || i >= num_contacts) { @@ -304,25 +260,6 @@ int BaseChatMesh::sendMessage(const ContactInfo& recipient, uint32_t timestamp, return rc; } -bool BaseChatMesh::sendContactTraceDirect(const ContactInfo& recipient, bool wantReply) { - if (recipient.out_path_len < 0) return false; // Error: no known path - - uint8_t temp[CIPHER_BLOCK_SIZE]; - memset(temp, 0, sizeof(temp)); - - uint32_t timestamp = getRTCClock()->getCurrentTime(); - memcpy(temp, ×tamp, 4); - temp[4] = wantReply ? 1 : 0; - // TODO: any other data to encrypt?? - - auto pkt = createDatagram(PAYLOAD_TYPE_TRACE, recipient.id, recipient.shared_secret, temp, sizeof(temp)); - if (pkt) { - sendDirect(pkt, recipient.out_path, recipient.out_path_len); - return true; // success - } - return false; // error -} - int BaseChatMesh::sendCommandData(const ContactInfo& recipient, uint32_t timestamp, uint8_t attempt, const char* text, uint32_t& est_timeout) { int text_len = strlen(text); if (text_len > MAX_TEXT_LEN) return MSG_SEND_FAILED; diff --git a/src/helpers/BaseChatMesh.h b/src/helpers/BaseChatMesh.h index 6a577828..30598f6c 100644 --- a/src/helpers/BaseChatMesh.h +++ b/src/helpers/BaseChatMesh.h @@ -114,7 +114,6 @@ protected: virtual void onSendTimeout() = 0; virtual void onChannelMessageRecv(const mesh::GroupChannel& channel, mesh::Packet* pkt, uint32_t timestamp, const char *text) = 0; virtual void onContactResponse(const ContactInfo& contact, const uint8_t* data, uint8_t len) = 0; - virtual void onContactTraceRecv(const ContactInfo& contact, uint32_t sender_timestamp, const uint8_t hash[], int8_t snr[], uint8_t path_len) = 0; // storage concepts, for sub-classes to override/implement virtual int getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) { return 0; } // not implemented @@ -126,7 +125,6 @@ protected: void getPeerSharedSecret(uint8_t* dest_secret, int peer_idx) override; void onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_idx, const uint8_t* secret, uint8_t* data, size_t len) override; bool onPeerPathRecv(mesh::Packet* packet, int sender_idx, const uint8_t* secret, uint8_t* path, uint8_t path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) override; - void onPeerTraceRecv(mesh::Packet* packet, int sender_idx, const uint8_t* secret, uint8_t* data) override; void onAckRecv(mesh::Packet* packet, uint32_t ack_crc) override; #ifdef MAX_GROUP_CHANNELS int searchChannelsByHash(const uint8_t* hash, mesh::GroupChannel channels[], int max_matches) override; @@ -151,7 +149,6 @@ public: bool shareContactZeroHop(const ContactInfo& contact); uint8_t exportContact(const ContactInfo& contact, uint8_t dest_buf[]); bool importContact(const uint8_t src_buf[], uint8_t len); - bool sendContactTraceDirect(const ContactInfo& recipient, bool wantReply); void resetPathTo(ContactInfo& recipient); void scanRecentContacts(int last_n, ContactVisitor* visitor); ContactInfo* searchContactsByPrefix(const char* name_prefix);