Design Spec: Standalone ISO-TP Utility Commands¶
Document Control¶
| Field | Value |
|---|---|
| Status | Planned |
| Command surface | canarchy isotp reassemble, canarchy isotp send |
| Primary area | CLI, protocol, transport, active-transmit safety |
| Related specs | docs/design/uds-transaction-workflows.md, docs/design/j1939-expanded-workflows.md, docs/design/active-transmit-safety.md |
| Issue | #328 |
Goal¶
Expose ISO 15765-2 transport utilities as standalone CLI commands so analysts can reassemble or transmit arbitrary ISO-TP messages without routing the workflow through UDS-specific commands.
User-Facing Motivation¶
CAN captures often contain diagnostic or vendor-specific ISO-TP exchanges that are not strictly UDS, or where the operator wants transport-layer evidence before protocol interpretation. A standalone isotp command group gives agents and human analysts a protocol-neutral path for message reconstruction, malformed-sequence triage, and safe single-message transmit planning.
Requirements¶
| ID | Type | Requirement |
|---|---|---|
REQ-ISOTP-01 |
Ubiquitous | The system shall provide an isotp command group with reassemble and send subcommands. |
REQ-ISOTP-02 |
Event-driven | When isotp reassemble --file <capture> is invoked, the system shall read CAN frames from the capture and emit reassembled ISO-TP messages with source metadata. |
REQ-ISOTP-03 |
Optional feature | Where --source <id> is specified for isotp reassemble, the system shall emit only ISO-TP data messages whose arbitration ID matches the source ID while still inspecting related reverse-direction flow-control frames for metadata. |
REQ-ISOTP-04 |
Optional feature | Where --target <id> is specified for isotp reassemble, the system shall use target ID metadata to classify request/response direction and flow-control relationships. |
REQ-ISOTP-05 |
Event-driven | When a complete single-frame or multi-frame ISO-TP message is observed, the system shall emit exactly one isotp_message event with complete equal to true. |
REQ-ISOTP-06 |
Unwanted behaviour | If a multi-frame ISO-TP message is truncated, out of order, or interrupted by a new first frame on the same arbitration ID, the system shall emit an isotp_message event with complete equal to false and preserve the partial payload bytes observed before the error. |
REQ-ISOTP-07 |
Event-driven | When ISO-TP flow-control frames appear in captured traffic, the system shall include them in per-message flow-control metadata without emitting them as standalone reassembled messages. |
REQ-ISOTP-08 |
Unwanted behaviour | If an ISO-TP frame has an unsupported or malformed protocol-control-information nibble, the system shall return or report a structured error with code ISOTP_MALFORMED_SEQUENCE. |
REQ-ISOTP-09 |
Event-driven | When isotp send <interface> --source <id> --target <id> --data <hex> is invoked, the system shall segment the payload as needed and transmit the ISO-TP frame sequence on the target interface. |
REQ-ISOTP-10 |
Optional feature | Where --dry-run is specified for isotp send, the system shall return the planned frame sequence without opening a transport. |
REQ-ISOTP-11 |
State-driven | While isotp send is running without --dry-run, the system shall enforce active-transmit safety controls before any CAN frame is transmitted. |
REQ-ISOTP-12 |
Unwanted behaviour | If live isotp send segments a multi-frame payload and does not receive required flow-control permission before a consecutive-frame timeout, the system shall return a structured error with code ISOTP_FLOW_CONTROL_TIMEOUT. |
REQ-ISOTP-13 |
Ubiquitous | The system shall honor the canonical CANarchy envelope for --json, one event per line for --jsonl, and protocol-aware summaries for --text. |
REQ-ISOTP-14 |
Ubiquitous | The system shall reuse the existing ISO-TP reassembly helpers proven by UDS workflows and avoid duplicating reassembly logic in CLI handlers. |
Command Surface¶
canarchy isotp reassemble --file <capture> [--source <id>] [--target <id>]
[--offset N] [--max-frames N] [--seconds T]
[--json] [--jsonl] [--text]
canarchy isotp send <interface> --source <id> --target <id> --data <hex>
[--dry-run] [--ack-active]
[--json] [--jsonl] [--text]
<id>, --source, and --target accept decimal or hex arbitration IDs. isotp send is an active-transmit command. isotp reassemble is passive and never opens a live transport.
Responsibilities And Boundaries¶
In scope:
- file-backed ISO-TP reassembly from candump and any capture formats already supported by file-backed analysis commands
- source-ID filtering for emitted data messages, while preserving related reverse-direction flow-control frames for metadata when target metadata is available
- single-frame and multi-frame message reconstruction
- incomplete-message reporting for malformed or truncated sequences
- flow-control metadata observed in captures
- single ISO-TP message transmission with active-transmit safety and dry-run planning
Out of scope:
- UDS service decoding; operators should pipe or correlate with
udsworkflows when UDS semantics are needed - J1939 transport-protocol reassembly, which remains under
j1939 tp - ISO-TP extended addressing, mixed addressing, CAN FD payload sizing, and block-size tuning until separately specified
- long-running ISO-TP client sessions, retries beyond one message, and ECU-specific diagnostic behavior
Data Model¶
isotp reassemble emits isotp_message events. Each event payload includes:
| Field | Description |
|---|---|
arbitration_id |
CAN ID carrying the ISO-TP payload frame sequence |
source_id |
Matched source ID when known, otherwise the observed arbitration ID |
target_id |
Target ID supplied by the operator, or null |
direction |
request, response, or unknown when source/target metadata is insufficient |
payload |
Reassembled application payload as lowercase hex |
payload_length |
Number of bytes in payload |
declared_length |
ISO-TP first-frame total length for multi-frame messages, otherwise payload length |
complete |
Whether the payload reached the declared length without sequence errors |
frame_count |
Number of data-bearing CAN frames consumed by the message |
flow_control_count |
Number of related flow-control frames observed |
sequence_error |
Sequence error description, or null |
timestamp_start |
Timestamp of the first data-bearing frame, or null |
timestamp_end |
Timestamp of the last related frame, or null |
isotp send --dry-run returns a frames array with CAN frame payloads in send order. Active single-frame sends transmit one CAN frame after active-transmit preflight. Active multi-frame sends transmit the first frame, wait for a flow-control frame from target_id, and only then transmit consecutive frames according to the observed flow-control status, block size, and separation-time metadata supported by the first implementation slice. Active sends return the same planned frames plus mode, interface, source_id, target_id, payload, frame_count, and active-transmit event metadata.
Output Contracts¶
--json returns the standard CANarchy envelope:
{
"ok": true,
"command": "isotp reassemble",
"data": {
"message_count": 1,
"messages": [
{
"event_type": "isotp_message",
"payload": {
"arbitration_id": 2024,
"source_id": 2024,
"target_id": 2016,
"direction": "response",
"payload": "62f190574457313233343536373839",
"payload_length": 15,
"declared_length": 15,
"complete": true,
"frame_count": 3,
"flow_control_count": 1,
"sequence_error": null,
"timestamp_start": 0.0,
"timestamp_end": 0.012
}
}
]
},
"warnings": [],
"errors": []
}
--jsonl emits one isotp_message event per line for reassemble and one planned/sent frame event per line for send. --text summarizes each message as source, target, direction, completeness, payload length, and payload hex.
Error Contracts¶
| Code | Trigger | Exit code |
|---|---|---|
CAPTURE_SOURCE_UNAVAILABLE |
--file path is missing or unreadable |
1 |
CAPTURE_PARSE_FAILED |
capture contains lines/records the existing capture reader cannot parse | 1 |
INVALID_CAN_ID |
--source, --target, or positional send IDs are malformed or outside the supported 11-bit range for the planned first slice |
1 |
INVALID_HEX_PAYLOAD |
--data is not valid hex or exceeds the planned payload limit |
1 |
ISOTP_MALFORMED_SEQUENCE |
PCI nibble, length field, consecutive-frame sequence, or frame length is invalid | 3 |
ISOTP_FLOW_CONTROL_TIMEOUT |
isotp send waits for flow-control permission and the timeout expires |
2 |
ACTIVE_ACK_REQUIRED |
active acknowledgement is required but omitted for live isotp send |
1 |
ACTIVE_CONFIRMATION_DECLINED |
active-transmit confirmation is declined for live isotp send |
1 |
TRANSPORT_UNAVAILABLE |
live send target interface cannot be opened | 2 |
Malformed sequences found during passive reassembly should be represented as incomplete isotp_message events when useful payload bytes were recovered. Fatal ISOTP_MALFORMED_SEQUENCE errors are reserved for inputs that cannot be associated with a coherent message event.
Active-Transmit Safety¶
isotp send shall be added to ACTIVE_TRANSMIT_COMMANDS when implemented. Live mode requires the same preflight warning, configurable --ack-active enforcement, and MCP-side safety posture as other active transmitters. --dry-run is the safe default expected for any future MCP mirror and must not open a transport. Live multi-frame sends shall wait for observed flow-control permission by default; an assumed-flow-control lab mode is not part of the initial command contract.
Deferred Decisions¶
- Whether extended, mixed, or normal-fixed addressing should be represented as flags or profile names.
- Whether CAN FD ISO-TP segmentation should be introduced with a
--can-fdflag and configurable data length. - Whether standalone ISO-TP utilities should be exposed through MCP in the first implementation slice or deferred until active-send behavior is stable.