From 0ef983dafdc4e8acfb0af47e074515d3136b64d9 Mon Sep 17 00:00:00 2001 From: "aiyion.prime" Date: Thu, 1 Jul 2021 12:23:48 +0200 Subject: [PATCH] ffh-obedient-meshing: add package --- ffh-obedient-meshing/Makefile | 28 ++++ .../usr/lib/micron.d/ffh-obedient-meshing | 1 + .../luasrc/usr/sbin/ffh-obedient-meshing | 152 ++++++++++++++++++ 3 files changed, 181 insertions(+) create mode 100644 ffh-obedient-meshing/Makefile create mode 100644 ffh-obedient-meshing/files/usr/lib/micron.d/ffh-obedient-meshing create mode 100755 ffh-obedient-meshing/luasrc/usr/sbin/ffh-obedient-meshing diff --git a/ffh-obedient-meshing/Makefile b/ffh-obedient-meshing/Makefile new file mode 100644 index 0000000..c3079fd --- /dev/null +++ b/ffh-obedient-meshing/Makefile @@ -0,0 +1,28 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=ffh-obedient-meshing +PKG_VERSION:=1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(TOPDIR)/../package/gluon.mk + +define Package/ffh-obedient-meshing + SECTION:=ffh + CATEGORY:=FFH + TITLE:=Automatically switch to the most popular domain in wifi reach, as soon as no mesh neighbours are available. + DEPENDS:=+gluon-core +gluon-state-check +iw +libiwinfo-lua +micrond @GLUON_MULTIDOMAIN + MAINTAINER:=Freifunk Hannover +endef + +define Package/ffh-obedient-meshing/description + This package checks periodically, whether the router has mesh-neighbours. + If it doesn't, + it scans for mesh-networks, + filters out the ones that are not part of its site and domainconf, + joins the most popular across all radios, regardless of their band. + It does so by switching its own domain. +endef + +$(eval $(call BuildPackageGluon,$(PKG_NAME))) diff --git a/ffh-obedient-meshing/files/usr/lib/micron.d/ffh-obedient-meshing b/ffh-obedient-meshing/files/usr/lib/micron.d/ffh-obedient-meshing new file mode 100644 index 0000000..507b52d --- /dev/null +++ b/ffh-obedient-meshing/files/usr/lib/micron.d/ffh-obedient-meshing @@ -0,0 +1 @@ +* * * * * sleep 10 && /usr/sbin/ffh-obedient-meshing diff --git a/ffh-obedient-meshing/luasrc/usr/sbin/ffh-obedient-meshing b/ffh-obedient-meshing/luasrc/usr/sbin/ffh-obedient-meshing new file mode 100755 index 0000000..bccd524 --- /dev/null +++ b/ffh-obedient-meshing/luasrc/usr/sbin/ffh-obedient-meshing @@ -0,0 +1,152 @@ +#!/usr/bin/lua +local uci = require("simple-uci").cursor() +local iwinfo = require "iwinfo" +local util = require "gluon.util" +local json = require "jsonc" +local sys_stat = require "posix.sys.stat" +local isreg = require "posix.sys.stat".S_ISREG +local isdir = require "posix.sys.stat".S_ISDIR +local unistd = require "posix.unistd" + + +local function has_state() + local state_path="/var/gluon/state" + local stat=sys_stat.lstat(state_path) + if nil~=stat then + return 0~=isdir(stat.st_mode) + end + return false +end + +local function has_neighbours() + local neighbours_path="/var/gluon/state/has_neighbours" + local stat=sys_stat.stat(neighbours_path) + if nil~=stat then + return 0~=isreg(stat.st_mode) + end + return false +end + +local function get_band(channel) + if channel >= 1 and channel <=14 then + return "wifi24" + elseif channel >= 36 and channel <= 165 then + return "wifi5" + end +end + +local function get_available_wifi_networks() + local radios = {} + local ssid_counts = {} + ssid_counts["wifi24"]={} + ssid_counts["wifi5"]={} + + uci:foreach('wireless', 'wifi-device', + function(s) + radios[s['.name']] = {} + end + ) + + for radio, _ in pairs(radios) do + local wifitype = iwinfo.type(radio) + local iw = iwinfo[wifitype] + if not iw then + return nil + end + local tmplist = iw.scanlist(radio) + for _, net in ipairs(tmplist) do + if net.mode and net.channel and net.ssid and "Mesh Point"==net.mode then + local band = get_band(net.channel) + if nil==ssid_counts[band][net.ssid] then + ssid_counts[band][net.ssid]=1 + else + ssid_counts[band][net.ssid]=ssid_counts[band][net.ssid]+1 + end + end + end + end + return ssid_counts +end + + +local function get_domain_list() + local list = {} + for _, domain_path in ipairs(util.glob('/lib/gluon/domains/*.json')) do + local is_primary = 0~=isreg(sys_stat.lstat(domain_path).st_mode) + if is_primary then + local domain_code = domain_path:match('([^/]+)%.json$') + local domain = assert(json.load(domain_path)) + + table.insert(list, { + domain_code = domain_code, + domain_name = domain.domain_names[domain_code], + wifi24 = domain.wifi24.mesh.id, + wifi5 = domain.wifi5.mesh.id + }) + end + end + + table.sort(list, function(a, b) return a.domain_name < b.domain_name end) + return list +end + + +local function to_domain_counts(band_ssid_counts) + local domain_code_counts={} + local domain_list = get_domain_list() + local function get_domaincode(band, ssid) + for _, domain in pairs(domain_list) do + if domain[band]==ssid then + return domain["domain_code"] + end + end + end + + for band, countlist in pairs(band_ssid_counts) do + --print(band) + for ssid, count in pairs(countlist) do + --print(ssid .. ": " ..count) + local code = get_domaincode(band, ssid) + if nil~=code then + --print(code .. ": +" ..count) + if nil==domain_code_counts[code] then + domain_code_counts[code]=count + else + domain_code_counts[code]=domain_code_counts[code]+count + end + end + end + end + + return domain_code_counts +end + +if not has_state() then + print("Device state is not available yet, aborting.") + os.exit() +end + +if has_neighbours() then + print("Device still has neighbours, no need to rescan.") + os.exit() +end + +local selected_domain = uci:get('gluon', 'core', 'domain') +print("selected domain: " .. selected_domain) +local networks = get_available_wifi_networks() + +local dom_counts = to_domain_counts(networks) + +local high = 0 +local high_dom +for dom, count in pairs(dom_counts) do + if count >= high then + high=count + high_dom=dom + end +end +print(high_dom .. ": " .. high) + + +local cmd = {[0]="gluon-switch-domain", "--no-reboot", high_dom} +unistd.execp(cmd[0], cmd)