Skip to main content

Module can

Module can 

Source
Expand description

CAN bus (SocketCAN) server — NetGet as an ECU on somebody’s vehicle bus.

CAN is a broadcast bus, not a network. There is no addressing, no routing, no session and no authentication: every frame reaches every node, and each node decides for itself whether the 11- or 29-bit identifier is one it answers. Arbitration is by identifier — the numerically lowest wins the bus — which is a priority scheme, not a security one.

That is what makes an LLM-driven ECU simulator worth building, and it is the same property that makes it dangerous. A NetGet instance on a real vehicle bus can claim any identifier and impersonate any controller, and nothing on the bus can tell. See CLAUDE.md.

§Two transports, one codec

The frame format lives in frame and is pure. This module is the thin layer that moves those bytes, and transport is the thinner one that touches the OS:

  • transport: "socketcan" (the default) — a real AF_CAN socket, which exists only in the Linux kernel. On macOS and Windows spawn() returns an error naming the reason rather than reporting a server that is up and hearing nothing. This code has never been compiled or run; see CLAUDE.md.
  • transport: "udp" — a testing transport carrying the same struct can_frame / struct canfd_frame octets as UDP datagram payloads, so the whole event → handler/LLM → action → frame path runs unprivileged. No real CAN node speaks it.

§LLM failure → silence, and there is no alternative

CAN has no error reply. The thing called an error frame is not a message: it is six dominant bits transmitted on top of a frame in flight, destroying it for every node on the bus, after which the transmitting controller increments an error counter. Enough of them make it error-passive and then bus-off, at which point it has disconnected itself. Emitting one to signal “the backend is down” would corrupt other nodes’ traffic and could take this node — or with enough repetition, another — off the bus entirely.

So a failure transmits nothing, and nothing derived from the error ever reaches the wire. Silence is also completely ordinary on CAN: almost every node ignores almost every frame. The distinction therefore survives only in the log, tagged decision= the way src/server/radius/ tags its own:

TagMeaning
decision=no_policyNo instruction and no handler — nothing is transmitted and no LLM call is made
decision=model_rejectThe model answered no_response — a real decision
decision=model_silentThe model returned nothing usable
decision=fail_closed_overloadedThe call failed and the backend is saturated (retryable)
decision=fail_closed_llm_errorThe call failed otherwise

Modules§

actions
CAN bus actions and events — what the model sees, and what it can do about it.
frame
The CAN frame: representation, validation and the SocketCAN wire encoding.
transport
Where CAN frames actually travel — and the one platform on which they can.

Structs§

CanServer
CAN bus server.