2 Punkte von GN⁺ 2024-11-12 | 1 Kommentare | Auf WhatsApp teilen
  • Als erster Schritt, um auf einem Mikrocontroller selbst einen TCP/IP-Stack aufzubauen, wurde versucht, mit einem STM32F401 Nucleo und einem Wiznet-W5100-Shield Ethernet-Frames zu übertragen
  • Die Hardware-TCP/IP-Funktionen des W5100 wurden nicht genutzt; stattdessen kam nur der MAC-Raw-Modus zum Einsatz, sodass der Chip lediglich die für die Frame-Übertragung nötige Low-Level-Verarbeitung übernimmt
  • Das erste Hindernis entstand dadurch, dass die SPI-Verdrahtung des Arduino Ethernet Shield nicht zum Nucleo passte; nach Prüfung des Routings über den ICSP-Header wurde es durch Modifikationsverdrahtung auf dem Board gelöst
  • Danach führten mutmaßliche Chip-Select-Timing-Probleme, ungewöhnliche MISO-Antworten und Garbage-Pakete in Wireshark dazu, dass ein Logic Analyzer und der Vergleich mit einer Referenzimplementierung zu den zentralen Debugging-Werkzeugen wurden
  • Die eigentliche Ursache war ein Bug in w5100_write16(), der das zweite Byte erneut an dieselbe Adresse schrieb; dank eines selbst geschriebenen Analysetools für SPI-Capture-CSV gelang schließlich die korrekte Paketübertragung

Ausgangspunkt für einen eigenen TCP/IP-Stack

  • Ziel ist der Start der Serie „Networking from scratch“, in der ein TCP/IP-Stack von Grund auf auf einem Mikrocontroller implementiert wird
  • Das sichtbare Ergebnis dieses Schritts ist zwar die erste Ethernet-Paketübertragung, der eigentliche Fokus liegt aber auf der Verfolgung von Bugs zwischen Hardware und Treiber
  • Verwendet wurde ein Nucleo-Entwicklungsboard auf Basis des STM32F401
    • ARM Cortex-M4
    • Betrieb mit bis zu 84 MHz
    • 96 KiB RAM
    • Wurde als ausreichend Speicher eingeschätzt, um mehrere Pakete vorzuhalten

Die Rolle von Ethernet und W5100

  • Ethernet ist nicht nur ein einfacher Port oder ein Frame-Format, sondern eine Familie von Technologien und Standards, die Hardware der physikalischen Schicht, Signalverfahren, Behandlung von Buskollisionen und Frame-Anordnung umfasst
  • Da die Ethernet-Signalverarbeitung komplex ist, übernimmt üblicherweise ein dedizierter ASIC die elektrischen Signale auf dem Kabel und verarbeitet Daten auf Frame-Ebene
  • Für das Projekt wurde ein Arduino Ethernet Shield mit Wiznet-W5100-Chip verwendet
    • Das verwendete Board war ein günstiger Klon, weshalb für den korrekten Betrieb Modifikationen nötig waren
  • Der W5100 ist ein Chip, der in einen Ethernet-ASIC einen Hardware-TCP/IP-Stack integriert
    • Er stellt 4 „Sockets“ bereit
    • Konfigurierbar auf TCP-, UDP-, IP- oder „MAC Raw“-Ebene
  • Da ein eigener TCP/IP-Stack implementiert werden soll, werden die TCP/IP-Funktionen des W5100 nicht genutzt; ein einzelner Socket wird nur im MAC-Raw-Modus verwendet
    • Der Nutzer übergibt einen Ethernet-Frame
    • Der W5100 führt die tatsächliche Übertragung aus
    • Preamble und Start-of-Frame-Marker sind Elemente auf elektrischer Ebene und werden vom Chip verarbeitet
    • Auch die 32-bit-CRC berechnet der W5100

