Creating a Wifi Access Point

In a previous post we saw how to connect to a wireless network to ssh into a linux board and control it headlessly. This presents the obvious advantage of not needing to setup a screen and keyboard, which is not necessarily a given in every board anyway, but also has a few drawbacks, such as not knowing in advance the IP address and having to perform a network scan to find it, or not being able to log in in a place without wifi.

nanoPiAP

To solve this problem while retaining the benefits of ssh-ing, an Access Point (AP) could be set up. This way the board would create its own wireless network to which we could connect, and since we can control every aspect of the system it would be simple matter of assigning a known static IP address to which to connect directly. This of course has the disadvantage of not being able to connect to the Internet but files needed can be transferred over scp or downloaded before creating the AP.

The modified files will follow this structure:

tree

The first thing to do while we’re still connected to the Internet is to install hostapd and udhcpd in the embedded board:

sudo apt-get install hostapd udhcpd

We’re going to set up hostapd to create the network and udhcpd to manage IP addresses.

Hostapd

First we modify (or create) the file to contain the following parameters to create the AP. We will then change SSID and WPA_PASSPHRASE to reflect our chosen name and password.

interface=wlan0
driver=nl80211
ssid=WifiName
hw_mode=g
channel=6
macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
wpa=2
wpa_passphrase=Password
wpa_key_mgmt=WPA-PSK
#wpa_pairwise=TKIP	# You better do not use this weak encryption (only used by old client devices)
rsn_pairwise=CCMP
ieee80211n=1          # 802.11n support
wmm_enabled=1         # QoS support
ht_capab=[HT40][SHORT-GI-20][DSSS_CCK-40]

Once the network is defined we tell the program where the configuration file is located.

# Defaults for hostapd initscript
#
# See /usr/share/doc/hostapd/README.Debian for information about alternative
# methods of managing hostapd.
#
# Uncomment and set DAEMON_CONF to the absolute path of a hostapd configuration
# file and hostapd will be started during system boot. An example configuration
# file can be found at /usr/share/doc/hostapd/examples/hostapd.conf.gz
#
DAEMON_CONF="/etc/hostapd/hostapd.conf"

# Additional daemon options to be appended to hostapd command:-
# 	-d   show more debug messages (-dd for even more)
# 	-K   include key data in debug messages
# 	-t   include timestamps in some debug messages
#
# Note that -B (daemon mode) and -P (pidfile) options are automatically
# configured by the init.d script and must not be added to DAEMON_OPTS.
#
#DAEMON_OPTS=""
Udhcpd

We now configure DHCP, taking care to modify the following lines:

# Sample udhcpd configuration file (/etc/udhcpd.conf)

# The start and end of the IP lease block

start		192.168.42.2	#default: 192.168.0.20
end		192.168.42.20	#default: 192.168.0.254


# The interface that udhcpd will use

interface	wlan0		#default: eth0


# The maximim number of leases (includes addressesd reserved
# by OFFER's, DECLINE's, and ARP conficts

#max_leases	254		#default: 254


# If remaining is true (default), udhcpd will store the time
# remaining for each lease in the udhcpd leases file. This is
# for embedded systems that cannot keep time between reboots.
# If you set remaining to no, the absolute time that the lease
# expires at will be stored in the dhcpd.leases file.

remaining	yes		#default: yes


# The time period at which udhcpd will write out a dhcpd.leases
# file. If this is 0, udhcpd will never automatically write a
# lease file. (specified in seconds)

#auto_time	7200		#default: 7200 (2 hours)


# The amount of time that an IP will be reserved (leased) for if a
# DHCP decline message is received (seconds).

#decline_time	3600		#default: 3600 (1 hour)


# The amount of time that an IP will be reserved (leased) for if an
# ARP conflct occurs. (seconds

#conflict_time	3600		#default: 3600 (1 hour)


# How long an offered address is reserved (leased) in seconds

#offer_time	60		#default: 60 (1 minute)

# If a lease to be given is below this value, the full lease time is
# instead used (seconds).

#min_lease	60		#defult: 60


# The location of the leases file

#lease_file	/var/lib/misc/udhcpd.leases	#defualt: /var/lib/misc/udhcpd.leases

# The location of the pid file
#pidfile	/var/run/udhcpd.pid	#default: /var/run/udhcpd.pid

# Everytime udhcpd writes a leases file, the below script will be called.
# Useful for writing the lease file to flash every few hours.

#notify_file				#default: (no script)

#notify_file	dumpleases	# <--- useful for debugging

# The following are bootp specific options, setable by udhcpd.

#siaddr		192.168.0.22		#default: 0.0.0.0

#sname		zorak			#default: (none)

#boot_file	/var/nfs_root		#default: (none)

