OpenWrt Forum Archive

Topic: LuCi fails to properly reboot

The content of this topic has been archived between 4 Feb 2018 and 26 Apr 2018. There are no obvious gaps in this topic, but there may still be some posts missing at the end.

I am using a function to check for a wireless connection and update 'wireless' based on availability of a defined set of APs.  While the function works as desired, it appears to somehow affect the routers ability to reboot using the LuCi Reboot function (System=>Reboot).

I am hoping that someone can identify the issue and suggest a remedy.

The code was written by dabyd64 and is published here. 
https://forum.openwrt.org/viewtopic.php?id=43352
I have made some mods and republished it here.
http://www.gl-inet.com/forums/topic/wif … post-11953

I have tested the code on two devices and it seems to operate the same.  Select the reboot function from LuCi and the page will sit for about 1 minute then return to the Status Overview Screen, not the Login.  Logs confirm the system did not reboot.  On occasion I will see "daemon.info procd: - shutdown -", but not every reboot attempt; otherwise nothing remarkable. The device will reboot with the reboot -f parameter.

There are 3 files.  1 in init.d, the main function in /user/bin/ and a config file in /etc/wifimgr.  If i remove the file (wifiMgr) from init.d, the system reboots normally.  Below is my modified version (wifiMgr.sh and config).

etc/init.d/wifiMgr

#!/bin/sh /etc/rc.common

START=99
APP=wifiMgr.sh
ARGS=--daemon
PID_FILE=/var/run/$APP.pid

start() {
        start-stop-daemon -S -x $APP -- "$ARGS" -p $PID_FILE -m -b
}

stop() {
        start-stop-daemon -K -n $APP -p $PID_FILE -s TERM
        rm -rf $PID_FILE
}

There is no file in /var/run/wifiMgr.pid and start and restart return a web page saying "Connection was reset".

/usr/bin/wifiMgr.sh

#!/bin/sh
. /etc/wifiMgr/config


randMacAddr()
{

     macaddr=$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null|md5sum|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/00:\2:\3:\4:\5:01/')
    uci set wireless.@wifi-iface[1].macaddr="$macaddr"
    uci commit wireless
    /etc/init.d/network restart

}


NetStatus()
{
    logger WifiMgr: Checking network...
    # Sleep adjusts for network not up on boot
    sleep $PingSleep
    net=$(ping $PingLocation -c5 |grep "time=")
    if [ "$net" ]; then
        logger WifiMgr: Network OK
                #got ping response!
                return
    else
        logger WifiMgr: Network failed. Starting network change...
        NetChange
    fi
}



NetChange()
{
    logger WifiMgr: Performing network scan...
        scanres=
        ifconfig wlan0 down
        iw phy phy0 interface add scan0 type station
        ifconfig scan0 up

        while [ "$scanres" = "" ]; do
                #Sometimes it shows nothing, so better to ensure we did a correct scan
                scanres=$(iw scan0 scan|grep SSID)
        done

        iw dev scan0 del
        ifconfig wlan0 up
        killall -HUP hostapd
    logger WifiMgr: WifiMgr: Searching available networks...
    
    if [ "$1" ]; then
        ssid=net"$1"_ssid
        eval ssid=\$$ssid
        echo Trying to connect to network "$1"":    $ssid"
        n=$(expr "$1" - "1")
    else
            n=0
        fi
        
        while [ "1" ]; do
                n=$(expr "$n" + "1")

                if [ "$n" = "99" ]; then
                                #too much counts. Crazy wireless count, breaking loop!
                                break
                fi

                ssid=net"$n"_ssid
                encrypt=net"$n"_encrypt
                key=net"$n"_key

                eval ssid=\$$ssid
                eval encrypt=\$$encrypt
                eval key=\$$key
                
                if [ "$ssid" = "" ]; then
                                #ssid not existing or empty. Assume it's the end of the wlist file
                uci set wireless.@wifi-iface[1].disabled="1"
                uci commit wireless
                /etc/init.d/network restart
                logger WifiMgr: No usable APs found, disabling the WWAN.
                                break
                fi
                echo SSID: $ssid
                echo Password: $key
                echo Encryption: $encrypt
                

                active=$(echo $scanres | grep " $ssid ">&1 )
                if [ "$active" ]; then
                    if [ "$1" ]; then
                        echo Network found. Connecting...
                    fi
            logger WifiMgr: "$ssid" network found. Applying settings..
                        uci set wireless.@wifi-iface[1].ssid="$ssid"
                        uci set wireless.@wifi-iface[1].encryption="$encrypt"
                        uci set wireless.@wifi-iface[1].key="$key"
            uci set wireless.@wifi-iface[1].disabled="0"
            uci delete wireless.@wifi-iface[1].bssid
                        uci commit wireless
                        /etc/init.d/network restart
                        
                        #wait some seconds for everything to connect and configure
                        sleep $NewConnCheckTimer
                        logger WifiMgr: Checking connectivity...

                        #check for internet connection, 5 ping sends
                        net=$(ping $PingLocation -c5 |grep "time=")
                        if [ "$net" ]; then
                #got ping response!
                logger WifiMgr: Internet working! Searching ended
                if [ "$1" ]; then
                    echo Sucess!
                fi
                            break
                        fi
                        if [ "$1" ]; then
                            echo Connection failed!
                            break
                        fi
            logger WifiMgr: Failed! Searching next available network...
                fi
        done
}

