An open-source TCP/IP stack and
bsdsocket.libraryv4.1 runtime for classic Commodore AmigaOS (68k), built on a pinned, hardened copy of lwIP 2.2.0 running as a dedicated AmigaOS Exec task (NO_SYS=1).
Classic AmigaOS has long lacked an actively maintained, production-grade, 100% open-source TCP/IP stack. Roadshow is proprietary commercial software. Miami and Miami Deluxe are discontinued abandonware. AmiTCP's last open-source release dates back to version 3.0b in 1994.
tolunnet bridges this gap: modern, fully documented, rigorously verified, and distributed under the GNU General Public License v3.0 (GPL-3.0-or-later). It provides a drop-in replacement bsdsocket.library for classic 68k Amiga systems (from a bone-stock Amiga 500 up to accelerated Amiga 4000 and PiStorm systems), complete with standard network diagnostic tools, a modern Setup wizard, and Workbench Preferences.
- Author: İsmail Öztürk
- Licence: GPL-3.0-or-later — see LICENSE.
- lwIP Core Licence: BSD-3-Clause — see THIRD_PARTY_LICENSES.md.
Compatibility Notice: Applications communicate with tolunnet strictly via the standard AmigaOS library interface:
OpenLibrary("bsdsocket.library", 4). Callingbsdsocket.libraryfunctions from any third-party application (freeware, shareware, or commercial) does not subject that application to the GPL.
bsdsocket.libraryv4.1 runtime: 139 total LVO slots (-30 … -858; 121 SFD functions + reserved) generated from Roadshow SDKsfd/bsdsocket_lib.sfdviascripts/gen_lvo_table.py; 70 BUILT (vector → IPC → daemon handler, or handled in-library), 51 honest stubs returning exact Roadshow error semantics (ENOSYS,ENXIO,NULL,NO_RECOVERY,FALSE), 0 BROKEN (marshaled without a daemon handler). A vector-by-vector status table (src/lib/lib_compat_table.gen.md) is generated locally bymake python-checks.
- Roadshow 1.8 & AmiTCP V4 API: socket primitives (
socket,bind,listen,accept,connect,shutdown,getsockname,getpeername,send/recv/sendmsg/recvmsg),SocketBaseTagList(-294),WaitSelect(timer-driven, SIGIO delivery),IoctlSocket,GetSocketEvents,Dup2Socket, netdb (gethostbyname,getservbyname/byport,getprotobyname/bynumber,getnetbyname/byaddr,getaddrinfo/getnameinfo),inet_*helpers,gethostname,gethostidandvsyslog. - Exec message-port IPC: client calls reach the daemon through native
PutMsg/WaitPort/ReplyMsg. The fast path reuses one message per library base; a per-callMEMF_PUBLICmessage is allocated only in IPC-timeout mode. - Universal 68k code (
-m68000 -msoft-float): one binary set for 68000 … 68060, no FPU required. - 68000 alignment defence: 4-byte memory pool alignment (
MEM_ALIGNMENT 4) andETH_PAD_SIZE 2keep IP/TCP headers aligned.-Werror=cast-alignandmake align-checkcatch#80000003Address Error regressions at build time. - SANA-II Rev 7 driver interface: register-convention buffer-management hooks (
A0/A1/D0), multiple outstanding reads,S2_ONEVENTlink tracking and an optional pipelined TX request pool (TX_QUEUE; the default0is synchronousDoIO). Works with standard Ethernet and wireless SANA-II drivers such asa2065.device,ariadne.device,cnet.deviceandwifipi.device. - PRNG seeding: the lwIP random source is seeded at start-up from
GetSysTime(µs resolution) and free Chip/Fast RAM, then from the adapter MAC address once the interface is open. - Text configuration:
DEVS:tolunnet.config(KEY=VALUE), described under Configuration.ENV:tolunnet.prefsoverrides it when newer. Changes take effect aftertolunnet RECONFIGorTolunnetControl RECONFIG. usergroup.library: resident library (LIBS:usergroup.library, 39 public LVOs) for user/group identity and credentials (getuid,geteuid,getpwuid,getpwnam,getgrnam,getgroups,crypt, …).- It has a built-in in-memory database: users
root,amiga,nobody; groupswheel,staff,nobody. - The first
passwd/groupfile found inAmiTCP:db/,DEVS:Internet/orDEVS:tolunnet/overrides that database. crypt()uses an internal FNV hash, not Unix DES; existing AmiTCP passwd files are not compatible.- Partial implementations are listed under Known limitations.
- It has a built-in in-memory database: users
- AutoIP (RFC 3927): optional link-local
169.254.x.x/16address fallback with Address Conflict Detection (lwIP DHCP/AutoIP cooperation, about 3–4 s). Off by default;AUTOIP=YESenables it. - mDNS responder (RFC 6762): optional Zeroconf responder that answers
<hostname>.localon224.0.0.251:5353and publishes a_workstation._tcpDNS-SD service (model=Amiga,os=AmigaOS,stack=tolunnet). Off by default;MDNS=YESenables it. - Workbench GUI:
TolunnetSetup: first-run wizard whose layout is computed from font metrics (TextLength(),tf_YSize). The bench verifies it on 640×200 NTSC and 640×256 PAL. The same code supports RTG screens, but the bench image has no RTG drivers to test them.TolunnetPrefs: GadTools preferences editor with non-blocking daemon Start/Stop, ToolTypes (TOOLPRI,PUBSCREEN) and WBStartup support.
The first-run wizard (TolunnetSetup) guides network configuration with automatic hardware detection and responsive layout adaptation across PAL and NTSC screens:
- Welcome & replacement: detects existing TCP/IP stacks (Roadshow, Miami, AmiTCP) and backs them up cleanly before proceeding.

