My new, shiny, home NAS-computer, running Ubuntu 20.04, has a gigabit wired connection and an ath-9k chipset dual-band (2.5 / 5 GHz) wifi card. My current wireless AP only has a 2.5 GHz radio, and in my region 2.5 GHz is fairly congested. I would like to bridge from the lan to a new 5 GHz wireless network using the new computer, but using the same DHCP server / default gateway / DNS servers as the lan / Wifi at the moment. This is because I have a single-board computer as a default gateway, transparently ad-blocking (amongst other things). I've achieved this by just disabling the DHCP server on my ISP's supplied router and using my own instead (which is also the gateway, routing packets to the router as the only device on it)

A brief ascii-art description of what I have is below:

+----+      +------------------+
| WAN+------+ISP Router        |
+----+      +------------------+         +--------------------+
            |1000-Base-T       +---------+LAN                 |
            |2.4 GHz (WPA2/PSK)+-------+ +--------------------+    +-----------------+
            +------------------+       | |SBC DHCPd / DNS / GW+----+Wired clients (*)|
                                       | +--------------------+    +-----------------+
                                       | +-----------------------+
                                       +-+2.4GHz Wireless clients|

I believe I'd like to configure the computer as a layer-2 bridge between its wired connection and wifi. I don't want to use hostapd as I don't want it to be doing NAT and routing -- I might want to ssh from a wired device to a wireless one that may be associated with it. I'd also like devices to seamlessly switch between 2.4 & 5 GHz as appropriate -- and I believe that doing that is as simple as having the same SSID, authentication method (i.e. WPA2/PSK) and key.

In short, I think that I'd like to change the above diagram to include a "5 GHz Wireless clients" at the node marked (*).

My card supports AP mode and quite a lot of other features: here's the output of lshw and the (very long!) output of iw list:

                          description: Wireless interface
                          product: AR93xx Wireless Network Adapter
                          vendor: Qualcomm Atheros
                          physical id: 0
                          bus info: pci@0000:03:00.0
                          logical name: wlp3s0
                          version: 01
                          serial: 14:cc:20:10:a6:fa
                          width: 64 bits
                          clock: 33MHz
                          capabilities: pm msi pciexpress bus_master cap_list rom ethernet physical wireless
                          configuration: broadcast=yes driver=ath9k driverversion=5.4.0-39-generic firmware=N/A latency=0 link=no multicast=yes wireless=IEEE 802.11
                          resources: irq:101 memory:fc900000-fc91ffff memory:fc920000-fc92ffff
