====== Reine Frame-Builder — eth, ipv4, udp, arp/frame, dhcp/frame ====== Fünf Units, die Netzwerk-Header **nur bauen und lesen** — ohne Sockets, ohne Syscalls, ohne Speicheranforderung. Jede Funktion schreibt in einen Puffer, den der Aufrufer stellt. Genau das macht sie **kernel-tauglich**: Sie haben keine Importe und keine Laufzeitabhängigkeit und lassen sich deshalb im Kernel von LyxOS ebenso verwenden wie in einem gewöhnlichen Linux-Programm. > **''std.net.arp.frame'' und ''std.net.dhcp.frame'' sind eigenständige Kopien, keine Basis der POSIX-Units.** ''[[lyx_-_programmiersprache:units:net:arp|std.net.arp]]'' und ''[[lyx_-_programmiersprache:units:net:dhcp|std.net.dhcp]]'' enthalten dieselben Bau- und Lesefunktionen unter denselben Namen noch einmal und ergänzen das, was Syscalls braucht (ioctl-Abfrage der ARP-Tabelle, UDP-Socket für die Lease). **Beide zusammen zu importieren gibt eine Namenskollision** — man entscheidet sich für eine Seite: die reine Fassung, wenn man die Bytes selbst verschickt oder im Kernel arbeitet, die POSIX-Fassung, wenn man ''ArpResolve'' oder ''DhcpLease'' braucht. ^ Unit ^ Aufgabe ^ | ''std.net.eth'' | Ethernet-II-Rahmen (14 Byte) | | ''std.net.ipv4'' | IPv4-Header (20 Byte) samt Prüfsumme | | ''std.net.udp'' | UDP-Header (8 Byte) | | ''std.net.arp.frame'' | ARP-Rahmen bauen und auswerten (RFC 826) | | ''std.net.dhcp.frame'' | DHCP-Pakete bauen und auswerten (RFC 2131) | → [[lyx_-_programmiersprache:units:net|std.net]] · [[lyx_-_programmiersprache:units:net:arp|std.net.arp]] · [[lyx_-_programmiersprache:units:net:dhcp|std.net.dhcp]] · [[lyx_-_programmiersprache:units|Standard Library]] ---- ===== std.net.eth — Ethernet II ===== ^ Konstante ^ Wert ^ | ''ETH_HDR_SIZE'' | 14 | | ''ETH_P_IP'' | 0x0800 (2048) | | ''ETH_P_ARP'' | 0x0806 (2054) | | ''ETH_P_IPV6'' | 0x86DD (34525) | ^ Signatur ^ Beschreibung ^ | ''EthBuildFrame(buf, dst_mac, src_mac, ethertype): int64'' | Schreibt den 14-Byte-Header; liefert 14. ''dst_mac''/''src_mac'' zeigen auf je 6 Byte | | ''EthBroadcastMac(buf)'' | Füllt 6 Byte mit ''ff:ff:ff:ff:ff:ff'' | | ''EthZeroMac(buf)'' | Füllt 6 Byte mit Nullen | | ''EthCopyMac(dst, src)'' | Kopiert 6 Byte | | ''EthReadType(buf): int64'' | Liest den EtherType (Offset 12, Big Endian) aus einem empfangenen Rahmen | Belegung: Bytes 0–5 Ziel-MAC, 6–11 Quell-MAC, 12–13 EtherType (Big Endian). ---- ===== std.net.ipv4 — IPv4-Header ===== ^ Konstante ^ Wert ^ | ''IPV4_HDR_SIZE'' | 20 | | ''IP_PROTO_ICMP'' / ''TCP'' / ''UDP'' / ''RAW'' | 1 / 6 / 17 / 255 | ^ Signatur ^ Beschreibung ^ | ''IpAddr(a, b, c, d): int64'' | Vier Oktette zu einer gepackten Adresse | | ''IpBroadcast(): int64'' | ''0xFFFFFFFF'' | | ''IpChecksum(hdr): int64'' | 16-Bit-Einerkomplement-Prüfsumme über den Header | | ''IpBuildHeader(buf, src, dst, proto, payload_len): int64'' | Schreibt den 20-Byte-Header samt Prüfsumme; liefert 20 | ---- ===== std.net.udp — UDP-Header ===== ^ Konstante ^ Wert ^ | ''UDP_HDR_SIZE'' | 8 | | ''UDP_PORT_DHCP_SERVER'' / ''CLIENT'' | 67 / 68 | | ''UDP_PORT_DNS'' / ''UDP_PORT_NTP'' | 53 / 123 | ^ Signatur ^ Beschreibung ^ | ''UdpBuildHeader(buf, src_port, dst_port, payload_len): int64'' | Schreibt den 8-Byte-Header; liefert 8. Ports in Wirtsbyte-Reihenfolge | | ''UdpReadSrcPort(buf)'' / ''UdpReadDstPort(buf)'' / ''UdpReadLength(buf)'' | Felder eines empfangenen Segments lesen | > **Die UDP-Prüfsumme wird auf 0 gesetzt, also abgeschaltet.** Über IPv4 ist das nach RFC 768 zulässig, über IPv6 dagegen **nicht** — dort ist die Prüfsumme Pflicht. Diese Unit taugt damit nur für IPv4. ---- ===== std.net.arp.frame — ARP bauen und auswerten ===== Der reine Teil von ''std.net.arp'': Rahmen bauen und einlesen. Wer die ARP-Tabelle des Kernels abfragen will (''SIOCGARP''-ioctl), nimmt ''[[lyx_-_programmiersprache:units:net:arp|std.net.arp]]''. ^ Signatur ^ Beschreibung ^ | ''ArpBuildRequest(buf, srcMac, srcIP, dstIP): int64'' | 42-Byte-Rahmen: „Wem gehört ''dstIP''?" — Eth-Ziel Broadcast, Ziel-MAC im ARP-Teil auf 00:00 | | ''ArpBuildReply(buf, srcMac, srcIP, dstMac, dstIP): int64'' | 42-Byte-Antwortrahmen | | ''ArpParse(buf, len, result): int64'' | Prüft EtherType, ''hlen'' und ''plen'' und schreibt das Ergebnis in einen ''ARP_RESULT_SIZE''-Puffer | ^ Konstantengruppe ^ Inhalt ^ | Frame-Offsets | ''ARP_ETH_DST'' 0, ''ARP_ETH_SRC'' 6, ''ARP_ETH_TYPE'' 12, ''ARP_HRD'' 14, ''ARP_PRO'' 16, ''ARP_HLEN'' 18, ''ARP_PLEN'' 19, ''ARP_OP'' 20, ''ARP_SHA'' 22, ''ARP_SIP'' 28, ''ARP_THA'' 32, ''ARP_TIP'' 38; ''ARP_FRAME_SIZE'' 42 | | Op-Codes | ''ARP_OP_REQUEST'' 1, ''ARP_OP_REPLY'' 2, ''ARP_OP_RREQUEST'' 3, ''ARP_OP_RREPLY'' 4 | | Typen | ''ARP_HTYPE_ETHER'' 1, ''ARP_PROTO_IPV4'' 0x0800 | | Ergebnis-Offsets | ''ARP_RESULT_SENDER_IP'' 0, ''SENDER_MAC'' 8, ''TARGET_IP'' 16, ''TARGET_MAC'' 24, ''OP'' 32, ''OK'' 40; ''ARP_RESULT_SIZE'' 48 | ---- ===== std.net.dhcp.frame — DHCP bauen und auswerten ===== Der reine Teil von ''std.net.dhcp''. Für die vollständige DORA-Sequenz über einen UDP-Socket ''[[lyx_-_programmiersprache:units:net:dhcp|std.net.dhcp]]'' verwenden. ^ Signatur ^ Beschreibung ^ | ''DhcpBuildDiscover(buf, mac, xid): int64'' | DISCOVER-Paket; liefert ''DHCP_MIN_LEN'' | | ''DhcpBuildRequest(buf, mac, xid, offIP, srvIP): int64'' | REQUEST-Paket auf ein Angebot | | ''DhcpParseReply(buf, len, result): int64'' | OFFER/ACK auswerten; NAK setzt das OK-Feld auf 0 | ^ Konstantengruppe ^ Inhalt ^ | Ports | ''DHCP_PORT_SERVER'' 67, ''DHCP_PORT_CLIENT'' 68 | | Nachrichtentypen | ''DHCP_MSG_DISCOVER'' 1 … ''DHCP_MSG_INFORM'' 8 (OFFER 2, REQUEST 3, ACK 5, NAK 6) | | Optionen | ''DHCP_OPT_SUBNET'' 1, ''ROUTER'' 3, ''DNS'' 6, ''HOSTNAME'' 12, ''DOMAIN'' 15, ''REQIP'' 50, ''LEASE'' 51, ''MSGTYPE'' 53, ''SERVERID'' 54, ''PARAMREQ'' 55, ''PAD'' 0, ''END'' 255 | | Feld-Offsets | ''DHCP_OFFS_OP'' 0, ''HTYPE'' 1, ''HLEN'' 2, ''HOPS'' 3, ''XID'' 4, … | ---- ===== Ein Paket von Hand zusammensetzen ===== Die drei Kopf-Units stapeln sich in der Reihenfolge, in der die Bytes auf der Leitung stehen — Ethernet, dann IPv4, dann UDP: import std.net.eth; import std.net.ipv4; import std.net.udp; fn BaueUdpPaket(buf: int64, srcMac: int64, dstMac: int64, nutzlast: int64): int64 { var pos: int64 := EthBuildFrame(buf, dstMac, srcMac, ETH_P_IP); var src: int64 := IpAddr(192, 168, 1, 10); var dst: int64 := IpAddr(192, 168, 1, 1); pos := pos + IpBuildHeader(buf + pos, src, dst, IP_PROTO_UDP, UDP_HDR_SIZE + nutzlast); pos := pos + UdpBuildHeader(buf + pos, 5000, UDP_PORT_DNS, nutzlast); return pos; // 14 + 20 + 8 = 42, danach folgt die Nutzlast } Die IPv4-Prüfsumme setzt ''IpBuildHeader'' selbst — ''IpChecksum'' braucht man nur, wenn man einen Header nachträglich verändert. ---- Letzte Aktualisierung: 2026-08-11