Problem 1: Die SPI-Signale erreichen den W5100 nicht

  • Der Datenaustausch mit dem W5100 erfolgt über SPI
    • MOSI: Ausgang des Mikrocontrollers als Hauptchip
    • MISO: Ausgang des W5100
    • Clock: Referenztakt für Daten
    • Chip Select: Signal, dass mit dem abhängigen Chip kommuniziert wird
  • Das Datenblatt des W5100 definiert über SPI ein 4-Byte-Befehlsprotokoll
    • 1 Byte Operation
    • 2 Byte 16-bit-Big-Endian-Adresse
    • 1 Byte Wert
  • Die Operation ist Schreiben 0xf0 oder Lesen 0x0f
    • Andere Werte sind ungültig und sollten ignoriert werden
  • Der W5100 gibt bei jedem ausgegebenen Byte einen bekannten Wert auf MISO zurück, sodass Kommunikationsfehler leicht zu erkennen sind
    • Bei einem Lesebefehl ist das 4. Byte der aus der angegebenen Adresse gelesene Wert
  • Anfangs erschienen auf MISO Garbage-Werte, obwohl Befehle über MOSI gesendet wurden
  • Die Ursache war das Design des Arduino Ethernet Shield, das die SPI-Signale nicht auf den Arduino-Standardheader, sondern auf den 6-poligen ICSP-Header routet
    • Bei offiziellen Arduino-Boards sind ICSP und die SPI-Signale des Standardheaders intern verbunden, daher gibt es dort kein Problem
    • Das Nucleo-Board hat keinen ICSP-Header, sodass die gesendeten SPI-Signale den W5100 nicht erreichten
  • Mit einem Multimeter wurde der Widerstand zwischen Stromschienen und SPI-Signalen gemessen, um das Verbindungsproblem zu bestätigen
    • Ein unendlicher Widerstand zeigt, dass die Verdrahtung unterbrochen ist
  • Mit Lötarbeiten und Kupferlackdraht wurden die Signale zwischen Nucleo und W5100 direkt verbunden

Problem 2: Chip-Select-Timing und ungewöhnliche MISO-Antworten

  • Nachdem die SPI-Signale tatsächlich verbunden waren, war Kommunikation mit dem W5100 möglich, und die nächsten Schritte wurden implementiert
    • Konfiguration der Raw-Ethernet-Übertragung des W5100
    • Setzen der MAC-Adresse
    • Konfiguration der TX/RX-Speichersegmente
    • Schreiben eines Test-Ethernet-Frames in den TX-Speicher und Auslösen der Übertragung
  • Nucleo und Shield wurden per CAT5-Kabel mit einem Laptop verbunden und Wireshark gestartet, aber es war kein Paket zu sehen
  • Low-Level-Probleme sind schwer zu verfolgen, weil es keine Fehlermeldungen oder Stack Traces gibt, sondern eher die Form: „Elektronen wurden bewegt, aber das Erwartete ist nicht passiert“
  • Zum Debugging wurde ein Logic Analyzer verwendet
    • Er sampelt die High/Low-Übergänge digitaler Signale auf mehreren Kanälen
    • Software interpretiert Signalbündel wie einen SPI-Bus und zeigt Transaction-Bytes an
    • Export in strukturierte Formate wie CSV ist möglich
  • Verwendet wurde ein Saleae Logic 8
    • Günstige Analyzer für etwa 10 € können ebenfalls mit Saleae Logic2 zusammenarbeiten, beim korrekten und konsistenten Betrieb gibt es jedoch Tradeoffs
  • Der erste SPI-Befehl sah korrekt aus
    • 0xf0 0x00 0x00 0x80
    • Setzt das höchstwertige Bit im Mode Register an Adresse 0x0000, um einen Software-Reset auszulösen
    • MISO antwortete korrekt von 0x00 bis 0x03
  • Beim nächsten Lesebefehl trat eine ungewöhnliche Antwort auf
    • MOSI: 0x0f 0x00 0x00 0x00
    • MISO: 0x03 0xff 0xff 0xff
  • Da 0x03 der letzte Wert der vorherigen Transaction war, lag ein Problem mit internem Zustand oder Timing des W5100 nahe
  • Der SPI-Clock lag weit unter dem im Datenblatt angegebenen Maximum von etwa 14 MHz und wurde daher nicht als Ursache betrachtet
  • Stattdessen wurde vermutet, dass Chip Select zu schnell wieder high wird und den Chip in einen schlechten Zustand versetzt; daher wurde vor dem Zustandswechsel eine Verzögerung von einigen Mikrosekunden eingefügt
    • Danach normalisierten sich die MISO-Antworten
    • Auch das erneute Auslesen der Konfigurationswerte ergab plausible Werte
  • Die genaue Ursache dieses Problems ist noch nicht vollständig verstanden
    • Die Einschränkungen zu Chip Select im SPI-Timing-Diagramm auf Seite 66 des Datenblatts wurden eingehalten
    • Die exakten Randbedingungen könnten erneut untersucht werden, derzeit hat jedoch der Fortschritt des Projekts Vorrang

Problem 3: Garbage-Pakete in Wireshark

  • Als Wireshark erneut gestartet wurde, erschienen zwar Pakete, aber nicht die beabsichtigten
  • In dem Moment, in dem der Mikrocontroller den Sendebefehl ausgab, erschien ein deutlich größeres Raw-Ethernet-Paket, gefüllt mit Garbage-Daten
  • Der Plan, die Implementierung nur anhand von Datenblatt und Spezifikation zu schreiben, wurde aufgegeben; in dieser Phase sollte stattdessen mit einer als funktionierend bekannten Implementierung verglichen werden
  • Arduino ist nützlich, um schnell eine Referenzimplementierung zu erstellen
    • Mit Arduino, Bibliothek und rund 5 Zeilen Code lässt sich komplexes Verhalten überprüfen
  • Mehr Zeit kostete es, eine Bibliothek für den Versand von Raw-Ethernet-Paketen zu finden
    • Die meisten Arduino-Nutzer versuchen nicht, Netzwerkfunktionen von Grund auf zu implementieren
    • Die offizielle Bibliothek hatte die Unterstützung für den Versand von Raw Packets aus der public API entfernt
  • Gefunden wurde das GitHub-Projekt W5100MacRaw, das Packet-Senden und -Empfangen mit minimalen Schritten ausführt
  • Der Vergleich dieses Quellcodes mit der eigenen Implementierung zeigte jedoch keine sofort entscheidenden Unterschiede
    • Die Reihenfolge von Register-Read/Write war unterschiedlich
    • Auf einer Seite gab es Reads/Writes, die auf der anderen fehlten
    • Üblicherweise wird angenommen, dass Reihenfolgeabhängigkeiten im Datenblatt erwähnt werden
  • Auch nachdem die Read/Write-Reihenfolge an die Referenzimplementierung angepasst wurde, zeigte Wireshark weiterhin Garbage-Pakete

Der eigentliche Bug, sichtbar gemacht durch ein kleines Tool

  • Die nächste Strategie bestand darin, ein Tool zu schreiben, das die SPI-Capture-CSV aus Saleae Logic2 parst und wieder als Liste von Register-Reads/-Writes anzeigt
  • Das Tool wurde in Python geschrieben und war insgesamt etwas über 200 Zeilen lang
    • Der größte Teil bestand aus aus dem Datenblatt kopierten Register-Namen und -Adressen
    • Die Erstellung dauerte etwa 1 Stunde
    • Argument Parsing wurde ebenfalls eingebaut, um Eingabe und Ausgabe klar zu machen
  • Von der Arduino-Referenzimplementierung und der eigenen Implementierung wurden jeweils SPI-Captures erstellt, als CSV exportiert, mit dem Tool verarbeitet und dann per diff verglichen
  • Das Problem lag in der Hilfsfunktion w5100_write16(u16 address, u16 value)
    • Viele Register des W5100 sind 16-bit-Werte
    • Das Befehlsformat kann jeweils nur 8-bit schreiben, daher muss in High- und Low-Byte aufgeteilt werden
    • Diese Funktion schrieb das zweite Byte nicht an address + 1, sondern erneut an dieselbe Adresse
  • Das Arduino-Referenzlog schrieb jeweils nach S0_TX_WR0 und S0_TX_WR1
    • S0_TX_WR0 [0x0424] 0x00
    • S0_TX_WR1 [0x0425] 0x3c
  • Das eigene Log schrieb beides nach S0_TX_WR0 [0x0424]
    • S0_TX_WR0 [0x0424] 0x00
    • S0_TX_WR0 [0x0424] 0x3c
  • Dieses Register war der Socket 0 transmit write pointer
    • Der W5100 erwartet den Ablauf, dieses 16-bit-Register der Reihe nach zu lesen
    • Bytes in den TX-Speicher zu schreiben
    • den neuen Write Pointer wieder zu schreiben
    • und anschließend den Socket-Send-Command zu senden
  • Weil das zweite Byte nicht geschrieben wurde und dennoch gesendet wurde, geriet der Chip in einen undefinierten, ungewöhnlichen Zustand; in Wireshark erschienen Pakete, die wie zufällige Ergebnisse wirkten
  • Nach Korrektur der Funktion wurde das Testpaket in Wireshark korrekt angezeigt

