====== MOSH Transport Layer ====== The MOSH transport layer is responsible for moving MOSH frames between physical transports, fragmenting large messages, reassembling inbound fragments, and deciding whether a frame should be processed locally or forwarded to another link. In the current implementation, the transport layer supports both a **data plane** and a **control plane**. ===== Overview ===== A MOSH transport can currently operate in one of these modes: * `NATIVE` * `HOST_BACKED` * `EXCLUDE` The intended meanings are: * `NATIVE` * The transport directly owns a MOSH data network. * Frames can be transmitted onto that network. * Examples: ESP-NOW, WiFi, LoRa, etc. * `HOST_BACKED` * The transport is an uplink to a controlling host, such as a USB serial connection to a bridge. * The host owns the higher-level protocol behavior. * The attached MCU acts as a radio coprocessor and forwards frames between the host and native transports. * `EXCLUDE` * Reserved for transports that should not participate in normal routing. ===== Physical vs Logical Behavior ===== The transport layer separates two concerns: * **Physical transport** * Serial, ESP-NOW, WiFi, etc. * **Logical routing** * Which control node should receive a control-plane frame * Which transport owns a given data network This lets a device act as: * a local MOSH endpoint for control messages * a forwarding node for host-backed traffic * a native network egress point for one or more data networks ===== Control Plane ===== The control plane uses: * `network_id = 0` The control plane is intended for: * radio configuration * transport configuration * diagnostics * status requests * firmware-level control messages Control-plane routing is based on **control node ID**, not on data network ownership. Each control-plane destination is represented by a control route entry. A control route defines: * the control node ID * whether that control node is local to this device * which uplink should be used if the control node is remote Example conceptually: * `0/1` = local ESP32 radio control endpoint * `0/2` = downstream radio reachable through another uplink ===== Data Plane ===== The data plane uses: * any `network_id != 0` The data plane is intended for normal MOSH network traffic. Data-plane routing is based on **network ownership**. Each data route defines: * the data network ID * which control node owns that network * which native transport should be used if the network is local to this device Example conceptually: * network `10` is owned locally and transmitted on ESP-NOW * network `20` is owned by another control node and must be forwarded toward that node ===== Routing Tables ===== The current transport manager contains two explicit routing tables: * **Control route table** * **Data route table** ==== Control Route Table ==== Each control route entry contains: * `controlNodeID` * `local` * `uplink` If `local == true`: * control-plane frames for that node are delivered to the local RX queue If `local == false`: * control-plane frames for that node are forwarded through the configured uplink ==== Data Route Table ==== Each data route entry contains: * `networkID` * `ownerControlNodeID` * `nativeTransport` If `nativeTransport != null`: * this device owns that data network locally * outbound data-plane frames are sent through that native transport If `nativeTransport == null`: * the data network is owned remotely * outbound data-plane frames are forwarded toward the owning control node ===== Queue Model ===== The transport manager currently maintains: * a TX queue of logical `MOSH_Frame` objects * an RX queue of completed logical `MOSH_Frame` objects ==== TX Queue ==== The TX queue contains logical outbound frames generated locally by the MCU. When processed: * control-plane frames are routed by control node * data-plane frames are routed by network ownership * large frames are fragmented if needed before transmission ==== RX Queue ==== The RX queue contains inbound logical frames that are ready for local processing. A frame reaches the RX queue only after: * raw frame reception * successful decode * fragment reassembly if needed * local delivery decision `MOSH_Core` drains this RX queue and performs higher-level protocol handling. ===== Fragmentation ===== The MOSH wire protocol currently uses a maximum encoded frame size of: * `1470 bytes` That full encoded frame contains: * 13-byte header * payload * 2-byte CRC footer This means the maximum single-frame payload is: * `1455 bytes` Any logical payload larger than that must be fragmented. ==== Fragment Header ==== When a frame is fragmented, the fragment payload begins with a 4-byte fragment header: * byte 0: fragment index * byte 1: fragment count * byte 2: original payload length low byte * byte 3: original payload length high byte The remaining bytes are fragment data. ==== Reassembly ==== Inbound fragments are stored in a reassembly buffer keyed by: * source network ID * source node ID * message ID A complete logical frame is delivered only when: * all fragments are present * fragment metadata matches * the reassembled payload length matches the declared original length Expired fragment sets are discarded after the configured timeout. ===== Forwarding Rules ===== The transport layer now distinguishes between **local delivery** and **forwarding**. ==== Control-Plane Ingress ==== If an inbound frame is on control network `0`: * if the destination control node is local: * deliver to local RX queue * if the destination control node is remote: * forward to the configured uplink * if no route exists: * drop the frame ==== Data-Plane Ingress ==== If an inbound frame is on a non-zero data network: * if the destination network is locally owned: * send to the local native transport * if the destination network is remotely owned: * forward toward the owning control node * if no explicit data route exists: * fallback behavior is used ===== Fallback Behavior ===== The current implementation still keeps a compatibility fallback for cases where explicit routing-table entries have not yet been registered. If no explicit data or control route is found: * host-backed ingress will still try to forward data-plane frames to a matching native network * native ingress will still try to forward data-plane frames upward to a host-backed uplink * local control-plane TX may still use the host-backed source-node fallback This is useful during transition, but the preferred long-term model is to explicitly populate control and data route tables. ===== TTL Handling ===== TTL is now managed consistently. ==== Rule ==== * Locally originated frames keep their original TTL * Any frame forwarded from one transport to another has TTL decremented by exactly 1 This applies to: * control-plane forwarding * data-plane forwarding * host-backed to native forwarding * native to host-backed forwarding If a frame has `TTL = 0` at the moment it would need to be forwarded: * it is not forwarded Local delivery does not decrement TTL. ===== Host-Backed Mode ===== `HOST_BACKED` mode is intended for the case where a bridge controls one or more radios through attached MCUs. In this model: * the bridge owns protocol behavior * the MCU provides radio I/O and forwarding * the control plane is used to configure the radio itself * the data plane is used for normal MOSH network traffic This allows one MCU to act as: * a local control endpoint * a forwarder for host-injected data traffic * a bridge to additional downstream radios ===== Registration API ===== The current transport manager exposes APIs for registering route ownership: * `RegisterLocalControlNode(...)` * `RegisterRemoteControlNode(...)` * `RegisterLocalDataNetwork(...)` * `RegisterRemoteDataNetwork(...)` These APIs are also exposed through `MOSH_Core`. They are intended to describe the topology explicitly, for example: * which control nodes are local * which control nodes are downstream * which data networks are locally owned * which data networks belong to downstream radios ===== Current Limitations ===== The current transport layer is functional, but still evolving. Known limitations include: * fallback behavior is still present alongside the explicit route tables * upstream selection for multiple host-backed uplinks is not yet fully topology-driven unless the route tables are populated correctly * control-plane opcodes and higher-level radio-management messages are not fully implemented yet * transport ownership discovery is not yet automatic ===== Intended Next Step ===== The next planned step is to allow MOSH radios to exchange control-plane MOSH messages that advertise or discover remote data-network ownership. That would allow routing tables to be learned dynamically rather than fully hard-coded.