velxio/backend/app/services/picow_net/arp.py

46 lines
1.5 KiB
Python
Raw Normal View History

"""
ARP responder answers chip ARP requests for the synthetic gateway
and any IP the chip wants to talk to.
The cyw43 lwIP stack will do an ARP lookup for the destination MAC of
its first packet to a remote host. We don't run a real network — there's
no real MAC behind the gateway IP. So we synthesize the gateway MAC
(``GATEWAY_MAC``) for everything, exactly the way QEMU's slirp does.
"""
from __future__ import annotations
from .consts import ARP_REPLY, ARP_REQUEST, GATEWAY_MAC, STA_IP, ip_to_bytes
from .protocols import Arp, Ethernet, make_frame_arp
class ArpResponder:
"""Stateless. Decides whether to answer an ARP request, and how."""
def handle(self, frame: Ethernet) -> bytes | None:
try:
arp = Arp.parse(frame.payload)
except ValueError:
return None
if arp.opcode != ARP_REQUEST:
# We don't track replies; they shouldn't happen anyway since
# we never send ARP requests to the chip.
return None
# Only answer requests that come from our own STA.
if bytes(arp.spa) != ip_to_bytes(STA_IP):
return None
target_ip = bytes(arp.tpa)
# We answer for *any* IP — the only network the chip can reach
# is via the gateway, so all IPs map to GATEWAY_MAC.
reply = Arp(
opcode=ARP_REPLY,
sha=GATEWAY_MAC,
spa=target_ip,
tha=arp.sha,
tpa=arp.spa,
)
return make_frame_arp(arp.sha, GATEWAY_MAC, reply)