Der Wert der Zeit, die man in Debugging-Tools steckt

  • Die erste Ethernet-Paketübertragung selbst ist keine gewaltige Leistung, war im Projekt aber ein Moment, der klar als Erfolg gelten kann
  • Bugs nachzuvollziehen macht in persönlichen Projekten Spaß, und Zeit in Tooling und die Erkundung des Debugging-Raums zu investieren, ist fast immer lohnend
  • In manchen professionellen Umfeldern gilt Arbeit, die nicht direkt ein Deliverable erzeugt, tendenziell als Verschwendung
    • Wenn Entwicklungsprozesse im JIRA-Stil zerlegt werden, wird Arbeit, die nicht unmittelbar eine Checkbox füllt, geringer bewertet
    • Solange man ein System noch nicht ausreichend versteht, kann Tooling genauso wichtig sein wie Tests zu schreiben, manchmal sogar wichtiger
  • Debugging ähnelt stark der Umsetzung der wissenschaftlichen Methode
    • Daten sammeln
    • Vorhersagen aufstellen
    • Vorhersagen durch Experimente überprüfen
    • Vorhersagen mit neuen Daten aktualisieren
  • Dieses Projekt bewegt sich danach zu Problemen auf höheren Abstraktionsebenen weiter
    • Missverständnisse bei RFCs
    • Schreiben von Multitasking-Code
    • Und neue Bugs, mit denen es weitergeht

