mirror of
https://github.com/alfishe/amiga-bootcamp.git
synced 2026-06-13 00:26:28 +00:00
Expand documentation suite: 30+ articles enriched with diagrams, code examples, and hardware details
Graphics: text_fonts (bitmap layout, styles), sprites (DMA, multiplexing), gfx_base (chipset detection), rastport (draw modes, clipping), ham_ehb (mermaid fixes), display_modes (HAM palettes) Devices: scsi (per-model interfaces, Gayle limits, CD-ROM, native vs vendor drivers), console (ANSI sequences, CON:/RAW:), parallel (CIA registers, pinout), timer (resource exhaustion), gameport (quadrature, XOR state) Libraries: workbench (WBStartup, AppWindow/Icon/MenuItem), rexxsyslib (ARexx port hosting, command parsing), diskfont (font directory, colour fonts), keymap (rawkey codes, dead keys), locale (catalogue system, date formatting), layers (ClipRect, refresh types), utility (TagItem chains), icon (DiskObject, ToolTypes), iffparse (IFF structure, ByteRun1), expansion (Zorro AutoConfig) Networking: tcp_ip_stacks (major rewrite - Amiga vs Unix architecture, SANA-II pipeline, PPP/SLIP dial-up, Ethernet cards, MiSTer), bsdsocket (pure API ref), sana2 (buffer hooks, driver requirements), protocols (all code examples). Deduplicated overlap between the three files. Toolchain: debugging (Enforcer patterns, SnoopDOS, GDB remote, kprintf checklist), sasc (pragma encoding, __saveds idioms), stormc (NEW - StormC IDE, C++, PowerPC) References: error_codes (DOS, Exec, trackdisk, Intuition error tables) Driver development: rtg_driver (Native driver analysis, P96 tuning) All 22 README indexes updated. Root README synced with stormc.md entry.
This commit is contained in:
parent
0ded078134
commit
f61c26b542
38 changed files with 6402 additions and 1065 deletions
|
|
@ -2,11 +2,13 @@
|
|||
|
||||
# Networking — Overview
|
||||
|
||||
AmigaOS has no built-in TCP/IP stack. Third-party stacks (AmiTCP, Miami, Roadshow) provide `bsdsocket.library` — a BSD-compatible socket API in user-space. Network hardware is abstracted via the SANA-II device driver standard.
|
||||
|
||||
## Section Index
|
||||
|
||||
| File | Description |
|
||||
|---|---|
|
||||
| [bsdsocket.md](bsdsocket.md) | bsdsocket.library — BSD socket API |
|
||||
| [sana2.md](sana2.md) | SANA-II — standard network device driver interface |
|
||||
| [tcp_ip_stacks.md](tcp_ip_stacks.md) | Stack comparison: AmiTCP, Miami, Roadshow |
|
||||
| [protocols.md](protocols.md) | Protocol implementation: DHCP, DNS, HTTP |
|
||||
| [tcp_ip_stacks.md](tcp_ip_stacks.md) | Stack architecture: Amiga vs Unix model, SANA-II integration, PPP/SLIP dial-up, modem setup, Ethernet cards, MiSTer virtual NIC, detailed stack comparison |
|
||||
| [bsdsocket.md](bsdsocket.md) | BSD socket API: per-task library base, LVO table, WaitSelect with Exec signals, error handling, BSD/POSIX differences |
|
||||
| [sana2.md](sana2.md) | SANA-II driver specification: buffer management hooks, send/receive patterns, device query, driver requirements |
|
||||
| [protocols.md](protocols.md) | Protocol implementation: DNS resolution, TCP client/server, WaitSelect integration, UDP, DHCP sequence |
|
||||
|
|
|
|||
|
|
@ -1,23 +1,39 @@
|
|||
[← Home](../README.md) · [Networking](README.md)
|
||||
|
||||
# bsdsocket.library — BSD Socket API
|
||||
# bsdsocket.library — BSD Socket API Reference
|
||||
|
||||
## Overview
|
||||
|
||||
`bsdsocket.library` is the AmigaOS implementation of the BSD socket API. It is provided by the active TCP/IP stack (AmiTCP, Miami, Roadshow) and presents a POSIX-like socket interface adapted to the Amiga's library-based architecture.
|
||||
`bsdsocket.library` is the AmigaOS implementation of the BSD socket API. It is provided by the active TCP/IP stack (AmiTCP, Miami, Roadshow). See [TCP/IP Stacks](tcp_ip_stacks.md) for how the stack architecture works and how it differs from Unix. See [Protocols](protocols.md) for working code examples.
|
||||
|
||||
---
|
||||
|
||||
## Opening
|
||||
## Per-Task Library Base
|
||||
|
||||
Unlike Unix (kernel-managed fd table), each Amiga task must open its own private `SocketBase`:
|
||||
|
||||
```c
|
||||
struct Library *SocketBase = OpenLibrary("bsdsocket.library", 4);
|
||||
if (!SocketBase) { /* no TCP/IP stack running */ }
|
||||
if (!SocketBase)
|
||||
{
|
||||
Printf("No TCP/IP stack running\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Configure per-task error variable: */
|
||||
LONG errno;
|
||||
SocketBaseTags(
|
||||
SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(LONG))), (ULONG)&errno,
|
||||
SBTM_SETVAL(SBTC_LOGTAGPTR), (ULONG)"myapp",
|
||||
TAG_DONE);
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> **Never share `SocketBase` between tasks.** Each task MUST `OpenLibrary` its own copy. Sharing causes socket state corruption and random crashes. This is the #1 Amiga networking bug.
|
||||
|
||||
---
|
||||
|
||||
## Core Functions (LVO Mapping)
|
||||
## Function Table (LVO Mapping)
|
||||
|
||||
| LVO | Function | BSD Equivalent |
|
||||
|---|---|---|
|
||||
|
|
@ -36,58 +52,83 @@ if (!SocketBase) { /* no TCP/IP stack running */ }
|
|||
| −102 | `gethostbyname(name)` | `gethostbyname()` |
|
||||
| −108 | `gethostbyaddr(addr, len, type)` | `gethostbyaddr()` |
|
||||
| −114 | `getnetbyname(name)` | `getnetbyname()` |
|
||||
| −168 | `Errno()` | `errno` (returns last error) |
|
||||
| −168 | `Errno()` | `errno` |
|
||||
| −174 | `CloseSocket(sock)` | `close()` |
|
||||
| −180 | `WaitSelect(nfds, rd, wr, ex, timeout, sigmask)` | `select()` + signals |
|
||||
| −210 | `inet_addr(cp)` | `inet_addr()` |
|
||||
| −216 | `Inet_NtoA(in)` | `inet_ntoa()` |
|
||||
| −222 | `inet_makeaddr(net, host)` | `inet_makeaddr()` |
|
||||
| −252 | `getservbyname(name, proto)` | `getservbyname()` |
|
||||
| −270 | `SocketBaseTagList(tags)` | (Amiga-specific) |
|
||||
|
||||
---
|
||||
|
||||
## WaitSelect — Amiga-Enhanced select()
|
||||
|
||||
Unlike BSD `select()`, `WaitSelect` integrates with Exec signals:
|
||||
The key Amiga-specific extension: `WaitSelect` simultaneously waits on socket file descriptors **and** Exec signal bits. This replaces the need for separate threads — a single event loop can handle sockets, windows, timers, and ARexx:
|
||||
|
||||
```c
|
||||
fd_set rdset;
|
||||
FD_ZERO(&rdset);
|
||||
FD_SET(sock, &rdset);
|
||||
|
||||
ULONG sigmask = SIGBREAKF_CTRL_C; /* also wait for Ctrl-C */
|
||||
struct timeval tv = { 5, 0 }; /* 5 second timeout */
|
||||
|
||||
LONG n = WaitSelect(sock + 1, &rdset, NULL, NULL, &tv, &sigmask);
|
||||
if (n > 0 && FD_ISSET(sock, &rdset)) { /* data ready */ }
|
||||
if (sigmask & SIGBREAKF_CTRL_C) { /* user pressed Ctrl-C */ }
|
||||
LONG WaitSelect(LONG nfds,
|
||||
fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||||
struct timeval *timeout,
|
||||
ULONG *sigmask);
|
||||
/* sigmask: on entry = signals to also wait for
|
||||
on exit = which signals fired */
|
||||
```
|
||||
|
||||
See [protocols.md](protocols.md) for a complete working example combining socket I/O with Intuition window events.
|
||||
|
||||
---
|
||||
|
||||
## Simple TCP Client
|
||||
## Error Handling
|
||||
|
||||
```c
|
||||
/* Amiga sockets use Errno() instead of global errno: */
|
||||
LONG sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
struct sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(80);
|
||||
addr.sin_addr.s_addr = inet_addr("93.184.216.34");
|
||||
|
||||
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
|
||||
send(sock, "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n", 38, 0);
|
||||
char buf[4096];
|
||||
LONG n = recv(sock, buf, sizeof(buf) - 1, 0);
|
||||
buf[n] = 0;
|
||||
Printf("%s\n", buf);
|
||||
if (sock < 0)
|
||||
{
|
||||
LONG err = Errno();
|
||||
Printf("socket() failed: error %ld\n", err);
|
||||
}
|
||||
CloseSocket(sock);
|
||||
|
||||
/* Or set up a per-task errno pointer (recommended): */
|
||||
LONG myErrno;
|
||||
SocketBaseTags(
|
||||
SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(LONG))), (ULONG)&myErrno,
|
||||
TAG_DONE);
|
||||
/* Now myErrno is updated automatically after each call */
|
||||
```
|
||||
|
||||
### Common Error Codes
|
||||
|
||||
| Value | Name | Meaning |
|
||||
|---|---|---|
|
||||
| 48 | `EADDRINUSE` | Address already in use |
|
||||
| 60 | `ETIMEDOUT` | Connection timed out |
|
||||
| 61 | `ECONNREFUSED` | Connection refused |
|
||||
| 64 | `EHOSTDOWN` | Host is down |
|
||||
| 65 | `EHOSTUNREACH` | No route to host |
|
||||
|
||||
---
|
||||
|
||||
## Differences from BSD/POSIX Sockets
|
||||
|
||||
| Aspect | BSD/POSIX | Amiga bsdsocket.library |
|
||||
|---|---|---|
|
||||
| Close socket | `close(fd)` | `CloseSocket(sock)` — `close()` is AmigaDOS |
|
||||
| Error variable | Global `errno` | Call `Errno()` or set `SBTC_ERRNOPTR` |
|
||||
| Multiplexing | `select()` / `poll()` / `epoll()` | `WaitSelect()` — also waits on Exec signals |
|
||||
| Headers | `<sys/socket.h>` | `<proto/socket.h>` or stack-specific |
|
||||
| Lifecycle | Kernel-managed | Must `OpenLibrary`/`CloseLibrary` per task |
|
||||
| fd namespace | Shared with files | Sockets are separate from DOS file handles |
|
||||
| Multi-thread | fd shared across threads | `SocketBase` is per-task, not shareable |
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `libraries/bsdsocket.h` (stack-specific)
|
||||
- Roadshow SDK documentation
|
||||
- [sana2.md](sana2.md) — network device driver layer
|
||||
- AmiTCP SDK: `bsdsocket.h` and autodocs
|
||||
- See also: [tcp_ip_stacks.md](tcp_ip_stacks.md) — stack architecture and configuration
|
||||
- See also: [protocols.md](protocols.md) — working code examples (TCP, UDP, DNS)
|
||||
- See also: [sana2.md](sana2.md) — network device driver layer below the stack
|
||||
|
|
|
|||
|
|
@ -1,67 +1,245 @@
|
|||
[← Home](../README.md) · [Networking](README.md)
|
||||
|
||||
# Protocol Implementation — DHCP, DNS, HTTP
|
||||
# Protocol Implementation — DNS, TCP, UDP, WaitSelect
|
||||
|
||||
## Overview
|
||||
|
||||
With `bsdsocket.library` providing a BSD-compatible API, standard network protocols can be implemented using familiar patterns adapted for the Amiga's single-address-space, library-based architecture.
|
||||
Working code examples for common network protocols on AmigaOS using [bsdsocket.library](bsdsocket.md). See [TCP/IP Stacks](tcp_ip_stacks.md) for the architecture that makes this possible and how it differs from Unix.
|
||||
|
||||
> [!NOTE]
|
||||
> Amiga socket functions are **library calls** (via `bsdsocket.library`), not system calls. You must `OpenLibrary("bsdsocket.library", ...)` before using any socket function. Use `CloseSocket()` instead of `close()`, and `Errno()` instead of `errno`.
|
||||
|
||||
---
|
||||
|
||||
## DNS Resolution
|
||||
|
||||
```c
|
||||
/* gethostbyname — provided by bsdsocket.library: */
|
||||
struct Library *SocketBase = OpenLibrary("bsdsocket.library", 4);
|
||||
if (!SocketBase) return;
|
||||
|
||||
struct hostent *he = gethostbyname("www.amiga.org");
|
||||
if (he) {
|
||||
struct in_addr addr = *(struct in_addr *)he->h_addr;
|
||||
Printf("IP: %s\n", Inet_NtoA(addr.s_addr));
|
||||
if (he)
|
||||
{
|
||||
struct in_addr addr;
|
||||
CopyMem(he->h_addr, &addr, sizeof(addr));
|
||||
Printf("Host: %s\n", he->h_name);
|
||||
Printf("IP: %s\n", Inet_NtoA(addr.s_addr));
|
||||
|
||||
/* May have multiple addresses: */
|
||||
char **p;
|
||||
for (p = he->h_addr_list; *p; p++)
|
||||
{
|
||||
CopyMem(*p, &addr, sizeof(addr));
|
||||
Printf(" Addr: %s\n", Inet_NtoA(addr.s_addr));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("DNS lookup failed\n");
|
||||
}
|
||||
|
||||
CloseLibrary(SocketBase);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## HTTP Client (Minimal)
|
||||
## TCP Client
|
||||
|
||||
```c
|
||||
struct Library *SocketBase = OpenLibrary("bsdsocket.library", 4);
|
||||
if (!SocketBase) return;
|
||||
|
||||
LONG sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0) { Printf("socket() failed\n"); goto out; }
|
||||
|
||||
struct hostent *he = gethostbyname("www.example.com");
|
||||
if (!he) { Printf("DNS failed\n"); goto close; }
|
||||
|
||||
struct sockaddr_in sa;
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_port = htons(80);
|
||||
CopyMem(he->h_addr, &sa.sin_addr, he->h_length);
|
||||
|
||||
connect(sock, (struct sockaddr *)&sa, sizeof(sa));
|
||||
if (connect(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0)
|
||||
{
|
||||
Printf("connect failed: %ld\n", Errno());
|
||||
goto close;
|
||||
}
|
||||
|
||||
/* Send HTTP request: */
|
||||
char req[] = "GET / HTTP/1.0\r\nHost: www.example.com\r\n\r\n";
|
||||
send(sock, req, strlen(req), 0);
|
||||
|
||||
char buf[8192];
|
||||
LONG total = 0, n;
|
||||
while ((n = recv(sock, buf + total, sizeof(buf) - total - 1, 0)) > 0)
|
||||
total += n;
|
||||
buf[total] = 0;
|
||||
Printf("%s\n", buf);
|
||||
/* Receive response: */
|
||||
char buf[4096];
|
||||
LONG n;
|
||||
while ((n = recv(sock, buf, sizeof(buf) - 1, 0)) > 0)
|
||||
{
|
||||
buf[n] = 0;
|
||||
Printf("%s", buf);
|
||||
}
|
||||
|
||||
CloseSocket(sock);
|
||||
close:
|
||||
CloseSocket(sock);
|
||||
out:
|
||||
CloseLibrary(SocketBase);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DHCP Overview
|
||||
## TCP Server
|
||||
|
||||
DHCP on Amiga is typically handled by the TCP/IP stack itself (Roadshow, Miami) or an external client (AmiTCP + `dhclient`). The sequence is standard:
|
||||
```c
|
||||
LONG listenSock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
1. `DHCPDISCOVER` — broadcast on port 67
|
||||
struct sockaddr_in sa;
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_port = htons(8080);
|
||||
sa.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
bind(listenSock, (struct sockaddr *)&sa, sizeof(sa));
|
||||
listen(listenSock, 5);
|
||||
|
||||
Printf("Listening on port 8080...\n");
|
||||
|
||||
while (running)
|
||||
{
|
||||
struct sockaddr_in clientAddr;
|
||||
LONG addrLen = sizeof(clientAddr);
|
||||
LONG clientSock = accept(listenSock,
|
||||
(struct sockaddr *)&clientAddr,
|
||||
&addrLen);
|
||||
if (clientSock >= 0)
|
||||
{
|
||||
Printf("Connection from %s\n",
|
||||
Inet_NtoA(clientAddr.sin_addr.s_addr));
|
||||
|
||||
char response[] = "HTTP/1.0 200 OK\r\n"
|
||||
"Content-Type: text/html\r\n\r\n"
|
||||
"<h1>Hello from Amiga!</h1>\n";
|
||||
send(clientSock, response, strlen(response), 0);
|
||||
CloseSocket(clientSock);
|
||||
}
|
||||
}
|
||||
|
||||
CloseSocket(listenSock);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## UDP Datagram
|
||||
|
||||
```c
|
||||
LONG udpSock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
/* Send: */
|
||||
struct sockaddr_in dest;
|
||||
dest.sin_family = AF_INET;
|
||||
dest.sin_port = htons(9999);
|
||||
dest.sin_addr.s_addr = inet_addr("192.168.1.255");
|
||||
|
||||
char msg[] = "Hello UDP";
|
||||
sendto(udpSock, msg, strlen(msg), 0,
|
||||
(struct sockaddr *)&dest, sizeof(dest));
|
||||
|
||||
/* Receive: */
|
||||
char buf[1024];
|
||||
struct sockaddr_in from;
|
||||
LONG fromLen = sizeof(from);
|
||||
LONG n = recvfrom(udpSock, buf, sizeof(buf), 0,
|
||||
(struct sockaddr *)&from, &fromLen);
|
||||
buf[n] = 0;
|
||||
Printf("From %s: %s\n", Inet_NtoA(from.sin_addr.s_addr), buf);
|
||||
|
||||
CloseSocket(udpSock);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## WaitSelect — Combined Socket + GUI Event Loop
|
||||
|
||||
The key pattern for responsive Amiga network applications. `WaitSelect` simultaneously waits on sockets **and** Exec signals (windows, ARexx, timers) — no threads needed:
|
||||
|
||||
```c
|
||||
/* Set up signal masks: */
|
||||
ULONG winSig = 1 << window->UserPort->mp_SigBit;
|
||||
ULONG ctrlSig = SIGBREAKF_CTRL_C;
|
||||
|
||||
fd_set readFDs;
|
||||
struct timeval tv;
|
||||
|
||||
BOOL running = TRUE;
|
||||
while (running)
|
||||
{
|
||||
FD_ZERO(&readFDs);
|
||||
FD_SET(sock, &readFDs);
|
||||
tv.tv_secs = 1;
|
||||
tv.tv_micro = 0;
|
||||
|
||||
ULONG sigmask = winSig | ctrlSig;
|
||||
|
||||
LONG result = WaitSelect(sock + 1, &readFDs, NULL, NULL,
|
||||
&tv, &sigmask);
|
||||
|
||||
/* Socket data ready? */
|
||||
if (result > 0 && FD_ISSET(sock, &readFDs))
|
||||
{
|
||||
LONG n = recv(sock, buffer, sizeof(buffer), 0);
|
||||
if (n > 0)
|
||||
{
|
||||
/* process network data */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* connection closed or error */
|
||||
running = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Window event? */
|
||||
if (sigmask & winSig)
|
||||
{
|
||||
struct IntuiMessage *imsg;
|
||||
while ((imsg = (struct IntuiMessage *)GetMsg(window->UserPort)))
|
||||
{
|
||||
switch (imsg->Class)
|
||||
{
|
||||
case IDCMP_CLOSEWINDOW:
|
||||
running = FALSE;
|
||||
break;
|
||||
/* ... handle other IDCMP events ... */
|
||||
}
|
||||
ReplyMsg((struct Message *)imsg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ctrl-C? */
|
||||
if (sigmask & ctrlSig)
|
||||
{
|
||||
Printf("*** Break\n");
|
||||
running = FALSE;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> `WaitSelect` eliminates the need for multi-threading in most Amiga network apps. A single event loop handles sockets, GUI, timers, and ARexx simultaneously — simpler and safer than threads in a non-protected memory environment.
|
||||
|
||||
---
|
||||
|
||||
## DHCP
|
||||
|
||||
DHCP is handled by the TCP/IP stack, not by applications. See [TCP/IP Stacks](tcp_ip_stacks.md) for configuration. The standard sequence is:
|
||||
|
||||
1. `DHCPDISCOVER` — stack broadcasts on port 67
|
||||
2. `DHCPOFFER` — server responds with IP offer
|
||||
3. `DHCPREQUEST` — client accepts
|
||||
4. `DHCPACK` — server confirms; lease begins
|
||||
|
||||
For MiSTer/FPGA cores with custom SANA-II drivers, DHCP is handled automatically once the SANA-II driver is online and the stack is configured for `IPTYPE=DHCP`.
|
||||
3. `DHCPREQUEST` — stack accepts
|
||||
4. `DHCPACK` — server confirms; interface is configured
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- [bsdsocket.md](bsdsocket.md) — socket API reference
|
||||
- [tcp_ip_stacks.md](tcp_ip_stacks.md) — stack configuration
|
||||
- [bsdsocket.md](bsdsocket.md) — API reference and LVO table
|
||||
- [tcp_ip_stacks.md](tcp_ip_stacks.md) — stack architecture and configuration
|
||||
- [sana2.md](sana2.md) — SANA-II driver layer
|
||||
|
|
|
|||
|
|
@ -4,75 +4,198 @@
|
|||
|
||||
## Overview
|
||||
|
||||
SANA-II is the standard device driver interface for network hardware on AmigaOS. It defines a uniform API that TCP/IP stacks use to communicate with any network card (Ethernet, WiFi, PPP, etc.).
|
||||
SANA-II (Standard Amiga Networking Architecture, version II) is the standardised `exec.device` interface between TCP/IP stacks and network hardware drivers. Any SANA-II compliant driver works with any SANA-II compliant stack — providing hardware independence analogous to NDIS on Windows or the Linux kernel network driver model.
|
||||
|
||||
---
|
||||
See [TCP/IP Stacks](tcp_ip_stacks.md) for how SANA-II fits into the full networking architecture.
|
||||
|
||||
## Architecture
|
||||
```mermaid
|
||||
flowchart TD
|
||||
subgraph "TCP/IP Stacks (any)"
|
||||
AT["AmiTCP"]
|
||||
RS["Roadshow"]
|
||||
MI["Miami"]
|
||||
end
|
||||
|
||||
```
|
||||
Application
|
||||
↓
|
||||
bsdsocket.library (TCP/IP stack)
|
||||
↓
|
||||
SANA-II device driver (e.g., prism2.device, a2065.device)
|
||||
↓
|
||||
Network hardware
|
||||
subgraph "SANA-II API (standardised)"
|
||||
API["CMD_READ / CMD_WRITE<br/>S2_ONLINE / S2_OFFLINE<br/>S2_DEVICEQUERY<br/>Buffer Management Hooks"]
|
||||
end
|
||||
|
||||
subgraph "SANA-II Drivers (any)"
|
||||
A2065["a2065.device<br/>(Ethernet)"]
|
||||
ARIADNE["ariadne.device<br/>(Ethernet)"]
|
||||
PPP["ppp.device<br/>(dial-up)"]
|
||||
MISTER["mister_eth.device<br/>(MiSTer virtual)"]
|
||||
end
|
||||
|
||||
AT --> API
|
||||
RS --> API
|
||||
MI --> API
|
||||
API --> A2065
|
||||
API --> ARIADNE
|
||||
API --> PPP
|
||||
API --> MISTER
|
||||
|
||||
style API fill:#fff9c4,stroke:#f9a825,color:#333
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Opening a SANA-II Device
|
||||
|
||||
SANA-II drivers require **buffer management hooks** — callback functions the driver uses to copy packet data to/from the application's buffers:
|
||||
|
||||
```c
|
||||
#include <devices/sana2.h>
|
||||
|
||||
struct MsgPort *port = CreateMsgPort();
|
||||
struct IOSana2Req *s2req = (struct IOSana2Req *)
|
||||
CreateIORequest(port, sizeof(struct IOSana2Req));
|
||||
|
||||
/* Provide buffer management hooks: */
|
||||
static struct TagItem s2tags[] = {
|
||||
{ S2_CopyToBuff, (ULONG)CopyToBuff },
|
||||
{ S2_CopyFromBuff, (ULONG)CopyFromBuff },
|
||||
/* Buffer management hooks (required): */
|
||||
static struct TagItem bufferTags[] = {
|
||||
{ S2_CopyToBuff, (ULONG)MyCopyToBuff },
|
||||
{ S2_CopyFromBuff, (ULONG)MyCopyFromBuff },
|
||||
{ TAG_DONE, 0 }
|
||||
};
|
||||
s2req->ios2_BufferManagement = s2tags;
|
||||
s2req->ios2_BufferManagement = bufferTags;
|
||||
|
||||
OpenDevice("a2065.device", 0, (struct IORequest *)s2req, 0);
|
||||
if (OpenDevice("a2065.device", 0, (struct IORequest *)s2req, 0))
|
||||
{
|
||||
Printf("Cannot open network device\n");
|
||||
}
|
||||
```
|
||||
|
||||
### Buffer Management Hooks
|
||||
|
||||
```c
|
||||
/* Called by the driver to copy received data into your buffer: */
|
||||
BOOL __asm MyCopyToBuff(register __a0 APTR to,
|
||||
register __a1 APTR from,
|
||||
register __d0 ULONG length)
|
||||
{
|
||||
CopyMem(from, to, length);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Called by the driver to copy transmit data from your buffer: */
|
||||
BOOL __asm MyCopyFromBuff(register __a0 APTR to,
|
||||
register __a1 APTR from,
|
||||
register __d0 ULONG length)
|
||||
{
|
||||
CopyMem(from, to, length);
|
||||
return TRUE;
|
||||
}
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> Buffer management hooks exist because SANA-II drivers may use DMA or special memory regions. The hooks let the driver control how data is copied — the stack never accesses driver buffers directly.
|
||||
|
||||
---
|
||||
|
||||
## Commands
|
||||
|
||||
| Code | Constant | Description |
|
||||
|---|---|---|
|
||||
| 2 | `CMD_READ` | Read a packet |
|
||||
| 3 | `CMD_WRITE` | Send a packet |
|
||||
| 9 | `S2_DEVICEQUERY` | Query hardware capabilities |
|
||||
| 10 | `S2_GETSTATIONADDRESS` | Get MAC address |
|
||||
| 11 | `S2_CONFIGINTERFACE` | Configure interface (set MAC) |
|
||||
| 14 | `S2_ONLINE` | Bring interface online |
|
||||
| 15 | `S2_OFFLINE` | Take interface offline |
|
||||
| 21 | `S2_GETGLOBALSTATS` | Get packet statistics |
|
||||
| 16 | `S2_ADDMULTICASTADDRESS` | Add multicast address |
|
||||
| 17 | `S2_DELMULTICASTADDRESS` | Remove multicast address |
|
||||
| Code | Constant | Direction | Description |
|
||||
|---|---|---|---|
|
||||
| 2 | `CMD_READ` | Receive | Read a packet (kept outstanding; completed when packet arrives) |
|
||||
| 3 | `CMD_WRITE` | Transmit | Send a packet |
|
||||
| 9 | `S2_DEVICEQUERY` | Query | Get hardware capabilities (type, MTU, speed) |
|
||||
| 10 | `S2_GETSTATIONADDRESS` | Query | Get hardware (MAC) address |
|
||||
| 11 | `S2_CONFIGINTERFACE` | Config | Set the hardware address |
|
||||
| 14 | `S2_ONLINE` | Control | Bring interface up (start receiving) |
|
||||
| 15 | `S2_OFFLINE` | Control | Take interface down |
|
||||
| 16 | `S2_ADDMULTICASTADDRESS` | Config | Subscribe to multicast address |
|
||||
| 17 | `S2_DELMULTICASTADDRESS` | Config | Unsubscribe from multicast |
|
||||
| 21 | `S2_GETGLOBALSTATS` | Query | Get packet/byte counters |
|
||||
| 22 | `S2_GETSPECIALSTATS` | Query | Get driver-specific statistics |
|
||||
|
||||
---
|
||||
|
||||
## Packet Reading
|
||||
## Sending a Packet
|
||||
|
||||
```c
|
||||
/* Prepare an Ethernet frame: */
|
||||
s2req->ios2_Req.io_Command = CMD_WRITE;
|
||||
s2req->ios2_WireError = 0;
|
||||
s2req->ios2_PacketType = 0x0800; /* IPv4 EtherType */
|
||||
s2req->ios2_DataLength = packetLength;
|
||||
|
||||
/* Set destination MAC: */
|
||||
CopyMem(destMAC, s2req->ios2_DstAddr, 6);
|
||||
|
||||
/* ios2_Data points to the packet payload (after Ethernet header): */
|
||||
s2req->ios2_Data = packetData;
|
||||
|
||||
DoIO((struct IORequest *)s2req);
|
||||
if (s2req->ios2_Req.io_Error)
|
||||
Printf("Send error: %ld (wire: %ld)\n",
|
||||
s2req->ios2_Req.io_Error, s2req->ios2_WireError);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Receiving Packets
|
||||
|
||||
The stack posts **multiple read requests** to keep a pipeline full:
|
||||
|
||||
```c
|
||||
/* Post a read request (non-blocking): */
|
||||
s2req->ios2_Req.io_Command = CMD_READ;
|
||||
s2req->ios2_WireError = 0;
|
||||
s2req->ios2_PacketType = 0x0800; /* IPv4 */
|
||||
s2req->ios2_PacketType = 0x0800; /* only IPv4 packets */
|
||||
SendIO((struct IORequest *)s2req);
|
||||
/* wait for packet... */
|
||||
|
||||
/* Wait for a packet: */
|
||||
WaitIO((struct IORequest *)s2req);
|
||||
/* s2req->ios2_Data* contains the received packet */
|
||||
|
||||
Printf("Received %ld bytes from %02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
s2req->ios2_DataLength,
|
||||
s2req->ios2_SrcAddr[0], s2req->ios2_SrcAddr[1],
|
||||
s2req->ios2_SrcAddr[2], s2req->ios2_SrcAddr[3],
|
||||
s2req->ios2_SrcAddr[4], s2req->ios2_SrcAddr[5]);
|
||||
|
||||
/* Immediately post another read to keep the pipeline full: */
|
||||
s2req->ios2_Req.io_Command = CMD_READ;
|
||||
SendIO((struct IORequest *)s2req);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Querying Device Capabilities
|
||||
|
||||
```c
|
||||
struct Sana2DeviceQuery query;
|
||||
query.SizeAvailable = sizeof(query);
|
||||
|
||||
s2req->ios2_Req.io_Command = S2_DEVICEQUERY;
|
||||
s2req->ios2_StatData = &query;
|
||||
DoIO((struct IORequest *)s2req);
|
||||
|
||||
Printf("Hardware type: %ld\n", query.HardwareType); /* 1 = Ethernet */
|
||||
Printf("MTU: %ld bytes\n", query.MTU); /* 1500 for Ethernet */
|
||||
Printf("Speed: %ld bps\n", query.BPS); /* 10000000 for 10 Mbps */
|
||||
Printf("Address size: %ld bits\n", query.AddrFieldSize); /* 48 for Ethernet MAC */
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Writing a SANA-II Driver
|
||||
|
||||
A SANA-II driver is a standard exec.device that implements the SANA-II command set. Key requirements:
|
||||
|
||||
| Requirement | Detail |
|
||||
|---|---|
|
||||
| Must be an exec.device | Standard `Open/Close/BeginIO/AbortIO` entry points |
|
||||
| Buffer management | Must use the caller's buffer hooks — never copy directly |
|
||||
| Multiple openers | Must support multiple tasks opening the device simultaneously |
|
||||
| Promiscuous mode | Should support `S2_ONEVENT` for link-level monitoring |
|
||||
| Error reporting | Must set both `io_Error` and `ios2_WireError` |
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- SANA-II Network Device Driver Specification (Commodore)
|
||||
- SANA-II Network Device Driver Specification (Commodore, 1992)
|
||||
- NDK39: `devices/sana2.h`
|
||||
- Aminet: `docs/hard/sana2.lha` — specification document
|
||||
- See also: [tcp_ip_stacks.md](tcp_ip_stacks.md) — stack architecture
|
||||
- See also: [bsdsocket.md](bsdsocket.md) — socket API above SANA-II
|
||||
|
|
|
|||
|
|
@ -1,66 +1,426 @@
|
|||
[← Home](../README.md) · [Networking](README.md)
|
||||
|
||||
# TCP/IP Stacks — AmiTCP, Miami, Roadshow
|
||||
# TCP/IP Stacks — Architecture, Integration, and Configuration
|
||||
|
||||
## Overview
|
||||
|
||||
AmigaOS has no built-in TCP/IP stack. Third-party stacks provide `bsdsocket.library`. All stacks present the same API to applications — only configuration and driver support differ.
|
||||
AmigaOS has **no built-in TCP/IP stack** — networking is entirely provided by third-party software that installs as an Amiga shared library (`bsdsocket.library`). This is fundamentally different from every other major OS where TCP/IP is a kernel subsystem.
|
||||
|
||||
---
|
||||
|
||||
## Stack Comparison
|
||||
## Architecture — How Amiga TCP/IP Differs
|
||||
|
||||
| Feature | AmiTCP 3.0b2 | Miami 3.2 | Roadshow 1.15 |
|
||||
|---|---|---|---|
|
||||
| License | Free (Genesis fork) | Commercial | Commercial (demo available) |
|
||||
| API version | bsdsocket.library v3 | v4 | v4 |
|
||||
| IPv6 | No | No | No |
|
||||
| PPP | Via serial | Built-in | Via driver |
|
||||
| DHCP | External (dhclient) | Built-in | Built-in |
|
||||
| DNS cache | No | Yes | Yes |
|
||||
| SANA-II | Yes | Yes | Yes |
|
||||
| GUI config | MUI prefs | Miami prefs | Roadshow prefs |
|
||||
| Active development | No | No | Yes (Olaf Barthel) |
|
||||
| MiSTer recommended | ✅ (free) | — | ✅ (most capable) |
|
||||
### The Library Model vs. Kernel Sockets
|
||||
|
||||
---
|
||||
```mermaid
|
||||
flowchart TD
|
||||
subgraph "Unix / Windows / macOS"
|
||||
UAPP["Application"] -->|"syscall boundary<br/>(kernel trap)"| KERN["Kernel TCP/IP Stack"]
|
||||
KERN --> KDRV["Kernel NIC Driver"]
|
||||
KDRV --> HW1["Network Hardware"]
|
||||
end
|
||||
|
||||
## Configuration (Roadshow)
|
||||
subgraph "AmigaOS"
|
||||
AAPP["Application"] -->|"Library call<br/>(JSR through LVO)"| BSL["bsdsocket.library<br/>(user-space process)"]
|
||||
BSL -->|"SANA-II IORequests"| SANA["SANA-II Driver<br/>(exec device)"]
|
||||
SANA --> HW2["Network Hardware"]
|
||||
end
|
||||
|
||||
```
|
||||
; DEVS:NetInterfaces/prism2
|
||||
DEVICE=prism2.device
|
||||
UNIT=0
|
||||
IPTYPE=DHCP
|
||||
; or:
|
||||
; ADDRESS=192.168.1.100
|
||||
; NETMASK=255.255.255.0
|
||||
; GATEWAY=192.168.1.1
|
||||
|
||||
; DEVS:NetInterfaces/lo0
|
||||
DEVICE=lo0.device
|
||||
UNIT=0
|
||||
ADDRESS=127.0.0.1
|
||||
NETMASK=255.0.0.0
|
||||
style KERN fill:#ffcdd2,stroke:#c62828,color:#333
|
||||
style BSL fill:#c8e6c9,stroke:#2e7d32,color:#333
|
||||
```
|
||||
|
||||
| Aspect | Unix/Linux/Windows | AmigaOS |
|
||||
|---|---|---|
|
||||
| **Stack location** | Kernel (ring 0) | User-space process (same address space) |
|
||||
| **Socket API** | System calls (trap to kernel) | Library vector calls (JSR) — no context switch |
|
||||
| **Driver model** | Kernel module / NDIS | SANA-II exec.device (user-space) |
|
||||
| **Multiple stacks** | One per kernel | Multiple possible (only one active) |
|
||||
| **Per-process state** | fd table in kernel | Socket "library base" per opener |
|
||||
| **Protection** | Full memory protection | None — any process can corrupt stack state |
|
||||
| **Signal integration** | select/poll/epoll | WaitSelect + Exec signal bits |
|
||||
| **Performance** | Optimised kernel path | No syscall overhead, but no DMA offload |
|
||||
|
||||
### The Full Network Stack
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
subgraph "Applications"
|
||||
IBR["IBrowse<br/>(HTTP)"]
|
||||
FTP["AmiFTP<br/>(FTP)"]
|
||||
IRC["AmiRC<br/>(IRC)"]
|
||||
PING["ping<br/>(ICMP)"]
|
||||
end
|
||||
|
||||
subgraph "bsdsocket.library"
|
||||
SOCK["Socket Layer<br/>(socket, bind, connect,<br/>send, recv, select)"]
|
||||
TCP["TCP"]
|
||||
UDP["UDP"]
|
||||
ICMP["ICMP"]
|
||||
IP["IP Layer<br/>(routing, fragmentation)"]
|
||||
ARP["ARP<br/>(address resolution)"]
|
||||
end
|
||||
|
||||
subgraph "Link Layer"
|
||||
SANA2["SANA-II Interface<br/>(standardised IORequest API)"]
|
||||
end
|
||||
|
||||
subgraph "Hardware Drivers"
|
||||
ETH["Ethernet Driver<br/>(e.g., ariadne.device)"]
|
||||
PPP["PPP Driver<br/>(e.g., ppp.device)"]
|
||||
SLIP["SLIP Driver"]
|
||||
LO["Loopback<br/>(lo0.device)"]
|
||||
end
|
||||
|
||||
subgraph "Physical"
|
||||
NIC["Ethernet NIC<br/>(Zorro/PCMCIA)"]
|
||||
MODEM["Serial Modem<br/>(via serial.device)"]
|
||||
LOOP["Internal loopback"]
|
||||
end
|
||||
|
||||
IBR --> SOCK
|
||||
FTP --> SOCK
|
||||
IRC --> SOCK
|
||||
PING --> SOCK
|
||||
|
||||
SOCK --> TCP --> IP
|
||||
SOCK --> UDP --> IP
|
||||
SOCK --> ICMP --> IP
|
||||
IP --> ARP --> SANA2
|
||||
IP --> SANA2
|
||||
|
||||
SANA2 --> ETH --> NIC
|
||||
SANA2 --> PPP --> MODEM
|
||||
SANA2 --> SLIP --> MODEM
|
||||
SANA2 --> LO --> LOOP
|
||||
|
||||
style SOCK fill:#e8f4fd,stroke:#2196f3,color:#333
|
||||
style SANA2 fill:#fff9c4,stroke:#f9a825,color:#333
|
||||
style IP fill:#c8e6c9,stroke:#2e7d32,color:#333
|
||||
```
|
||||
|
||||
### Per-Opener Library Base
|
||||
|
||||
Each Amiga task that opens `bsdsocket.library` gets its own **private library base** with isolated socket state — there is no kernel fd table. This means `SocketBase` must **never** be shared between tasks. See [bsdsocket.md](bsdsocket.md) for the full API reference and per-task setup pattern.
|
||||
|
||||
---
|
||||
|
||||
## Configuration (AmiTCP)
|
||||
## SANA-II — The Network Driver Layer
|
||||
|
||||
SANA-II (Standard Amiga Networking Architecture, version II) is the standardised interface between TCP/IP stacks and network hardware drivers. It's an `exec.device` protocol — drivers communicate via IORequests.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph "TCP/IP Stack"
|
||||
IP["IP Layer"]
|
||||
end
|
||||
|
||||
subgraph "SANA-II API"
|
||||
direction TB
|
||||
OPEN["OpenDevice<br/>(driver, unit)"]
|
||||
WRITE["CMD_WRITE<br/>(send frame)"]
|
||||
READ["CMD_READ<br/>(receive frame)"]
|
||||
ONLINE["S2_ONLINE<br/>(bring up link)"]
|
||||
CONFIG["S2_CONFIGINTERFACE<br/>(set HW address)"]
|
||||
QUERY["S2_DEVICEQUERY<br/>(get capabilities)"]
|
||||
end
|
||||
|
||||
subgraph "Drivers"
|
||||
A2065["a2065.device<br/>(Commodore Ethernet)"]
|
||||
ARIADNE["ariadne.device<br/>(Village Tronic)"]
|
||||
CNET["cnet.device<br/>(Hydra/X-Surf)"]
|
||||
PPPDEV["ppp.device<br/>(dial-up modem)"]
|
||||
end
|
||||
|
||||
IP --> OPEN
|
||||
IP --> WRITE
|
||||
IP --> READ
|
||||
OPEN --> A2065
|
||||
OPEN --> ARIADNE
|
||||
OPEN --> CNET
|
||||
OPEN --> PPPDEV
|
||||
|
||||
style OPEN fill:#e8f4fd,stroke:#2196f3,color:#333
|
||||
```
|
||||
|
||||
### How the Stack Sends a Packet
|
||||
|
||||
1. Application calls `send(sock, data, len, 0)`
|
||||
2. TCP/IP stack builds TCP segment + IP header
|
||||
3. ARP resolves destination MAC address (or uses cached entry)
|
||||
4. Stack fills a `struct IOSana2Req` with the complete Ethernet frame
|
||||
5. `DoIO` / `SendIO` to the SANA-II driver
|
||||
6. Driver writes frame to hardware registers / DMA buffer
|
||||
|
||||
### How the Stack Receives a Packet
|
||||
|
||||
1. Stack posts **read requests** (`CMD_READ`) to the SANA-II driver (kept outstanding)
|
||||
2. When a frame arrives, the driver completes the IORequest
|
||||
3. Stack parses the Ethernet frame → IP → TCP/UDP → delivers to socket buffer
|
||||
4. Application's `recv()` or `WaitSelect()` returns the data
|
||||
5. Stack immediately posts a new `CMD_READ` to keep the pipeline full
|
||||
|
||||
---
|
||||
|
||||
## Dial-Up Networking — PPP and SLIP
|
||||
|
||||
Before broadband, most Amiga internet connections were via **serial modem** using PPP or SLIP over `serial.device`:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph "Amiga"
|
||||
BSL2["bsdsocket.library"] --> PPP2["PPP/SLIP Driver"]
|
||||
PPP2 --> SER["serial.device<br/>(CIA UART)"]
|
||||
end
|
||||
|
||||
SER -->|"RS-232<br/>up to 115200 baud"| MODEM["External Modem<br/>(AT commands)"]
|
||||
MODEM -->|"Phone line<br/>V.34/V.90"| ISP["ISP<br/>PPP Server"]
|
||||
|
||||
style PPP2 fill:#fff9c4,stroke:#f9a825,color:#333
|
||||
style MODEM fill:#ffcdd2,stroke:#c62828,color:#333
|
||||
```
|
||||
|
||||
### PPP Connection Sequence
|
||||
|
||||
```
|
||||
1. Modem initialisation:
|
||||
→ ATZ (reset modem)
|
||||
← OK
|
||||
→ AT&F1 (factory defaults, hardware flow control)
|
||||
← OK
|
||||
|
||||
2. Dial ISP:
|
||||
→ ATDT 555-1234 (tone dial)
|
||||
← CONNECT 33600 (connected at 33.6 kbps)
|
||||
|
||||
3. PPP negotiation (automatic):
|
||||
← LCP Configure-Request
|
||||
→ LCP Configure-Ack
|
||||
→ LCP Configure-Request
|
||||
← LCP Configure-Ack
|
||||
→ PAP Authenticate (username/password)
|
||||
← PAP Authenticate-Ack
|
||||
→ IPCP Configure-Request
|
||||
← IPCP Configure-Ack (IP=203.0.113.42, DNS=203.0.113.1)
|
||||
|
||||
4. Link up — IP traffic flows over PPP frames on serial line
|
||||
```
|
||||
|
||||
### PPP Configuration (Miami)
|
||||
|
||||
Miami had the most user-friendly dial-up setup:
|
||||
|
||||
| Setting | Value | Notes |
|
||||
|---|---|---|
|
||||
| Serial device | `serial.device` | Or `duart.device` for A2232 multi-port |
|
||||
| Unit | 0 | |
|
||||
| Baud rate | 57600 or 115200 | Must match modem's DTE rate |
|
||||
| Flow control | RTS/CTS (hardware) | **Required** — XON/XOFF causes corruption |
|
||||
| Init string | `ATZ` then `AT&F1` | Hardware flow control defaults |
|
||||
| Dial command | `ATDT <number>` | |
|
||||
| Login | PAP or script-based | |
|
||||
| VJ compression | Yes | Van Jacobson TCP header compression |
|
||||
|
||||
### PPP Configuration (AmiTCP)
|
||||
|
||||
```
|
||||
; AmiTCP:db/interfaces
|
||||
prism2 DEV=DEVS:Networks/prism2.device UNIT=0 IP=DHCP
|
||||
ppp0 DEV=DEVS:Networks/ppp.device UNIT=0
|
||||
|
||||
; AmiTCP:bin/startnet script must:
|
||||
; 1. Open serial port
|
||||
; 2. Send modem commands
|
||||
; 3. Wait for CONNECT
|
||||
; 4. Hand off to PPP
|
||||
```
|
||||
|
||||
### SLIP (Serial Line IP)
|
||||
|
||||
SLIP is the simpler, older protocol — no authentication, no compression, no error detection:
|
||||
|
||||
```
|
||||
; AmiTCP:db/interfaces
|
||||
sl0 DEV=DEVS:Networks/slip.device UNIT=0
|
||||
|
||||
; SLIP frames:
|
||||
; Each IP packet is framed with END bytes (0xC0)
|
||||
; ESC (0xDB) used to escape END and ESC within data
|
||||
```
|
||||
|
||||
| Feature | SLIP | PPP |
|
||||
|---|---|---|
|
||||
| Authentication | None | PAP, CHAP |
|
||||
| IP negotiation | Manual (both sides must know IPs) | Automatic (IPCP) |
|
||||
| Compression | None | VJ header compression |
|
||||
| Error detection | None | FCS (frame check) |
|
||||
| Multi-protocol | IP only | IP, IPX, AppleTalk |
|
||||
|
||||
---
|
||||
|
||||
## Stack Comparison (Detailed)
|
||||
|
||||
| Feature | AmiTCP 3.0b2 / Genesis | Miami 3.2 | Roadshow 1.15 |
|
||||
|---|---|---|---|
|
||||
| **License** | Free (Genesis fork) | Commercial ($30) | Commercial (demo: 5-min limit) |
|
||||
| **API version** | bsdsocket.library v3 | v4 | v4 |
|
||||
| **Based on** | NetBSD TCP/IP stack | Custom implementation | Custom implementation |
|
||||
| **IPv6** | No | No | No |
|
||||
| **PPP** | External (AmiPPP) | Built-in dialer + PPP | Via SANA-II PPP driver |
|
||||
| **SLIP** | Yes | Yes | Via SANA-II SLIP driver |
|
||||
| **DHCP** | External (dhclient) | Built-in | Built-in |
|
||||
| **DNS cache** | No | Yes | Yes |
|
||||
| **DNS over TCP** | No | Yes | Yes |
|
||||
| **Multi-homing** | Limited | Yes | Yes (multiple interfaces) |
|
||||
| **SANA-II v2** | Yes | Yes | Yes |
|
||||
| **GUI config** | Genesis MUI prefs | Miami prefs GUI | Roadshow prefs editor |
|
||||
| **CLI config** | `ifconfig`, `route` | Via GUI only | Text file + CLI tools |
|
||||
| **Syslog** | Yes | Yes | Yes |
|
||||
| **Active development** | No (last: ~2002) | No (last: ~2003) | Yes (Olaf Barthel, ongoing) |
|
||||
| **Stability** | Good | Good | Excellent |
|
||||
| **MiSTer notes** | ✅ Free, easy to set up | ❌ Requires registration | ✅ Most capable, demo limit |
|
||||
|
||||
### Which Stack for MiSTer?
|
||||
|
||||
- **AmiTCP / Genesis**: Free, works well for basic networking. Use `Genesis.lha` from Aminet.
|
||||
- **Roadshow**: Most capable and actively maintained. Demo works for 5 minutes at a time — sufficient for testing. Full license recommended for permanent setups.
|
||||
|
||||
---
|
||||
|
||||
## Ethernet Cards (SANA-II Hardware)
|
||||
|
||||
| Card | Device | Bus | Chipset | Speed |
|
||||
|---|---|---|---|---|
|
||||
| Commodore A2065 | `a2065.device` | Zorro II | AMD LANCE | 10 Mbps |
|
||||
| Village Tronic Ariadne | `ariadne.device` | Zorro II | AMD PCnet | 10 Mbps |
|
||||
| Village Tronic Ariadne II | `ariadne2.device` | Zorro II | SMC 91C94 | 10 Mbps |
|
||||
| Hydra Systems Amiganet | `amiganet.device` | Zorro II | AMD LANCE | 10 Mbps |
|
||||
| X-Surf | `xsurf.device` | Clock port | RTL8019AS | 10 Mbps |
|
||||
| X-Surf 100 | `xsurf100.device` | Zorro II/III | AX88796B | 100 Mbps |
|
||||
| PCMCIA Ethernet | `cnet.device` | PCMCIA (A600/A1200) | Various | 10 Mbps |
|
||||
|
||||
### MiSTer Virtual NIC
|
||||
|
||||
MiSTer emulates a network interface that bridges to the Linux HPS network:
|
||||
|
||||
```
|
||||
; DEVS:NetInterfaces/mister0 (Roadshow)
|
||||
DEVICE=mister_eth.device
|
||||
UNIT=0
|
||||
IPTYPE=DHCP
|
||||
MTU=1500
|
||||
```
|
||||
|
||||
The virtual driver presents a standard SANA-II interface — the TCP/IP stack sees no difference from a real Ethernet card.
|
||||
|
||||
---
|
||||
|
||||
## Configuration — Roadshow
|
||||
|
||||
### Network Interface
|
||||
|
||||
```
|
||||
; DEVS:NetInterfaces/eth0
|
||||
DEVICE=ariadne.device ; or your card's device name
|
||||
UNIT=0
|
||||
IPTYPE=DHCP ; or STATIC for manual
|
||||
|
||||
; Static configuration:
|
||||
; ADDRESS=192.168.1.100
|
||||
; NETMASK=255.255.255.0
|
||||
```
|
||||
|
||||
### Name Resolution
|
||||
|
||||
```
|
||||
; DEVS:Internet/name_resolution
|
||||
NAMESERVER 8.8.8.8
|
||||
NAMESERVER 8.8.4.4
|
||||
DOMAIN local
|
||||
SEARCH local
|
||||
```
|
||||
|
||||
### Default Gateway
|
||||
|
||||
```
|
||||
; DEVS:Internet/default_gateway
|
||||
DEVICE=ariadne.device
|
||||
UNIT=0
|
||||
GATEWAY=192.168.1.1
|
||||
```
|
||||
|
||||
### Startup
|
||||
|
||||
```
|
||||
; S:User-Startup
|
||||
Run >NIL: C:AddNetInterface eth0
|
||||
WaitForPort AMITCP
|
||||
; Stack is now ready
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration — AmiTCP / Genesis
|
||||
|
||||
### Interface Configuration
|
||||
|
||||
```
|
||||
; AmiTCP:db/interfaces
|
||||
eth0 DEV=DEVS:Networks/ariadne.device UNIT=0 IP=DHCP
|
||||
|
||||
; Static:
|
||||
; eth0 DEV=DEVS:Networks/ariadne.device UNIT=0 IP=192.168.1.100 NETMASK=255.255.255.0
|
||||
```
|
||||
|
||||
### DNS and Hosts
|
||||
|
||||
```
|
||||
; AmiTCP:db/netdb-myhost
|
||||
HOST 127.0.0.1 localhost
|
||||
HOST 192.168.1.1 gateway
|
||||
NAMESERVER 8.8.8.8
|
||||
DOMAIN local
|
||||
```
|
||||
|
||||
### Startup
|
||||
|
||||
```
|
||||
; S:User-Startup
|
||||
Run >NIL: AmiTCP:AmiTCP
|
||||
WaitForPort AMITCP
|
||||
; bsdsocket.library is now available
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Verifying the Network
|
||||
|
||||
```
|
||||
; CLI commands (provided by the stack):
|
||||
ifconfig ; show interface configuration
|
||||
netstat -r ; show routing table
|
||||
netstat -a ; show active connections
|
||||
ping 8.8.8.8 ; test connectivity
|
||||
nslookup amiga.org ; test DNS resolution
|
||||
traceroute 8.8.8.8 ; trace route to destination
|
||||
```
|
||||
|
||||
```c
|
||||
/* Programmatic check: */
|
||||
struct Library *SocketBase = OpenLibrary("bsdsocket.library", 4);
|
||||
if (!SocketBase)
|
||||
Printf("No TCP/IP stack running — start AmiTCP or Roadshow\n");
|
||||
else
|
||||
CloseLibrary(SocketBase);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- Roadshow SDK: http://roadshow.apc-tcp.de/
|
||||
- AmiTCP SDK: Aminet `comm/tcp/AmiTCP-SDK-4.3.lha`
|
||||
- Genesis (free AmiTCP fork): Aminet `comm/tcp/Genesis.lha`
|
||||
- SANA-II specification: Aminet `docs/hard/sana2.lha`
|
||||
- See also: [bsdsocket.md](bsdsocket.md) — socket API reference
|
||||
- See also: [sana2.md](sana2.md) — SANA-II driver specification
|
||||
- See also: [protocols.md](protocols.md) — DNS, HTTP, UDP implementation examples
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue