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.
6.2 KiB
SANA-II — Standard Amiga Network Architecture
Overview
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 for how SANA-II fits into the full networking architecture.
flowchart TD
subgraph "TCP/IP Stacks (any)"
AT["AmiTCP"]
RS["Roadshow"]
MI["Miami"]
end
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:
#include <devices/sana2.h>
struct MsgPort *port = CreateMsgPort();
struct IOSana2Req *s2req = (struct IOSana2Req *)
CreateIORequest(port, sizeof(struct IOSana2Req));
/* Buffer management hooks (required): */
static struct TagItem bufferTags[] = {
{ S2_CopyToBuff, (ULONG)MyCopyToBuff },
{ S2_CopyFromBuff, (ULONG)MyCopyFromBuff },
{ TAG_DONE, 0 }
};
s2req->ios2_BufferManagement = bufferTags;
if (OpenDevice("a2065.device", 0, (struct IORequest *)s2req, 0))
{
Printf("Cannot open network device\n");
}
Buffer Management Hooks
/* 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 | 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 |
Sending a Packet
/* 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:
/* Post a read request (non-blocking): */
s2req->ios2_Req.io_Command = CMD_READ;
s2req->ios2_WireError = 0;
s2req->ios2_PacketType = 0x0800; /* only IPv4 packets */
SendIO((struct IORequest *)s2req);
/* Wait for a packet: */
WaitIO((struct IORequest *)s2req);
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
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, 1992)
- NDK39:
devices/sana2.h - Aminet:
docs/hard/sana2.lha— specification document - See also: tcp_ip_stacks.md — stack architecture
- See also: bsdsocket.md — socket API above SANA-II