# iw list
Wiphy phy0
    max # scan SSIDs: 4
    max scan IEs length: 2257 bytes
    max # sched scan SSIDs: 0
    max # match sets: 0
    max # scan plans: 1
    max scan plan interval: -1
    max scan plan iterations: 0
    Retry short limit: 7
    Retry long limit: 4
    Coverage class: 0 (up to 0m)
    Device supports RSN-IBSS.
    Device supports AP-side u-APSD.
    Device supports T-DLS.
    Supported Ciphers:
        * WEP40 (00-0f-ac:1)
        * WEP104 (00-0f-ac:5)
        * TKIP (00-0f-ac:2)
        * CCMP-128 (00-0f-ac:4)
        * CCMP-256 (00-0f-ac:10)
        * GCMP-128 (00-0f-ac:8)
        * GCMP-256 (00-0f-ac:9)
        * CMAC (00-0f-ac:6)
        * CMAC-256 (00-0f-ac:13)
        * GMAC-128 (00-0f-ac:11)
        * GMAC-256 (00-0f-ac:12)
    Available Antennas: TX 0x7 RX 0x7
    Configured Antennas: TX 0x7 RX 0x7
    Supported interface modes:
         * IBSS
         * managed
         * AP
         * AP/VLAN
         * monitor
         * mesh point
         * P2P-client
         * P2P-GO
         * outside context of a BSS
    Band 1:
        Capabilities: 0x11ef
            RX LDPC
            SM Power Save disabled
            RX HT20 SGI
            RX HT40 SGI
            TX STBC
            RX STBC 1-stream
            Max AMSDU length: 3839 bytes
            DSSS/CCK HT40
        Maximum RX AMPDU length 65535 bytes (exponent: 0x003)
        Minimum RX AMPDU time spacing: 8 usec (0x06)
        HT TX/RX MCS rate indexes supported: 0-23
        Bitrates (non-HT):
            * 1.0 Mbps
            * 2.0 Mbps (short preamble supported)
            * 5.5 Mbps (short preamble supported)
            * 11.0 Mbps (short preamble supported)
            * 6.0 Mbps
            * 9.0 Mbps
            * 12.0 Mbps
            * 18.0 Mbps
            * 24.0 Mbps
            * 36.0 Mbps
            * 48.0 Mbps
            * 54.0 Mbps
            * 2412 MHz [1] (20.0 dBm)
            * 2417 MHz [2] (20.0 dBm)
            * 2422 MHz [3] (20.0 dBm)
            * 2427 MHz [4] (20.0 dBm)
            * 2432 MHz [5] (20.0 dBm)
            * 2437 MHz [6] (20.0 dBm)
            * 2442 MHz [7] (20.0 dBm)
            * 2447 MHz [8] (20.0 dBm)
            * 2452 MHz [9] (20.0 dBm)
            * 2457 MHz [10] (20.0 dBm)
            * 2462 MHz [11] (20.0 dBm)
            * 2467 MHz [12] (20.0 dBm)
            * 2472 MHz [13] (20.0 dBm)
            * 2484 MHz [14] (disabled)
    Band 2:
        Capabilities: 0x11ef
            RX LDPC
            SM Power Save disabled
            RX HT20 SGI
            RX HT40 SGI
            TX STBC
            RX STBC 1-stream
            Max AMSDU length: 3839 bytes
            DSSS/CCK HT40
        Maximum RX AMPDU length 65535 bytes (exponent: 0x003)
        Minimum RX AMPDU time spacing: 8 usec (0x06)
        HT TX/RX MCS rate indexes supported: 0-23
        Bitrates (non-HT):
            * 6.0 Mbps
            * 9.0 Mbps
            * 12.0 Mbps
            * 18.0 Mbps
            * 24.0 Mbps
            * 36.0 Mbps
            * 48.0 Mbps
            * 54.0 Mbps
            * 5180 MHz [36] (23.0 dBm)
            * 5200 MHz [40] (23.0 dBm)
            * 5220 MHz [44] (23.0 dBm)
            * 5240 MHz [48] (23.0 dBm)
            * 5260 MHz [52] (23.0 dBm) (no IR, radar detection)
            * 5280 MHz [56] (23.0 dBm) (no IR, radar detection)
            * 5300 MHz [60] (23.0 dBm) (no IR, radar detection)
            * 5320 MHz [64] (23.0 dBm) (no IR, radar detection)
            * 5500 MHz [100] (disabled)
            * 5520 MHz [104] (disabled)
            * 5540 MHz [108] (disabled)
            * 5560 MHz [112] (disabled)
            * 5580 MHz [116] (disabled)
            * 5600 MHz [120] (disabled)
            * 5620 MHz [124] (disabled)
            * 5640 MHz [128] (disabled)
            * 5660 MHz [132] (disabled)
            * 5680 MHz [136] (disabled)
            * 5700 MHz [140] (disabled)
            * 5745 MHz [149] (30.0 dBm)
            * 5765 MHz [153] (30.0 dBm)
            * 5785 MHz [157] (30.0 dBm)
            * 5805 MHz [161] (30.0 dBm)
            * 5825 MHz [165] (30.0 dBm)
    Supported commands:
         * new_interface
         * set_interface
         * new_key
         * start_ap
         * new_station
         * new_mpath
         * set_mesh_config
         * set_bss
         * authenticate
         * associate
         * deauthenticate
         * disassociate
         * join_ibss
         * join_mesh
         * remain_on_channel
         * set_tx_bitrate_mask
         * frame
         * frame_wait_cancel
         * set_wiphy_netns
         * set_channel
         * set_wds_peer
         * tdls_mgmt
         * tdls_oper
         * probe_client
         * set_noack_map
         * register_beacons
         * start_p2p_device
         * set_mcast_rate
         * connect
         * disconnect
         * channel_switch
         * set_qos_map
         * set_multicast_to_unicast
    Supported TX frame types:
         * IBSS: 0x00 0x10 0x20 0x30 0x40 0x50 0x60 0x70 0x80 0x90 0xa0 0xb0 0xc0 0xd0 0xe0 0xf0
         * managed: 0x00 0x10 0x20 0x30 0x40 0x50 0x60 0x70 0x80 0x90 0xa0 0xb0 0xc0 0xd0 0xe0 0xf0
         * AP: 0x00 0x10 0x20 0x30 0x40 0x50 0x60 0x70 0x80 0x90 0xa0 0xb0 0xc0 0xd0 0xe0 0xf0
         * AP/VLAN: 0x00 0x10 0x20 0x30 0x40 0x50 0x60 0x70 0x80 0x90 0xa0 0xb0 0xc0 0xd0 0xe0 0xf0
         * mesh point: 0x00 0x10 0x20 0x30 0x40 0x50 0x60 0x70 0x80 0x90 0xa0 0xb0 0xc0 0xd0 0xe0 0xf0
         * P2P-client: 0x00 0x10 0x20 0x30 0x40 0x50 0x60 0x70 0x80 0x90 0xa0 0xb0 0xc0 0xd0 0xe0 0xf0
         * P2P-GO: 0x00 0x10 0x20 0x30 0x40 0x50 0x60 0x70 0x80 0x90 0xa0 0xb0 0xc0 0xd0 0xe0 0xf0
         * P2P-device: 0x00 0x10 0x20 0x30 0x40 0x50 0x60 0x70 0x80 0x90 0xa0 0xb0 0xc0 0xd0 0xe0 0xf0
    Supported RX frame types:
         * IBSS: 0x40 0xb0 0xc0 0xd0
         * managed: 0x40 0xd0
         * AP: 0x00 0x20 0x40 0xa0 0xb0 0xc0 0xd0
         * AP/VLAN: 0x00 0x20 0x40 0xa0 0xb0 0xc0 0xd0
         * mesh point: 0xb0 0xc0 0xd0
         * P2P-client: 0x40 0xd0
         * P2P-GO: 0x00 0x20 0x40 0xa0 0xb0 0xc0 0xd0
         * P2P-device: 0x40 0xd0
    software interface modes (can always be added):
         * AP/VLAN
         * monitor
    valid interface combinations:
         * #{ managed } <= 2048, #{ AP, mesh point } <= 8, #{ P2P-client, P2P-GO } <= 1,
           total <= 2048, #channels <= 1, STA/AP BI must match
    HT Capability overrides:
         * MCS: ff ff ff ff ff ff ff ff ff ff
         * maximum A-MSDU length
         * supported channel width
         * short GI for 40 MHz
         * max A-MPDU length exponent
         * min MPDU start spacing
    Device supports TX status socket option.
    Device supports HT-IBSS.
    Device supports SAE with AUTHENTICATE command
    Device supports low priority scan.
    Device supports scan flush.
    Device supports AP scan.
    Device supports per-vif TX power setting
    P2P GO supports CT window setting
    Driver supports full state transitions for AP/GO clients
    Driver supports a userspace MPM
    Device supports active monitor (which will ACK incoming frames)
    Driver/device bandwidth changes during BSS lifetime (AP/GO mode)
    Device supports configuring vdev MAC-addr on create.
    Supported extended features:
        * [ RRM ]: RRM
        * [ FILS_STA ]: STA FILS (Fast Initial Link Setup)
        * [ CQM_RSSI_LIST ]: multiple CQM_RSSI_THOLD records
        * [ CONTROL_PORT_OVER_NL80211 ]: control port over nl80211
        * [ TXQS ]: FQ-CoDel-enabled intermediate TXQs
        * [ AIRTIME_FAIRNESS ]: airtime fairness scheduling