if [ "$1" = "" ]; then
    echo "No arguments supplied"

elif [ "$1" = "--force" ]; then
    NetChange $2

elif [ "$1" = "--daemon" ]; then
    
    if [ "$randMac" = "1" ]; then
        randMacAddr    
    fi
    NetChange
    
    while [ "1" ]; do
        sleep $ConnCheckTimer
            NetStatus
    done

else
    echo "Wrong arguments"
fi

/etc/wifiMgr/config

# Background internet connection checking interval
ConnCheckTimer=60

# After new network is set, time to wait for network to establish, before checking if it's working
# If too low the router may be still waiting for the dhcp assignment from the main router, causing the script to discard the network
NewConnCheckTimer=25

# Set the loation you wish the program to use to ping for a connection.
# Choose a location with a low response time.  Google public DNS Server.
# The default is Level 3's Public DNS server.
PingLocation=209.244.0.3

# Set a time delay for to wait for the network to come up on intial boot.
PingSleep=5

# Set a random MAC each boot
randMac="0"


net1_ssid="Dummy1"
net1_encrypt="psk2"
net1_key="dumbkey1"

net2_ssid="Dummy2"
net2_encrypt="psk2"
net2_key="dumbkey2"

net3_ssid="Dummy3"
net3_encrypt="psk2"
net3_key="dumbkey3"

net4_ssid="Dummy4"
net4_encrypt="psk2"
net4_key="dumbkey4"

net5_ssid="Dummy5"
net5_encrypt="psk2"
net5_key="dumbkey5"

net6_ssid=""
net6_encrypt=""
net6_key=""

You read and followed this of course.

@MaxHopper
I had not, and now have.  I do not know what I am suppose to follow.  You know the history here and I am not the author and not a programmer.

My take away from this is that there is a Start=99, but no Stop=99

There is no restart, reload, enable or disable sections, and I expect proper structure would suggest these exist.  Enable/Disabled does appear to work.  The icon goes red, but using the "current state query" at the bottom I can confirm this.  I would expect it not to work as there are no related entries.

Unclear if the error I get using start or restart relates to the pid file not being created or created incorrectly.  Assuming stop is irrelevant if there is no pid file to remove.

Not clear on how the system knows the function is in /usr/bin/ to run.  I do not see a path to this in the wifiMgr file in init.d

Unclear if you are pointing me to a solution to the reboot issue or the System=>Startup=> initscripts connection error.

I appreciate the fishing lesson, but think I fell in over my head.

RangerZ wrote:

Enable/Disabled does appear to work.

...because -

wiki.openwrt.org wrote:

By this rc.common template, the available commands for an init scripts are as follows:

      start   Start the service
      stop    Stop the service
      restart Restart the service
      reload  Reload configuration files (or restart if that fails)
      enable  Enable service autostart
      disable Disable service autostart

/etc/rc.common provides those functions -

    ...
disable() {
    name="$(basename "${initscript}")"
    rm -f "$IPKG_INSTROOT"/etc/rc.d/S??$name
    rm -f "$IPKG_INSTROOT"/etc/rc.d/K??$name
}

enable() {
    name="$(basename "${initscript}")"
    disable
    [ -n "$START" -o -n "$STOP" ] || {
        echo "/etc/init.d/$name does not have a START or STOP value"
        return 1
    }
    [ "$START" ] && ln -s "../init.d/$name" "$IPKG_INSTROOT/etc/rc.d/S${START}${name##S[0-9][0-9]}"
    [ "$STOP"  ] && ln -s "../init.d/$name" "$IPKG_INSTROOT/etc/rc.d/K${STOP}${name##K[0-9][0-9]}"
}
    ...

Any more questions?

Would the suggestion of employing a programmer to craft solutions to your functional requirements find favour? http://i180.photobucket.com/albums/x71/saccillia/emotes/wall.gif

(my hourly rate: 0,355BTC)

@maxHopper

MaxHopper wrote:

Any more questions?

I could come up with a few.  Still no clue as to how to apply this information or what the problem is.  Just not in my skill set.

Thank you for your offer, but I am not really interested in paying for development.  The solution works, as do my work a rounds. I was hoping that someone in the community would be interested enough to identify the issues and suggest a solution. 

Reading other posts on this issues, I am surprised this and the original have garnered so little interest in this type of solution.

RangerZ wrote:

... but I am not really interested in paying for development.
    ...
I was hoping that someone in the community would be interested enough to identify the issues and suggest a solution.

Elder of Max Hopper wrote:

Advice is worth what you paid.

EDIT: removal of innocuous .gif image.

Max Hopper wrote:
RangerZ wrote:

... but I am not really interested in paying for development.
    ...
I was hoping that someone in the community would be interested enough to identify the issues and suggest a solution.
http://i796.photobucket.com/albums/yy250/HisChocolate/Smiley-Begging_zpsbe90a856-1.gif