# The remainer of options are DHCP options and can be specifed with the
# keyword 'opt' or 'option'. If an option can take multiple items, such
# as the dns option, they can be listed on the same line, or multiple
# lines. The only option with a default is 'lease'.

#Examles
#opt	dns	192.168.10.2 192.168.10.10
#option	subnet	255.255.255.0
#opt	router	192.168.10.2
#opt	wins	192.168.10.10
#option	dns	129.219.13.81	# appened to above DNS servers for a total of 3
#option	domain	local
#option	lease	864000		# 10 days of seconds

opt dns 8.8.8.8 4.2.2.2 # The DNS servers client devices will use.
opt subnet 255.255.255.0
opt router 192.168.42.1 # The Pi's IP address on wlan0 which we will set up shortly.
opt lease 864000 # 10 day DHCP lease time in seconds

# Currently supported options, for more info, see options.c
#opt subnet
#opt timezone
#opt router
#opt timesrv
#opt namesrv
#opt dns
#opt logsrv
#opt cookiesrv
#opt lprsrv
#opt bootsize
#opt domain
#opt swapsrv
#opt rootpath
#opt ipttl
#opt mtu
#opt broadcast
#opt wins
#opt lease
#opt ntpsrv
#opt tftp
#opt bootfile
#opt wpad

# Static leases map
#static_lease 00:60:08:11:CE:4E 192.168.0.54
#static_lease 00:60:08:11:CE:3E 192.168.0.44

This time instead of giving the location to the file we just comment the first parameter to enable it.

# Comment the following line to enable
#DHCPD_ENABLED="no"

# Options to pass to busybox' udhcpd.
#
# -S    Log to syslog
# -f    run in foreground

DHCPD_OPTS="-S"
Interfaces

Since in the previous tutorial we set up the board to automatically connect to a network we must now adapt the file to its new behaviour.

#CONNECT TO WIFI NETWORK
#auto wlan0
#allow-hotplug wlan0
#iface wlan0 inet dhcp
#wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
#iface default inet dhcp


#CREATE ACCESS POINT
auto wlan0
iface wlan0 inet static
  address 192.168.42.1
  netmask 255.255.255.0


#Local loopback
auto lo
iface lo inet loopback

Once all the files have been updated we reboot the board and the new network should appear,  making it now possible to log in headlessly anywhere.

However we will probably want to connect to the internet to download packages in the future, so instead of going through all the hassle of modifying the files each time I wrote the script toggleWifiMode.py to toggle between AP and regular client automatically.

#!/usr/bin/python

import os


def toggleComment(string):
    if string.startswith("#"):
        return string[1:]
    else:
        return "#"+string


def hostapd():
    lineHostapd = "DAEMON_CONF="
    with open("/etc/default/hostapd", "r") as fileIn:
        with open("/etc/default/hostapd2", "w") as fileOut:
            for line in fileIn:
                if lineHostapd in line:
                    line = toggleComment(line)
                    fileOut.write(line)
                else:
                    fileOut.write(line)
    os.rename("/etc/default/hostapd2", "/etc/default/hostapd")


def udhcpd():
    lineUdhcpd = "DHCPD_ENABLED="
    with open("/etc/default/udhcpd", "r") as fileIn:
        with open("/etc/default/udhcpd2", "w") as fileOut:
            for line in fileIn:
                if lineUdhcpd in line:
                    line = toggleComment(line)
                    fileOut.write(line)
                else:
                    fileOut.write(line)
    os.rename("/etc/default/udhcpd2", "/etc/default/udhcpd")


def interfaces():
    lineClient = "#CONNECT TO WIFI NETWORK"
    lineAp = "#CREATE ACCESS POINT"
    numClient = 10000
    numAp = 10000
    with open("/etc/network/interfaces", "r") as fileIn:
        with open("/etc/network/interfaces2", "w") as fileOut:
            for numLine, line in enumerate(fileIn):
                if line.startswith(lineClient):
                    numClient = numLine
                if line.startswith(lineAp):
                    numAp = numLine
                if numLine > numClient and numLine <= numClient+5:
                    line = toggleComment(line)
                    fileOut.write(line)
                if numLine > numAp and numLine <= numAp+4:
                    line = toggleComment(line)
                    fileOut.write(line)
                elif not (numLine > numClient and numLine <= numClient+5)   \
                        and not (numLine > numAp and numLine <= numAp+4):
                    fileOut.write(line)
    os.rename("/etc/network/interfaces2", "/etc/network/interfaces")

hostapd()
udhcpd()
interfaces()
os.system('reboot')

To execute it simply write

sudo python toggleWifiMode.py

This will create the files and restart the board to apply the changes. Happy hacking!

github
https://github.com/alvaroferran/WifiAP

Leave a Reply

Your email address will not be published. Required fields are marked *