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.
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:
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!