Elder of Max Hopper wrote:

Advice is worth what you paid.

Actually not true.  Advice is frequently worth a lot more.  The perceived value of the advice however is generally what the recipient has paid for it.

I have been a consultant (manufacturing) for many years.  I know that the more I bill, the more people listen.  Unfortunately I am not billing right now, which impacts my ability to pay for development.

Your approach has been very clinical, and probably works well for a "nurse" or other "doctor" (developers) but I am a patient, and your not dumbing this down enough.  I just do not understand what your trying to tell me.

You have not even directly answered the question of are you suggesting fixes for the reboot issue, the start/restart issue or both.

RangerZ wrote:

...Unfortunately I am not billing right now, ...

Thus, you completely support registrants of this forum, amongst which are professional *nix developers, that expect a market norm 'giveback' for their expertise.

Max Hopper wrote:
RangerZ wrote:

...Unfortunately I am not billing right now, ...

Thus, you completely support registrants of this forum, amongst which are professional *nix developers, that expect a market norm 'giveback' for their expertise.

I think your on the wrong forum, you should go troll the dd-wrt forums if your looking to get paid for nothing.

@op, can you post the output of the "ps" command before then during the initiation of the luci reboot cycle

@hostle19, Thank you.

I have created a text file here.  https://www.dropbox.com/s/0y2lhjjk6zeifvv/PS.txt?dl=0

I have run this twice, with a division between runs of ======.  The first time I ran it I did not widen the putty window and lines were truncated.  The results differed slightly so I am presenting both.  I also ran PS shortly after the system returned to the Overview window.  Not sure of it's of value, but I was curious. 

If I am correct the differences occur after PID 8576.  wifiMgr is seen in 886 and 888.

I believe the sleep 300 comes from the time I have set between checks (a variable in the config file for the wifiMgr.sh).  I believe the sleep 7 is a secondary delay I added after the check starts to retard the very first check on boot as the check is occurring before the network is up and thus fails.

@ MaxHopper

This is a forum where people ask questions and help eachother. If you ask something then you most likely get a gratis answer as well. 

If you don't want to to share knowledge then why join the conversation in the first place?  I'm sure you asked questions here and did not have to pay for them either.

To get paid for coding then have a look at fiver.com or consider to build iPhone apps. But begging for bitcoins on an OpenSource forum? I don't get it... I'm sure there are people here who write code and make money, but i don't see any of them begging for money. If you are good enough then someone may offer you a coding job one day but then it's best to be friends with them in advance.   It's a bit blunt to use those kind of emoticons if someone just asks for some advice. 

OK enough off topic babble.  I had a look at the script but I also don't understand how this could break the reboot functionality. I'm also still learning this stuff... It's not as obvious as Max makes us believe.

frietpan wrote:

This is a forum where people ask questions and help eachother. If you ask something then you most likely get a gratis answer as well.

Correct. And do review those topics begun by myself to evaluate the percentage of forum to self-discovered (Read The Fine Wiki) answers.

frietpan wrote:

If you don't want to to share knowledge then why join the conversation in the first place?  I'm sure you asked questions here and did not have to pay for them either.

Advice was offered to the OPer. Guidance towards self-reliance in the form of a 'fishing lesson', is supportive.

hostle19 wrote:

I think your on the wrong forum, you should go troll the dd-wrt forums if your looking to get paid for nothing.

Max Hopper wrote:

Thus, you completely support registrants of this forum, amongst which are professional *nix developers, that expect a market norm 'giveback' for their expertise.

In an open source forum, the market norm 'giveback' is a contribution in knowledge and many posters do not adhere to this convention. Therefore, I humbly submitted an alternative manner for giving back.


The OPer has injected a private process into a working system without investigation of the mechanism -

Max Hopper wrote:

You read and followed this of course.

RangerZ wrote:

I had not, and now have.  I do not know what I am suppose to follow.  You know the history here and I am not the author and not a programmer.

and puzzles openly over the failure whilst opining for community effort to code a solution to their self-proclaimed unimportant, to the community, problem -

RangerZ wrote:

Reading other posts on this issues, I am surprised this and the original have garnered so little interest in this type of solution.

Indeed, this platform is intended for symbiotic relationships. Here, learning, not pleading, is the order of the day.

Thus, my contributions to the community are demonstratable and reciprocal. Chiding about obstinancy when others steadfastly refuse to expend personal effort before posting requests for community, read free, support, is misdirected.

seems your init script never finishes execution because it waits for wifiMgr.sh to finish ... which it never does. The whole thing looks pretty scabby but as a quick fix the "&" should fix up your init script. Try this ..

#!/bin/sh /etc/rc.common

START=90
APP=wifiMgr.sh
ARGS=--daemon
PID_FILE=/var/run/$APP.pid

start() {
        start-stop-daemon -S -x $APP -- "$ARGS" -p $PID_FILE -m -b &
}

stop() {
        start-stop-daemon -K -n $APP -p $PID_FILE -s TERM
        rm -rf $PID_FILE
}