1 Kommentare

 
GN⁺ 2024-11-12
Hacker-News-Meinungen
  • Die Fähigkeit, sich direkt kleine Tools bauen zu können, ist eine Superkraft und steckt oft im Kern dessen, was man gemeinhin einen 10x-Programmierer nennt.
    Leider zeigt sich diese Fähigkeit meist still und leise an Stellen, die kaum sichtbar sind.

    • Solche Situationen habe ich auch schon erlebt. Organisationen brauchen auch Entwickler, die wie Zahnräder funktionieren, und in vielen Organisationen läuft es tatsächlich nur auf diese Weise.
      Aber für jemanden, der neugierig ist und über Sekundäreffekte oder Funktionen nachdenkt, die bald gebraucht werden, kann die Zusammenarbeit mit Entwicklern, die das nicht tun, ziemlich schmerzhaft sein.
      Ich räume gerade ein Projekt auf, das jemand, mit dem ich kürzlich gearbeitet habe, umgesetzt hat — kein schlechter Mensch, aber er hat zu 100 % nur das implementiert, was im Ticket stand. Das neue Projekt sollte Probleme der bestehenden Software ersetzen, ließ aber aus denselben Gründen alle alten Probleme unverändert bestehen.
      Allerdings riecht der Ausdruck 10x-Entwickler ein wenig nach Buzzword. Er erinnert mich an waghalsige Entwickler, die ohne Aufsicht „die Arbeit erledigen“, dabei hohe Kosten hinterlassen, alles siloartig aufbauen und es später wie ein Kartenhaus zusammenfällt, sobald jemand anderes etwas anfassen muss oder diese Person geht.
    • Umgekehrt betrachtet: Während Frank Ethernet-Pakete verschickt, müssen andere die eigentliche Arbeit erledigen, die für die gesamte Organisation nötig ist. Da der Backlog realer Probleme, die gelöst werden müssen, praktisch unendlich ist, kann man auch einwenden: Warum innoviert man nicht dort?
      Idealerweise sollte jeder Explorationszeit bekommen, aber man braucht Manager, die das strikt schützen, auch wenn das obere Management sagt: „Das muss schneller fertig werden.“ Noch schwieriger wird es, wenn Manager anderer Teams fragen: „Darf dieses Team zusätzliche Leute einstellen, um die verlorene Zeit auszugleichen? Wir brauchen diese Kapazität auch.“
      Am Ende braucht es Regelungen auf Organisationsebene, und selbst Google hat seine 20%-Zeit aufgegeben.
      Die „unethische“ Lösung besteht darin, solche Zeit ein wenig in die Entwicklungsschätzungen einzupreisen.
    • 10x-Entwickler sind meistens nicht die Leute, die an die von Managern oder Product Ownern festgelegten obersten Prioritäten gebunden sind. Ob das daran liegt, dass sie sich weigern, Anweisungen zu bekommen, daran, dass sie selbst Manager sind, oder daran, dass es von vornherein keinen Manager gibt, weiß ich nicht.
      Eigene Tools zu bauen ist in passenden Situationen nützlich, aber ich sehe produktive Entwickler auch als solche, die möglichst wenig Code schreiben und nutzen, was bereits existiert. Auf das Beispiel im Artikel bezogen: Niemand muss einen TCP-Stack selbst neu bauen; es gibt bereits hervorragende Implementierungen.
      Trotzdem kann Selberbauen der beste Weg sein, um ein tiefes Verständnis zu erlangen, und tiefes Verständnis ist ein Bestandteil des mythischen 10x-Entwicklers. Ich würde allerdings nicht erwarten, dass der Arbeitgeber diesen Prozess bezahlt.
    • Ich habe beide Extremreaktionen erlebt. Es gab Reaktionen wie: „Wow, das ist wirklich nützlich. Dieses Tool hat unser Modell verifiziert“, aber auch: „Haben Sie zuerst den PM gefragt? Man muss aufpassen, sich nicht in einem Kaninchenbau zu verlieren.“
      Wenn etwas normalerweise innerhalb eines Tages erledigt ist, mache ich es einfach. Es war noch nie falsch und auch nie verschwendet. Im schlimmsten Fall kopiere ich den Code später an eine andere Stelle.
    • Kürzlich habe ich bei der Arbeit mit einer Mischung aus Python und Shell eine kleine Tool-Sammlung gebaut, die unter WSL läuft, und mein Chef war ziemlich beeindruckt, als er sah, wie ich damit das IoT-System eines Kunden debuggt habe.
      Dann fing er an zu verlangen, dass auch Nichtprogrammierer sie nutzen können, und plötzlich wurden diese Tools zu einer viel größeren Aufgabe als erwartet.
  • Der Titel ist ziemlich vage; der Artikel ist der Auftakt zu einer Serie, in der von Grund auf ein TCP/IP- und Ethernet-Framing-Stack für Mikrocontroller gebaut wird.
    Der Autor verwendet einen W5100-Chip, der TCP/IP selbst verarbeiten kann, aber auch unterstützt, vorgefertigte Ethernet-Frames zu übergeben. Präambel und CRC-Berechnung übernimmt allerdings der Chip.
    Der Großteil des Artikels handelt davon, mit dem Chip selbst zu kommunizieren und ein Testpaket zu senden. Es sieht nach einem hartcodierten Paket aus, wird im Artikel aber nicht ausdrücklich gesagt.
    Persönlich hatte ich gehofft, es ginge darum, Ethernet auf völlig abwegiger Hardware per Bit-Banging zu betreiben.

    • Der RP2040 kann Ethernet per Bit-Banging, wenn man nur einen Transceiver hat, und sogar 100 Mb/s.
      Einer der Tricks besteht darin, ein gängiges PHY-+MagJack-Board so umzubauen, dass der RP2040 das Taktsignal erzeugt. Dadurch sind die Signale synchronisiert und RMII muss nicht überabgetastet werden.
      Wenn nur 10 Mb/s nötig sind, geht es auch mit noch schmutzigeren Methoden. Ich warte immer noch auf ein „modernes“ Glass-Terminal, das DVI/HDMI-Videoausgabe und Ethernet auf dem RP2040 kombiniert. Telnet allein würde schon reichen; SSH ist vermutlich zu viel verlangt.
    • Vor einiger Zeit hat jemand so etwas mit einem ATTiny85 gemacht: https://hackaday.com/2014/08/29/bit-banging-ethernet-on-an-a...
  • Ich bin kürzlich beruflich auf etwas ungewöhnliche Weise in Richtung Ethernet-zentriertes FPGA-Engineering gewechselt.
    Es war eine interessante Reise und führte schließlich dazu, dass ich selbst Hard-MAC-IP entworfen und Pakete über eine Custom-PHY-IP verschickt habe.
    Ich kann diese Herausforderung sehr empfehlen, wenn man sie im „Hard Mode“ angehen möchte. Networking ist für Nutzer so stark abstrahiert, dass es wirklich wertvoll war zu verstehen, wie Ethernet-Karten, Modems und Switches die einzelnen Teile eines Pakets zusammensetzen und zerlegen und wie PHY/PCS Signale auf dem Link wiederherstellen.

    • Vor etwa zehn Jahren habe ich an einem Projekt mitgearbeitet, bei dem TCP direkt auf einem FPGA verarbeitet wurde.
      Für Debugging und Verifikation haben wir eine mit Verilator erstellte Simulationsversion an ein Linux-TUN/TAP-Gerät anschließbar gemacht, sodass man sich direkt von der Entwickler-Maschine aus verbinden konnte, ohne die physische Hardware zu belegen. Das war besonders nützlich, weil es nur ein einziges Hardware-Exemplar gab.
    • Ich frage mich, ob du zu Beginn bereits mit Networking oder Ethernet vertraut warst. Falls nicht, würde mich interessieren, welche Materialien du genutzt hast, um das Gesamtbild zu verstehen.
      Mein Networking-Wissen endet bei einem sehr grundlegenden Verständnis des OSI-Modells, aber ich würde gern tiefer in die Networking-Welt eintauchen.
  • Das ist das erste Mal, dass ich eine Neuinterpretation von MOSI/MISO gesehen habe: Statt master out/slave in heißt es main out/subordinate in.
    So kann man die Pins weiterhin MOSI/MISO nennen, daher werde ich das wohl auch verwenden. Die Alternative COPI/CIPO (controller out/peripheral in) ist bei mir nie richtig hängen geblieben.

  • Ich wundere mich, warum der Autor ein W5100-Ethernet-Shield und einen STM32F401 verwendet. Genauso einfach könnte man ein STM32F407-Board nehmen; das hat einen integrierten Ethernet-MAC und lässt sich zusammen mit einem günstigen Ethernet-PHY-Board entwickeln.
    Es gibt auch viele Beispielprojekte für Ethernet, und die Entwicklung ist genauso einfach wie beim STM32F401.
    Außerdem halte ich die Erklärung, „wegen der Komplexität der Ethernet-Signalverarbeitung verwendet man normalerweise einen dedizierten ASIC“, im Kontext von Mikrocontrollern größtenteils nicht für zutreffend. In vielen Fällen ist Ethernet als integriertes Peripheriegerät im Mikrocontroller enthalten, etwa beim STM32F407 oder ESP32.

    • Ich bin der Autor. Der Grund ist ziemlich ernüchternd: Als ich beschloss, das Projekt zu starten, waren das die Teile, die ich zur Hand hatte.
      Es ist definitiv sinnvoller, einen Chip mit integrierter Ethernet-Peripherie zu verwenden. Allerdings tauscht man damit auch die Komplexität der W5100-Konfiguration gegen die Komplexität der ST-Peripheriekonfiguration ein.
      Der Networking-Code abstrahiert den tatsächlichen Chip bereits hinter einem Treiber-Interface (etwa in der Form read/write/ioctl), daher sollte das Portieren ziemlich einfach sein.
      In dieser Serie werde ich mir den STM32F407 ansehen.
    • Für manche ist der Lernprozess an sich der Spaß, nicht unbedingt die modernste Vorgehensweise.
    • Als ich mir heute ESP32-Boards mit Ethernet angesehen habe, schien es so, als würden die meisten oder zumindest viele von ihnen Ethernet wie ein serielles Gerät verwenden.
  • Ethernet arbeitet nicht mit Paketen, sondern mit Frames.
    Pakete sind ein IP-Konzept.

    • RFC 791, das IP definiert, spricht sowohl von Paketen als auch von Datagrammen. IP sendet Datagramme, und jedes IP-Datagramm wird je nach darunterliegendem L2-Netzwerk in ein oder mehrere Pakete fragmentiert.
      Allerdings stammt RFC 791 aus einer Zeit, in der das darunterliegende L2-Netzwerk mit hoher Wahrscheinlichkeit das ARPAnet mit 128-Byte-Paketen war.
      Heute sollte diese Unterscheidung praktisch bedeutungslos sein. Wenn man sich darauf verlässt, große IP-Datagramme per IP-Fragmentierung über mehrere L2-Pakete zu verschicken, läuft etwas falsch. IPv6 unterstützt nicht einmal Fragmentierung innerhalb des Netzwerks.
      In der Praxis ist die Unterscheidung mit der Zeit fast verschwunden. Normalerweise enthält ein Ethernet-Frame ein IP-Datagramm, und alle nennen das einfach Paket.
    • Das gibt es nur auf HN: Jemand implementiert Networking von Grund auf, und in den Kommentaren wird er wegen eines einzelnen Begriffs so abgewertet, als wüsste er nicht, was er tut.
    • Bei Ethernet ist ein Paket ein Konzept der physikalischen Schicht und kapselt einen Frame, der ein Konzept der Sicherungsschicht ist.
      https://en.wikipedia.org/wiki/Ethernet_frame
    • Pakete sind ein TCP-Konzept, IP sendet Datagramme.
  • Wenn man auf einem Mikrocontroller kabelgebundenes Ethernet ausprobieren möchte: Einige der größeren STM32-Nucleo-Boards haben 100-Mbps-Ethernet integriert und sind mit etwa 25 Dollar ziemlich günstig.
    Die Bewertungen der STM32Cube-Software sind gemischt, aber sie erzeugt ein funktionierendes Beispiel für Ethernet-Kommunikation.
    https://www.st.com/en/evaluation-tools/nucleo-f439zi.html

    • Wenn man etwas ESP32-basiertes möchte, kostet der WT32-ETH01 auf Aliexpress etwa 7 Dollar. Persönlich fand ich den Einstieg damit genauso einfach wie mit STM-Teilen, wenn nicht einfacher.
      MQTT, HTTP-Client und -Server usw. werden mitgeliefert.
      Als ich Cube-MX zuletzt benutzt habe, war die Erfahrung insgesamt äußerst unangenehm. Wenn ich wieder STM32 verwenden würde, würde ich wahrscheinlich stm32-hal oder libopencm3 bevorzugen. Das Tool selbst und der generierte Code hatten alle möglichen üblen Bugs und Grenzfälle, sodass ich Tage mit Debugging verbrachte. Vielleicht ist es inzwischen besser.
      https://github.com/egnor/wt32-eth01
    • Interessant ist, dass es RISC-V-ESP32-P4-Boards mit Ethernet für etwa 20 Dollar gibt.
      https://liliputing.com/waveshare-esp32-p4-nano-is-a-tiny-ris...
      Ich habe gerade gesehen, dass es auch günstigere Module gibt. Dinge wie der WT32-ETH01 könnten weniger leistungsfähig sein.
    • STM32Cube erzeugt zwar ein funktionierendes Beispiel für Ethernet-Kommunikation, ist auf mancher Hardware aber kaputt.
    • Zum Glück gibt es auf GitHub mehrere alternative CMake-Projekte.
    • STM32Cube hat ein deutliches „90er-Jahre“-Gefühl.
  • Wenn man unter Linux selbst einen Netzwerk-Stack schreiben möchte, kann man socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)) verwenden und auf einer Abstraktionsebene arbeiten, die sich nicht stark von der in diesem Artikel unterscheidet.
    SOCK_RAW-Pakete werden zwischen Gerätetreiber und Anwendung übertragen, ohne die Paketdaten zu verändern. Beim Empfangen wird die Adresse geparst und in der standardmäßigen Adressstruktur sockaddr_ll übergeben.
    Beim Senden muss der vom Benutzer bereitgestellte Buffer den Header der physikalischen Schicht enthalten, und das Paket landet unverändert in der Netzwerk-Treiber-Queue des Interfaces, das durch die Zieladresse angegeben ist.
    https://man7.org/linux/man-pages/man7/packet.7.html

    • Wenn man es in die andere Richtung machen möchte, kann man leicht ein tun-Interface (virtuelles IP) oder tap-Interface (virtuelles Ethernet) öffnen.
      Das fügt dem Netzwerk-Stack ein virtuelles Interface hinzu, ähnlich wie ein VPN-Interface. Packet-Sockets erlauben dagegen die direkte Kommunikation mit einem realen Interface.
  • Genau genommen sollte man wohl Ethernet-Frame sagen.

  • Gut gemacht. Ich habe gerade die letzten 16 Arbeitsstunden mit der Gegenrichtung verbracht: einer Implementierung, die Ethernet II (einschließlich VLAN), IPv4+6 und UDP bis hin zu Automotive-IP-Protokollen parst.
    Zweck ist es, einen proprietären Bus-Capture-Stream zu verstehen; dieser Stream transportiert Ethernet-Frames, die wiederum in Ethernet-Frames verschachtelt sind usw., und ich empfange sie über Raw Sockets.
    Für solche Arbeiten sind Wireshark und ChatGPT wirklich unschätzbar wertvoll.