This is an old revision of the document!


Wifi Switcher

Ziel

Bei dieser Anleitung geht es um das Einrichten und Erklären des SDK Scripts das automatisch zu einem der WLAN access point wechselt. Die erlaubten APs und das dazu passende Passwort sind in einer seperaten Datei zu finden.

Anwendungsbeispiel

Hintergrund ist das ein Kunde, der unsere Router in Zügen einsetzt, gerne automatisiert zu dem WLAN am jeweiligen Bahnhof wecheln möchte. Jedoch aber nur zu diesen APs und nicht zu irgendwelchen anderen WLAN Netzen die irgendwo noch verfügbar sein sollten.

Einrichten

Es folgt nun der step-by-step guide zum Einrichten der Wifi Switcher funktionalität.

Zunächst ist zu beachten das, nach dem Einrichten den Wifi Client, unser WLAN an Position 2 im Link Manager zu finden ist. Dies ist nötig damit das Script das richtige WAN Interface nach seinem Status abfragt. Die Rheinfolge der WAN Interfaces kann unter INTERFACES → WAN → Link Management geändert werden. Das WLAN Interface wird auch auf permanent gesetzt.

Script anlegen und verknüpfen

Nach den folgenden Schritten ist das wifi-switcher.are Script(findet sich weiter unten in dieser Anleitung) angelegt und kann schon laufen. Es fehlt allerdings noch die Liste der Access Points (erledigen wir im nächsten Schritt).

Trigger

Hier richten wir den Trigger ein der das SDK Script starten wird. Da es die ganze Zeit laufen soll wird hier event-based → sdk-startup gewählt. Sobald SDK also enabled ist wird auch under Wifi Switcher Script laufen.

Script

Hier laden wir unser Wifi Switcher Script hoch. Es ist weiter unten in dieser Anleitung zu finden.

Job

Zu guter letzt muss nun noch das Script und der Trigger in einem Job zusammengeführt werden.

Wifi Networks Liste

Anders als das Wifi Switcher Script ist es hier nicht nötig für diese Liste von Access Points Job und Trigger zu setzen. Es reicht aus wenn die Datei einfach nur zu finden ist. Der Grund warum wir die Liste via GUI einfügen und nicht einfach per Hand auf den Router kopieren ist das es so Update sicher ist und auch in der config auftaucht.

Wichtig ist aber das hier der korrekte Namen eingetragen wird. Also einfach die Liste (auch weiter unten zu finden) hoch laden und den Namen “wifi-networks.cfg” vergeben. Es können übrigens beliebig viele WLAN Access Points in diese Liste eingetragen werden.

Nach erfolgreichem Einrichten solle unser Scripts Tab nun so aussehen.

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")
);