This should allow the init script to exit properly and allow the LuCI reboot to function properly.Later this evening I will consider cleaning it up and adding a LuCI page for configuration and control so it can be controlled and configured using LuCI.

Cheers

(Last edited by hostle19 on 16 Feb 2016, 17:23)

@hostle19, Thanks, that seems to have done the trick!

I see you reduced the priority to 90.  Is there a reason for this?

I am not sure I will understand, but could you please direct me to info on or explain the parameters (-m -b &).  I was not able to construct a google that answered the question.

I am not qualified to comment on the quality of the code, but functionally it's the best thing I have found.

I am not sure what effort or direction you are contemplating here, but the single biggest issue with the function right now is the initial check occurring to early.  I have attempted to fix this with "PingSleep". If the network is not up, it then disables the STAtion side, which is good as it allows access to the router.  One then needs to wait for the check period to get wireless back.  This adds a minute (default check period) to the connection process.

There is a problem when there is no WWAN (STA status =1).  Every check period the wireless will get set to disabled again, even if it already is.   The restart will kill the WLAN connection for about 5 seconds.  Not an issue for me, but it's still wrong.  I could see it being a problem streaming media from the device when it's off line.

The big missing piece, one that a true connection manager has, is the ability to add the current functioning SAT entry to the list of saved ones.   Adding it through a config page would be good, auto would be better.

Two other notes. 
1 - The original author added the mac address piece to address issues in cafes where a time limit is placed on a MAC. 
2 - When one manually adds a STA the entry includes a BSSID.  I chose to kill the BSSID as it was easier than updating the code to support it.  Easy, not right.  Important, I do not know.

Hopefully understanding these items will save you some time in discovery.

(Last edited by RangerZ on 16 Feb 2016, 21:46)

Hi,

start-stop-daemon has its roots in Debian.  Man page (from Ubuntu) here for use, switches, etc:

http://manpages.ubuntu.com/manpages/har … mon.8.html

Haven't run Debian in over 10 years now so I'm no longer in practice.  But... I'm confused by the need for the '&' at the end of the command:

1.) '-m' creates a PID file (you mention looking for this in /var/run).
2.) '-b' is used to "background" the program you're running.  But you also need to use '&' which backgrounds the start-stop-daemon command itself.

So in effect you're forking/backgrounding twice.  It acts like start-stop-daemon isn't forking itself before it starts wifiMgr.sh, but why?  It should fork a subprocess which starts wifiMgr.sh, then the parent process should exit and return control to the script, wifiMgr, without needing the '&'.

Someone better with Debian and at debugging scripting should be able to help you.  But '&' works, so you've got that going for you, which is nice smile

Clemmitt

Clemmitt, thanks for the explanation!

I made a couple edits, I redid the init script to use the procd system since the start-stop daemon doesn't play nice with openwrt, and i also made a few changes to the wifiMgr.sh ..most notably I add a flag to your $PingSleep so it is only fired during initial boot, and I exchanged the network restarts for ifup and ifdowns should the entire network isn't nuked when a change is applied. I am not sure if this is exactly what you were after but it should give you the idea. I also change the path of the config to "/etc/config/wifiMgr" for future purposes(when i make the LuCI page for configuration) I also switched out the echo's for logger's

#!/bin/sh /etc/rc.common

START=90
USE_PROCD=1

start_service() {
    procd_open_instance 
    procd_set_param command /usr/bin/wifiMgr.sh --daemon -b -a
    procd_set_param respawn 
    procd_close_instance 

}

service_stop() {
    stop
}

and the edited wifiMgr.sh

#!/bin/sh
. /etc/config/wifiMgr

## INITIAL BOOT FLAG ##
firstboot=0

randMacAddr()
{

     macaddr=$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null|md5sum|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/00:\2:\3:\4:\5:01/')
    uci set wireless.@wifi-iface[1].macaddr="$macaddr"
    uci commit wireless
    ifdown wwan
    sleep 2
    ifup wwan

}

NetStatus()
{
    logger WifiMgr: Checking network...
    # Sleep adjusts for network not up on boot
   if [ $firstboot -eq 0 ]; then
     firstboot=1
     sleep $PingSleep
   fi
    net=$(ping $PingLocation -c5 |grep "time=")
    if [ "$net" ]; then
        logger WifiMgr: Network OK
                #got ping response!
                return
    else
        logger WifiMgr: Network failed. Starting network change...
        NetChange
    fi
}

