‹ All AirLink docs

AirLink

Protocol and state machine

What a node does when a link comes up, when a packet arrives and when it sends, and the call state machine from dial to hang-up.

Node events

A mesh node reacts to three kinds of event from its transports.

  1. Record the peer and give it a fresh reassembly buffer. A link reported twice is counted once.
  2. Offer it every message in the outbox that it has not been offered before, oldest first.
  3. Send a hello now and again 1.5 seconds later.
  1. Forget the peer and its reassembly buffer.
  2. Forget any mapping from a person to that link. Voice for them falls back to broadcast until they are heard on another link.

Bytes arrive

Feed them to the peer's reassembly buffer and handle each complete packet.

Handling a packet

StepConditionAction
1Identifier already seenDrop
2Older than 6 hours, or more than 15 minutes in the futureDrop
3VoiceDeliver if addressed here. Never relay
4Direct or receipt addressed hereDeliver. Do not relay
5BroadcastDeliver, and relay if the hop limit is above 1
6Addressed to someone elseRelay if the hop limit is above 1

A relayed packet is sent on every link with its hop limit reduced by one. The identifier is recorded as seen at step 1, so every node forwards a given packet at most once.

Delivering by kind

  • Hello. Parse the contact card. Ignore it if it is invalid or is this device's own. Remember the card, map the person to the link it arrived on, and announce the new contact to the interface.
  • Direct. Open the sealed message and verify the signature. If either fails, drop it silently. Map the sender to the link, send a sealed receipt back without queuing it, and pass the content to the interface.
  • Receipt. Open it, read the acknowledged identifier, remove that message from the outbox and mark it delivered.
  • Voice. Hand the sealed frame to the call.

Sending

A message

  1. Prefix the content type byte, pad, sign and seal to the recipient.
  2. Set the hop limit from the number of peers in range: 8 below three, 6 from three to five, 5 from six up.
  3. Record the identifier as seen, so an echo is not treated as news.
  4. Add the packet to the outbox, unless it is a receipt or a call signal.
  5. Send it on every link.

A voice frame

  1. Seal the frame with the call's send key and the next sequence number.
  2. Wrap it in a voice packet with a hop limit of one.
  3. Send it to the link the recipient was last heard on, or on every link if that is unknown.

A hello

A plaintext contact card to everyone, with a hop limit of two.

Outbox

RuleValue
What goes inMessages this device originated, except receipts and call signals
OfferedTo each new peer once, oldest first
RemovedWhen a sealed receipt for it arrives, or after 24 hours
Effective delivery window6 hours, because receivers drop older packets
PersistenceMemory only, for as long as the app runs

Call state machine

                 call()
   idle ─────────────────────────> dialling ──(accept)──────> connected
     │                                │                           │
     │ invite                         │ 60 s, no answer           │ end (either side)
     v                                v                           v
  ringing ──(answer)──> connected   ended("No answer")          ended
     │
     ├──(decline)──────────> ended
     └──(no invite for 12 s)──> ended("Missed call")
StateMeaning
IdleNo call
DiallingWe sent an invite and are repeating it every 2 seconds
RingingWe received an invite and are ringing
ConnectedKeys agreed and audio running
EndedThe call is over, with a reason such as "No answer" or "Missed call"

Rules

  • Microphone first. A call is not placed, and an answer not sent, until microphone permission is granted. Without it the call ends with "No microphone".
  • One call at a time. An invite that arrives while busy is declined with the invite's own nonce.
  • Nonces. Every signal carries the call nonce, and signals whose nonce does not match the live call are ignored.
  • Beacons. While dialling, the same invite is re-sent every 2 seconds. A repeated invite for the call being rung keeps the ring alive. A ring that hears no invite for 12 seconds ends as missed.
  • Stale calls. The last eight ended nonces are remembered. A late invite for one of them is declined, never rung.
  • Never queued. Invite, accept, decline and end are sent only to devices reachable now.

Media roads

EventMesh roadDirect road
Call connectsCarries every frameSocket opening
First frame arrives over UDPStops carrying framesCarries every frame
No UDP frame for 2.5 secondsResumesKeeps sending when the socket is ready

Received frames are checked against a 64-frame replay window before decryption, so a frame that arrives by both roads plays once, and a frame more than 64 behind is dropped.

Timers

TimerValue
Hello repeat after link up1.5 s
Invite beacon2 s
Ring without a beacon12 s
Ring patience at the caller60 s
Direct road trusted after last frame2.5 s
Wi-Fi dial timeout10 s
TCP keepalive5 s idle, 5 s interval, 2 probes
Duplicate table8,192 entries, 30 minutes
Maximum packet age6 hours, 15 minutes of clock skew allowed
Outbox patience24 hours