July 6th, 2021: Added information about transitioning from OpenWrt 19 (current stable release) to OpenWrt 21 (next stable release) to a new section called Bonus content: Moving from OpenWrt 19 to 21. In brief, the next stable release includes changes to the network configuration syntax that are incompatible with this guide. Once the release version 21 becomes the current stable, however, I will update the main guide to reflect those changes. In the meantime, I added a few references to the OpenWrt forum that should help anyone interested in using version 21 instead of 19. Thanks to Steve for testing and sharing his batman-adv configuration running on OpenWrt 21.

Feb 17th, 2021: Per a reader’s suggestion (Joshua), I added a vi cheat table that has a summary of the main commands, and in the Mesh node basic config section, I included additional instructions on how to copy and paste the configuration files from one mesh node to another using scp. (Alternatively, it’s also possible to do so using Luci’s backup/restore option.)

Jan 9th, 2021, Update #2: Added instructions on how to automatically upgrade all installed packages with a single command. This information is in Updating and installing packages.

Jan 9th, 2021, Update #1: Added a new section about hardware-specific configurations that are sometimes required for enabling the mesh point mode of operation.

Dec 7th, 2020: Publication of the original guide



In this tutorial, we will learn how to create mesh networks (IEEE 802.11s) using OpenWrt and the layer-2 implementation of the Better Approach to Mobile Adhoc Networking, called batman-adv. All the software mentioned here is free and open-source, as opposed to commercial alternatives (UniFi Mesh or Google’s Nest Wifi).

This is not meant to be an exhaustive presentation of any of the covered topics. If you have suggestions on how to improve this guide, feel free to get in touch with me. I’m always eager to learn new things and share them. Also, I plan on updating this article every once in a while to best reflect my knowledge about the topics covered here and to add information provided by the readers. Check the changelog for updates.


Why am I writing this guide?

Even though the concept of mesh networking has been around for quite some time now, the documentation of its implementation is still scarce/nichey, proprietary, or outdated. I don’t feel qualified to speculate on why this is so but I find it odd because many of the radio devices found in popular wireless routers actually support mesh networking–but the original firmware rarely supports it.

My intention with this tutorial is to help closing the gap between concept and implementation of mesh networking using up-to-date software that anyone can download and install on cheap, commonly available hardware–primarily consumer wireless routers (from old to new, single- or multi-band) but the principles should be extendable to any cellphones, laptops, PCs or servers running Linux. The content is partially based on my own experience and builds upon the work of other, much more talented individuals who shared their knowledge on the Web. More specifically, the content is notably influenced by the following:



  1. Get familiar with /etc/config/ files in OpenWrt devices (namely, wireless, network, dhcp, firewall) to quickly and permanently configure mesh nodes.
  2. Edit files directly from the terminal using the default text editor vi.
  3. Configure OpenWrt devices to play one of three possible roles in the network: (a) mesh node, (b) mesh + bridge node, or (c) mesh + gateway node.
  4. Install and configure the Kernel module batman-adv on an OpenWrt device using the opkg package manager.
  5. Use batctl to test, debug, and monitor connectivity within the mesh.
  6. Add encryption to the mesh network with the package wpad-mesh-openssl.
  7. Use VLANs to create default, iot, and guest networks within the mesh using batman-adv.



From this point forward, the article is divided into four main parts:

  1. Concepts and documentation: Optional for advanced users. Brief introduction to just enough network concepts to allow the implementation of simple mesh networks. When appropriate, a link to the relevant OpenWrt documentation was also provided.
  2. Hardware: Optional for everyone. A few notes about the hardware used in the examples and recommendations for those who are planning on buying new/used devices for their mesh project.
  3. Software: Optional for everyone. A few notes about the software used in the examples.
  4. Implementation: Required. Step-by-step procedure to configure mesh nodes, bridges, and gateways. It goes from flashing OpenWrt to configuring VLANs with batman-adv. You probably came here for this part.


Concepts and documentation

