Why am I getting slow speeds when a Linux machine as Wi-Fi AP?

I’m using a Raspberry Pi 5 as a Wi‑Fi bridge (AP for my laptop + STA to dorm Wi‑Fi). I expected laptop speeds to approach the Pi’s WAN speed, but there’s a ~40 Mbps gap I can’t explain.

My setup

  • Raspberry Pi 5 with Debian trixie, kernel 6.12.47+rpt-rpi-2712
  • wlan1 (Edimax EW‑7811UTC) connects to dorm Wi‑Fi
  • wlan0 (internal) hosts AP
  • NAT/forwarding enabled (NetworkManager ipv4.method=shared, ipv4.ip_forward=1, nftables masquerade)

Commands I used to set up the AP + NAT

  • AP (wlan0), 5 GHz, 80 MHz, NAT/shared
  sudo nmcli con add type wifi ifname wlan0 con-name Hotspot autoconnect yes ssid PiAP

  sudo nmcli con mod Hotspot 802-11-wireless.mode ap 
    802-11-wireless.band a 
    802-11-wireless.channel 36 
    802-11-wireless.channel-width 80 
    802-11-wireless-security.key-mgmt wpa-psk 
    802-11-wireless-security.psk "mypassword" 
    ipv4.method shared 
    ipv6.method disabled

Key link rates

  • Pi → dorm AP (wlan1): 5 GHz, 40 MHz, 200 Mbps PHY
  • Laptop → Pi AP (wlan0): 80 MHz, 433 Mbps PHY

Local hop isn’t the bottleneck because iperf gives

  • iperf3 laptop ↔ Pi over Wi-Fi: ~252 Mbps

Pi WAN is stable

  • Pi → Internet (Cloudflare 50 MB test):
    ~148 Mbps avg (5 runs)

But laptop via Pi is capped

  • Laptop → Internet via Pi (same Cloudflare test):
    ~107 Mbps avg (5 runs)

So: local hop can do ~250 Mbps; WAN is ~148 Mbps; yet laptop tops out ~107 Mbps. That’s a ~40 Mbps loss.

Question: Where is the ~40 Mbps disappearing? Is this expected overhead for:

  • Wi‑Fi AP+STA bridging on a Pi?
  • NAT/iptables/nftables?
  • TCP over the WAN path with extra Wi‑Fi hop?
  • Something like queueing/buffering in NetworkManager’s “shared” mode?