@Jeremy Thanks for the screenshots — they changed my read of this quite a bit, and I owe you a correction first.
Correction: earlier I said pxe get “finding” pxelinux.cfg/01-88-a2-9e-53-34-c0 proved the file-generation side worked. It didn’t. U-Boot prints Retrieving file: ... before it sends the request, and the Loading: T T T T that follows means the server never answered at all. A file that really is missing gives you TFTP error: 'File not found', not timeouts. So the file-side was never proven, and it turns out it was broken on my side of the fence.
The FOG bug, now fixed: FOG was writing the 01-<mac> file under the directory it keeps the HTTP-served kernels in (/var/www/html/fog/service/ipxe/), not under /tftpboot. The TFTP daemon runs chrooted to /tftpboot, so the file existed but TFTP could never see it. That’s fixed in working-1.6 (PR #1664) with a new setting, FOG Settings → TFTP Server → FOG_TFTP_ROOT_DIR, which the installer sets to the real TFTP root. Run the updater once it’s merged and check that setting reads /tftpboot; after that, queue a task for the Pi and you should see /tftpboot/pxelinux.cfg/01-88-a2-9e-53-34-c0 appear on the server. Please confirm that file is there before the next boot test — it’s the one thing I can check in code but not on your box.
Your current boot loop is a different, earlier step. From the console shot: U-Boot itself loaded cardless, which means the Pi’s EEPROM network boot already pulled the firmware and u-boot.bin from /tftpboot over TFTP. That proves the OPNsense next-server, the FOG TFTP service and the firewall are all fine for this client — so ignore my earlier firewall angle. What’s looping is bootcmd=bootflow scan: that’s U-Boot’s standard-boot sequence, which tries mmc, usb, then ethernet, and the ethernet step starts with U-Boot’s own DHCP request (BOOTP broadcast 1, 2, 3...). That DHCP never succeeds, and it’s never been shown to work in this thread — your earlier manual test set ipaddr/serverip by hand and skipped DHCP entirely. The empty per-architecture filenames in OPNsense are fine, by the way: the pxe boot method doesn’t need a bootfile name at all. (Side note, unrelated to the Pi: the iPXE-class filename in OPNsense is what gets handed to a client that is already running iPXE, and FOG expects default.ipxe there, not ipxe.efi — with ipxe.efi your x86 UEFI clients will reload iPXE forever. Worth a look when you’re back on those.)
Two things to try at the U-Boot prompt, and please paste the exact text rather than a screenshot if you can:
dhcpon its own. If it also loops on BOOTP, then U-Boot’s network driver isn’t getting a lease and we look at OPNsense’s DHCP log for that MAC (does the request even arrive, does it offer). If it does get an address, then:
pxe get pxe bootonce the FOG update above is in and the 01-... file is confirmed on disk. If that works by hand, setenv bootcmd 'dhcp; pxe get; pxe boot' and saveenv gets you the automated path — bootflow scan should get there too, but the manual sequence tells us which step is at fault when it doesn’t.