NetChange()
{
    logger WifiMgr: Performing network scan...
        scanres=
        ifconfig wlan0 down
        iw phy phy0 interface add scan0 type station
        ifconfig scan0 up

        while [ "$scanres" = "" ]; do
                #Sometimes it shows nothing, so better to ensure we did a correct scan
                scanres=$(iw scan0 scan|grep SSID)
        done

        iw dev scan0 del
        ifconfig wlan0 up
        killall -HUP hostapd > /dev/null 2>&1
    logger WifiMgr: WifiMgr: Searching available networks...
    
    if [ "$1" ]; then
        ssid=net"$1"_ssid
        eval ssid=\$$ssid
        logger Trying to connect to network "$1"":    $ssid"
        n=$(expr "$1" - "1")
    else
            n=0
        fi
        
        while [ "1" ]; do
                n=$(expr "$n" + "1")

                if [ "$n" = "99" ]; then
                                #too much counts. Crazy wireless count, breaking loop!
                                break
                fi

                ssid=net"$n"_ssid
                encrypt=net"$n"_encrypt
                key=net"$n"_key

                eval ssid=\$$ssid
                eval encrypt=\$$encrypt
                eval key=\$$key
                
                if [ "$ssid" = "" ]; then
                                #ssid not existing or empty. Assume it's the end of the wlist file
                uci set wireless.@wifi-iface[1].disabled="1"
                uci commit wireless
                ifdown wwan
        sleep 2
        ifup wwan
                logger WifiMgr: No usable APs found, disabling the WWAN.
                                break
                fi
                logger SSID: $ssid
                logger Password: $key
                logger Encryption: $encrypt
                

                active=$(logger $scanres | grep " $ssid ">&1 )
                if [ "$active" ]; then
                    if [ "$1" ]; then
                        logger Network found. Connecting...
                    fi
            logger WifiMgr: "$ssid" network found. Applying settings..
                        uci set wireless.@wifi-iface[1].ssid="$ssid"
                        uci set wireless.@wifi-iface[1].encryption="$encrypt"
                        uci set wireless.@wifi-iface[1].key="$key"
            uci set wireless.@wifi-iface[1].disabled="0"
            uci delete wireless.@wifi-iface[1].bssid
                        uci commit wireless
                        ifdown wwan
            sleep 2
            ifup wwan
                        
                        #wait some seconds for everything to connect and configure
                        sleep $NewConnCheckTimer
                        logger WifiMgr: Checking connectivity...

                        #check for internet connection, 5 ping sends
                        net=$(ping $PingLocation -c5 |grep "time=")
                        if [ "$net" ]; then
                #got ping response!
                logger WifiMgr: Internet working! Searching ended
                if [ "$1" ]; then
                    logger Sucess!
                fi
                            break
                        fi
                        if [ "$1" ]; then
                            logger Connection failed!
                            break
                        fi
            logger WifiMgr: Failed! Searching next available network...
                fi
        done
}

if [ "$1" = "" ]; then
    logger "No arguments supplied"

elif [ "$1" = "--force" ]; then
    NetChange $2

elif [ "$1" = "--daemon" ]; then

    if [ "$randMac" = "1" ]; then
        randMacAddr    
    fi
    NetChange

    while [ "1" ]; do
        sleep $ConnCheckTimer
            NetStatus
    done

else
    logger "Wrong arguments"
fi

(Last edited by hostle19 on 17 Feb 2016, 06:02)

Hi,

Quick question:

hostle19 wrote:

I also switched out the echo's for logger's and fixed a typo..

killall -HUP hostapd ... should be hostpad

I've never heard of 'hostpad'.  I searched but failed miserably.  Is there a good reference link?  TIA.

Clemmitt

ahh nope, that's pure late night dyslexia on my behalf hahaha ..thanks for pointing that out smile too funny, I will fix that in my post

(Last edited by hostle19 on 17 Feb 2016, 05:59)

Thanks for the review and freshening up.

I have loaded the new wifiMgr for the startup.  Unfortunately I am having problems.  It appears as "Disabled" in startup.  I can enable it, but when I click "Start" it becomes disabled.  Same for restart.  It also shows as PID 2, even though it says 90 in the script.  Executing at the CLI I get

"Command '/etc/init.d/wifiMgr enable' failed with return code 2 and error message /bin/sh: can;t open 'etc.rc,common'

I admittedly do not understand the details behind the commands, but reading this https://wiki.openwrt.org/doc/uci/network it's not clear to me that restarting the wwan interface for the change of STA to a STA on a different channel is adequate.  The AP channel will also need to be reconfigured to match the new STA.  (line 109 or so)  This does not matter when the existing AP is just disabled. (line 86)  No clue about the MAC change.

It's not something I can test at home.  All my test devices are on a single channel, which is that of my main AP.

Config path change is good, now it's in the back up file I assume.  Just easier to deal with in general.

that's strange, it works great here, do you c/p it or type it into the file ? looking at the error i see a comma where a period should be ...

'etc.rc,common'

if you c/p perhaps their is extra windows characters present since i used a windows pc to upload it, check it with vi for windows style line feeds ... M^

(Last edited by hostle19 on 17 Feb 2016, 17:17)

I am thinking about cleaning it up and redoing it in lua, however I am not sure I completely understand what its main purpose is ... from what i gather, it scans from available AP's and compares them against the known AP's from the config file, if it finds a match it then test for a net connection and if it succeeds it add the connection to the wireless config ?

I take it it sets up as a client, however how do you determine you should use @wifi-iface[1] ? my wireless client sets up on @wifi-iface[0] ... i could dertermine this be searching for the mode=sta value and grab the number index that way, I was just curious how you determined to use 1

User error(s).... sorry
The code above was mis-typed while looking at a windows dialog box issued by the CLI component of WinSCP in response to /etc/init.d/wifiMgr enable (what a mouthful).