Main network definitions

  • Mesh node: Any network device that is connected to the mesh network and that helps routing data to (and from) mesh clients. Here, however, if a mesh node acts as a bridge or gateway, it will always be referred by the latter role, even though by definition, mesh bridges and mesh gateways are also mesh nodes.
    In addition, even though it’s possible to route mesh traffic via cable, in this tutorial, all mesh nodes are also wireless devices, meaning that they have access to a radio with mesh point (802.11s) capabilities.
  • Bridge: A network device that joins any two or more network interfaces (e.g., LAN ethernet and wireless) into a single network. Here, when a device is referred to as a bridge, it means that in addition to being a mesh node, the only other thing it does is bridge interfaces. But of course, a gateway device, such as a router with a built-in modem, or a firewall appliance, may also work as a bridge for multiple interfaces. The distinction in the examples is just used to highlight its main role in the network. Therefore, a mesh bridge in this tutorial is a mesh node that simply bridges the mesh network with a WiFi access point for non-mesh clients, for example, or its LAN ports.

  • Gateway: A network device that translates traffic from one network (LAN) to another (WAN) and here, acts as both a firewall and DHCP server. (If there’s more than one DHCP server in the same network, they assign IPs to different ranges, such as .1-100, .101-200, and so on.)
  • DNS: In brief, a system for translating domain names (e.g., into IP addresses (,,, DNS filtering systems, such as PiHole, work by catching such requests–usually sent through port 53–and checking if the domain is blacklisted or not. In this tutorial, we will always use an external DNS server, such as (Cloudflare) or (Google), but if you have your own DNS resolver, feel free to use it instead when configuring your mesh network but then make sure the mesh network/VLAN has access to its address.

  • DHCP: An IP management system that dynamically assigns layer-3 addresses for devices connected to a network. For instance, it might dynamically assign IPs between and (i.e., to any devices connected to LAN. Of note, because this is a network layer protocol, it uses IP addresses, whereas batman-adv uses MAC addresses because it works at the data link layer (and therefore, batman-adv actually doesn’t need DHCP and IPs to discover and manage mesh clients but we’re going to use them to make it more intuitive and easier to integrate mesh with non-mesh clients).
  • Firewall: A network system that monitors and controls network traffic, such as specifying rules for incoming WAN traffic (e.g., deny all), outgoing LAN traffic (accept all), geoblocking and IP filtering systems, intrusion prevention/detection systems (Suricata), and so on. OpenSense and pfSense are examples of dedicated firewall software. If a mesh node is acting as a mesh gateway, it’s imperative to configure the firewall or your mesh network will likely end up without access to external networks (e.g., WAN) and their services (e.g., DNS servers).
  • VLAN: A virtual LAN that is partitioned and isolated in a network at the layer-2 level. They are often followed by an integer to differentiate each other (e.g., VLAN 1, VLAN 50) and used to better manage network clients that belong to different groups (e.g., administrators, IoT devices, security cameras, guests).

Network topologies

Mesh networks

What are mesh networks?

Where can I learn more about mesh networking?

Routing protocols

There are dozens of algorithms for routing packets in a mesh network. A few notable ones are the Optimized Link State Routing (OLSR) and the Hybrid Wireless Mesh Protocol (HWMP).

In this tutorial, however, we will cover only one of them, called Better Approach to Mobile Adhoc Networking (B.A.T.M.A.N.), because it has long been incorporated into the Linux Kernel and is thus easily enabled on Linux devices. It is also a fairly well-documented algorithm that has been continuously improved over the years. Another noteworthy feature of batman-adv is its lack of reliance on layer-3 protocols for managing mesh clients because it works at the layer-2 and its ability to create VLANs. Think of it as if it were a big, smart, virtual switch, in which its VLANs are port-based segmentations. If you want an interface to use a particular mesh VLAN, just “plug it” into the approriate port of the batX switch (e.g., bridge if-guest and bat0.2 to give the guest network access to the bat0 VLAN 2).


As mentioned before, B.A.T.M.A.N. has gone through multiple changes over the years, which means that there are actually multiple versions of the algorithm. I’ve had a good experience with B.A.T.M.A.N. IV and therefore, the examples here make use of it. However, you are free to try whatever version you want and even run them in parallel to each other, by assigning a different batX interface to each version of the algorithm (versions are chosen with option routing_algo in the /etc/config/network config file for each enabled batX interface).

Config-wise, there’s very little to do because the default settings should work very well in most environments. One exception is when you have multiple gateways in the network to provide high availability, for example, and you might want to let each mesh node know about them and their speeds to better route the mesh traffic. This requires setting option gw_mode to server or client, for example. Many other tweaks that are not covered here are described in their wiki.


Another very cool feature of B.A.T.M.A.N. is the ability to test, debug, monitor, and set settings with the package batctl. A few noteworthy options:

  • Ping mesh node/client with its MAC address f0:f0:00:00:00:00
    batctl p f0:f0:00:00:00:00
  • tcpdump for all mesh traffic in the bat0 interface
    batctl td bat0
  • Prints useful stats for all mesh traffic, such as sent and received bytes
    batctl s
  • Shows the neighboring mesh nodes
    batctl n
  • Displays the gateway servers (option gw_mode 'server') in the mesh network
    batctl gwl

It goes without saying that if you want to dive deep into batman-adv, you should take a good look at batctl, too.



Unless otherwise specified, all mesh nodes used in the various implementations had the following hardware:

TP-Link 1043nd

This was mainly a matter of convenience–I had a few lying around and they are very, very cheap–and because the examples in the OpenWrt documentation often refer to them as well, so the community support is good.

However, the general ideas presented here should apply to any wireless device that meets the following criteria:

  1. Compatible with the latest OpenWRT version. Refer to their Hardware List;
  2. Has access to a radio that supports the mesh point (802.11s) mode of operation. If you already have OpenWrt installed on a wireless device, you can type iw list and search for mesh point under Supported interface modes, or simply check if the following command outputs * mesh point below the name of a detected radio (e.g., phy0, phy1):

    iw list | grep -ix "^wiphy.*\|^.*mesh point$"

    If it does, then the associated radio can be configured as a mesh point.

Now, if you’re looking for devices to buy and experiment on, my suggestion is to look for dual-band wireless routers to allow a better segmentation of the wireless networks. If you can afford spending more for a mesh node, look for tri-band devices. Netgear and Linksys have solid options that are compatible with OpenWrt. For example, the Linksys WRT1900AC (v1/v2) dual-band wireless router would make for a good mesh node:

Linksys WRT1900AC

For single-board computer (SBC) fans like me, you can run OpenWrt with most of them and then use a combination of on-board wireless and USB adapter to create a powerful mesh node. ClearFog boards with one or two mini PCIe wireless cards would make very good candidates for such a project, for example:

ClearFog Pro

Of course, you can install OpenWrt on bare metal x86-64 machines (e.g., standard PC or server running Intel/AMD), which will give you lots of options to put together an impressive mesh device. However, if you just want your work/home laptops/PCs to be part of the mesh (i.e., become a mesh node), there are better alternatives than installing OpenWrt as its OS. For example, you can run OpenWrt with a virtual machine or as a docker container. Naturally, it’s also possible to configure batman-adv on Linux distributions other than OpenWrt, such as Arch, Debian, and Ubuntu. See Getting started with batman-adv on any Linux device.

As mentioned before, even if the existing/on-board radio of your SBC/laptop/PC/server does not support the mesh point mode of operation, you can always buy a compatible PCIe card or USB adapter to turn your device into a mesh node and then use the other radio for another purpose. For example, many Alfa Network adapters can operate in mesh point mode, like the cheap AWUS036NH:

Alfa AWUS036NH

All that said, most home users will be just fine with a cheapo, used, old, single-band router. For a brand reference, TP-Link has good and affordable devices that can be used in a mesh networking project without issues. If you’re new to this, start from here (small, simple) and think about efficiency over power. You don’t need to drive a Lamborghini to get a snack at the grocery store.

Hardware-specific configurations

Every once in a while, I run into hardware that is capable of operating in mesh point mode but the default OpenWrt firmware uses a module for the wireless adapter that is loaded with incompatible parameters. Here is a list of a few of the known ones and their solution.

ath9k modules

If your device uses the ath9k module, there’s a chance that you’ll need to enable the nohwcrypt parameter of the module to use the mesh with encryption. First, however, try without changing the default module parameters. After rulling out possible typos in the network and wireless configuration files, try the following:

  1. Edit the /etc/modules.d/ath9k file and add nohwcrypt=1 to it. If there’s something in the file, use a whitespace to separate parameters.
  2. Save the file, and reboot your device.
  3. Once the device comes back, check if nohwcrypt is now enabled by typing
    cat /sys/module/ath9k/parameters/nohwcrypt

    If nohwcrypt is enabled, the output will be 1; otherwise, it will be 0.

  4. Check your mesh configuration once again and add encryption to your wireless mesh stanza.
  • Known affected devices:

    brand model version
    TP-Link WR-1043-ND 1.8

ath10k modules

I’ve noticed that radio devices that use the ath10k module and more specifically, the ones using ath10k-firmware-qca988x-ct, are not able to operate in mesh point mode by default. If you check the syslog, you’ll notice that there will be a few messages stating that the ath10k module must be loaded with rawmode=1 to allow mesh. However, I’ve tried that before without much success. Instead, my current recommendation to get mesh point working with the QCA988x is the following (Internet connection required to download packages via opkg):

  1. Remove the Candela Tech (*-ct) modules as follows:
    opkg remove ath10k-firmware-qca988x-ct kmod-ath10k-ct
  2. Install the non-ct modules:
    opkg update && opkg install ath10k-firmware-qca988x kmod-ath10k
  3. Reboot your device and then check the status of your mesh network.
  • Known affected devices:

    brand model version
    TP-Link Archer C7 2.0
    TP-Link Archer C7 (US) 2.0



Unless otherwise specified, all mesh nodes were running the following software:

OpenWrt default SSH welcome

To find out the version of all installed packages, type

opkg list-installed

or if you prefer to filter the output, use grep. For example, the following will show the version of all installed packages containing bat (e.g., batctl, kmod-batman-adv):

opkg list-installed | grep bat

Huge differences in firmware, kernel, or package versions might make the implementation of a mesh network a little bit different than the way it was explained here. Of note, devices running the batman-adv version 2019.0-2 and older are certainly incompatible with the instructions found in this tutorial, the reason being that the module was modified after then to better integrate with the network interface daemon. Fortunately, the implementation using old modules is just a simple as with the latest one. Check what the B.A.T.M.A.N. wiki has to say about it. However, it’s worth mentioning that with old batman modules, changes to /etc/config/network will likely require a reboot instead of simply reloading /etc/init.d/network.

Also, I’ve noticed that when installing kmod-batman-adv, the package manager will install a minimal version of batctl, called batctl-tiny, that lacks some of the options mentioned here (e.g., batctl n and batnctl o). However, if you install batctl first and then kmod-batman-adv, the package manager will preserve batctl-default, which is the package used in this tutorial and that has all the options referred to in the batctl man page.

Finally, the installation of wpad-mesh-openssl will conflict with the already installed wpad-basic package. This means you have to remove the latter before installing the former. To remove the wpad-basic package, simply type

opkg remove wpad-basic

VI text editor

The default text editor in a standard OpenWrt image is vi, which is an old, screen oriented editor that most modern users will find counterintuitive to use. Fortunately, once you get the hang of it, vi becomes very easy to use and it becomes a very convenient way of editing config files. Here’s all that you need to know about using vi in a terminal:

You can open a file by adding the filename as an argument to vi, as follows

vi /etc/config/network

and if the file does not exist, vi will create one with that name.

By default, vi will start in command mode. Such a mode let’s you navigate the file with the arrow keys and use the delete button to delete characters. (Also, in command mode, you can type dd to delete entire lines, which is very useful if you need to delete lots of things quickly.)

However, if you need to type characters and have more flexibility to edit the file, you need to tell vi to enter insert mode. To enter insert mode, type (no need to hit return/enter afterwards)


and at the bottom of the screen, you will see that it now shows a I to indicate that vi is in insert mode. You can now type freely and even paste multiple things at once in insert mode.

When you’re done, press the button Esc to go back into command mode. Notice that at the bottom of the screen, now there’s a - where the I was, which tells you you’re in command mode once again.

In command mode, you can then write changes to the file by typing (followed by return/enter)


Now you’ve saved the file. To quit, type


Alternatively, you can write and quit by simply typing :wq.

vi has other commands as well but honestly, that’s pretty much all that you need to know about vi in order to use in the examples covered here. Give it a try!

VI cheat table

mode key/command action
command i key Enter insert mode
insert Esc key Return to command mode
command dd (or hold d key) Erase entire row
command :w + Enter/Return Write to file
command :q + Enter/Return Quit to terminal
command :q! + Enter/Return Quit without saving changes
command :wq + Enter/Return Write to file and quit

Alternatives to VI

Now, if you still don’t like to use vi, you can always transfer files from your laptop/PC to OpenWrt via sftp, for example, or utilities like scp.



In this section, we will see how to configure four mesh nodes in three different network topologies. More specifically:

  • Gateway-Bridge: A mesh network in which one node plays the role of a mesh gateway and another, of a bridge, while the remaining are just mesh nodes. This is a very typical scenario for a home or small office, for example.

Topology - Gateway-Bridge

  • Bridge-Bridge: Two nodes play the role of a bridge, therefore making the mesh network transparent to the external (non-mesh) networks.

Topology - Bridge-Bridge

  • Gateway-Gateway: Two nodes play the role of a gateway to provide high-availability to mesh clients/nodes.

Topology - Gateway-Gateway

First, however, we will start with the aspects that are common to all topologies, such as planning the mesh network, and the installation and basic configuration of OpenWrt mesh nodes. Then, we will move to the specifics of each of the aforementioned mesh network topologies. Finally, we end the section with a slightly more complex scenario to illustrate how to create mesh VLANs with batman-adv and a very brief introduction to using batman-adv on other Linux distros.

Topology - Mesh VLANs

Even though the examples show static nodes, none of the mesh nodes need to be static. The mesh network and its components can be partially or totally mobile. For example, if some of your nodes are mobile units (e.g., vehicles, drones, robots, cellphones, laptops), they can leave and join the mesh, recreate the mesh elsewhere, join a completely different mesh, and so on. The routing algorithm (batman-adv) will automatically (and seamlessly) take care of changes to the network topology. (But of course, if there’s a single gateway and it does not reach any node, the network is bound to stop working as intended without proper configuration to handle such scenarios.)

Topology - Moving nodes


Just like any other type of network, deploying a mesh network–especially over large areas, with dozens of nodes–requires a fair deal of planning; Otherwise, you are bound to experience, for instance, bottlenecks, uneven access point signal quality, and unstable WAN connectivity across the mesh. Also, features like high availability go well beyond the configuration and topology of a mesh network (e.g., power source, whre your WAN connections are coming from, and the hardware you are using all play important roles when it comes to high availability). Mesh networks are very, very easy to scale but planning is key.

Eli the Computer Guy has an old video about mesh networks that goes into things like high availability and bottlenecks. If that matters to you, take a look. The relevant content starts at 03:30 and ends at 17:30, approximately.

The examples in this tutorial are simple by design–they were created to illustrate different scenarios in a way that makes it easy to understand what is going on. The idea is to use the examples as templates for more complex implementations.

OpenWrt installation and initial configuration

Now that you have the hardware, the first thing to do is to install OpenWrt. Flashing a default OpenWrt image onto a compatible device is a very easy and safe procedure because it’s been tested multiple times. (For extra safety precautions, you might want to search the Web for your device + OpenWrt to see if there’s any indexed forum post or comment regarding installation issues and bugs, for example.)

If you’re new to this, the folks at OpenWrt were kind enough to provide a plethora of instructions on how to install and uninstall OpenWrt and even put together an installation checklist. At the very least, do the following:

  1. Look for your device’s model and version in the Table of Hardware and open its Device Page (e.g., TP-Link TL-WR1043ND);
  2. Double check that the model and version match your device’s model and version in the Supported Versions table;
  3. In the Installation table, you will find a column called Firmware OpenWrt Install URL and another one called Firmware OpenWrt Upgrade URL. If your device is still running the original firmware, then download the binary from the Firmware OpenWrt Install URL column; otherwise, download the binary from the Firmware OpenWrt Upgrade URL column. Both files should have a .bin extension;
  4. Regardless of the binary file downloaded, verify its checksum afterwards;
  5. Disconnect your laptop/PC from any access point or switch, and connect your laptop/PC directly to the device’s ethernet port.
  6. Open your device’s web UI, go to its Settings and/or find the Firmware Upgrade option. Then, select the downloaded OpenWrt binary, and let it do its thing. Once it’s done, the device will reboot with OpenWrt installed. (You should be able to reach it at if connected to a LAN port.)

If you can reach the OpenWrt web UI, then you’ve successfully installed OpenWrt and it’s now time to configure it.

Initial configuration

As mentioned before, we will not use the web UI in this tutorial, even if the OpenWrt image you’re using has LuCI installed by default. Instead, we will access our device and configure it using only SSH. So, open a terminal and ssh into your OpenWrt device, as follows

ssh root@

in which is your OpenWrt device’s IP address (that’s usually the case after a fresh install but if it’s different, use the proper IP then). Because this is the first time using the system, you’ll need to set a password for the root user. You can do that by typing


and following the instructions. At this point, it’s good practice to label this device (e.g., node01) and take note of its MAC address. To find out the latter, type

ip link

and keep a record of the device’s name and its MAC address–if there are multiple different addresses, take note of all of them and their interface.

(Optional: Configure key-based authentication and disable password login. Reboot and check that ssh access methods are correctly configured.)

From this point forward, we will start editing files using vi. If you’ve not read the section about how to use vi yet, this is a good time to do so.

Default config for the hardware

Regardless of the hardware, before doing anything related to the mesh network, always take your time and study the default configuration found in /etc/config/. For reference, I usually go over the following:

  • How many ethernet ports?
  • Are they labeled either LAN or WAN or there’s both?
  • In /etc/config/network, how is the router handling multiple ethernet ports? If there’s both LAN and WAN, how is the router separating LAN from WAN?
  • If there is both LAN and WAN, how is the firewall handling them in /etc/config/firewall? (Probably two zones, LAN and WAN, with LAN->WAN accept all but WAN->LAN deny all?)
  • In /etc/config/dhcp, how is the device handling IP addresses? (Is there a DHCP server for LAN?)

And finally, look at the wireless settings (/etc/config/wireless):

  • How many radio devices and their names? (e.g., radio0)
  • Configuration-wise, what is the device using by default vs. what is it capable of? (iw list)
  • Is the radio enabled or disabled? (Keep/add option disabled 1 to disable it before configuration; to re-enable, simply comment this line out or set the value to 0.)
  • Are there pre-configured wireless access points being broadcast? If yes, which option network is it using by default? (Likely lan or whatever the LAN interface is being called in /etc/config/network.)

For example, many wireless routers, including the TP-Link WR1043ND, have LAN and WAN ports which are handled by a switch configuration with VLANs enabled to separate LAN from WAN. Take note of it; understand what is going on in the config files; play with them; then, continue. Also, take this opportunity to go over the Device Page to check if there’s any warnings or special configuration notes (e.g., warnings and gotchas with the 1043ND).

This understanding is instrumental to the way the device will be configured to play different roles in the mesh network and a good grasp of the device’s default settings will greatly reward you later on.

Updating and installing packages

(Only experienced users: If you used a default image, this is a good opportunity to remove unnecessary packages. See the OpenWrt FAQ for a reference of safe to remove packages, for example. If this is your first time playing with mesh, leave any unmentioned pkg alone until you get everything working as intended.)

In order to update and install packages, you need to give your device temporary access to the Internet. More often than not, if you have an existing network with access to the Internet on-site, then just connect the device to a router/switch via cable. If that doesn’t work, go ahead and configure your device to act like a dumb access point first. You can check that the device has access to the Internet by pinging or, as follows


If it all looks good, it’s time to update the package list, as follows

opkg update

Optional. Upgrade all installed packages. Type opkg list-upgradable to find which packages can be upgraded and then opkg upgrade PKG, in which PKG is the package name. If opkg list-upgradable run into memory issues, try commenting out a few lines in /etc/opkg/distfeeds.conf and try again. Alternatively, it’s possible to use the following command to automatically upgrade all packages at once, per the opkg openwrt wiki examples:

opkg list-upgradable | cut -f 1 -d ' ' | xargs opkg upgrade

Be careful with mass upgrades though, especially if you’re running a device with limited memory. You might end up even bricking your device.

Now, let’s install the mesh-related packages and remove conflicting packages. First, remove wpad-basic with

opkg remove wpad-basic

then install batctl, batman-adv, and wpad-mesh-openssl with

opkg install batctl kmod-batman-adv wpad-mesh-openssl

Make sure there are no error messages and if there are, troubleshoot them before proceeding.

Remove the connection that gave your device temporary access to the Internet. Then, reboot (type reboot in the terminal) and restart the SSH session with your laptop/PC still connected to the device via cable.

If you’re using the TP-Link WR1043ND v1.x in your mesh project, take a look at my previous note about the ath9k module in the hardware section. In brief, if you have issues running the mesh with encryption, then you have to enable the nohwcrypt parameter of the ath9k module.

Mesh node basic config

It is time to configure the basics of our mesh network and nodes. To do so, we will edit multiple files in /etc/config/ but first, let’s find out the capabilities of the detected radios in our wireless device, as follows

iw list

which will output something like this

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 AP-side u-APSD.
	Device supports T-DLS.
	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: 0x104e
			SM Power Save disabled
			RX HT40 SGI
			Max AMSDU length: 3839 bytes
		Maximum RX AMPDU length 65535 bytes (exponent: 0x003)
		Minimum RX AMPDU time spacing: 8 usec (0x06)
		HT TX/RX MCS rate indexes supported: 0-15
			* 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)
	valid interface combinations:
		 * #{ managed } <= 2048, #{ AP, mesh point } <= 8, #{ P2P-client, P2P-GO } <= 1, #{ IBSS } <= 1,
		   total <= 2048, #channels <= 1, STA/AP BI must match, radar detect widths: { 20 MHz (no HT), 20 MHz, 40 MHz }
	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
	Supported extended features:
		* [ RRM ]: RRM
		* [ CQM_RSSI_LIST ]: multiple CQM_RSSI_THOLD records
		* [ CONTROL_PORT_OVER_NL80211 ]: control port over nl80211
		* [ TXQS ]: FQ-CoDel-enabled intermediate TXQs

Here, we are particularly interested in

  • the supported modes of operation, and more specifically, that the device is indeed able to operate in mesh point mode (it is), as shown under Supported interface modes:;
  • the total number of bands (only one band, Band 1);
  • then for each band
    • the possible htmode (supports htmode 'HT20' and htmode 'HT40'), as shown in HT20/HT40, under Capabilities:;
    • the acceptable channels (from channel '1' to channel '13'), as shown under Frequencies:.

With such information, we can now configure our radio devices in /etc/config/wireless, as follows

vi /etc/config/wireless

and then edit each config wifi-device accordingly. In the 1043ND, there’s only one wifi-device and my config looks like the following

config wifi-device 'radio0'
        option type 'mac80211'
        option channel 3
        option hwmode '11g'
        option path 'platform/ahb/180c0000.wmac'
        option htmode 'HT20'
        option country 'BR'

If this radio device will be used for the mesh traffic, make sure all mesh nodes use the same channel. However, if the radio will be used as an access point for non-mesh clients, use a different channel than the mesh channel. In addition, for HT20/HT40 devices, stick to HT20 if you are deploying the mesh in a crowded area, such as an apartment building; otherwise, the interference might make HT40 actually slower than HT20. Finally, remember to edit the country code before enabling the radio.

Comment out any config wifi-iface automatically generated after a fresh install by adding a # at the beginning of each line, as follows

#config wifi-iface 'default_radio0'
#        option device 'radio0'
#        option network 'lan'
#        option mode 'ap'
#        option ssid 'OpenWrt'
#        option encryption 'none'

Then, at the end of the file, let’s add a wifi-iface for the wireless mesh, called wmesh, as follows

config wifi-iface 'wmesh'
        option device 'radio0'	#must match the name of a wifi-device
        option ifname 'if-mesh'	#name for this iface
        option network 'mesh'	#mesh stanza in /etc/config/network
        option mode 'mesh'		#use 802.11s mode
        option mesh_id 'MeshCloud'	#like an ssid of the wireless mesh
        option encryption 'sae'	#
        option key 'MeshPassword123'	#mesh password if encryption is enabled
        option mesh_fwding 0	#let batman-adv handle routing
        option mesh_ttl 1		#time to live in the mesh
        option mcast_rate 24000	#routes with a lower throughput rate than the mcast_rate will not be visible to batman-adv
#       option disabled 1		#uncomment to disable

The comments are just for educational purpose. Feel free to remove them in your device’s config file.

Because all mesh nodes must operate on the same channel, use the same authentication, etc., multiple config options are often dictated by the “lowest common denominator” across all mesh nodes–that is, the best possible config that will work with all nodes, not just the ones with the best hardware and software available. For example, not all devices will necessarily be able to use SAE because it’s very new and therefore, won’t be able to connect to mesh networks that use it. Instead, you might want to set encryption to something like psk2+aes, which should be good enough for most devices out there. So, keep that in mind when configuring your mesh nodes.

Save the file and exit it.

Now we need to configure /etc/config/network to allow wmesh to use batman-adv. To do so, edit the network file, as follows

vi /etc/config/network

and let’s add an interface called bat0 at the bottom of the file, as follows

config interface 'bat0'
        option proto 'batadv'
        option routing_algo 'BATMAN_IV'
        option aggregated_ogms 1
        option ap_isolation 0
        option bonding 0
        option bridge_loop_avoidance 1
        option distributed_arp_table 1
        option fragmentation 1
        option gw_mode 'off'
        option hop_penalty 30
        option isolation_mark '0x00000000/0x00000000'
        option log_level 0
        option multicast_mode 1
        option multicast_fanout 16
        option network_coding 0
        option orig_interval 1000

which has options with (mostly) default values to facilitate fine-tuning later on. (For more details, refer to the Protocol Documentation and more specifically, the Tweaking section.) Then, at the bottom of the same file, let’s add an actual network interface to transport batman-adv packets, which in our case will be the network used by wmesh in the /etc/config/wireless config file, namely mesh, as follows

config interface 'mesh'
        option proto 'batadv_hardif'
        option master 'bat0'
        option mtu 2304
        option throughput_override 0

Save the file and exit.

Next, let’s reboot the device (type reboot in the terminal) and once it comes back online, ssh into it once again because we want to check that our batman-adv interfaces are up. To do so, type

ip link | grep bat0

and if the config is right, you should now see bat0 and if-mesh in the output. Similarly, we can use batctl to show us all active interfaces, as follows

batctl if

If it all looks good, exit the ssh session, disconnect your laptop/PC from the wireless device (but keep it running nearby), and go ahead and configure at least one other node. This can be done manually just like you’ve just configured the current node. However, if your other mesh nodes are identical to the one you have already configured–that is, it is the same brand, model, and it is running the same OpenWrt version–then you can simply copy the modified files and then paste them on the /etc/config/ dir of the new device. To copy all such files from the configured device to your laptop/PC current directory, you can use scp, as follows:

scp -r root@IP_MESH_NODE:/etc/config ./

which should create a config dir on your laptop/PC that has all the config files from the already configured device. Then, it’s just a matter of doing the reverse process on the unconfigured devices:

scp -r ./config/* root@IP_NEW_MESH_NODE:/etc/config/

Because we’re starting SSH sessions with different machines using the same IP addr (, it’s quite possible that your SSH client will complaint about the authenticity of the host at To get rid of this message, simply remove the relevant entry in your user’s known_hosts file or delete it altogether. On Linux distros, such file can be found at ~/.ssh/known_hosts–that is, the ssh folder for your current user.

Afterwards, ssh into one of the configured mesh nodes and type

batctl n

which will show a table with the interfaces (if-mesh), MAC address of the neighboring mesh nodes, and when each of them was last seen. Copy the MAC address (e.g., f0:f0:00:00:00:01) from each neighboring mesh node and ping them through the mesh (using batctl p) to see if they are all replying, as follows (press Ctrl+C to stop)

batctl p f0:f0:00:00:00:01

which should output something like the following if everything is working fine

PING f0:f0:00:00:00:01 (f0:f0:00:00:00:01) 20(48) bytes of data
20 bytes from f0:f0:00:00:00:01 icmp_seq=1 ttl=50 time=3.01 ms
20 bytes from f0:f0:00:00:00:01 icmp_seq=2 ttl=50 time=1.71 ms
20 bytes from f0:f0:00:00:00:01 icmp_seq=3 ttl=50 time=1.10 ms
--- f0:f0:00:00:00:01 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss
rtt min/avg/max/mdev = 1.103/1.942/3.008/0.794 ms

Pat yourself on the back because you have successfully configured multiple mesh nodes!

Go ahead and configure all your mesh nodes the same way as before and only then move on to bridges, gateways, and VLAN configs, as described next.

(Optional: This is a good time to tweak the mesh configuration as well.)

Troubleshooting mesh issues

These are a few tips in case you run into issues when configuring gateways and bridges.

To test node to node connectivity, connect to a mesh node and use

batctl p MAC

in which MAC is another node’s MAC address. If the node does not reply, there’s an issue with batman-adv or its configuration. Try rebooting both nodes before doing anything else.

A more powerful tool to see what is going on in the mesh network is the tcpdump utility for batman-adv. To use it, connect to a mesh node and type

batctl td batX

in which batX is a batman-adv interface (usually bat0 but if you have more than one, then bat1, etc.). This is quite useful when configuring VLANs because it will show the VLAN ID of each client as well. In addition, it is possible to specify the VLAN ID in the td argument to constraint the output to one particular VLAN (e.g., batctl td bat0.1). Depending on the scale of your mesh network, you might need to filter the output because things can get wild with tcpdump really fast.

For more details, see the batctl man page.

Finally, if you’ve been following my suggestion to name and take note of each device’s MAC address, you can create a file called bat-hosts in /etc/ that contains pairs of MAC address and name, as follows

f0:f0:00:00:00:00 node01
f0:f1:00:00:00:00 node02
f0:f2:00:00:00:00 node03
f0:f3:00:00:00:00 node04

which makes it much easier to identify the mesh nodes when issuing a command like batctl n and other debug tables. As far as I’m aware, however, you have to create and update such file in each node because such information will just be available to nodes that have a bat-hosts file.

Configuring common mesh networks

Here, we will see how to turn one or two of our configured mesh nodes into either a mesh bridge or a mesh gateway. To avoid repetition, the configuration of bridges and gateways is described in more detail in the first example, and only a few small differences and observations are highlighted afterwards. In addition, only IPv4 addresses and configurations were used but nothing prohibits the use of IPv6 in a mesh network.


This first example applies to the following topology:

Topology - Gateway-Bridge

More specifically, the mesh has access to the WAN (Network A) via a gateway device and has a single, private network defined in the IP range, which is used by both the mesh network devices and the Network B, non-mesh devices. The latter is enabled by a bridge device that works as an access point for non-mesh clients.

First, let’s configure our mesh gateway.

Mesh gateway configuration

Get one of the pre-configured mesh nodes that has at the very least two ethernet ports, a LAN port and a WAN port. (This, of course, is not required for a gateway device because there are multiple ways to connect to WAN but having separate physical ports makes the explanation much simpler to follow. If that is not your case, just adapt to whatever interfaces you have configured that play the role of default lan and wan.)

If you’ve configured this node as a dumb access point to temporarily give it access to the Internet while updating and installing packages, undo the configuration before proceeding because we will use both the firewall and dhcp config files in the gateway configuration.

Connect your laptop/PC to the mesh node via cable using the LAN port–this way, the mesh node’s IP address should still be Then, ssh into the mesh node and let’s take a look at the /etc/config/network, as follows

vi /etc/config/network

At the beginning of the file, there should a bunch of config interface for loopback, lan, and wan, for example, and at the end, there should be the mesh interfaces we previously created for the mesh node, namely bat0 and mesh. There are at least two options at this point:

  1. Create an entirely new lan interface for bat0 (e.g., lan_bat0), at the expense of additional dhcp and firewall configuration;
  2. Or use the existing, default lan interface by simply bridging lan and bat0.

While the latter option is much easier than the former, we will choose the first here (i.e., create a new lan from the ground up) because it makes this tutorial compatible with multiple devices (switched or switchless) and it allows us to keep the default lan ( as a management/debugging network. (Later on, we will see how to bridge the default lan with any bat0 VLAN, for example, so the default lan becomes accessible to the mesh as well. For now, keep it simple.)

At the bottom of the /etc/config/network file, let’s add the following lan_bat0 configuration

config interface 'lan_bat0'
#        option type 'bridge'	#uncomment if bridging in ifname as well
        option ifname 'bat0'
        option proto 'static'
        option ipaddr ''	#static addr for this gateway on the net
        option netmask ''
#        list dns ''	#uncomment to enable cloudflare dns server instead
        list dns ''	#google dns server

Save the file and exit it.

Next, let’s edit the /etc/config/dhcp config to run a DHCP server on the new interface, as follows

vi /etc/config/dhcp

and at the end of the file, add the following

config dhcp 'lan_bat0'
        option interface 'lan_bat0'
        option start 50		#start leasing at addr
        option limit 100		#max leases, so for 100, leased addr goes from .50 to .149
        option leasetime '3h'
        option ra 'server'

Save the file and exit it.

Finally, let’s edit the /etc/config/firewall config. Many things that can be done at the firewall level and for this reason, it’s often the most overwhelming part of the configuration. Fortunately, in our case, all that we need to do here is simply copy the default lan config for the new lan_bat0. That is, anything that has lan we will

  1. copy the related config;
  2. paste it immediately below the equivalent default lan config;
  3. and then change lan for lan_bat0 in the new config.

Start by editing the firewall config file with vi, as follows

vi /etc/config/firewall

then the first set of configs we will add (immediately below the equivalent lan config) is the zone settings, namely

config zone
        option name     lan_bat0
        list network    'lan_bat0'
        option input    ACCEPT
        option output   ACCEPT
        option forward  ACCEPT

the second set of configs will be for the forwarding settings, namely

config forwarding
        option src   lan_bat0
        option dest  wan

and that is it!

(Optional: At the end of the firewall config file, there’s a bunch of examples that you could use as template for more avdanced usage of this device’s firewall. Feel free to play around with them once you get everything up and running.)

Save the file and exit it.

(Optional: Because we’re not going to use IPv6, I suggest disabling odhcpd, as follows

/etc/init.d/odhcpd stop && /etc/init.d/odhcpd disable

and you could also comment out any related config in the files we just edited.)

Reboot the device and connect the WAN cable to the device’s WAN ethernet port.

Once the device comes back online, ssh into it. Then, let’s check the new configuration. First, type

ip a | grep bat0

and as before, there should be bat0 and if-mesh interfaces, but now, your gateway device should have the static IP in the new network under the bat0 interface. (Of note, if you enabled the option type 'bridge' in the lan_bat0 stanza, then there should be an additional br-lan_bat0interface now because OpenWrt adds a br- prefix to bridges, and your device’s static IP should be associated to it instead of the bat0 interface.)

In addition, because we preserved the default lan configuration, the device will continue to have the static IP and should always be reachable there with an ethernet cable directly connected to one of its LAN ethernet ports.

If you don’t see the static IP on the new network, then review the files we have just configured because there’s likely a misconfiguration. Don’t expect to get things working until you fix this issue.

Mesh bridge configuration

The configuration of a mesh bridge is much simpler than of a mesh gateway because contrary to the gateway config, our mesh bridge doesn’t require the use of a DHCP server and firewall. In fact, both services will be disabled in a mesh bridge and instead, the ony thing we will do is join interfaces to make them look like a single one to any connected device.

As before, get one of the other pre-configured mesh nodes and to start things off, we will configure it as a dumb access point. Follow the instructions in the OpenWrt documentation, except for the following when configuring the default lan interface

  • add bat0 to the list of ifname;
  • set a static IP for the device on the network, such as, pointing to our gateway at;
  • the configuration of the default lan should then look something like this
    config interface lan
          option type 'bridge'
          option ifname 'eth0.1 eth1 bat0'	#ethX might be different for your device
          option proto 'static'
          option ipaddr ''
          option netmask ''
          option gateway ''
          option dns ''

After applying this configuration, it will let any non-mesh client to join the mesh via ethernet cable–that is, by connecting a cable to one of the LAN/WAN ports of the mesh bridge device. As long as the gateway is reachable, everything should work like a standard network, you could use the device’s own switch or connect the device to a switch and manage things there, and so on.

Save the file and exit it.

Similarly, you can create a wireless access point (WAP) for non-mesh clients, and the instructions in the dumb access point documentation will work just fine because it uses a network that is bridged with our mesh–namely, the default lan. To avoid confusion, make sure to use a different SSID for the WAP(s) than the mesh_id used for the mesh. In addition, if at all possible, use a different radio or band for the WAP(s) and set it to operate on a different channel than the mesh channel (channel 3, unless you changed yours). If that is not possible, that is probably okay for most home users but keep in mind that node hoping will start affecting performance quite noticeably.

Finally, in the terminal, make sure to disable dnsmasq, odhcpd, and the firewall, as follows

/etc/init.d/dnsmasq stop && /etc/init.d/dnsmasq disable 
/etc/init.d/odhcpd stop && /etc/init.d/odhcpd disable
/etc/init.d/firewall stop && /etc/init.d/firewall disable

Reboot your device and on your laptop/PC, disable networking altogether (this will force it to get a new IP from the bridge when it comes back)–alternatively, just disconnect the ethernet cable.

Once the bridge is back online (wait at least a minute or two to give it enough time to connect to the mesh first), re-enable networking on your laptop/PC (or reconnect the ethernet cable) and it should receive an IP addr from our mesh gateway in the network (on a Linux distro, type ip a or ip addr or ifconfig), the bridge node should now be reachable at, and you should be able to access the Internet from your laptop/PC through the mesh (try ping, for example). If something doesn’t work, review the config files mentioned here and then go over the ones for the gateway, reboot all mesh nodes (gateway first, then nodes, then bridge) and test again.


This second example applies to the following topology:

Topology - Bridge-Bridge

Contrary to the first example, there’s no mesh gateway device and as such, this topology could be used to extend an already existing private network (Networks A and B) over the wireless mesh (all defined in the IP range). However, to make matters simple, we will assume that the existing network has a gateway/firewall in either Network A or B that can be found at the IP addr, and there’s a DHCP server being advertised on the network. (If your existing Networks A and B are not defined in the IP range, just edit your previous config files accordingly and the mesh network will follow your existing network instead.)

Config-wise, the mesh bridges in this topology are configured exactly as in the first example, except for the following differences in the configuration of the /etc/config/network config file:

  • Each mesh bridge should have a different static IP address in the lan interface, as indicated by option ipaddr. For example, the first mesh bridge will have option ipaddr '', while the second mesh bridge will have option ipaddr '';

  • The option gateway '' in the default lan stanza must match an existing gateway on either Network A or B, and similarly, option dns '' must point to a valid DNS resolver;

  • As mentioned before, if your existing Networks A and B are not defined in the IP range, then just edit the config file accordingly.


The third and final example applies to the following topology:

Topology - Gateway-Gateway

Specifically, there’s only one private network (mesh, defined in the IP range) and notably, two mesh gateways. This provides “high availability” of the Internet connection to mesh nodes and surprisingly enough, the configuration of each mesh gateway is just like in the first example, with the following exceptions

  • Like in the bridge-bridge example, we must assign different static IP addresses to each mesh gateway. This is done by editing the /etc/config/network config file, and in the lan interface configuration, add a different IP addr next to the option ipaddr option. For example, the first mesh gateway will have option ipaddr '', while the second mesh gateway will have option ipaddr ''.

  • Because we will now run two DHCP servers on the same network, we need to find a way of avoiding conflicts when assigning an IP address to new clients. The easiest way of doing that is by assigning different intervals to each DHCP server running on the same network. In OpenWrt, this is done by editing the /etc/config/dhcp config file, and in the lan_bat0 DHCP configuration, we add a different starting point next to the option start option. For example, while the DHCP server running on the first gateway will have option start '50', the DHCP server running on the second gateway will have option start '150' instead. This way, the first DHCP server leases addresses from to .149, whereas the second leases addresses from to .249.

  • Optional: In the bat0 interface config of the /etc/config/network config file, we can now enable the option gw_mode 'server' and specify the WAN connection speed with option gw_bandwidth '10000/2000' (i.e., 10000kbps download and 2000kbps upload). Then, in each other mesh node, we set the option gw_mode to 'client' instead of 'off'. This way, we can make each mesh node aware of the two gateways on the network (and their speeds) to better route mesh traffic.

Mesh VLANs

You don’t need to configure VLANs in order to use batman-adv but it is one of its best features. In brief, this is a way of using our already configured wireless mesh network to route traffic to/from multiple and all networks in a secure, isolated way (as far as VLANs go). No need for additional hardware–the combination of OpenWrt and batman-adv turns even cheap wireless hardware into powerful virtual switches. It’s just a matter of tagging the additional (and virtual) networks instead of using the untagged bat0 (or similarly, in a port-based analogy, “plugging” standard interfaces into different ports of our bat0 switch). This is a fairly advanced topic but surprisingly easy to incorporate to our existing batman-adv configuration.

Consider, for example, the following network

Topology - Mesh VLANs

There’s a single gateway device that provides WAN access to the mesh and Networks B, C, and D, which are all private networks defined in different IP ranges. In addition, all the Networks B, C, and D traffic should go via any mesh node in the mesh network while keeping them isolated from each other. To make it easier to remember and distinguish each private network, let’s call

  • Network B by iot network (;
  • Network C by guest network (;
  • and Network D by default network (

To implement such a mesh network with VLANs, we’re going to follow very similar steps to the first example of a gateway-bridge mesh network, except for the following:

  • We will have two additional bridges in the network–that is, one for each mesh VLAN, for a total of three bridges. This is not a necessity but a matter of convenience to keep the example simple. The same bridge device can definitely bridge more than one mesh VLAN;
  • In the gateway device, we will create VLAN IDs for the iot (2), guest (5), and default (1) networks, each with a separate set of DHCP server and firewall rules;
  • In each bridge device, we will join the default lan with the VLAN ID of the mesh VLAN (bat0.1, bat0.2, bat0.5), instead of bat0.

Surprisingly enough, we don’t need to do a thing about the mesh nodes that are not gateways or bridges–that is, the mesh node basic config is both necessary and sufficient for simple mesh nodes, even when using VLANs. The only exception is if one of your mesh nodes is, for example, a laptop and you want it to use a particular mesh VLAN instead of the untagged bat0. In our case, however, the pre-configured mesh nodes are ready to route traffic of any VLAN that belongs to bat0.

As before, let’s start with the gateway configuration.

Mesh gateway with VLAN configuration

First, configure the gateway the same way as in the gateway-bridge example.

Now, instead of lan_bat0, we’re going to change it to default in the config files, then do the same for iot and guest. So, if you’re ready, ssh back into it and let’s start by editing the /etc/config/network config file, as follows

vi /etc/config/network

and at the end, comment out the lan_bat0 config, as follows

#config interface 'lan_bat0'
#        option type 'bridge'		#uncomment if adding other interfaces to ifname
#        option ifname 'bat0'
#        option proto 'static'
#        option ipaddr ''	#static addr for this gateway on the net
#        option netmask ''
#        list dns ''			#cloudflare dns server
#        list dns ''			#google dns server

then below it, let’s add a new interface for default, as follows

config interface 'lan_bat0_1'
#        option type 'bridge'	#uncomment if adding other interfaces to ifname
        option ifname 'bat0.1'
        option proto 'static'
        option ipaddr ''
        option netmask ''
        list dns ''
#        list dns ''	#make it use cloudflare

then another one for iot

config interface 'lan_bat0_2'
#        option type 'bridge'	#uncomment if adding other interfaces to ifname
        option ifname 'bat0.2'
        option proto 'static'
        option ipaddr ''
        option netmask ''
#        list dns ''	#make it use google
        list dns ''

and another one for guest

config interface 'lan_bat0_5'
#        option type 'bridge'	#uncomment if adding other interfaces to ifname
        option ifname 'bat0.5'
        option proto 'static'
        option ipaddr ''
        option netmask ''
#        list dns ''	#make it use google
        list dns ''

Save the file and exit it.

Now, let’s edit the /etc/config/dhcp config file, as follows

vi /etc/config/dhcp

and once again, comment out all lan_bat0 config, as follows

#config dhcp 'lan_bat0'
#        option interface 'lan_bat0'
#        option start 50		#start leasing at addr
#        option limit 100		#max leases, so for 100, leased addr goes from .50 to .149
#        option leasetime '3h'
#        option ra 'server'

then add a DHCP server config for the default interface below it

config dhcp 'lan_bat0_1'
        option interface 'lan_bat0_1'
        option start 50
        option limit 100
        option leasetime '12h'
        option ra 'server'

and like before, we will add another one for the iot interface

config dhcp 'lan_bat0_2'
        option interface 'lan_bat0_2'
        option start 50
        option limit 100
        option leasetime '6h'
        option ra 'server'

and another one for the guest interface

config dhcp 'lan_bat0_5'
        option interface 'lan_bat0_5'
        option start 50
        option limit 100
        option leasetime '1h'
        option ra 'server'

Save the file and exit it.

Finally, let’s edit the /etc/config/firewall config file, as follows

vi /etc/config/firewall

and once again, comment out the lan_bat0 configs, as follows

#config zone
#        option name     lan_bat0
#        list network    'lan_bat0'
#        option input    ACCEPT
#        option output   ACCEPT
#        option forward  ACCEPT
#config forwarding
#        option src   lan_bat0
#        option dest  wan

and below each one of them, add one for the default interface

config zone
        option name     lan_bat0_1
        list network    'lan_bat0_1'
        option input    ACCEPT
        option output   ACCEPT
        option forward  ACCEPT
config forwarding
        option src   lan_bat0_1
        option dest  wan

then another one for the iot interface

config zone
        option name     lan_bat0_2
        list network    'lan_bat0_2'
        option input    ACCEPT
        option output   ACCEPT
        option forward  ACCEPT
config forwarding
        option src   lan_bat0_2
        option dest  wan

and another one for the guest interface

config zone
        option name     lan_bat0_5
        list network    'lan_bat0_5'
        option input    ACCEPT
        option output   ACCEPT
        option forward  ACCEPT
config forwarding
        option src   lan_bat0_5
        option dest  wan

Save the file and exit.

Reboot the device.

Once the gateway device is back online–by the way, it should still be at because the gateway’s default lan is intact, so even if we fuck something up, we should be able to find the gateway via a direct cable connection–ssh into it once again and type

ip a

which now should show the new interfaces we created (e.g, bat0.1@bat0) and the static IP addr of your device in each one of them ( (As mentioned before, if the option type 'bridge' was enabled in the /etc/config/network config stanza, then there will be an additional interface with the br- prefix attached to it and the static IP addr of your device will be associated with it.)

If everything looks good, we’re done with the gateway configuration! We’re now ready to tell our bridges which VLAN ID to join with their standard interfaces.

You don’t need to use interface names such as lan_bat0_1; they can be whatever you find intuitive. However, whatever you choose, keep them short–that is, less than 14 characters long–or you’ll start experiencing config issues.

Mesh bridge with VLAN configuration

Here, we’ll also configure the bridges the same way as in the gateway-bridge example. However, each bridge device will bridge a different VLAN ID–namely, either bat0.1 or bat0.2 or bat0.5–with its default lan, instead of bridging bat0 with its default lan.

Let’s start with the Network B (IoT) bridge.

Configure one of the mesh nodes as in the gateway-bridge example, except that in the default lan interface stanza of the /etc/config/network file, let’s do the following:

  • In option ifname, change bat0 for bat0.2;
  • In option ipaddr, change 192.168.10. for 192.168.20.;
  • In both option gateway and option dns, change for;
  • Then, the default lan stanza should look something like this
    config interface lan
          option type 'bridge'
          option ifname 'eth0.1 eth1 bat0.2'	#ethX might be different for your device
          option proto 'static'
          option ipaddr ''
          option netmask ''
          option gateway ''
          option dns ''

Save the file and exit it.

Reboot your device.

Once it comes back on, your laptop/PC will receive an IP addr from our mesh gateway in the network, the bridge node should be reachable at, and you should be able to access the Internet via the IoT network (try ping, for example).

If something doesn’t work, review the config files from your gateway and then from the bridge, then reboot the gateway and the bridge, and test again.

If this config is working, repeat the same steps in the config of the other two bridges, with the following exceptions

  • In the Network C bridge (Guest), use bat0.5 instead of bat0.2, and similarly, use the 192.168.50. IP addr instead of 192.168.20.;

  • In the Network D bridge (Default), use bat0.1 instead of bat0.2, and similarly, use the 192.168.10. IP addr instead of 192.168.20.;

Optional: When configuring a Guest WAP, for example, you can add option isolate 1 to the relevant stanza in the /etc/config/wireless config file to deny client-to-client connectivity without the need of re-enabling the firewall in the bridge device. If that’s not enough, re-enable the firewall and configure it according to your needs–at the bottom of the /etc/config/firewall file, there are examples you can use as template.

Getting started with batman-adv on any Linux device

OpenWrt makes using batman-adv a nearly trivial thing but you certainly don’t need OpenWrt to implement a mesh network or even to use batman-adv in your mesh. As mentioned before, batman-adv has long been added to the Linux Kernel and therefore, you should be able to configure it on pretty much any device running Linux.

Even though the specifics of configuring network interfaces and managing connections might be different across Linux distributions, the initial steps always consist of the following:

  1. Installing (in popular distros, this is not needed) and loading (always needed) the batman-adv Kernel module. lsmod will show a list of active modules, so we can grep it to check if the batman-adv module has already been loaded, as follows
    lsmod | grep batman

    then if it isn’t loaded, we add the batman-adv kmod to /etc/modules and load it with modprobe, as follows

    # append batman-adv to /etc/modules
    echo 'batman-adv' | sudo tee -a /etc/modules > /dev/null
    # load the batman-adv module
    sudo modprobe batman-adv
    # check that the batman-adv module is now loaded
    lsmod | grep batman

    Afterwards, you can check the sysfs of each network device in /sys/class/net/ and there should be a batman_adv folder. When the batman-adv module gets configured to use a particular network device, the files batman_adv/iface_status and batman_adv/mesh_iface will change their contents to reflect that. In addition, once enabled, bat0 will show up as a new network device in /sys/class/net/ and its options (e.g., gw_mode) can be modified by echoing new values to their corresponding file in /sys/class/net/bat0/mesh/ (echo 'client' > /sys/class/net/bat0/mesh/gw_mode).

  2. Installing the batctl package. On apt-based distros like Debian, you should be able to install it with the following
    sudo apt install batctl
  3. Using a combination of iw and ip to configure the network interfaces, as illustrated in the B.A.T.M.A.N. quick start guide. In our case, however, the wireless mode of operation (as in the specification of type in the iw interface creation command) is mesh (or mp), instead of adhoc (or ibss).
  4. Using something like wpa_supplicant to manage connections.

If you know of a program that has a GUI and is able to handle such configurations on popular Linux distros, let me know about it. As far as I know, there’s currently nothing like that and it would be so very useful.


Bonus content: Physical computing

If your device has unused general purpose I/O pins, it’s possible to do all sorts of things with them. Check the GPIO documentation for examples of how to install new LEDs and buttons, for instance. (Your device’s OpenWrt page can be very useful as well.)

Also, if you want to change the functionality of a few of the existing LEDs on your wireless device, check the LED configuration documentation. Now that you have new mesh interfaces, you can use the LEDs to blink depending on the status of neighboring nodes, mesh gateways, or WAN connectivity through the mesh, to mention a few examples. (As mentioned before, your device’s OpenWrt page can be very useful here.)


Bonus content: Moving from OpenWrt 19 to 21

As mentioned before, this guide was written for the current stable release version of the OpenWrt software, namely version 19. However, the next stable version–OpenWrt 21–is already available for anyone to try.

There are a few aspects about the configuration syntax that has changed between 19 and 21 that make the instructions from this guide incompatible with 21. Of note, the Ethernet network switch framework is changing from reliance on swconfig to the Distributed Switch Architecture (DSA), which comes with implications to how switches and bridges are configured in the /etc/config/network file.

I’ve not tested the next stable release yet and likely will not until it becomes the current stable version. When that happen, my plan is to update the main mesh guide to make it compatible with the release version 21 configuration syntax. Until then, I recommend reading the following posts for anyone interested in trying to use batman-adv with the OpenWrt version 21:


Final remarks

Futurama Hubert Farnsworth

Good news, everyone! You’ve reached the end of this tutorial, which means it’s time to start planning your own mesh networking project. I love to hear about different takes on the projects I post on my blog, so don’t hesitate to contact me if you just want to share or bounce a few ideas. Different perspectives give an opportunity to learn, grow, and innovate.

Other similar mesh solutions

If you find this guide overwhelming but you’re still curious about mesh networking, take a look at the following alternatives (in alphabetical order):

They have pre-configured images that will work “out of the box” with compatible devices. You might find instructive to start playing around with their software first and once comfortable, build your own configuration from a default (or customized from the source) OpenWrt image.


Posted on: