Search code examples
pythonbashubuntuflaskwpa-supplicant

Checking wpa_supplicant output from Python app


I have a Python/Flask web app on a Raspberry Pi that calls the following bash script (connect_to_wifi) to connect to WiFi:

sudo killall wpa_supplicant
sudo wpa_supplicant -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf
sudo dhclient wlan0

Basically, a user enters their WiFi credentials, which are saved in wpa_supplicant.conf, and then this script is run. It works great...however, if they mistype their credentials, dhclient hangs forever before failing.

What I want to do is detect if the credentials are correct before proceeding with dhclient. I know that I can check the output of the wpa_supplicant command for a 4-Way Handshake failure if creds are wrong, but when I call this script from my Python app via:

p = Popen(['connect_to_wifi'], stdout=PIPE, bufsize=1)
with p.stdout:
    for line in iter(p.stdout.readline, b''):
        print line,
p.wait()

None of the output from the sudo wpa_supplicant -i... line is being captured. All I want to do is end immediately if I detect a handshake failure, but I'm having trouble capturing the output in Python.


Solution

  • John Bullard's answer was really clean and solid, but I was having trouble getting it to work consistently because of the comment I made on it:

    There is a brief period where iw wlan0 link says it is connected even if invalid credentials are entered in wpa_supplicant.conf. I'm assuming it connects, then verifies creds, and if they're wrong, disconnects. So this script doesn't actually work, at least not every time.

    What I ended up doing, with help from that answer, is using the -f flag for wpa_supplicant and writing the output of wpa_supplicant to a file. The while loop then greps for the connected status, in which case it will call dhclient. If it doesn't connect, it will either time out or result in a 4-way handshake failed (if the latter, the script will end earlier).

    #!/bin/bash
    
    sudo ip addr flush dev wlan0
    sudo killall wpa_supplicant
    sudo truncate -s 0 wifi_connection_status.txt
    sudo wpa_supplicant -B -i wlan0 -f wifi_connection_status.txt -c /etc/wpa_supplicant/wpa_supplicant.conf
    
    declare -i i=0
    declare -i timeout=15
    while [ $i -le $timeout ]; do
        if grep -iq 'CTRL-EVENT-CONNECTED' wifi_connection_status.txt; then
            sudo dhclient wlan0
            exit 2
        elif grep -iq '4-Way Handshake failed' wifi_connection_status.txt; then
            exit 2
        fi
    
        (( i++ ))
        sleep 1
    done