diff options
| author | user <user@clank> | 2026-07-17 12:39:01 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-07-17 12:39:01 +0200 |
| commit | 09ae37313a8b6d567a05a3ae886de78e88cd1afe (patch) | |
| tree | 8d4707fbd2c6c7fec56a1c9c31abbd9dc66cf7bb /c/sock.h | |
| parent | net: ping - GB-originated ICMP echo (a Game Boy pings the real internet) (diff) | |
| download | gbos-09ae37313a8b6d567a05a3ae886de78e88cd1afe.tar.gz gbos-09ae37313a8b6d567a05a3ae886de78e88cd1afe.tar.xz gbos-09ae37313a8b6d567a05a3ae886de78e88cd1afe.zip | |
net: proper socket API in the kernel (SYS_NET) - no more SLIP in userland
The network stack moves into the kernel. src/socket.asm owns SLIP framing,
IPv4, RFC1071 checksums, and ICMP; programs now speak a socket API through one
syscall (SYS_NET, DE=&netreq dispatched by op): net_socket/connect/send/recv/
close/poll (c/sock.h). No program touches SLIP, IP headers, or checksums.
- Socket table (4 sockets) + tx/rx buffers in WRAM0; our IP = 10.0.0.2.
- net_pump: drains the link, reassembles SLIP frames, demuxes IPv4. Inbound
ICMP echo requests are auto-answered in-kernel, so the GB replies to pings
whenever any process pumps RX.
- ICMP sockets: send() emits an echo request to the connected peer; recv()
returns the matching reply (with a spin/yield timeout).
ping.c is now a ~15-line socket client; netd.c is just `for(;;){net_poll();
yield();}`. Verified over tunbridge:
/# ping 1.1.1.1 -> replies from the real internet (kernel builds it all)
host# ping 10.0.0.2 -> 4/4, 0% loss (kernel auto-answers)
Gotchas recorded: gbos.inc isn't a make dep (touch asm after editing); this
crt0 doesn't copy initializers (fill arrays at runtime); and the arg string at
0xA000 overlaps _DATA, so parse targets must sit past it (big buffer first).
UDP and TCP sockets build on this same core next.
Diffstat (limited to 'c/sock.h')
| -rw-r--r-- | c/sock.h | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/c/sock.h b/c/sock.h new file mode 100644 index 0000000..9af2351 --- /dev/null +++ b/c/sock.h @@ -0,0 +1,52 @@ +#ifndef SOCK_H +#define SOCK_H +/* gbos socket API - the kernel owns SLIP/IP/ICMP/UDP/TCP; programs just do + socket()/connect()/send()/recv()/close(). Header-only: one copy per program. + The netreq layout must match include/gbos.inc (NR_* / NET_* / SOCK_*). */ +#include "gbos.h" + +#define SOCK_ICMP 1 +#define SOCK_UDP 2 +#define SOCK_TCP 3 + +struct netreq { + unsigned char op; + unsigned char sock; + unsigned char *buf; + unsigned char len; + unsigned char ip[4]; + unsigned char port_hi, port_lo; +}; +static struct netreq _nr; + +/* -> socket id, or 0xFF if the table is full */ +static unsigned char net_socket(unsigned char type) { + _nr.op = 0; _nr.sock = type; + return sys_net(&_nr); +} +/* set the remote address/port for send()/recv() */ +static unsigned char net_connect(unsigned char s, const unsigned char *ip, unsigned int port) { + unsigned char i; + _nr.op = 1; _nr.sock = s; + for (i = 0; i < 4; i++) _nr.ip[i] = ip[i]; + _nr.port_hi = (unsigned char)(port >> 8); _nr.port_lo = (unsigned char)port; + return sys_net(&_nr); +} +/* send 'len' payload bytes to the connected peer -> 0 ok / 0xFF error */ +static unsigned char net_send(unsigned char s, void *buf, unsigned char len) { + _nr.op = 2; _nr.sock = s; _nr.buf = (unsigned char *)buf; _nr.len = len; + return sys_net(&_nr); +} +/* receive up to 'max' payload bytes -> length, or 0xFF on timeout */ +static unsigned char net_recv(unsigned char s, void *buf, unsigned char max) { + _nr.op = 3; _nr.sock = s; _nr.buf = (unsigned char *)buf; _nr.len = max; + return sys_net(&_nr); +} +static void net_close(unsigned char s) { + _nr.op = 4; _nr.sock = s; sys_net(&_nr); +} +/* pump the RX path once (answers inbound pings) without blocking */ +static void net_poll(void) { + _nr.op = 6; sys_net(&_nr); +} +#endif |