I have reformatted and uploaded the file and it seems to work.  I did notice the first time I loaded it it was "disabled", however it still showed that it ran in the logs.  I enabled it and started it in System => Startup.  Restart gave a "Connection Reset", but after a reboot all now works fine.

I have not tested the core function yet.

The need is for an automated Wifi Manager for a travel router.  I should be able to use the device in known and unknown locations.  In a known location it should auto scan and connect to an AP in the order that is specified in a list (automatically).  In unknown locations I should be able to scan for an AP and connect (manually in LuCi).  I should also be able to add this to the list for future use.

The functionality is pretty much like one sees on any laptop or wireless device.

The devil is always in the details.

The code was written by dabyd64 about 18 months ago for a similar, but different need.  The big issue in OpenWrt land is the missing WWAN fails the WLAN.  Was not an issue in the original need.

1 - The function periodically checks for a connection (ping test) and if a working connection is found sleeps for a period (default 1 minute). 

2 - If no connection is found it then tests the configs in the list to see which is available. 

3 - If it finds one, it then uses that info to update the wireless config.  If not it disables the WWAN and returns to (1)

4 - After the config is updated it tests it again to make sure its really working. 

5 - If it's working it goes to sleep and returns to (1).  If it's not working it goes back to the list (2) and continues where it left off

I do not fully understand all the code, like around line 31 #Sometimes it shows nothing.....

There is a check at line 70 which the author limited the list of saved APs to 99.  Don't care really.  I could see with a save AP feature that the list could get long, but that's more of a maintenance issue.  Not sure how long it takes to check an AP.  Ping time x number of checks x number of APs =???

I added the process to disable the existing STA in step 3 before continuing, as with out this there is NO access to the WLAN (a basic issue) and there are legit times that this will occur (car, plane, etc).  There probably should be a check up front of the status for the condition of the device already having a disabled WWAN in which case it is not disabled again. 

I added the PingSleep to address the issue about the network starting.   I have kept increasing this value, trying to find the value that gets the network running before a scan, but it's still not reliable.  It really should be tied to an event or status of the networking.  This is a small irritant in the function. 

I am not married to the logic or tools used. 

For example there are two sections of code to check for a connection.  One up front and the other right after a change.  I expect they could be a single function called twice.  I am of the opinion that there may be a better way to check for a network connection than ping. 

You asked about the wifi-iface naming.  I chose wifi-iface[1] because to manually change APs in Luci I find I have to delete the STA and then add a new one by unchecking the box.  If I do not do it this way the existing configs are replaced.  When you delete the STA, it moves the Master up to the first location.  If we assume we will use this tool to manually add a new STAtion (current method) and that we will not want to change our WLAN side connection, then this made the tool much more reliable as the Master should not go away (the original code was wifi-iface[0]).   I think calling the element by STA as opposed to iface would be better, though not sure it's possible.  It also might better support multiple radios (I use a 2nd USB radio in one device, not tested it yet) though not a big concern  The goal, in part, is to fix the issue that drove me to 2 radios.

The adding of a new manual station also drove the BSSID fix (delete).  The function does not use BSSID, and it appears (good/bad/right/wrong) that it's not absolutely needed, but is added in a manual add of an AP.  I believe there are six elements that are required to define the iface,.  The function only uses some, i added at BSSID and the not fully required Status.  I am not clear what good practice suggests. 

A LuCi GUI would be real nice.  The level of sophistication is up to you.  I would see a form with 2 sections.  One for STAtion management and another for operating parameters.  The operating parameters I think are straight forward.  As for station management, there are numerous approaches, but it's basically a list and a form I think.  If the form had a button that could populate the existing station that would be great. 

Hope I have not scared you off.  The function really seems to work pretty good in practice, but can be improved.  The ability to add a STAtion, even manually, inside of Luci would be great.  Anything you are willing to do is appreciated.

I have installed the new function. 

This link has a copy of the related system logs.  You can see that there is a redundant and strange SSID line being generated.  The line is actually a list of the available SSIDs in reverse order.
https://www.dropbox.com/s/a55iq9wk4pbnh … g.txt?dl=0

The function is not finding any APs, and will disable an existing good AP. 
Force will not update an AP either.

It also appears that the password for the last SSID is not being read right.  The SSID is not in range and the password has what might be considered special chrs.

I am not sure what you mean by new function ?  Regardless, I have pretty well redone the whole deal in lua, the necessary functions are complete, and I have created a LuCI interface to set the general config settings and add networks. I just need to finish the main dispatcher function which acts like a thread dispatcher firing the functions based on intervals instead of sleeping.

here's a look at the functions...

--[[ NETWORK MANAGER MODULE ]]--

-- VERSION 1.00
-- By HOSTLE 2/17/2016

module("wifiMgr.functions", package.seeall)


--## DEPENDANCIES ##--
require ("uci")
local util = require ("luci.util")
local sys = require ("luci.sys")
local uci = uci.cursor()

--## LOCAL BUFFERS ##--
local buf = {}
local ssta = {}
local csta = {}

