|
| 1 | +#!/usr/bin/lua |
| 2 | + |
| 3 | +local uci = require("simple-uci").cursor() |
| 4 | +local util = require 'gluon.util' |
| 5 | + |
| 6 | +function safety_exit(t) |
| 7 | + io.write(t .. ", exiting with error code 2") |
| 8 | + os.exit(2) |
| 9 | +end |
| 10 | + |
| 11 | +function logger(m) |
| 12 | + os.execute('logger -s -t "gluon-offline-ssid" -p 5 "' .. m .. '"') |
| 13 | +end |
| 14 | + |
| 15 | +function file_exists(name) |
| 16 | + local f = io.open(name, "r") |
| 17 | + return f ~= nil and io.close(f) |
| 18 | +end |
| 19 | + |
| 20 | +local ut = util.get_uptime() |
| 21 | +if ut < 60 then |
| 22 | + safety_exit('less than one minute') |
| 23 | +end |
| 24 | + |
| 25 | +-- only once every timeframe minutes the ssid will change to the offline-ssid |
| 26 | +-- (set to 1 minute if you want to change immediately every time the router gets offline) |
| 27 | +local minutes = tonumber(uci:get('gluon-offline-ssid', 'settings', 'switch_timeframe') or '30') |
| 28 | + |
| 29 | +-- the first few minutes directly after reboot within which an offline-ssid always may be activated |
| 30 | +-- (must be <= switch_timeframe) |
| 31 | +local first = tonumber(uci:get('gluon-offline-ssid', 'settings', 'first') or '5') |
| 32 | + |
| 33 | +-- the offline-ssid will start with this prefix use something short to leave space for the nodename |
| 34 | +-- (no '~' allowed!) |
| 35 | +local prefix = uci:get('gluon-offline-ssid', 'settings', 'prefix') or 'Offline_' |
| 36 | + |
| 37 | +local disabled = uci:get('gluon-offline-ssid', 'settings', 'disabled') == '1' or false |
| 38 | +if disabled then |
| 39 | + print("offline-ssid is disabled") |
| 40 | +end |
| 41 | +local phys = { length = 0 } |
| 42 | +uci:foreach('wireless', 'wifi-device', function(config) |
| 43 | + local phy = util.find_phy(config) |
| 44 | + if phy then |
| 45 | + phys[config['.name']] = phy |
| 46 | + phys['length'] = phys['length'] + 1 |
| 47 | + end |
| 48 | +end) |
| 49 | +if phys['length'] == 0 then |
| 50 | + safety_exit('no hostapd-phys') |
| 51 | +end |
| 52 | + |
| 53 | +local ssids = { } |
| 54 | +uci:foreach('wireless', 'wifi-iface', function(config) |
| 55 | + if config['mode'] == 'ap' and config['network'] == 'client' then |
| 56 | + local ssid = config['ssid'] |
| 57 | + if ssid then |
| 58 | + table.insert(ssids, { ssid = ssid , phy = phys[config['device']] }) |
| 59 | + end |
| 60 | + end |
| 61 | +end) |
| 62 | +if #ssids == 0 then |
| 63 | + safety_exit('no ssids') |
| 64 | +end |
| 65 | + |
| 66 | +-- generate the ssid with either 'nodename', 'mac' or to use only the prefix set to 'none' |
| 67 | +local settings_suffix = uci:get('gluon-offline-ssid', 'settings', 'suffix') or 'nodename' |
| 68 | + |
| 69 | +local suffix |
| 70 | +if settings_suffix == 'nodename' then |
| 71 | + local pretty_hostname = require 'pretty_hostname' |
| 72 | + suffix = pretty_hostname.get(uci) |
| 73 | + -- 32 would be possible as well |
| 74 | + if ( string.len(suffix) > 30 - string.len(prefix) ) then |
| 75 | + -- calculate the length of the first part of the node identifier in the offline-ssid |
| 76 | + local half = math.floor((28 - string.len(prefix) ) / 2) |
| 77 | + -- jump to this charakter for the last part of the name |
| 78 | + local skip = string.len(suffix) - half |
| 79 | + -- use the first and last part of the nodename for nodes with long name |
| 80 | + suffix = string.sub(suffix,0,half) .. '...' .. string.sub(suffix, skip) |
| 81 | + end |
| 82 | +elseif settings_suffix == 'mac' then |
| 83 | + local sysconfig = require 'gluon.sysconfig' |
| 84 | + suffix = sysconfig.primary_mac |
| 85 | +else |
| 86 | + -- 'none' |
| 87 | + suffix = '' |
| 88 | +end |
| 89 | +local offline_ssid = prefix .. suffix |
| 90 | + |
| 91 | +-- temp file to count the offline incidents during switch_timeframe |
| 92 | +local tmp = '/tmp/offline-ssid-count' |
| 93 | +local off_count = '0' |
| 94 | +if not file_exists(tmp) then |
| 95 | + assert(io.open(tmp, 'w')):write('0') |
| 96 | +else |
| 97 | + off_count = tonumber(util.readfile(tmp)) |
| 98 | +end |
| 99 | + |
| 100 | +-- if tq_limit_enabled is true, the offline ssid will only be set if there is no gateway reacheable |
| 101 | +-- upper and lower limit to turn the offline_ssid on and off |
| 102 | +-- in-between these two values the ssid will never be changed to preven it from toggeling every minute. |
| 103 | +local tq_limit_enabled = tonumber(uci:get('gluon-offline-ssid', 'settings', 'tq_limit_enabled') or '0') |
| 104 | + |
| 105 | +local check |
| 106 | +local msg |
| 107 | +if ( tq_limit_enabled == 1 ) then |
| 108 | + -- upper limit, above that the online ssid will be used |
| 109 | + local tq_limit_max = tonumber(uci:get('gluon-offline-ssid', 'settings', 'tq_limit_max') or '45') |
| 110 | + -- lower limit, below that the offline ssid will be used |
| 111 | + local tq_limit_min = tonumber(uci:get('gluon-offline-ssid', 'settings', 'tq_limit_min') or '35') |
| 112 | + -- grep the connection quality of the currently used gateway |
| 113 | + local gateway_tq = util.exec('batctl gwl | grep -e "^=>" -e "^\\*" | awk -F %'[()]%' %'{print $2}%' | tr -d " "') |
| 114 | + if ( gateway_tq == '' ) then |
| 115 | + -- there is no gateway |
| 116 | + local gateway_tq = 0 |
| 117 | + end |
| 118 | + msg = "tq is " .. gateway_tq |
| 119 | + |
| 120 | + if ( gateway_tq >= tq_limit_max ) then |
| 121 | + check = 1 |
| 122 | + elseif ( gateway_tq < tq_limit_min ) then |
| 123 | + check = 0 |
| 124 | + else |
| 125 | + -- get a clean run if we are in-between the grace period |
| 126 | + print(msg .. ", do nothing") |
| 127 | + os.exit(0) |
| 128 | + end |
| 129 | +else |
| 130 | + msg = "" |
| 131 | + check = os.execute('batctl gwl -H | grep -v "gateways in range"') |
| 132 | +end |
| 133 | + |
| 134 | +local up = ut / 60 |
| 135 | +local m = math.floor(up % minutes) |
| 136 | + |
| 137 | +-- debug: |
| 138 | +print("uptime in minutes:"..up..", every "..minutes.." minutes, countdown:"..m) |
| 139 | + |
| 140 | +local hup_needed = 0 |
| 141 | +local ssid_grep = 'grep "^ssid=' |
| 142 | + |
| 143 | +-- debug: |
| 144 | +-- check=0 -- set this to set the node always offline |
| 145 | + |
| 146 | +if check > 0 or disabled then |
| 147 | + print("node is online") |
| 148 | + -- check status for all physical devices |
| 149 | + for _, ssid in ipairs(ssids) do |
| 150 | + local hostapd = '/var/run/hostapd-' .. ssid.phy .. '.conf' |
| 151 | + |
| 152 | + -- first grep for online-SSID in hostapd file |
| 153 | + if os.execute(ssid_grep .. ssid.ssid .. '" ' .. hostapd) == 0 then |
| 154 | + print("current ssid is correct") |
| 155 | + break |
| 156 | + else |
| 157 | + -- set online |
| 158 | + |
| 159 | + -- debug: grep for offline_ssid in hostapd file |
| 160 | + if os.execute(ssid_grep .. offline_ssid .. '" ' .. hostapd) ~= 0 then |
| 161 | + logger('misconfiguration: did neither find ssid ' .. ssid.ssid .. ' nor ' .. offline_ssid .. '. please reboot') |
| 162 | + end |
| 163 | + |
| 164 | + local current_ssid = util.trim(util.exec(ssid_grep .. '" ' .. hostapd .. ' | cut -d"=" -f2')) |
| 165 | + -- TODO: replace ~ in current_ssid and ssid.ssid |
| 166 | + |
| 167 | + logger(msg .. ' - ssid is ' .. current_ssid .. ', change to ' .. ssid.ssid) |
| 168 | + os.execute('sed -i "s~^ssid=' .. current_ssid .. '~ssid=' .. ssid.ssid .. '~" ' .. hostapd) |
| 169 | + hup_needed = 1 |
| 170 | + end |
| 171 | + end |
| 172 | +elseif check == 0 then |
| 173 | + print("node is considered offline") |
| 174 | + if up < first or m == 0 then |
| 175 | + -- set ssid offline, only if uptime is less than first or exactly a multiplicative of switch_timeframe |
| 176 | + local t = minutes |
| 177 | + if up < first then |
| 178 | + t = first |
| 179 | + end |
| 180 | + if off_count >= t / 2 then |
| 181 | + -- node was offline more times than half of switch_timeframe (or than first) |
| 182 | + for _, ssid in ipairs(ssids) do |
| 183 | + local hostapd = '/var/run/hostapd-' .. ssid.phy .. '.conf' |
| 184 | + local current_ssid = util.trim(util.exec(ssid_grep .. '" ' .. hostapd .. ' | cut -d"=" -f2')) |
| 185 | + |
| 186 | + -- first grep for offline_ssid in hostapd file |
| 187 | + if os.execute(ssid_grep .. offline_ssid .. '" ' .. hostapd) == 0 then |
| 188 | + print('ssid ' .. current_ssid .. ' is correct') |
| 189 | + break |
| 190 | + else |
| 191 | + -- set offline |
| 192 | + |
| 193 | + -- debug: grep for online-SSID in hostapd file |
| 194 | + if os.execute(ssid_grep .. ssid.ssid .. '" ' .. hostapd) == 0 then |
| 195 | + logger('misconfiguration: did neither find ssid ' .. ssid.ssid .. ' nor ' .. offline_ssid .. '. please reboot') |
| 196 | + end |
| 197 | + |
| 198 | + logger(msg .. ' - ' off_count .. ' times offline, ssid is ' .. current_ssid .. ', change to ' .. offline_ssid) |
| 199 | + os.execute('sed -i "s~^ssid=' .. ssid.ssid .. '~ssid=' .. offline_ssid .. '~" ' .. hostapd) |
| 200 | + hup_needed = 1 |
| 201 | + end |
| 202 | + end |
| 203 | + end |
| 204 | + -- else print("minute ' .. m .. ', just count ' .. off_count .. '") |
| 205 | + end |
| 206 | + |
| 207 | + assert(io.open(tmp, 'w')):write(off_count + 1) |
| 208 | +end |
| 209 | + |
| 210 | +if hup_needed == 1 then |
| 211 | + -- send hup to all hostapd to load the new ssid |
| 212 | + os.execute('killall -hup hostapd') |
| 213 | + print("hup!") |
| 214 | +end |
| 215 | + |
| 216 | +if m == 0 then |
| 217 | + -- set counter to 0 if the timeframe is over |
| 218 | + assert(io.open(tmp, 'w')):write('0') |
| 219 | +end |
0 commit comments