I've tried to do this with bridge-utils, i.e. by bridging the interfaces directly:

   $ brctl addbr br0
   $ brctl addif br0 enp4s0 wlp3s0

Unfortunately, this stopped all DNS resolution on the computer (!) and resulted in some 'interesting' routing errors I didn't understand: e.g. I could ping but not dig @ google.com. Even doing

   $ brctl br0 down
   $ brctl delbr br0

still resulted in a restart of /etc/init.d/networking.

I don't understand why this doesn't work. I've also tried using Ubuntu's network-manager gui, creating a new 'shared' AP -- which just opens hostapd and also googled extensively, but can't find a clear answer. I know that network topologies with multiple wireless bridges definitely exist -- what's the simplest way to configure it?

  • (i also don't know if this would be a better fit for other SO sites like Networking) – Landak Jul 1 '20 at 14:36
  • hostapd dosen't do routing and DHCP - I have a "full" stack of firewall (iptables with a firewalld ) doing masqurading and NAT, dnsmasq covering DHCP and DNS, didn't explicitly do any routing stuff, and hostapd just runs on its own. Its been a while so I'll need to review my setup to post a proper answer... – Journeyman Geek Jul 9 '20 at 12:13
  • journeymangeek.com/?p=196 for reference - that's my setup. Couple of other fun things - IIRC network manager does bridges its own way (and I have notes somewhere) and modern ubuntu uses netplan to manage bridges - so you need to explicitly switch to the classical way of network management – Journeyman Geek Jul 9 '20 at 12:26

There's a couple of complications worth considering.

The simplest one is? hostapd doesn't do routing or DHCP and will probably run quite happily on its own.

The simplest most minimal hostapd config file looks like this

#change wlan0 to your wireless device

All it cares about it wifi, and the only lower level network option I recall is vlan tagging for various reasons.

I have a whole long answer on how to run the whole stack and you literally have different tools doing nat masqurade (your firewall), DNS (Bind9 if you're good, DNSMASQ if you're lazy), DHCP (DHCPd or DNSMASQ), bridging (in your case, network manager, but systemd/networkd - either with netplan as an optional tool to configure or classic network settings with bridgectl..). ip does routing but I never explicitly touched that.

Literally there's 2-3 tools for each of these, and they're all optional and may or may not run on the same box.

But the simple answer is turning on a shared AP with network-manager GUI should just work, and presumably pick up the dns and dhcp stack you are running.

  • Thank you for your suggestions -- but the short answer is that the network-manager gui was really not terribly happy, and wanted to start dhcpd on the other interface. I have however "worked it out for myself", in part due to your help, and will post another answer below shortly. The only trouble I've found is that systemd-resolve would not be able to resolve at all once the bridge was up. I've got around it by just managing /etc/resolv.conf manually and disabling systemd-resolve. Given resolv.conf only points to my local network DNS server, I don't think I am missing much. – Landak Aug 28 '20 at 20:34

More than a month of experimentation later, I'd like to post how I (as OP) managed to come to a solution. The main trouble I found was that many of the network-manager based gui tools would try to start a DHCP server on the bound interface, and I found the explanations of what "automatic" would do to be woefully unclear.

In the end, the following approach worked.

Physical layer

First of all, I created an appropriate modified hostapd configuration file, in order to create a wireless access point:

cp /usr/share/doc/hostapd/examples/hostapd.conf /etc/hostapd/hostapd.conf

For my TP-Link TL-WDN4800 N900 PCI-e card, this required modprobe-ing the ath9k driver (if it wasn't already), and then adjusting the (wonderfully detailed!) configuration file with respect to the interface (wlp3s0 for me), explicitly informing it that we want to create a bridge (bridge=br0) and setting the country_code, ssid, and the hw_mode=a for 5 GHz 802.11ac (if VHT is enabled, further below). By enabling VHT, 80 MHz channels, and a variety of other settings, I have actually managed to get a link speed (on a nearby MacbookPro) of 780 MiB/s, exceeding the box-advertised speed of the link. If it helps anyone else, I've put the whole file as a gist here.

This whole thing needs to run, ideally on startup, so, we need to explicitly enable this (if you like! A more "manual" option is just invoking it in a shell, or using the -B option to daemonise):

sudo systemctl unmask hostapd
sudo systemctl enable hostapd
sudo systemctl start hostapd

By this point, as Journeyman Geek stated, you have a broadcasting SSID, to which devices can authenticate. But, their packets go nowhere.

Creating the bridge

After a lot of fiddling around, I ultimately realised that my previous 'woes' were as follows: (a) I didn't realise that the bridge itself needs to have the same ip on both network segments (obviously), and moreover that the individual physical interfaces need to go down as a result, and (b) for some reason I do not understand, systemd-resolvconf failed to resolve anything once the bridge was up.

Let's cheat and use the outdated, but convenient, brutils package:

apt install bridge-utils #If required 
brctl addbr br0 #Create the bridge 
brctl addif br0 enp4s0 #Add interfaces to it 
brctl addif br0 wlp3s0

We then assign an IP to the bridge (here on my network), and remove it from the other interfaces:

ifconfig br0 netmask
ifconfig enp4s0
ifconfig wlp3s0

Finally, bring the bridge up: for me, this nuked the default routing table, as the default route information was associated with the hardware enp4s0 interface. So, let's re-add it and the router ( directly:

ifconfig br0 up
route add default gateway

Now, at this point, everything -- as I thought before -- should work, but irritatingly, er, didn't. What's left? Routing (properly) and DNS. Routing is easy: we need to explicitly enable this, and just add some iptables rules to hammer this point home:

echo 1 > /proc/sys/net/ipv4/ip_forward 
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -i enp4s0 -j ACCEPT
iptables -A INPUT -i wlp3s0 -j ACCEPT
iptables -A INPUT -i br0 -j ACCEPT
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

DNS was more problematic. Despite playing around with systemd-resolvconf for a very long period of time, all of my DNS queries would mysteriously vanish into the aether, almost as if it were sending packets to the (now non-functional) hardware enp4s0 interface.

By far the quickest thing for me was disabling systemd-resolve (systemctl disable systemd-resolve), and just editing /etc/resolv.conf to be a file (rather than a symlink) containing my local network's DNS server (also and domain information.

Suddenly, everything works! I have a fast, configurable, transparent wireless bridged "range extender" (taking advantage of my gigabit network).

For future reference, this was a great introduction to the various forms of virtual networking present within linux -- for which a very good overview is here (archive.org link). Hope it is vaguely helpful to some other person on the planet.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.