mirror of
https://git.k-space.ee/arti/vt1200.git
synced 2026-10-31 12:05:05 +02:00
lance_bcast.c drives the chip entirely on its own -- init block, PADR/LADRF, eight TX and eight RX descriptors, INIT/IDON/STRT, TDMD, completion polling -- and test-bcast.sh runs it in MAME and reports: TXD=6 RXF=5 ET=0x88B5 source MAC 0xC6FC ok=1 PASS The tap capture separates the directions: six 60-byte 0x88b5 broadcasts from 08:00:2b:16:4b:5a (our payload) and 49 from the host. RXF counts host frames (early stop at five) and the recorded source MAC is the host's. Fixes behind it: per-frame TX descriptor (the chip advances its own ring position), cfg-net needed for a tap to exist at all, pkill -x instead of -f, and two bit-vs-byte addressing bugs.
66 lines
2.4 KiB
Python
66 lines
2.4 KiB
Python
#!/usr/bin/env python3
|
|
"""sendraw.py -- send raw Ethernet frames from the host.
|
|
|
|
Used to exercise the VT1200 payload's receive path without a protocol stack:
|
|
the payload counts frames and records the last ethertype and source MAC on its
|
|
panel, so a single broadcast frame is enough to prove RX works.
|
|
|
|
# MAME: the bridge floods to the enslaved tap
|
|
sudo python3 harness/udpstream/sendraw.py --iface vt1200 --count 3
|
|
|
|
# real unit: the host's own NIC
|
|
sudo python3 harness/udpstream/sendraw.py --iface eth0 --dst ff:ff:ff:ff:ff:ff
|
|
|
|
Options default to a 60-byte broadcast frame with ethertype 0x88B5, which is the
|
|
one the payload's panel shows in its ET row.
|
|
"""
|
|
import argparse
|
|
import socket
|
|
import struct
|
|
import sys
|
|
import time
|
|
|
|
|
|
def parse_mac(s):
|
|
parts = s.split(":")
|
|
if len(parts) != 6:
|
|
raise argparse.ArgumentTypeError("expected aa:bb:cc:dd:ee:ff")
|
|
return bytes(int(p, 16) for p in parts)
|
|
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser(description=__doc__,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
ap.add_argument("--iface", required=True, help="interface to send on")
|
|
ap.add_argument("--dst", type=parse_mac, default=parse_mac("ff:ff:ff:ff:ff:ff"),
|
|
help="destination MAC (default broadcast)")
|
|
ap.add_argument("--src", type=parse_mac, default=None,
|
|
help="source MAC (default: the interface's own)")
|
|
ap.add_argument("--ethertype", type=lambda v: int(v, 0), default=0x88B5)
|
|
ap.add_argument("--size", type=int, default=60, help="frame size from dst onwards")
|
|
ap.add_argument("--count", type=int, default=1)
|
|
ap.add_argument("--gap", type=float, default=0.2, help="seconds between frames")
|
|
args = ap.parse_args()
|
|
|
|
src = args.src
|
|
if src is None:
|
|
with open("/sys/class/net/%s/address" % args.iface) as f:
|
|
src = parse_mac(f.read().strip())
|
|
|
|
size = max(args.size, 14)
|
|
body = bytes((i & 0xFF) for i in range(size - 14))
|
|
frame = args.dst + src + struct.pack(">H", args.ethertype) + body
|
|
|
|
s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW)
|
|
s.bind((args.iface, 0))
|
|
for i in range(args.count):
|
|
s.send(frame)
|
|
print("sent %d B on %s: %s -> %s ethertype 0x%04x"
|
|
% (len(frame), args.iface, src.hex(":"), args.dst.hex(":"), args.ethertype))
|
|
time.sleep(args.gap)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|