aboutsummaryrefslogtreecommitdiffstats
path: root/c/dhcp.c
diff options
context:
space:
mode:
authoruser <user@clank>2026-07-17 14:11:22 +0200
committeruser <user@clank>2026-07-17 14:11:22 +0200
commita2cb756693229c7880d926d2cdde2f838c697415 (patch)
treee327278e7d8b7150d7a2b01cf38b4895caab7356 /c/dhcp.c
parentkernel: sys_sleep - a cooperative delay off the DIV timer (+ ping pacing) (diff)
downloadgbos-a2cb756693229c7880d926d2cdde2f838c697415.tar.gz
gbos-a2cb756693229c7880d926d2cdde2f838c697415.tar.xz
gbos-a2cb756693229c7880d926d2cdde2f838c697415.zip
net: DHCP client - lease the IP at boot instead of hardcoding it
The address is no longer baked in. net_init starts at 0.0.0.0; a DHCP client runs as the first thing on boot (init/shell forks it and waits), and only once it has a lease (or gives up) does the prompt appear. Kernel: - IP is configurable: 0.0.0.0 until leased; NET_SETIP op stores it. - 16-bit frame length. DHCP/BOOTP packets are ~272 bytes, over the old 255-byte frame cap, so net_slip_send takes a 16-bit length, net_pump assembles into a 320-byte buffer with a 16-bit wNetRxLen, and udp_send writes a 16-bit IP total. Payloads stay <=255 (kept small on purpose) so the per-protocol datalen math is unchanged. wNetTx/wNetRxBuf 256->320, SK_RXBUF 208->288. Userland: - c/dhcp.c: DISCOVER->OFFER->REQUEST->ACK over a UDP socket, then net_setip(); times out gracefully (shell still boots) if there's no server. sh.c runs it before the prompt. Bridge (self-contained DHCP server, no dnsmasq): - tunbridge.py + netboot intercept UDP->:67 and answer OFFER/ACK leasing 10.0.0.2 (gateway 10.0.0.1); everything else is bridged/NATed as before. Regression-tested ICMP/UDP/TCP after the 16-bit change. Verified end to end: dhcp: discovering dhcp: leased 10.0.0.2 /# ping 10.0.0.1 -> 4/4 (traffic from the leased address)
Diffstat (limited to 'c/dhcp.c')
-rw-r--r--c/dhcp.c72
1 files changed, 72 insertions, 0 deletions
diff --git a/c/dhcp.c b/c/dhcp.c
new file mode 100644
index 0000000..e4186f4
--- /dev/null
+++ b/c/dhcp.c
@@ -0,0 +1,72 @@
+#include "sock.h"
+/* dhcp - a minimal DHCP client. DISCOVER -> OFFER -> REQUEST -> ACK over UDP
+ (kernel owns UDP; this owns BOOTP/DHCP), then hands the leased address to the
+ kernel with net_setip(). Run at boot before the shell. Times out gracefully
+ if there's no server (the shell then comes up unconfigured). */
+
+static unsigned char pkt[288]; /* BOOTP is ~240B + options (frames > 255) */
+static unsigned char ip[4];
+static unsigned char bcast[4];
+
+/* fill the fixed BOOTP request header + magic cookie; options start at 240 */
+static void bootp(void) {
+ unsigned int i;
+ for (i = 0; i < 240; i++) pkt[i] = 0;
+ pkt[0] = 1; pkt[1] = 1; pkt[2] = 6; /* op=request htype=eth hlen=6 */
+ pkt[4] = 0x12; pkt[5] = 0x34; pkt[6] = 0x56; pkt[7] = 0x78; /* xid */
+ pkt[10] = 0x80; /* flags: broadcast reply */
+ pkt[28] = 0x02; pkt[29] = 0x47; pkt[30] = 0x42; pkt[33] = 0x01; /* client MAC */
+ pkt[236] = 0x63; pkt[237] = 0x82; pkt[238] = 0x53; pkt[239] = 0x63; /* magic */
+}
+
+/* DHCP message type from the received packet (option 53), or 0 */
+static unsigned char mtype(void) {
+ unsigned int p = 240;
+ while (p < 280 && pkt[p] != 255) {
+ if (pkt[p] == 0) { p++; continue; } /* pad */
+ if (pkt[p] == 53) return pkt[p + 2];
+ p += 2 + pkt[p + 1];
+ }
+ return 0;
+}
+
+void main(void) {
+ unsigned char s, i, n;
+ unsigned int p;
+ bcast[0] = 255; bcast[1] = 255; bcast[2] = 255; bcast[3] = 255;
+
+ puts("dhcp: discovering"); nl();
+ s = net_socket(SOCK_UDP);
+ if (s == 0xFF) { puts("dhcp: no socket"); nl(); return; }
+ net_bind(s, 68);
+ net_connect(s, bcast, 67);
+
+ /* DISCOVER -> OFFER (retry a few times for startup timing) */
+ bootp();
+ p = 240;
+ pkt[p++] = 53; pkt[p++] = 1; pkt[p++] = 1; /* DHCPDISCOVER */
+ pkt[p++] = 255;
+ n = 0xFF;
+ for (i = 0; i < 3 && n == 0xFF; i++) {
+ net_send(s, pkt, (unsigned char)p);
+ n = net_recv(s, pkt, 255);
+ }
+ if (n == 0xFF || mtype() != 2) { puts("dhcp: no offer"); nl(); net_close(s); return; }
+ ip[0] = pkt[16]; ip[1] = pkt[17]; ip[2] = pkt[18]; ip[3] = pkt[19]; /* yiaddr */
+
+ /* REQUEST -> ACK */
+ bootp();
+ p = 240;
+ pkt[p++] = 53; pkt[p++] = 1; pkt[p++] = 3; /* DHCPREQUEST */
+ pkt[p++] = 50; pkt[p++] = 4; /* requested IP */
+ pkt[p++] = ip[0]; pkt[p++] = ip[1]; pkt[p++] = ip[2]; pkt[p++] = ip[3];
+ pkt[p++] = 255;
+ net_send(s, pkt, (unsigned char)p);
+ n = net_recv(s, pkt, 255);
+ net_close(s);
+ if (n == 0xFF || mtype() != 5) { puts("dhcp: request failed"); nl(); return; }
+ ip[0] = pkt[16]; ip[1] = pkt[17]; ip[2] = pkt[18]; ip[3] = pkt[19];
+
+ net_setip(ip);
+ puts("dhcp: leased "); for (i = 0; i < 4; i++) { putu(ip[i]); if (i < 3) putc('.'); } nl();
+}