1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
# max25d — Linux daemon
**max25d** supervises TNC/modem hardware, runs per-device RX/TX backends, and exposes M25/1 to `max25-terminal`.
Linux only. Config: `share/max25/max25d.ini.example`.
## Components
| File | Role |
|------|------|
| `max25d` | Python 3 daemon — M25/1 server, stack lifecycle |
| `device_backends.py` | Backend abstraction (TNC, BayCom, CRDOP) |
| `kiss_bridge.py` | Serial KISS for command-mode TNCs (TNC2C/PK-TNC2) |
| `banlist.py` | AX.25 source ban list (silent RX drop) |
| `test_multi_device.py` | Multi-device routing smoke |
## Backends
| Device id | Backend | Notes |
|-----------|---------|-------|
| `tnc2c`, `pktnc2` | `KissSerialBackend` | CI-tested |
| `max25e0` (`max25-bcpr:bc0`) | bcpr / KISS PTY | BayCom/based SER12 userspace — [docs/BAYCOM.md](../../docs/BAYCOM.md) |
| `baycom-kiss` | `KissRawSerialBackend` | USB/async KISS (not SER12 product face) |
| `soft-crdop` | `CrdopTcpBackend` | MAX25-SoftModem (CRDOP) — standard; KISS default; sound IN/OUT + radio like hardware modem |
Untested backends log a startup warning; SEND/RX return `ERR link not ready` when the stack path is unavailable.
## Quick start
```bash
# Protocol only (no hardware):
./max25d --no-stack -c ../../share/max25/max25d.ini.example
# With stack auto-start:
sudo ./max25d -c /etc/max25/max25d.ini
```
## One RF device per Linux host
**Target:** one `[devices]` id per `max25d`. See [ARCHITECTURE.md](../../docs/ARCHITECTURE.md#linux-host-policy--one-rf-device).
```ini
[devices]
default = tnc2c
tnc2c = /dev/ttyS4
```
**Legacy multi-id** (deprecated for new sites): `share/max25/max25d.full-station.ini.example`, `max25d.dual-baycom.ini.example`.
M25/1: `devices=` in `STATUS`, `SET DEVICE <id>`, `GET DEVICES`, `RX device=<id> …`.
## Source ban list
Block unwanted AX.25 callers (source address on incoming UI frames). Banned traffic is dropped silently — no terminal display, no daemon log line.
```ini
[modem]
bans_file = /etc/max25/bans.txt
```
File format: one callsign per line (`#` comments allowed). Ban without SSID blocks all SSIDs of that call (`DG1ABC` blocks `DG1ABC-7`). Ban with SSID (`DK0WC-7`) matches only that SSID.
M25/1: `BAN <callsign>`, `UNBAN <callsign>`, `BANS`. Changes persist to `bans_file` immediately.
## Install
```bash
./scripts/install-max25.sh --deps
# Installs: /usr/local/bin/max25d, kiss_bridge.py, device_backends.py, max25-terminal
```
Host setup guide: [docs/LINUX-HOST-SETUP.md](../../docs/LINUX-HOST-SETUP.md). Protocol: [include/max25/protocol.md](../../include/max25/protocol.md). Client: [docs/MAX25-CLIENT.md](../../docs/MAX25-CLIENT.md).
|