RamsesV
Posts: 5
Joined: Mon Aug 07, 2017 9:12 am

[HOWTO] Setting up a Raspberry Pi as a wireless bridge

Sun Jan 20, 2019 1:42 pm

First of all, I will start this post saying that this is my very first time starting a content post and so, will welcome your kind opinions, corrections and patience if I breach any of the forums rules and besides will greatly appreciate any necessary assistance from moderators and other members to correct such mistakes.

Having said that, this is a project that I have been working on for a while now and that numerous times I have seen people asking around the internet without much success. I refer to the idea of creating a wireless (wireless to wireless interface) transparent bridge using a Raspberry Pi; or well, I do not see a problem in using a similar approach to do the same at least on any other Debian based system. I have to say as well, that this method will not create a layer 2 bridge (transparent bridge) per se, but still, will make the Raspberry Pi to behave in a very similar fashion with the exception that the RPi will get an IP address too (something that a layer2 bridge shouldn't do) and other technical characteristics that would not let to classify this as a "transparent" wireless bridge. On the other side, the RPi will relay DHCP messages from the router and let devices from one side to the other of the RPi to be visible and communicate as it is supposed to happen when using a bridge; something very useful when for example in my case, needed to connect to a printer that was too far away from my home router and extending my WiFi range to the rooms at the back of the house and still allow those PC's to be on the same network of other devices in the house. Something that would not be possible if using the typical guides to setup the RPi as a wireless router access point. In order to do so, in this method I use proxy ARP bridging. I will leave the long technical explanations for you to find or else, this post will become very long.

Finally, my setup for this project is:
I am using a RPi 2 B+ and 2 cheap Realtek 802.11AC USB dongles. And with this, I would like to make emphasis that I tried in the pass to work with a RPi 3, using its built-in WiFi and an external WiFi usb dongle and I had many complications because sometimes the RPi will label the built-in WiFi with a name different to Wlan0 which gave me a couple of headaches at the moment. So, I would recommend to use 2 USB dongles and disable the built-in WiFi or use some method similar to the explained in https://www.raspberrypi.org/forums/view ... 6&t=198946, but will leave that out of this guide and leave it to you to figure out how to do that.

Anyway, without any more preambles:

HOW TO SETUP A RASPBERRY PI AS A WIRELESS BRIDGE

In this guide, we will setup wlan0 to be the port that connects to your home wireless router and wlan1 will be our relaying wireless access point. Besides, to do so, it is necessary to create a bash script that will run every time that the RPi boots and will essentially manage the bridging proper functioning.

First, we need to install all the necessary software:

Code: Select all

sudo apt install parprouted dhcp-helper hostapd bcrelay
Note: bcrelay is optional.

Bcrelay is a tool used to relay (pass) broadcast messages and should be installed just if you need to broadcast messages in your network. I needed to do this for an specific application in the pass, but is really rarely used by standard users and everyday applications.

We need to stop the wlan1 port (our relaying wireless access point) from being allocated IP addresses by the DHCP client on the Raspberry Pi. So open up

Code: Select all

sudo nano /etc/dhcpcd.conf
and add the following lines at the bottom of the file:

Code: Select all

allowinterfaces eth0 wlan0
denyinterfaces wlan1
Note: This lines must be added above any interfaces lines you may have added before.
Note2: The allowinterfaces line is overkill, since it is supposed to be done by default.

Now, we need to setup our relaying access point. To do so, create a configuration file for hostapd with

Code: Select all

sudo nano /etc/hostapd/hostapd.conf
and add the necessary access point detail. As a reference, my hostapd.conf file looks something like this:

Code: Select all

# WiFi interfaces to use for AP (Access Point)
interface=wlan1

# Use the nl80211 driver
driver=nl80211

# AP name
ssid=My-test-AP

# Use the 5GHz band. Use "a" for 5GHz and "g" for 2.4GHz
hw_mode=a

# Use channel 48. It can be set to "0" to let hostapd to find the best channel but only works with Atheros
#  based chips
channel=48

# Limit the frequencies used to those allowed in the country
ieee80211d=1
# Country Code
country_code=AU
# Enable 802.11n support
ieee80211n=1
# Enable 802.11ac support
ieee80211ac=1
# Enable WMM (QoS support)
wmm_enabled=1

# Enable 40MHz channels with 20ns guard interval. Do we need this at all?
#ht_capab=[HT40][SHORT-GI-20][DSSS_CCK-40]

# Accept all MAC addresses
macaddr_acl=0

# Use WPA authentication (1=wpa, 2=wep, 3=both)
auth_algs=1
# Use WPA2
wpa=2
# Use a pre-shared key
wpa_key_mgmt=WPA-PSK
# Use AES, instead of TKIP
rsn_pairwise=CCMP
# AP password
wpa_passphrase=myTestPass
Enable ipv4 packet forwarding. To do so, open up

Code: Select all

sudo nano /etc/sysctl.conf
and uncomment (remove the "#") the line
net.ipv4.ip_forward=1
.

To be able to use all this setup as a bridge, start and if necessary to re-establish the bridge, I wrote a bash script. By the way, I created this script with my basics knowledge of bash and semi-decent "C" programming logic, so I do not intent this script to be an ultimate solution and am aware that is very probable there is room for improvement in the script.
To do so, create a file at some known location. I created mine with

Code: Select all

sudo nano /home/pi/bin/LAN2_Bridge.sh
and paste the following script:

Code: Select all

#!/bin/bash

#---------------------------------------------------------------------------
#                            Variables declaration
#---------------------------------------------------------------------------

# Uncomment if broadcast-relaying is necessary
#bcRelay_ON=1

wlanCXed=0

idx=0
err_ON=0

scriptPath=""

#---------------------------------------------------------------------------
#                               Local Functions
#---------------------------------------------------------------------------

arp_routing(){
    local __iface1=$1
    local __iface2=$2
    
    parprouted $__iface1 $__iface2 >> "$scriptPath" 2>&1
    if [ "$(echo $?)" -ne 0 ]
    then
        sleep 1
        return 1
    fi
    return 0
}

dhcp_relay(){
    local __iface1=$1
    local __iface2=$2
    
    #local dhcp_server=$(grep -w "dhcp-server" \
    #/var/lib/dhcp/dhclient.$__iface1.leases | tail -n1 | awk '{print $3}' \
    #| cut -d';' -f1)
    local dhcp_server=$(grep -R "offered" \
    /var/log/* | tail -n1 | awk '{print $(NF)}')
    
    dhcp-helper -s "$dhcp_server" -i "$__iface2" >> "$scriptPath" 2>&1
    if [ "$(echo $?)" -ne 0 ]
    then
        sleep 1
        return 1
    fi
    return 0
}

host_ap(){
    hostapd -B /etc/hostapd/hostapd.conf >> "$scriptPath" 2>&1
    if [ "$(echo $?)" -ne 0 ]
    then
        sleep 1
        return 1
    fi
    return 0
}

bc_relay(){
    local __iface1=$1
    local __iface2=$2
    
    bcrelay -d -n -i "$__iface1" -o "$__iface2" >> "$scriptPath" 2>&1
    if [ "$(echo $?)" -ne 0 ]
    then
        sleep 1
        return 1
    fi
    return 0
}

kill_process(){
    local __proc2kill=$1
    local CMDresult=$(ps aux | grep -v grep | grep "$__proc2kill")
    if [ -n "$CMDresult" ]
    then
        killall "$__proc2kill" >> "$scriptPath" 2>&1
        #while read line
        #do
        #    kill $(echo $line | cut -d' ' -f2) >> "$scriptPath" 2>&1
        #done <<< $CMDresult
    fi
}
RST_process(){
    until ( ifconfig wlan1 down >> "$scriptPath" 2>&1 )
    do
        sleep 1
    done
    sleep 1
    
    until (ip addr flush dev wlan1 >> "$scriptPath" 2>&1)
    do
        sleep 1
    done

    kill_process "parprouted"
    
    kill_process "dhcp-helper"
    
    kill_process "hostapd"
    
    # Executes this section if bcRelay_ON is enabled (not commented)
    if [ -v bcRelay_ON ]
    then
        kill_process "bcrelay"
    fi
    
    sleep 1
}

CX_start(){
    err_ON=0
    RST_process
    
    wlan0Info=""
    while [ "$wlan0Info" == "" ]
    do
        # Check if wlan0 has an IP. Drops results and logs error messages
        if [ "$(ifconfig wlan0 2>>"$scriptPath" | grep -w "inet" | awk '{print $2}')" != "" ]
        then
            # Using wlan0Info just as a test condition to help exit this loop.
            #  wlan0Info is reused later
            wlan0Info="exit"
        else
            sleep 1
        fi
    done
    
    wlan0Info=$(ip a show wlan0)
    wlan0IP=$(echo "$wlan0Info" | grep -w "inet" | awk '{print $2}' | cut -d'/' -f1)
    wlanIPMask=$(echo "$wlan0Info" | grep -w "inet" | awk '{print $2}' | cut -d'/' -f2)
    wlanbrd=$(echo "$wlan0Info" | grep -w "inet" | awk '{print $4}')
    wlan1IP1=$(echo "$wlanbrd" | cut -d'.' -f1)
    wlan1IP2=$(echo "$wlanbrd" | cut -d'.' -f2)
    wlan1IP3=$(echo "$wlanbrd" | cut -d'.' -f3)
    wlan1IP4=$(($(echo "$wlanbrd" | cut -d'.' -f4) - 1))
    wlan1IP=$(echo "$wlan1IP1"'.'"$wlan1IP2"'.'"$wlan1IP3"'.'"$wlan1IP4")
    
    until ( ifconfig wlan1 up >> "$scriptPath" 2>&1 )
    do
        sleep 1
    done
    sleep 1
    
    until (ip addr flush dev wlan1 >> "$scriptPath" 2>&1)
    do
        sleep 1
    done
    
    until ( ip addr add $(echo "$wlan1IP"'/'"$wlanIPMask") brd + dev wlan1 \
    >> "$scriptPath" 2>&1 )
    do
        sleep 1
    done
    
    until ( $(arp_routing "wlan0" "wlan1") )
    do
        idx=$(("$idx"+1))
        if [ "$idx" -eq 5 ]
        then
            echo "parprouted failed" >> "$scriptPath" 1>&1
            err_ON=1
            break
        fi
    done
    
#    echo "here1"
    
    if [ $err_ON -eq 0 ]
    then
        idx=0
        until ( $(dhcp_relay "wlan0" "wlan1") )
        do
            idx=$(("$idx"+1))
            if [ "$idx" -eq 5 ]
            then
                echo "dhcp-relay failed" >> "$scriptPath" 1>&1
                err_ON=1
                break
            fi
        done
    fi
    
    if [ $err_ON -eq 0 ]
    then
        idx=0
        until ( $(host_ap) )
        do
            idx=$(("$idx"+1))
            if [ "$idx" -eq 5 ]
            then
                echo "Host AP failed" >> "$scriptPath" 1>&1
                err_ON=1
                break
            fi
        done
    fi
    
    # Executes this section if bcRelay_ON is enabled (not commented)
    if [ -v bcRelay_ON ]
    then
        for i in $(seq 1 2)
        do
            if [ $err_ON -eq 0 ]
            then
                idx=0
                iface1="wlan0"
                iface2="wlan1"
                if [ $i -eq 2 ]
                then
                    iface1="wlan1"
                    iface2="wlan0"
                fi
                until ( $(bc_relay "$iface1" "$iface2") )
                do
                    idx=$(("$idx"+1))
                    if [ "$idx" -eq 5 ]
                    then
                        echo "BC_Relay failed" >> "$scriptPath" 1>&1
                        err_ON=1
                        break
                    fi
                done
            fi
        done
    fi
    
    if [ $err_ON -eq 0 ]
    then
        wlanCXed=1
    else
        sleep 10
    fi
}

check_processes(){
    if [ "$(ps aux | grep -v grep | grep parprouted)" == "" ]
    then
        return 1
    elif [ "$(ps aux | grep -v grep | grep dhcp-helper)" == "" ]
    then
        return 1
    elif [ "$(ps aux | grep -v grep | grep hostapd)" == "" ]
    then
        return 1
    elif [ -v bcRelay_ON ]
    then
        if [ "$(ps aux | grep -v grep | grep bcrelay)" == "" ]
        then
            return 1
        fi
    fi
    return 0
}
CX_check(){
    if [ "$(ifconfig wlan0 | grep inet)" != "" ] && \
       [ $(check_processes; echo $?) -eq 0 ]
    then
        sleep 1m
    else
        RST_process
        wlanCXed=0
    fi
}


#---------------------------------------------------------------------------
#                                    Main
#---------------------------------------------------------------------------

scriptPath="$(cd "$(dirname $0)"; pwd -P)""/log_err"
echo "Start" > "$scriptPath" 1>&1

# Main Loop. Starts and keep checking on connection to not to break, and
#  all of the packages used to not to be ended. If any of this two conditions
#  happen, kills all processes, wait the connection to the router
#  to be re-stablished and start all processes again
while true
do
    if [ $wlanCXed -eq 0 ]
    then
        CX_start
    else
        CX_check
    fi
done

exit 0

#---------------------------------------------------------------------------
#                                    END
#---------------------------------------------------------------------------
Note: If you installed bcrelay and intent to use broadcast messages in your network setup, uncomment the variable "bcRelay_ON" at line 8(remove "#").

After created, saved and closed, we need to change the script permissions to allow the file to be executable. This can be easily be done with the chmod command. In my example, I did with:

Code: Select all

sudo chmod 755 /home/pi/bin/LAN2_Bridge.sh
Finally, setup the script to run at startup. To do so, you can use different alternatives, but I would personally recommend to use the methods explained here https://www.dexterindustries.com/howto/ ... t-startup/. I have personally tried "rc.local" and "systemd" before and would recommend any of this two but for whatever strange reason, "rc.local" did not work for me when trying to use the script above so I ended up using "systemd". Notice that when using "systemd" as described in the link above, it takes around a minute for the service to be launched after the RPi finishes booting, but I really do not consider as a major problem that my bridge takes about a minute to be started.

Now, to finish all this setup up, connect wlan0 to your wireless router so that your router details are saved or do it manually by editing the file "/etc/wpa_supplicant/wpa_supplicant.conf" (will leave it at your preference) and reboot the RPi.

After rebooting, the bridge should be available soon after and ready to be used. Be sure that wlan0 is connecting automatically to your home router since the whole bridging process depends on this interface to be up, running and connected to a router.
Last edited by RamsesV on Mon Jan 21, 2019 11:49 am, edited 1 time in total.

Kirk Fraser
Posts: 50
Joined: Thu Feb 13, 2014 6:52 am

Re: [HOWTO] Setting up a Raspberry Pi as a wireless bridge

Sun Jan 20, 2019 9:34 pm

Ok, I did it with my neighbor watching me cut and paste the code. Still nothing. The 3B+ did not even show up on my laptop with an SSID name. I have a wireless plug in so one can receive and the other send. What should I do now? Thanks.

RamsesV
Posts: 5
Joined: Mon Aug 07, 2017 9:12 am

Re: [HOWTO] Setting up a Raspberry Pi as a wireless bridge

Mon Jan 21, 2019 12:35 am

Hi Kirk, something that I just noticed I forgot to include in the instructions is to set permissions of the script after you create it (paste the code and save it), edit the file permissions with chmod to make it executable. In my case, with the example I used for the guide, I would do:

Code: Select all

sudo chmod 755 /home/pi/bin/LAN2_Bridge.sh
I will update the guide with this later.

Try that, and besides if it does still not work, the script creates as well a log file at its path location, so please share the contents of that file if any, and please let me know as well what way did you use to execute the script at boot.

Good luck and hope you get it working soon

mccartjt
Posts: 8
Joined: Mon Jan 14, 2013 3:49 am

Re: [HOWTO] Setting up a Raspberry Pi as a wireless bridge

Sat Sep 07, 2019 6:32 pm

I'm trying to get a HP Laserjet 5000 to be seen on a WiFi network, any clues if this will work?

RamsesV
Posts: 5
Joined: Mon Aug 07, 2017 9:12 am

Re: [HOWTO] Setting up a Raspberry Pi as a wireless bridge

Thu Sep 26, 2019 8:30 am

mccartjt wrote:
Sat Sep 07, 2019 6:32 pm
I'm trying to get a HP Laserjet 5000 to be seen on a WiFi network, any clues if this will work?
It would be hard to tell since I don't know or used the printer myself, but my initial guess would be that it will, since the RPi behaves almost as a transparent bridge, and if you have all the components to setup all as described, it should not take you long to set everything up and try it. The only detail that comes to mind is that you need to check if your printer can connect to 5GHz band WiFis, else, change the access point band in the "hostapd.conf" to be 2.4GHz.

yentz
Posts: 1
Joined: Thu Nov 21, 2019 2:08 pm

Re: [HOWTO] Setting up a Raspberry Pi as a wireless bridge

Thu Nov 21, 2019 2:12 pm

Hi,
thanks for the great tutorial. Unfortunately I get an errorlog saying SIOCSIFFLAGS: Operation not permitted when running the script.
Any idea what could be the problem?
For the Wlan 1 adapter I changed the driver to RTL8188EUS because this is the driver to the chipset used in the usb adapter.
Does it have to be installed? The adapter is working plug & play so I dont know which driver it uses.
Really no knowledge of linux here unfortunately :(

Cheers,
Jens

Return to “Networking and servers”