mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-09-02 22:43:47 +00:00
92 lines
3.7 KiB
C++
92 lines
3.7 KiB
C++
/*
|
|
* SPDX-License-Identifier: MIT
|
|
* ZephCore RoutingPolicy - flood hop limits and server reply routing
|
|
*
|
|
* Ported from Arduino MeshCore fad11c90 ("Fix replies dropped when
|
|
* flood.max.unscoped is low", PR #3106). Pure decision logic, no I/O: the
|
|
* repeater and the room server share it so the two roles cannot drift.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <mesh/Packet.h>
|
|
#include <stdint.h>
|
|
|
|
namespace mesh {
|
|
|
|
/**
|
|
* Test a flood packet against the configured hop limits.
|
|
*
|
|
* @param packet inbound flood packet (caller has already checked isRouteFlood())
|
|
* @param flood_max hop ceiling for any flood packet
|
|
* @param flood_max_unscoped hop ceiling for un-scoped (ROUTE_TYPE_FLOOD) packets;
|
|
* may be clamped lower than scoped/transport floods
|
|
* @param flood_max_advert hop ceiling for ADVERT floods, typically tighter still
|
|
* so advert churn stays local
|
|
* @returns true if a limit is exceeded and the packet must not be forwarded
|
|
*/
|
|
inline bool isFloodHopLimitExceeded(const Packet *packet, uint8_t flood_max,
|
|
uint8_t flood_max_unscoped, uint8_t flood_max_advert)
|
|
{
|
|
uint8_t hops = packet->getPathHashCount();
|
|
|
|
if (hops >= flood_max) return true;
|
|
if (packet->getRouteType() == ROUTE_TYPE_FLOOD && hops >= flood_max_unscoped) return true;
|
|
if (packet->getPayloadType() == PAYLOAD_TYPE_ADVERT && hops >= flood_max_advert) return true;
|
|
return false;
|
|
}
|
|
|
|
/** How a server routes a reply back to the requesting client. */
|
|
enum ReplyRoute : uint8_t {
|
|
REPLY_ROUTE_PATH_RETURN, // request arrived by flood: reply with a PATH return, flooded back
|
|
REPLY_ROUTE_DIRECT_SUPPLIED, // reply DIRECT, along the return path supplied in the request
|
|
REPLY_ROUTE_DIRECT_OUT_PATH, // reply DIRECT, along the out_path already stored for this client
|
|
REPLY_ROUTE_FLOOD, // no return path known: flood the reply
|
|
};
|
|
|
|
/**
|
|
* @param inbound_is_flood the request arrived as a flood packet
|
|
* @param have_supplied_path the request payload carried an explicit reply path
|
|
* @param have_out_path this server already holds a stored out_path for the client
|
|
*/
|
|
inline ReplyRoute chooseReplyRoute(bool inbound_is_flood, bool have_supplied_path,
|
|
bool have_out_path)
|
|
{
|
|
if (inbound_is_flood) return REPLY_ROUTE_PATH_RETURN;
|
|
if (have_supplied_path) return REPLY_ROUTE_DIRECT_SUPPLIED;
|
|
if (have_out_path) return REPLY_ROUTE_DIRECT_OUT_PATH;
|
|
return REPLY_ROUTE_FLOOD;
|
|
}
|
|
|
|
/** Which transport scope a flooded reply should carry. */
|
|
enum ReplyScope : uint8_t {
|
|
REPLY_SCOPE_REQUEST, // re-use the scope the request arrived on
|
|
REPLY_SCOPE_DEFAULT, // fall back to this node's default region scope
|
|
REPLY_SCOPE_NONE, // send un-scoped (ROUTE_TYPE_FLOOD)
|
|
};
|
|
|
|
/**
|
|
* @param request_scope_known request arrived scoped, and its Region's transport key resolved
|
|
* @param request_was_unscoped_flood request arrived as an un-scoped flood
|
|
* @param default_scope_known this node has a default Region with a usable transport key
|
|
*/
|
|
inline ReplyScope chooseReplyScope(bool request_scope_known, bool request_was_unscoped_flood,
|
|
bool default_scope_known)
|
|
{
|
|
if (request_scope_known) return REPLY_SCOPE_REQUEST;
|
|
|
|
/* The requester chose un-scoped, so mirror it. Replying scoped would
|
|
* change a path that works today, and repeaters not holding our default
|
|
* Region would drop it anyway. */
|
|
if (request_was_unscoped_flood) return REPLY_SCOPE_NONE;
|
|
|
|
/* Scope unknowable: a DIRECT request carries no transport codes, or the
|
|
* code matched no Region. Un-scoped would be dropped at hop 0 by every
|
|
* repeater running flood.max.unscoped=0, so use our own default. */
|
|
if (default_scope_known) return REPLY_SCOPE_DEFAULT;
|
|
|
|
return REPLY_SCOPE_NONE;
|
|
}
|
|
|
|
}
|