aboutsummaryrefslogtreecommitdiffstats
path: root/tools/gateway.py
diff options
context:
space:
mode:
authoruser <user@clank>2026-07-17 02:05:26 +0200
committeruser <user@clank>2026-07-17 02:05:26 +0200
commited752bba5a5d06275531182245737600bf1f72e9 (patch)
treeba250a89b079403c55119cd33ce56ec6d2d562ed /tools/gateway.py
parentnet: real IP stack, milestone A - ICMP echo (you can ping a Game Boy) (diff)
downloadgbos-ed752bba5a5d06275531182245737600bf1f72e9.tar.gz
gbos-ed752bba5a5d06275531182245737600bf1f72e9.tar.xz
gbos-ed752bba5a5d06275531182245737600bf1f72e9.zip
net: IP stack milestone B - UDP echo (pseudo-header checksum)
Refactor netd into a protocol dispatcher (IP -> ICMP/UDP) and add UDP echo: swap addresses + ports and recompute the UDP checksum over the pseudo-header (src/dst IP + proto + length) plus the datagram. This is the same pseudo- header TCP uses, so it de-risks the next milestone. tools/gateway.py --mode udp sends a datagram and verifies the echo. Verified: 'hello udp gbos' echoes back with cksum=ok.
Diffstat (limited to 'tools/gateway.py')
-rw-r--r--tools/gateway.py28
1 files changed, 27 insertions, 1 deletions
diff --git a/tools/gateway.py b/tools/gateway.py
index 590526e..f5fc701 100644
--- a/tools/gateway.py
+++ b/tools/gateway.py
@@ -126,9 +126,19 @@ def icmp_echo(seq, payload=b"gbos-ping-0123456789"):
ip = ip[:10] + struct.pack("!H", inet_cksum(ip)) + ip[12:]
return ip + icmp
+def udp_packet(sport, dport, payload):
+ ulen = 8 + len(payload)
+ udp = struct.pack("!HHHH", sport, dport, ulen, 0) + payload
+ pseudo = GW_IP + GB_IP + bytes([0, 17]) + struct.pack("!H", ulen)
+ ck = inet_cksum(pseudo + udp) or 0xffff
+ udp = udp[:6] + struct.pack("!H", ck) + udp[8:]
+ ip = struct.pack("!BBHHHBBH", 0x45, 0, 20+ulen, 7, 0, 64, 17, 0) + GW_IP + GB_IP
+ ip = ip[:10] + struct.pack("!H", inet_cksum(ip)) + ip[12:]
+ return ip + udp
+
def main():
ap = argparse.ArgumentParser()
- ap.add_argument("--mode", default="echo", choices=["echo", "http", "chat", "irc", "ping"])
+ ap.add_argument("--mode", default="echo", choices=["echo", "http", "chat", "irc", "ping", "udp"])
ap.add_argument("--cmd", default="necho")
ap.add_argument("--nick", default="gameboy")
ap.add_argument("--channel", default="#sl0p")
@@ -159,6 +169,17 @@ def main():
m = bytes(payload).decode("latin1", "replace")
sys.stderr.write("\n[gw] GB says: %s\n" % m)
return [("<bot> " + m).encode()]
+ elif a.mode == "udp":
+ def on_frame(payload):
+ p = bytes(payload)
+ if len(p) >= 28 and p[9] == 17:
+ ihl = (p[0] & 0x0f) * 4
+ sport, dport, ulen = struct.unpack("!HHH", p[ihl:ihl+6])
+ data = p[ihl+8:ihl+8+ulen-8]
+ ck_ok = inet_cksum(GB_IP + GW_IP + bytes([0,17]) + p[ihl+4:ihl+6] + p[ihl:]) == 0
+ sys.stderr.write("\n[gw] UDP echo %d->%d: %r cksum=%s\n"
+ % (sport, dport, data, "ok" if ck_ok else "BAD"))
+ return []
elif a.mode == "ping":
def on_frame(payload):
p = bytes(payload)
@@ -183,6 +204,11 @@ def main():
except Exception: pass
irc_holder[0] = IRC(a.host, a.port, a.nick, a.channel, to_gb)
threading.Thread(target=irc_holder[0].loop, daemon=True).start()
+ if a.mode == "udp":
+ time.sleep(1.0)
+ p.stdin.write(slip_encode(udp_packet(5000, 7, b"hello udp gbos"))); p.stdin.flush()
+ sys.stderr.write("[gw] sent UDP :5000->:7 'hello udp gbos'\n")
+ time.sleep(2.0)
if a.mode == "ping":
time.sleep(1.0)
for seq in range(1, 5):