- Hardware detection: scans installed SANA-II device drivers and configures unit selection.

- Wireless networks: scans available Wi-Fi networks (SSID, signal strength, security) and stores passphrases.

- Address mode (DHCP): automated dynamic host configuration and hostname assignment.

- Address mode (Static): manual configuration of static IP address, subnet mask, gateway, and DNS servers.

- Connection test & finish: verifies network operations and saves configuration with User-Startup integration.

The release archive ships the following programs, in C/ unless noted. The installer (Install_Tolunnet) installs the complete command set, companion tools and libraries to SYS:C/, SYS:Prefs/ and SYS:Libs/.
| Command | ReadArgs template / purpose |
|---|---|
tolunnet |
Stack daemon and bsdsocket.library provider. START/S,STOP/S,STATUS/S,RECONFIG/S,STATS/S,RAW/S,WATCH/N,DEVICE,UNIT/N,IP,NETMASK,GATEWAY. With no arguments it reads DEVS:tolunnet.config. |
TolunnetControl |
COMMAND/A: START, STOP, RESTART, STATUS, RECONFIG, STATS, VERSION. |
TolunnetSetup (SYS:Prefs/) |
First-run network wizard: hardware detection, DHCP/static setup, connection test. |
TolunnetPrefs (SYS:Prefs/) |
Preferences editor with stack Start/Stop. |
TolunnetStatus, ifconfig, netstat |
One read-only binary that takes no arguments. The name it is started under picks the output: stack status, interface summary, or socket/route summary. |
ShowNetStatus |
INTERFACES/S,ROUTES/S,DNS/S,SOCKETS/S,FULL/S |
GetNetStatus |
ONLINE/S,ADDRESS/S,GATEWAY/S,DNS/S: status query for scripts, answered through the return code. |
TolunnetPing, ping |
HOST/A,COUNT/N,SIZE/N,INTERVAL/N,TTL/N,TIMEOUT/N,QUIET/S,UDP/S: ICMP echo with min/avg/max/mdev. |
TolunnetGet, wget, curl |
URL/A,PORT/N,PATH,TO/K,QUIET/S: HTTP/1.1 client with 301/302/303/307/308 redirects, chunked transfer and Range resume. |
route |
SHOW/S,ADD/S,DEST/K,NETMASK/K,GATEWAY/K,DELETE/S,DEFAULT/S |
AddNetRoute, DeleteNetRoute |
DEST/A,MASK/K,GATEWAY/K and DEST/A,MASK/K (Roadshow-style names). |
AddNetInterface |
FILE (Roadshow-style interface control). |
ConfigureNetInterface |
NAME/M,ADDRESS/K,NETMASK/K,GATEWAY/K,DHCP/K |
Online, Offline |
NAME |
CheckNetConfig |
FILE: syntax check of a tolunnet config file. |
NetShutdown |
FORCE/S: orderly stack shutdown. |
arp |
SHOW/S: shows the ARP cache via SIOCGARP. |
hostname |
HOSTNAME,SAVE/S |
nslookup |
NAME/A,SERVER: forward (A) and reverse (PTR) lookups. |
traceroute |
HOST/A,MAXHOPS/N,QUERIES/N,WAIT/N,NUMERIC/S: UDP probe routing diagnosis with per-hop IP_TTL and ICMP replies. |
whois |
QUERY/A,SERVER (default server whois.iana.org). |
telnet |
HOST/A,PORT/N: raw TCP terminal. Telnet option negotiation (IAC/SB) is filtered out, not negotiated. |
nc |
HOST/A,PORT/N,UDP/S,LISTEN/S,TIMEOUT/N |
ftp |
HOST,PORT/N,USER,PASS,SCRIPT,QUIET/S,PASVANY/S: passive-mode FTP client. The PASV address must match the control connection's peer unless PASVANY is given. |
tftp |
HOST/A,GET/S,PUT/S,FILE/A,LOCAL: RFC 1350, octet mode. |
sntp |
HOST,SET/S,OFFSET/N |
iperf |
CLIENT/K,SERVER/S,PORT/N,SECONDS/N: simple TCP throughput sink/source with its own format, default port 5201. Not wire-compatible with iperf2 or iperf3. |
TestSocket |
Minimal socket smoke test. |
usergroup.library (SYS:Libs/) |
See Key Architecture & Features. |
DEVS:tolunnet.config holds one KEY=VALUE per line. TolunnetSetup and TolunnetPrefs write it.
| Key | Meaning |
|---|---|
DEVICE, UNIT |
SANA-II driver and unit |
DHCP |
YES/NO |
IP, NETMASK, GATEWAY |
static addressing (aliases IP_ADDR, MASK, GW) |
DNS, DNS2 |
resolvers (aliases DNS1, NAMESERVER) |
HOSTNAME, MTU |
host name, interface MTU |
AUTOIP, MDNS |
optional link-local fallback and mDNS responder (default NO; enable with AUTOIP=YES, MDNS=YES) |
TX_QUEUE |
TX request pool depth (0 = synchronous, the release default) |
LOG, LOGLEVEL, DEBUG, SYSLOG |
logging |
PRIORITY, SELECTORS, STATS, S2EVENTS, DATABASE_ORDER |
daemon tuning |
DNS_PORT, DNS_PENDING, DNS_RETRIES |
resolver tuning |
FONT |
font for TolunnetSetup (default: the screen font) |
Minimal example:
DEVICE=ethernet.device
UNIT=0
DHCP=YES
DNS=1.1.1.1
LOG=NIL:AmigaOS has no memory protection, so one unaligned access or use-after-free ends in a Guru Meditation. Every change therefore goes through three layers of testing. STATUS.md has the current results.
The 20 test programs in tests/host/ are built with the host compiler under AddressSanitizer and UndefinedBehaviorSanitizer (-Werror). They compile against the real project headers, with a mock lwIP/Exec layer underneath:
test_config, test_constants, test_dns_pending, test_errstr, test_fdset, test_http, test_ifreader, test_inet_addr, test_ipc, test_ipc_dispatch, test_lvo_table, test_queues, test_route, test_sbtc, test_slot_table, test_sockaddr, test_sockopt, test_stats, test_usergroup, test_wizard_config.
After the tests, make test-host runs python-checks: the LVO table generators must be up to date, icon formats are validated, and a gate checks the Forbid()/Disable() regions.
A headless WinUAE harness boots a clean Workbench 3.0 hard-disk image on Kickstart 3.1, in two profiles:
- a1200: 68EC020, AGA, PAL.
- 68000: A600-class 68000, ECS, NTSC, Fast RAM.
Each run does two cycles in the same OS session, without rebooting:
- Cycle 1:
- Start the daemon and obtain a DHCP lease.
- Run the
SocketConformancesuite: TCP/UDP/raw ICMP, non-blockingWaitSelect, socket events, a call into each of the 139 LVO slots, and every bundled command. - Run the third-party
bsdsocktestsuite, then stop the daemon.
- Cycle 2: relaunch the daemon, which re-opens the SANA-II device and gets a fresh lease, then repeat the tests.
A run only counts if the tree was clean (dirty: NO). The harness has a MuForce/Enforcer hook, but it currently reports SKIP because the tool image is not part of the bench.
Hobbyist Amigas are used for a few hours at a time, so the soak models many short sessions rather than long uptime. It runs 12 cycles of 10 minutes on the a1200 profile with TX_QUEUE=4:
- Each cycle runs periodic loopback
pingandwgetrequests and takes anAvailsnapshot, thenTolunnetControl STOP/START. - The run is then reviewed for Gurus and freezes,
not oklines, one fresh lwIP initialisation per cycle, and Fast RAM drift (budget: 8 KB or less).
The owner's target machine is an Amiga 500 with a PiStorm and wifipi.device. Real-hardware retests are done by hand on that machine.
Cross-compile with m68k-amigaos-gcc on Linux or WSL:
git clone https://github.com/tolon/tolunnet.git
cd tolunnet
# Binaries, LhA archive and ADF image (version from include/version.h)
make package CROSS=/path/to/m68k-amigaos/bin/m68k-amigaos-
# Host unit tests (ASan/UBSan) + generator/lint checks
make test-host
# Host-gcc strict cast-alignment gate over src/
make align-checkOutputs in build/:
build/tolunnet-<version>.lha: the full release, with binaries, icons, installer,README.guideand licences.build/tolunnet.adf: an 880 KB floppy image with only the strippedC/binaries andusergroup.library. It has no installer and no GUI icons.
- Extract
tolunnet-<version>.lhatoRAM:or any drawer. - Double-click
Install_Tolunnet:- It asks for the SANA-II device name and unit, and for DHCP or static addressing.
- It detects existing TCP/IP stacks (Roadshow, Miami, AmiTCP), backs up
LIBS:bsdsocket.libraryand emitsS:tolunnet-undo. - It copies the complete command set to
SYS:C/,usergroup.librarytoSYS:Libs/, and GUI tools toSYS:Prefs/. - It writes
DEVS:tolunnet.configand adds the config-driven startup line toS:User-Startup.
- At the end it launches
SYS:Prefs/TolunnetSetup, which validates the configuration and tests the connection.
- Copy files from the archive:
- the
C/programs you want, toSYS:C/; Libs/usergroup.librarytoLIBS:;TolunnetPrefsandTolunnetSetupwith their.infofiles toSYS:Prefs/.
- the
- Run
TolunnetSetuponce, or createDEVS:tolunnet.configby hand (see Configuration). - Start the stack from
S:User-Startup:Stack 32768 Run <NIL: >NIL: C:tolunnet
Release state, test results and known limitations are tracked in STATUS.md.
- tolunnet is Copyright (C) 2026 İsmail Öztürk, licensed under the GNU General Public License v3.0 or later. See LICENSE.
- lwIP (BSD-3-Clause) and the other third-party material, including the Roadshow SDK headers and the BSD network headers, are listed in THIRD_PARTY_LICENSES.md with their notices.