This is an old revision of the document!


Wifi Switcher

Goal

In this guide we will describe how to setup the WiFi Switcher SDK script on a Netmodule router. This script will take care of automatically connecting to a WiFi Access Point when it is part of a List we defined. The list is in a seperate file and consists of SSIDs and associated Password.

Application example

Background for this script is a customer who uses our routers in railway applications. The router in the train is supposed to connect to a WiFi network on each respective train station. Only WiFi access points that can be found in the list of defined networks should be used to connect to.

Setup

Here we will describe step-by-step how to setup the router with the wifi switcher funktionality.

First we need to pay attention that, after setting up our WiFi client, the WLAN1 is supposed to be in position 2 in the link manager. This is neccessary so that the script queries the correct interface for it's status. The order of WAN interfaces can be changed under INTERFACES → WAN → Link Management. WLAN1 should be set to permanent.

Setup Trigger

Here we setup a trigger that will start our SDK script later on. Since the script is supposed to run at all times we will set our trigger to event-based → sdk-startup. As soon as SDK is enabled our wifi switcher script will be running.

Setup Script

This is where we insert the code of our wifi-switcher script (can be found further down in this guide).

Setup Job

Finally we have to bring script and trigger together in a job so that the trigger will be applied to our script.

Setup Wifi Networks List

Unlike the wifi-switcher script the list of allowed wifi networks does not need to be connected with a job or trigger. It just needts to be available on the device. The reason why we use the GUI to insert this list is update security and also having this file be part of the router config. This wold not be the case when we simply just copy it by hand.

It is important to use the correct name “wifi-networks.cfg” for this file, otherwise the wifi switcher script will not be able to find it. So just get the list example (can be found at the end of this guide) and adjust SSIDs and passwords to your scenario. The list is not limited to 7 entrys, it is possible to put a arbitary number of SSIDs to the file.

After succesfull setup your Scripts Tab should look like this.

Code

wifi-switcher.are

Hier eine kurze Erklärung wie das Script funktioniert.

DEBUG kann optional auf 1 gesetzt werden um Output im tail-log zu erhalten.

Das Script fragt in der while Schleife immer wieder den status vom WLAN Uplink (WANLINK2) ab. Wenn hier “dialing” oder “up” zurück gegeben wird machen wir nichts, warten 5 Sekunden und fragen nochmal.

Falls das WLAN down sein sollte und bereits mehr als 30 Sekunden seit dem letzten Scan vergangen sind machen wir jetzt einen neuen Scan der uns die aktuell sichtbaren WLAN NEtzwerke liefern wird.

Nachdem der Scan abgeschlossen holen wir und die Daten der Access Points und schauen in der Liste nach ob dort dieser AP vorhanden ist. Falls ja wird das WLAN umkonfiguriert jedoch nur wenn mehr als 120 Sekunden seit der letzten konfiguration vergangen sind.

wifi-switcher.are
include "wifi-networks.cfg";
 
DEBUG=0;
SLEEP=5;
SCAN_TIME_WAIT=30;
CFG_TIME_WAIT=120;
 
string enc_to_cfg(enc) {
    switch(enc) {
    case "WPA2-SAE":
    enc = "wpa3";
    break;
    case "WPA2-PSK":
    enc = "wpa2";
    break;
    default:
    enc = "wpa2";
    if(DEBUG) nb_syslog("wifi swticher: undefinded enc: %s, using wpa2...", enc);
    }
    return enc;
}
 
while(1) {
    // we get the current state of wanlink2 (wlan)
    wan_status=nb_status("wan");
    state=struct_get(wan_status, "WANLINK2_STATE");
    if(DEBUG) nb_syslog("wifi switcher: current state = %s", state);
 
    // in case the wlan connection is up or dialing we do not start a new scan
    if (state != "down") {
        sleep(SLEEP);
        continue;
    }
 
    // only scan networks if last scan is more than SCAN_TIME_WAIT in the past
    if(DEBUG) nb_syslog("wifi switcher: last scan was %ds ago", uptime() - SCAN_TIME);
    if (uptime() - SCAN_TIME > SCAN_TIME_WAIT){
        SCAN_TIME=uptime();
        scan_res = nb_scan_networks("WLAN1");
        if(DEBUG) nb_syslog("wifi switcher: scanning WLAN networks took %ds", uptime() - SCAN_TIME);
    }
    found=false;
    i=1;
 
    // get all the wifi information from the ap
    do {
        ssid=   struct_get(scan_res, sprintf("NETWORK%d_SSID", i));
        chipher=struct_get(scan_res, sprintf("NETWORK%d_CIPHER_1", i));
        enc=    struct_get(scan_res, sprintf("NETWORK%d_ENCRYPTION_1", i));
        /* if(DEBUG) nb_syslog("wifi switcher: position in do loop i = %d",i); */
        i++;
        for (j=0; j<length(wifi_list); j++) {
            if (ssid == wifi_list[j][0]) {
                if(DEBUG) nb_syslog("wifi switcher: configuring wifi with ssid: %s", ssid);
                cfg=sprintf("wlan.0.client.0.ssid=%s ", ssid);
                cfg=strcat(cfg, sprintf("wlan.0.client.0.secmode=wpa-psk "));
                cfg=strcat(cfg, sprintf("wlan.0.client.0.secproto=%s ", enc_to_cfg(enc)));
                cfg=strcat(cfg, sprintf("wlan.0.client.0.cipher=%s ", tolower(chipher)));
                cfg=strcat(cfg, sprintf("wlan.0.client.0.minqual=2 "));
                cfg=strcat(cfg, sprintf("wlan.0.client.0.minrssi=-99 "));
                cfg=strcat(cfg, sprintf("wlan.0.client.0.psk=%s", wifi_list[j][1]));
 
                // only apply config if last config set is more tan CFG_TIME_WAIT in the past
                if(DEBUG) nb_syslog("wifi switcher: last config set was %ds ago", uptime() - CFG_TIME);
                if (uptime() - CFG_TIME > CFG_TIME_WAIT){
                    CFG_TIME = uptime();
                    nb_config_set(cfg);
                    if(DEBUG) nb_syslog("wifi switcher: new wlan config got setup");
                }
                found=true;
                break;
            }
        }
        if(found) break;
    } while ( !is_void(ssid) );
    sleep(SLEEP);
}

wifi-networks.are

wifi-networks.cfg
wifi_list=mkarray(
    mkarray("SSID1", "wifipassword1"),
    mkarray("SSID2", "wifipassword2"),
    mkarray("SSID3", "wifipassword3"),
    mkarray("SSID4", "wifipassword4"),
    mkarray("SSID5", "wifipassword5"),
    mkarray("SSID6", "wifipassword6"),
    mkarray("SSID7", "wifipassword7")
);