--## PING ADDRESS ##--
local p_addr = uci:get("wifiMgr", "conn", "PingLocation")

--## TEST IF NETWORK IS UP ##--
function network_up(net)
  local ip_pat = "%d+.%d+.%d+.%d+"
  local str = sys.exec("ifconfig "..net.." |grep 'inet addr:'")
  if str:find(ip_pat) then return true else return false end
end

--## RANDOM MAC ADDRESS ##--
local function randmac()
  local mac = sys.exec("dd if=/dev/urandom bs=1024 count=1 2>/dev/null|md5sum|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/00:\2:\3:\4:\5:01/'")
  mac = string.format("%s:%s:%s:%s:%s:%s", mac:sub(0,2),mac:sub(3,4), mac:sub(6,7),mac:sub(9,10),mac:sub(12,13),mac:sub(15,16))
  mac = mac:upper()
 return mac
end

--## TEST FOR INTERNET CONNECTION ##--
function nettest()
  repeat
    local up = network_up("wlan0")
  until up
  print("NETWORK IS UP")
  local has_net = sys.exec("ping "..p_addr.." -c1 |grep -o time")
  if has_net:sub(0,-2) == "time" then return true else return false end
 return
end

--## FIND THE CONFIG SECTION FOR A GIVEN FIELD AND VALUE ##--
local function conf_sec(field,val)
  local i = 0
  local sec
  repeat
    sec = uci:get("wifiMgr.@wifi["..i.."]."..field)
    i = i + 1
    if sec == nil then return end
  until sec == val
 return i-1
end

--## FIND THE STA SECTION IN THE WIFI CONFIG ##--
local function net_sec()
  local i = 0
  local sec
  repeat
    sec = uci:get("wireless.@wifi-iface["..i.."].mode")
    i = i + 1
   if sec == nil then return end
  until sec == "sta"
 return i-1
end

