Section 1
Why the gateway changed
Linux 7.1 drops the kernel AX.25 stack. Every program that does socket(AF_AX25, …) — ax25d, axspawn, call, DX cluster doors, mailboxes — needs somewhere else to go.
iw2ohx-gw used to carry a full Linux packet stack: kernel interfaces ax0/ax1/ax2, kissattach on pty pairs, two ax25ipd, kernel NET/ROM, flexnetd and URONode. Most of that duplicated what LinBPQ IW2OHX-13 (with our FlexNet extension) already does better: routing, NET/ROM, FlexNet, user commands. So the change came in two steps on the same day:
- Step 1
- URONode retired. LinBPQ IW2OHX-13 became the only node on the host. IW2OHX-7, IW2OHX-3 (flexnetd) and OHXGW:IW2OHX-1 (kernel NET/ROM) are gone. Their services are LinBPQ applications now: DX, CONV, IGATE, SHELL.
- Step 2
- Kernel AX.25 replaced by WAMPES. The few Linux programs that still need AX.25 — the DXSpider door, the shell login and a telnet gate — now reach it through WAMPES in user space, via the userspace build of libax25 (unix-ax25-stack, DL9SAU). The kernel modules are blocked; the host already runs as it will on 7.1.
Section 2 — the idea
A connector, not a node
WAMPES can be a complete node. Here it is deliberately not: it does no routing, carries no FlexNet and relays nothing between its ports. It only adapts.
One AXUDP link on loopback joins the node and the connector; the service socket joins the connector and Linux
- LinBPQ
- Owns the network: RF, FlexNet, NET/ROM, telnet logins, every user command. Its port 7 is a plain BPQAXIP port pointing at 127.0.0.1.
- WAMPES
- Claims two callsigns with listen ax25 add … client: IQ2LB-6 (the cluster) and IW2OHX-11 (the shell). A connect to either is handed, as an open descriptor, to whichever program has bound that callsign over the service socket. Nothing else is answered or forwarded.
- libax25
- The userspace build intercepts socket, bind, connect, listen, accept. At bind() it sees that the port belongs to a WAMPES node (listed in wampes.conf) and moves the socket there. After connect() the program holds a plain byte stream — nothing of the library is left on the data path. ax25d and axspawn run unmodified.
Because the node already exists, and it is the one users know. Keeping all routing in LinBPQ means one routing table, one set of FlexNet links, one place to look when a path breaks. WAMPES adds exactly one capability that LinBPQ lacks — lending an AX.25 stack to ordinary Linux programs — and nothing that competes with it.
Section 3
One session, step by step
A user at the BPQBOL prompt types DX.
- LinBPQ runs the application DX = C 7 IQ2LB-6: an AX.25 SABM on port 7, from the user's own callsign to IQ2LB-6.
- BPQAXIP wraps the frame in UDP to 127.0.0.1:10095 (MAP entry for IQ2LB-6).
- WAMPES iface bpq receives it and learns the user's callsign → 127.0.0.1:10096 for the replies (axip-learn on).
- IQ2LB-6 has a client listener, and ax25d holds it: WAMPES accepts the link and hands the session over the service socket.
- ax25d matches [IQ2LB-6 VIA wampes] and starts the DXSpider client as user sysop, with the session on stdin/stdout and the caller's callsign as argument.
- DXSpider greets the user by their callsign — the identity survived every hop.
SHELL is the same path to IW2OHX-11, where ax25d starts axspawn → /bin/login. As at DB0FHN, the account is created on the first connect from the caller's callsign, and over AX.25 no password is ever asked — the callsign is the login. From that shell the user runs passwd if they also want the telnet gate (Section 6); a notice says so until a password is set.
Anyone with a callsign can get a Unix shell here, so the shells are boxed in: the group ax25 may open no network connection at all (an iptables owner match on OUTPUT allows only the local DX cluster port — not the AGWPE port or the node's AXUDP port, which would let a shell transmit under any callsign), has no sudo and no cron, runs under process limits, and gets a private home. An empty password authenticates nowhere: the nullok option is gone from PAM and both SSH daemons refuse passwords. A shell over the Internet is not offered.
Section 4
How to connect
The node is IW2OHX-13, NET/ROM alias BPQBOL. URONode callsigns IW2OHX-7, IW2OHX-3 and OHXGW are retired.
| From | How | Notes |
|---|---|---|
| RF VHF/UHF | 144.825 MHz AFSK 1200 Bd or 433.725 MHz G3RUH 9600 Bd → C IW2OHX-12, then C IW2OHX-13 | IW2OHX-12 BOLFLX is the RF access node |
| FlexNet | C IW2OHX-13 · cluster: C IQ2LB-6 | through IW2OHX-14 (X)Net DLC7 BOLNET |
| NET/ROM | C BPQBOL | also BOLNET:IW2OHX-14, BOLHF:IW2OHX-15 |
| 44Net | telnet iw2ohx.ampr.org 23 (gate) · telnet iw2ohx.ampr.org 7300 (DXSpider) | gate: password set via SHELL first — Section 6 |
| HAMNET | telnet pr.iw2ohx.hamnet.radio 23 (gate) · telnet dx.iw2ohx.hamnet.radio 7300 | same |
| Internet | SSH gateway, key-only, by request | menu: DXSpider / IW2OHX-13 |
At the BPQBOL prompt: DX cluster, CONV convers (DB0FHN-12 via IGATE), IGATE, CHAT, BBS, XNET, BPQHF, SHELL, FL FlexNet links, D destinations.
Section 5 — copy the reasoning, not the numbers
Sample configurations
The live files of iw2ohx-gw, trimmed. WAMPES is built with TCPDIR=/tcp, libax25 and the ax25 tools with prefix /opt/uax25.
net.rc — the whole AX.25 side of the connector
Built with a prefix such as /opt/uax25, axspawn looks for useradd in that prefix — a symlink to /usr/sbin/useradd is needed, or every new account fails
LinBPQ binds port 7 on every address. Loopback is accepted earlier in the chain, so this DROP makes it reachable from the host alone.
After a WAMPES restart, ax25d notices the lost listeners and claims IQ2LB-6 and IW2OHX-11 again by itself within about ten seconds.
WAMPES has its own IP stack. On iw2ohx-gw it is dual-homed through two tun links: 44.134.24.8 on 44Net and 44.144.128.135 on HAMNET (proxy ARP on the HAMNET interface). Policy rules on the host send traffic from .8 into the AMPRNet tunnel and keep .135 strictly on HAMNET. It is not needed for the AX.25 connector — it is there for IP-over-AX.25 later.
Section 6
The telnet gate: AX.25 as yourself
Modelled on the telnet port of DB0FHN, rewritten for this host.
- Telnet to port 23 on iw2ohx.ampr.org or pr.iw2ohx.hamnet.radio. Only 44Net and HAMNET sources are let in.
- Login: your callsign, SSID allowed. Station calls and NOCALL are refused before anything else.
- Password: the one you set yourself with passwd after your first SHELL by radio, FlexNet or NET/ROM. An account without a password cannot log in here. Five failures lock it for 15 minutes.
- The daemon drops root and opens an AX.25 connection from your callsign to IW2OHX-13 through WAMPES. You land at the BPQBOL prompt exactly as if you had come in by radio.
ax25telnetd is about 1,300 lines of C11: a telnet filter that strips every option negotiation and maps line ends (CR LF ↔ CR), the callsign rules, PAM, privilege drop and a relay loop. It is an ordinary libax25 program — socket(AF_AX25), bind to the user's callsign via the WAMPES port, connect — and contains no WAMPES-specific code at all. No account is handed out by mail: the first SHELL over packet radio creates it. The password travels in clear, so use one you use nowhere else.
Section 7
What cost us time
Commits used: libax25 1ff923b, ax25-tools 3b33d6b, ax25-apps b78e3cc, wampes c028c51 (October 2026), on a Raspberry Pi 4 with 64-bit Debian 13.
WAMPES on 64-bit ARM needs two patches
At this commit net is not built at all (proc.h sees HAS_UCONTEXT before configure.h; the top-level make runs with -i, so it says nothing), and once built it segfaults: alloc.c uses WAMPES' own 32-bit allocator on every 64-bit platform except x86_64. Check that /tcp/sbin/net exists after make install. Reported upstream.
axip-learn off drops your users
A session from LinBPQ carries the user's callsign, not the node's. On a non-learning iface WAMPES only accepts callsigns the sysop wrote down, so every user frame vanished before the interface counters even moved.
A learned route remembers the wrong port
A callsign heard first via the node, then via IW2OHX-12, got its address updated but stayed bound to the first iface — replies went out the loopback socket and were lost. Fixed here with a three-line patch to axip.c, reported upstream.
chmod on the socket does nothing
WAMPES recreates its sockets and resets sockets/ to 0755 at every start. Access is set in net.rc with axsock mode/group. Leave sockets/packet at root: a client whose primary group owns it may close any session.
Block the kernel modules
Even with nothing configured, a probe socket loaded ax25.ko at every start. install ax25 /bin/false in modprobe.d made the host behave like a 7.1 kernel — and everything kept working.
Debian packages shadow the userspace library
A packaged libax25 is built for the kernel stack. An apt pin with Pin-Priority: -1 for libax25, ax25-tools and friends keeps them off the host.
Section 8
Further reading
In the WAMPES source tree, doc/PERMISSIONS.md and doc/LIBAX25-BRIDGE.md, and in libax25 AX25-WITHOUT-KERNEL-SYSOP.md, explain the design far better than this page. Thanks to Thomas, DL9SAU, for keeping AX.25 alive on Linux.