--## LOAD TRUSTED NETWORKS FROM CONFIG INTO TABLE ##--
local function config_sta()
  uci:foreach("wifiMgr", "wifi", function(s) if s.ssid ~= nil then csta[#csta+1]=s.ssid end end )
end

--## SCAN AVAILABLE NETWORKS AND LOAD INTO TABLE ##--
local function scan()
  local i = 1
  sys.exec("ifconfig wlan0 down")
  sys.exec("iw phy phy0 interface add scan0 type station")
  sys.exec("ifconfig scan0 up")
  local file = io.popen("iw scan0 scan")
  for line in file:lines() do
    buf[i] = line:sub(line:find("%w"),-1)
    --print(buf[i])
    i = i +1
  end
  file:close()
  sys.exec("iw dev scan0 del")
  sys.exec("ifconfig wlan0 up")
 return buf
end

--## SORT SCANNED NETWORKS AND CREATE A TABLE WITH SSID AS KEY AND BSSID AS VAL ##--
local function avail_sta()
  local x = 1
  local ss
  local bssid
  for i=1, #buf do
    if buf[i]:find("BSS") then
      bssid = buf[i]:sub(5,-11)
      x = 1
      repeat
      if buf[i+x]:find("SSID") and buf[i+x]:len() > 7 then
        ss = buf[i+x]:sub(7,-1)
      end
      x = x + 1
      until ss ~= nil
     -- print(ss)
      ssta[ss]=bssid:upper()
     -- print(ssta[ss])
      bssid = nil
      ss = nil
    end
  end
 return ssta
end

--## DEBBUGGING FUNCTION FOR NEWTWORK SCAN ##--
local function get_ssta()
  local x = 1
  local sta = {}

  for i,v in pairs(buf) do
    if v:find("BSS") then
      sta[x] = { ["BSSID"] = v:sub(5,-11) }
      print(sta[x]["BSSID"]:upper())
    end
    if v:find("signal") then
      sta[x]= { ["SIG"]= v:sub(10,-4) }
      print(sta[x]["SIG"])
    end
    if v:find("SSID") and v:len() > 8 then
      sta[x]= { ["SSID"]= v:sub(7,-1) }
      print(sta[x]["SSID"].."\n")
    end
    x = x + 1
  end
end

--## ADD THE NETWORK TO THE WIRELESS CONFIG ##--
local function set_client(ssid,enc,key)
  local sec = net_sec()
  local bssid = ssta[ssid]
  --print(ssid,enc,key,bssid)
  uci:set("wireless.@wifi-iface["..sec.."].ssid="..ssid)
  uci:set("wireless.@wifi-iface["..sec.."].encryption="..enc)
  uci:set("wireless.@wifi-iface["..sec.."].key="..key)
  uci:set("wireless.@wifi-iface["..sec.."].bssid="..bssid)
end

--## PREPARE A NETWORK ENTRY AND SEND IT TO SET_NETWORK TO BE ADDED ##--
local function prep_client(ssid)
  local sec = conf_sec("ssid", ssid)
  local ssid = ssid
  local enc = uci:get("wifiMgr.@wifi["..sec.."].encrypt")
  local key = uci:get("wifiMgr.@wifi["..sec.."].key")
  set_client(ssid,enc,key)
end

--## SCAN FOR NETWORKS AND FIND A MATCH IF ANY ##--
function find_network()
  scan()
  avail_sta()
  config_sta()

  for i,v in pairs(ssta) do
    if util.contains(csta, i) then
      print("FOUND A MATCH")
      prep_client(i)
      return true
    end
  end
 return false
end

--## ADD THE CURRENT NETWORK TO THE CONFIG IF IT DOESN'T EXIST ##--
function add_network()
  local sec = net_sec()
  config_sta()
  local ssid = uci:get("wireless.@wifi-iface["..sec.."].ssid")
  local enc = uci:get("wireless.@wifi-iface["..sec.."].encryption")
  local key = uci:get("wireless.@wifi-iface["..sec.."].key")
  if not util.contains(csta, ssid) then
    uci:add("wifiMgr", "wifi")
    uci:commit("wifiMgr")
    uci:set("wifiMgr.@wifi[+1].ssid="..ssid)
    uci:set("wifiMgr.@wifi[+1].encrypt="..enc)
    uci:set("wifiMgr.@wifi[+1].key="..key)
    uci:commit("wifiMgr")
  else
    print("SSID: "..ssid.." ALREADY EXISTS")
  end 
 return
end

and the new config ..
/etc/config/wifiMgr

config set 'conn'
    option ConnCheckTimer '60'
    option NewConnCheckTimer '25'
    option PingLocation 'www.google.com'
    option PingSleep '5'
    option randMac '0'

config wifi
    option encryption 'ON'
    option encrypt 'psk2'
    option ssid 'dummy'
    option key 'secret'

the luci controller
/usr/lib/lua/luci/controller/admin/wifiMgr.lua

--[[
LuCI - Lua Configuration Interface
$Id: wifiMgr.lua 2/17/2016 by Hostle 
]]--

module("luci.controller.admin.wifiMgr", package.seeall)




function index()
    entry({"admin", "wifiMgr"}, alias("admin", "wifiMgr", "wifiMgr"), _("wifiMgr"), 66).index = true
    entry({"admin", "wifiMgr", "wifiMgr"}, cbi("admin_wifiMgr/wifiMgr"), _("wifiMgr Options"), 60)
    entry({"admin", "wifiMgr", "start"}, call("action_start"), _(""),62 )
    entry({"admin", "wifiMgr", "restart"}, call("action_restart"), _(""),63 )
    entry({"admin", "wifiMgr", "clear"}, call("action_clear"), _(""),64 )
    entry({"admin", "wifiMgr", "stop"}, call("action_stop"), _(""),65 )
end

function action_start()
  wm.start_wifiMgr()
 return
end

function action_restart()
  wm.restart_wifiMgr()
 return
end

function action_clear()
  wm.clear_log()
 return
end

function action_stop()
  wm.stop_wifiMgr()
 return
end

and the model
/usr/lib/lua/luci/model/cbi/admin_wifiMgr/wifiMgr.lua

--[[
LuCI - Lua Configuration Interface
$Id: wifiMgr.lua 2/17/2016 by Hostle
]]--

local m, s, o

m = Map("wifiMgr", translate("Wifi Manager"), translate("Here you can configure your AP Settings"))


s = m:section(NamedSection, "conn", "set",  translate("General Settings"))
s.anonymous = true
s.addremove = false

--
-- General Settings
--

o = s:option(Value, "ConnCheckTimer", translate("Check Connection Interval"))
o.default = 60
o.rmempty = false

o = s:option(Value, "NewConnCheckTimer", translate("Network Check Interval"))
o.default = 25
o.rmempty = false

o = s:option(Value, "PingLocation", translate("Ping Adddress"))
o.default = "www.google.com"
o.rmempty = false

o = s:option(Value, "PingSleep", translate("Firstboot Interval"))
o.default = 60
o.rmempty = false

o = s:option(Value, "randMac", translate("Randonmize Mac Address"))
o.default = 0
o.rmempty = false

--
-- Trusted AP Settings
--

s = m:section(TypedSection, "wifi", translate("Trusted AP's"))
s.anonymous = true
s.addremove = true

function s.parse(self, ...)
    TypedSection.parse(self, ...)
end

o = s:option(Value, "ssid", translate("SSID"))
o.default = "Dummy"
o.rmempty = false

o = s:option(ListValue, "encryption", translate("Wireless Security"))
o.default = "OFF"
o.rmempty = false
o:value("ON", "ON")
o:value("OFF", "OFF")


o = s:option(ListValue, "encrypt", translate("Encyption Type"))
o.default = "psk2"
o.rmempty = false
o:depends("encryption", "ON")
o:value("none", "No Encryption")
o:value("wep-open", "Wep Open")
o:value("wep-shared", "No Wep Shared")
o:value("psk", "WPA-PSK")
o:value("psk2", "WPA-PSK2")
o:value("psk-mixed", "WPA-PSK/WPA2-PSK Mixed Mode")

o = s:option(Value, "key", translate("Password"))
o.rmempty = false

return m

I will hopefully get a chance to finish it off this weekend

(Last edited by hostle19 on 18 Feb 2016, 03:22)