From 475f371bb8506b03004b23ecd20da47ac0ca88e0 Mon Sep 17 00:00:00 2001 From: Tim Wilkinson Date: Wed, 6 Dec 2023 10:12:11 -0800 Subject: [PATCH] Initial OpenWRT 23.05.0 merge (#963) * Initial OpenWRT 23.05.0 merge * Fix get_rfchannels for new iwinfo format * Fix initial wlan name * Move patches to 5.15 from 5.10 * Fix flash write problem on Ubiquiti devices * Use new ssl patch * Reduce binary sizes * Have to have hostapd installed now, even on tiny builds * Simplify device support * Revert Mikrotik NAND sysupgrade system. OpenWRT doesnt really support Mikrotik NAND devices after 2019 and the new support appeared broken. So reverted to the 2022 mechanism which does work and avoid upgrade problems. * Fixes for tiny builds * More tiny shrinking * Fix newly added firewall rules * Update permanent packages * Update permanent packages * Support for Nanobeam 2AC (2.4GHz) device. 20MHz channels only. * Update support * Add GL.iNet B1300 * Add to radios.json * Update supported devices * Dont force the LAN DHCP to run * Revert CURL SSL test * Fix radio count when there are no radios * Switch the lan ports on the gl-b1300 * Add support for GL.iNET Beryl MT1300 * Fix visual lat/lon setting bug * Make the setup "Save Changes" button also save the location data * Fix location/map system with geo location fallback * Recolor * Fix default bandwidth selection * Support multi-band radios * Generic mechanism to set compat version to 1.1 * Switch ethernet ports * 20 MHz channels only * Update docs * Add ham channels to Mediatek chips (20MHz only) * Automatically update the permpkg list when we upgrade * Fix 10MHz mode for Ubiquiti AC devices * Fix tiny builds * Bump the watch timeout for restarting olsrd olsrd is reliable these days, and very occasionally this was restarting it unnecessarily --- .circleci/config.yml | 20 +- Makefile | 2 +- SUPPORTED_DEVICES.md | 10 +- configs/ath79-generic.config | 2 +- configs/ath79-tiny.config | 6 +- configs/common.config | 3 +- configs/ipq40xx-generic.config | 3 + configs/ramips-mt7621.config | 3 + feeds.conf | 2 +- files/etc/config.mesh/network | 4 + files/etc/config/dhcp | 1 + files/etc/mesh-release | 2 +- files/etc/permpkg | 60 +- files/etc/radios.json | 18 + files/etc/uci-defaults/11_compat_version | 21 +- files/etc/uci-defaults/94_update_permpkg | 4 + files/usr/lib/lua/aredn/hardware.lua | 40 +- files/usr/lib/lua/aredn/utils.lua | 2 +- files/usr/lib/lua/luci/ohttp.lua | 554 + files/usr/local/bin/mgr/watchdog.lua | 2 +- files/usr/local/bin/mgr/wireless_monitor.lua | 6 - files/usr/local/bin/node-setup | 6 + files/www/cgi-bin/admin | 2 +- files/www/cgi-bin/advancedconfig | 2 +- files/www/cgi-bin/advancednetwork | 2 +- files/www/cgi-bin/mesh | 2 +- files/www/cgi-bin/ports | 2 +- files/www/cgi-bin/scan | 2 +- files/www/cgi-bin/setup | 88 +- files/www/cgi-bin/signal | 2 +- files/www/cgi-bin/status | 2 +- files/www/cgi-bin/vpn | 2 +- files/www/cgi-bin/vpnc | 2 +- files/www/dot.png | Bin 262 -> 788 bytes openwrt.mk | 2 +- ...79-add-support-for-TP-Link-CPE605-v1.patch | 189 - ...-ath79-cpe220v3-sysupgrade-supported.patch | 3 +- ...01-ath79-reverse-wpad-basic-mbedtls.patch} | 14 +- patches/006-flash-fixes.patch | 28 + patches/006-rocket-m-flash-fix.patch | 15 - patches/010-lz77-decompression-support.patch | 5 +- patches/701-ath9k-reset.patch | 99 - patches/701-extended-spectrum.patch | 6 +- patches/706-MeshNode-SSID.patch | 25 +- patches/708-define-aredn-ath79-networks.patch | 30 +- .../708-define-aredn-ipq40xx-networks.patch | 49 +- .../708-define-aredn-ramips-networks.patch | 13 + .../708-define-aredn-rocket-m-networks.patch | 13 - patches/709-iperf-fw-restart.patch | 2 +- .../711-aredn-ports-dumbswitch-ar8216.patch | 8 +- patches/712-auto-distance-settings.patch | 14 +- patches/719-disable-ipv6.patch | 38 +- patches/730-ipq40xx-dsa.patch | 19078 ---------------- patches/731-ag71xx-updates-and-fixes.patch | 97 - .../742-5-and-10mhz-ath10k-ct-support.patch | 10 +- .../742-radio-extend-mediatek-support.patch | 88 + patches/743-mac80211-ath10k.patch | 22 +- patches/747-mikrotik-extra-support.patch | 326 +- patches/749-copy-tiny-nodes-to-generic.patch | 130 - patches/752-mikrotik-nand-revert.patch | 37 + patches/753-ubiquiti-2ac.patch | 77 + patches/800-upgrade-compatibility.patch | 6 +- patches/series | 13 +- 63 files changed, 1227 insertions(+), 20089 deletions(-) create mode 100755 configs/ipq40xx-generic.config create mode 100755 configs/ramips-mt7621.config create mode 100755 files/etc/uci-defaults/94_update_permpkg create mode 100755 files/usr/lib/lua/luci/ohttp.lua mode change 100644 => 100755 files/www/dot.png delete mode 100644 patches/0001-ath79-add-support-for-TP-Link-CPE605-v1.patch rename patches/{001-ath79-reverse-wpad-basic-wolfssl.patch => 001-ath79-reverse-wpad-basic-mbedtls.patch} (82%) mode change 100644 => 100755 create mode 100644 patches/006-flash-fixes.patch delete mode 100644 patches/006-rocket-m-flash-fix.patch delete mode 100755 patches/701-ath9k-reset.patch create mode 100755 patches/708-define-aredn-ramips-networks.patch delete mode 100644 patches/708-define-aredn-rocket-m-networks.patch delete mode 100644 patches/730-ipq40xx-dsa.patch create mode 100644 patches/742-radio-extend-mediatek-support.patch delete mode 100644 patches/749-copy-tiny-nodes-to-generic.patch create mode 100755 patches/752-mikrotik-nand-revert.patch create mode 100755 patches/753-ubiquiti-2ac.patch diff --git a/.circleci/config.yml b/.circleci/config.yml index c2138d56..b9f93aef 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -79,14 +79,22 @@ jobs: name: Build ath79/nand command: make MAINTARGET=ath79 SUBTARGET=nand no_output_timeout: 1h + - run: + name: Build ipq40xx/generic + command: make MAINTARGET=ipq40xx SUBTARGET=generic + no_output_timeout: 2h - run: name: Build ipq40xx/mikrotik command: make MAINTARGET=ipq40xx SUBTARGET=mikrotik - no_output_timeout: 2h + no_output_timeout: 1h - run: name: Build x64/64 command: make MAINTARGET=x86 SUBTARGET=64 no_output_timeout: 2h + - run: + name: Build ramips/mt7621 + command: make MAINTARGET=ipq40xx SUBTARGET=mt7621 + no_output_timeout: 2h - run: name: Compress build files command: tar -cjf ~/${CIRCLE_BRANCH}_${ARTIFACTS_FILE} -C ${MY_WORKING_DIRECTORY}/${ARTIFACTS_DIR} . @@ -126,14 +134,22 @@ jobs: name: Build ath79/nand command: make MAINTARGET=ath79 SUBTARGET=nand no_output_timeout: 1h + - run: + name: Build ipq40xx/generic + command: make MAINTARGET=ipq40xx SUBTARGET=generic + no_output_timeout: 2h - run: name: Build ipq40xx/mikrotik command: make MAINTARGET=ipq40xx SUBTARGET=mikrotik - no_output_timeout: 2h + no_output_timeout: 1h - run: name: Build x64/64 command: make MAINTARGET=x86 SUBTARGET=64 no_output_timeout: 2h + - run: + name: Build ramips/mt7621 + command: make MAINTARGET=ipq40xx SUBTARGET=mt7621 + no_output_timeout: 2h - run: name: Compress build files command: tar -cjf ~/${CIRCLE_BRANCH}_${ARTIFACTS_FILE} -C ${MY_WORKING_DIRECTORY}/${ARTIFACTS_DIR} . diff --git a/Makefile b/Makefile index 8c06940e..3f04e84f 100644 --- a/Makefile +++ b/Makefile @@ -96,7 +96,7 @@ feeds-update: stamp-clean-feeds-updated .stamp-feeds-updated cd $(OPENWRT_DIR); ./scripts/feeds install curl cd $(OPENWRT_DIR); ./scripts/feeds install ntpclient cd $(OPENWRT_DIR); ./scripts/feeds install socat - cd $(OPENWRT_DIR); ./scripts/feeds install luci-base + cd $(OPENWRT_DIR); ./scripts/feeds install luci-lib-base cd $(OPENWRT_DIR); ./scripts/feeds install luci-lib-nixio cd $(OPENWRT_DIR); ./scripts/feeds install luci-lib-ip cd $(OPENWRT_DIR); ./scripts/feeds install luci-lib-jsonc diff --git a/SUPPORTED_DEVICES.md b/SUPPORTED_DEVICES.md index fa3ed8cc..de9f13a4 100644 --- a/SUPPORTED_DEVICES.md +++ b/SUPPORTED_DEVICES.md @@ -15,9 +15,9 @@ The 'target' and 'subtarget' identify the directory in which to find the image o ## Mikrotik Model | SKUs | Band | Target | Subtarget | Image | RAM | Stability | Status :------ | :----: | :----: | :------: | :---------: | :-----: | :---: | :---------: | :------ -hAP ac lite
hAP ac lite TC | RB952Ui-5ac2nD
RB952Ui-5ac2nD-TC | 2 | ath79 | mikrotik | mikrotik-952ui-5ac2nd | 64MB | stable | released -hAP ac² | RBD52G-5HacD2HnD-TC | 2 | ipq40xx | mikrotik | mikrotik_hap-ac2 | 128MB | stable | released -hAP ac³ | RBD53iG-5HacD2HnD | 2 | ipq40xx | mikrotik | mikrotik_hap-ac3 | 256MB | stable | released +hAP ac lite
hAP ac lite TC | RB952Ui-5ac2nD
RB952Ui-5ac2nD-TC | 2 & 5 | ath79 | mikrotik | mikrotik-952ui-5ac2nd | 64MB | stable | released +hAP ac² | RBD52G-5HacD2HnD-TC | 2 & 5 | ipq40xx | mikrotik | mikrotik_hap-ac2 | 128MB | stable | released +hAP ac³ | RBD53iG-5HacD2HnD | 2 & 5 | ipq40xx | mikrotik | mikrotik_hap-ac3 | 256MB | stable | released SXTsq Lite2 | RBSXTsq2nD | 2 | ath79 | mikrotik | mikrotik-sxt-2nd | 64MB | stable | released SXTsq Lite5 | RBSXTsq5nD | 5 | ath79 | mikrotik | mikrotik-sxt-5nd | 64MB | stable | released SXTsq 5 High Power | RBSXTsq5HPnD | 5 | ath79 | mikrotik | mikrotik-sxt-5hpnd | 64MB | stable | released @@ -47,6 +47,7 @@ Bullet M2 XW || 2 | ath79 | generic | ubnt_bullet-m-xw | 64MB | untested | relea LiteAP 5AC | LAP-120
LAP-120-US
LBE-5AC-16-120
LBE-5AC-16-120-US | 5 | ath79 | generic | ubnt_lap-120 | 64MB | stable | released LiteBeam AC5 Gen2 | LBE-5AC
LBE-5AC-US | 5 | ath79 | generic | ubnt_litebeam-ac-gen2 | 64MB | stable | released LiteBeam M5 || 5 | ath79 | - | - | 64MB | untested | released +NanoBeam 2AC 13 (2WA) || 2 | ath79 | generic | ubnt_nanobeam-2ac-13 | 64MB | stable | nightly NanoBeam AC 5 (WA) || 5 | ath79 | generic | ubnt_nanobeam-ac | 64MB | untested | released NanoBeam AC 5 (XC) || 5 | ath79 | generic | ubnt_nanobeam-ac-xc | 64MB | stable | released NanoBeam AC 5 Gen 2 (WA) || 5 | ath79 | generic | ubnt_nanobeam-ac-gen2 | 128MB | stable | released @@ -131,6 +132,8 @@ Model | SKUs | Band | Target | Subtarget | Image | RAM | Stability | Status Shadow (16MB NOR) | GL-AR300M16
GL-AR300M16-Ext | 2 | ath79 | generic | glinet_gl-ar300m16 | 64MB | stable | released Shadow (128MB NAND) | GL-AR300M
GL-AR300M-Ext | 2 | ath79 | nand | gl-ar300m | 64MB | untested | released Mudi | GL-E750 | 2 | ath79 | nand | gl-e750 | 128MB | untested | released +Convexa-B | GL-B1300 | 2 & 5 | ipq40xx | generic | gl-b1300 | 256MB | untested | nightly +Beryl | GL-MT1300 | 2 & 5 | ramips | mt7621 | gl-mt1300 | 256MB | untested | nightly (4) **Sunset Devices** | | | | | | | | White | GL-AR150 | 2 | ath79 | generic | glinet_gl-ar150 | 64MB | stable | sunset (3) Microuter | GL-USB150 | 2 | ath79 | generic | glinet_gl-usb150 | 64MB | stable | sunset (3) @@ -146,6 +149,7 @@ Meraki MR-16 | MR16-HW | 5 | ath79 | - | - | 64MB | unsupported | **brick** 1. This device is supported for new installs. It can also be upgraded from 3.22.12.0 after first installing the [DangerousUpgrade package](https://github.com/kn6plv/DangerousUpgrade/raw/main/dangerousupgrade_0.1_all.ipk) to disable the firmware compatibility checks. Proceed carefully. 2. Tiny builds exclude support for *tunnels* and *WiFi AP* mode due to lack of resources. The relevant packages can be installed separately but this is not recommended. 3. These devices are no longer being manufactured by GL-iNET. They may not reboot reliably and you may need to power cycle them (several times) during an update. + 4. 20MHz channels only. Latest installation instructions are found at: https://docs.arednmesh.org/en/latest/ diff --git a/configs/ath79-generic.config b/configs/ath79-generic.config index 9fdb8e1f..c6a55310 100644 --- a/configs/ath79-generic.config +++ b/configs/ath79-generic.config @@ -20,11 +20,11 @@ CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_tplink_wbs210-v1=y CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_tplink_wbs210-v2=y CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_tplink_wbs510-v1=y CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_tplink_wbs510-v2=y -CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_ubnt_bullet-m-xw=y CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_ubnt_bullet-ac=y CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_ubnt_bullet-m-xw=y CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_ubnt_lap-120=y CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_ubnt_litebeam-ac-gen2=y +CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_ubnt_nanobeam-2ac-13=y CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_ubnt_nanobeam-ac-gen2=y CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_ubnt_nanobeam-ac=y CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_ubnt_nanobeam-ac-xc=y diff --git a/configs/ath79-tiny.config b/configs/ath79-tiny.config index 338bce5e..765edea2 100644 --- a/configs/ath79-tiny.config +++ b/configs/ath79-tiny.config @@ -11,9 +11,11 @@ CONFIG_TARGET_DEVICE_ath79_tiny_DEVICE_ubnt_picostation-m=y CONFIG_KERNEL_CC_STACKPROTECTOR_NONE=y CONFIG_KERNEL_PRINTK=n CONFIG_PACKAGE_ATH_SPECTRAL=n -CONFIG_PACKAGE_wpad-mini=m -CONFIG_PACKAGE_vtun=m CONFIG_PACKAGE_ethtool=m CONFIG_PACKAGE_iperf3=m +CONFIG_PACKAGE_libustream-mbedtls=m +CONFIG_PACKAGE_vtun=m +CONFIG_PACKAGE_wireguard=m +CONFIG_PACKAGE_wireguard-tools=m CONFIG_PKG_CC_STACKPROTECTOR_NONE=y CONFIG_PKG_FORTIFY_SOURCE_NONE=y diff --git a/configs/common.config b/configs/common.config index 9ae75f6d..bbbadf2b 100644 --- a/configs/common.config +++ b/configs/common.config @@ -115,7 +115,6 @@ CONFIG_PACKAGE_lua-bit32=y CONFIG_PACKAGE_luaposix=n CONFIG_PACKAGE_luasocket=y CONFIG_PACKAGE_lua=y -CONFIG_PACKAGE_luci-base=n CONFIG_PACKAGE_luci-lib-base=y CONFIG_PACKAGE_luci-lib-ip=y CONFIG_PACKAGE_luci-lib-jsonc=y @@ -157,6 +156,8 @@ CONFIG_PACKAGE_wpad-mini=y CONFIG_PACKAGE_xinetd=n CONFIG_PACKAGE_zlib=m CONFIG_PACKAGE_zram-swap=n +CONFIG_PKG_ASLR_PIE_NONE=y +CONFIG_PKG_RELRO_NONE=y CONFIG_PREINITOPT=y CONFIG_SECCOMP=n CONFIG_STRIP_KERNEL_EXPORTS=y diff --git a/configs/ipq40xx-generic.config b/configs/ipq40xx-generic.config new file mode 100755 index 00000000..99dbbd26 --- /dev/null +++ b/configs/ipq40xx-generic.config @@ -0,0 +1,3 @@ +CONFIG_TARGET_ipq40xx=y +CONFIG_TARGET_ipq40xx_generic=y +CONFIG_TARGET_DEVICE_ipq40xx_generic_DEVICE_glinet_gl-b1300=y diff --git a/configs/ramips-mt7621.config b/configs/ramips-mt7621.config new file mode 100755 index 00000000..77b79631 --- /dev/null +++ b/configs/ramips-mt7621.config @@ -0,0 +1,3 @@ +CONFIG_TARGET_ramips=y +CONFIG_TARGET_ramips_mt7621=y +CONFIG_TARGET_DEVICE_ramips_mt7621_DEVICE_glinet_gl-mt1300=y diff --git a/feeds.conf b/feeds.conf index c4e5ef47..f5711628 100644 --- a/feeds.conf +++ b/feeds.conf @@ -1 +1 @@ -src-git arednpackages https://github.com/aredn/aredn_packages;develop +src-git arednpackages https://github.com/kn6plv/aredn_packages;working diff --git a/files/etc/config.mesh/network b/files/etc/config.mesh/network index 7d231807..bb822a3b 100644 --- a/files/etc/config.mesh/network +++ b/files/etc/config.mesh/network @@ -1,3 +1,7 @@ +#### Globals +config globals 'globals' + option packet_steering '1' + #### Loopback configuration config interface loopback option device "lo" diff --git a/files/etc/config/dhcp b/files/etc/config/dhcp index 9944f991..73d54c2d 100644 --- a/files/etc/config/dhcp +++ b/files/etc/config/dhcp @@ -3,6 +3,7 @@ config dhcp option start 5 option limit 20 option leasetime 12h + option force 1 config dhcp option interface wan diff --git a/files/etc/mesh-release b/files/etc/mesh-release index fd640a29..f87245c8 100644 --- a/files/etc/mesh-release +++ b/files/etc/mesh-release @@ -1 +1 @@ -KN6PLV-lz77decompression-d708f8c +KN6PLV-main-cdeb1b1d diff --git a/files/etc/permpkg b/files/etc/permpkg index 3526939d..30e7d748 100644 --- a/files/etc/permpkg +++ b/files/etc/permpkg @@ -4,6 +4,7 @@ ath10k-firmware-qca4019-ct ath10k-firmware-qca9887-ct ath10k-firmware-qca988x-ct base-files +bnx2-firmware busybox ca-bundle curl @@ -14,6 +15,9 @@ firewall4 fstools fwtool getrandom +grub2 +grub2-bios-setup +grub2-efi hostapd-common iperf3 iw @@ -22,12 +26,17 @@ jansson4 jshn jsonfilter kernel +kmod-amazon-ena +kmod-amd-xgbe kmod-ath kmod-ath10k-ct kmod-ath10k-ct-smallbuffers kmod-ath9k kmod-ath9k-common +kmod-bnx2 +kmod-button-hotplug kmod-cfg80211 +kmod-crypto-acompress kmod-crypto-aead kmod-crypto-ccm kmod-crypto-cmac @@ -43,42 +52,72 @@ kmod-crypto-null kmod-crypto-rng kmod-crypto-seqiv kmod-crypto-sha256 +kmod-crypto-sha512 +kmod-e1000 +kmod-e1000e +kmod-forcedeth +kmod-fs-vfat kmod-gpio-button-hotplug kmod-hwmon-core +kmod-i2c-algo-bit +kmod-i2c-core +kmod-igb +kmod-igc +kmod-input-core kmod-ipip kmod-iptunnel kmod-iptunnel4 +kmod-ixgbe kmod-leds-gpio kmod-ledtrig-gpio kmod-lib-crc32c +kmod-lib-lzo +kmod-libphy kmod-mac80211 +kmod-mdio +kmod-mdio-devres +kmod-mii kmod-nf-conntrack kmod-nf-flow kmod-nf-log kmod-nf-nat -kmod-nf-reject kmod-nfnetlink +kmod-nf-reject kmod-nft-core kmod-nft-fib kmod-nft-nat kmod-nft-offload kmod-nls-base +kmod-nls-cp437 +kmod-nls-iso8859-1 +kmod-nls-utf8 +kmod-phy-realtek +kmod-pps +kmod-ptp +kmod-r8169 +kmod-tg3 kmod-tun kmod-usb-core kmod-usb-dwc3 kmod-usb-dwc3-qcom +libblkid1 libblobmsg-json20220515 +libblobmsg-json20230523 libc libcurl4 +libf2fs6 libgcc1 +libiperf3 +libiwinfo20210430 +libiwinfo20230701 libiwinfo-data libiwinfo-lua -libiwinfo20210430 libjson-c5 libjson-script20220515 +libjson-script20230523 liblua5.1.5 -liblucihttp-lua liblucihttp0 +liblucihttp-lua liblzo2 libmbedtls12 libmnl0 @@ -86,13 +125,18 @@ libnftnl11 libnl-tiny1 libpthread librt +libsmartcols1 libubox20220515 -libubus-lua +libubox20230523 libubus20220601 -libuci-lua +libubus20230605 +libubus-lua libuci20130104 +libuci-lua libuclient20201210 libucode20220812 +libustream-mbedtls20201210 +libuuid1 libxtables12 logd lua @@ -101,6 +145,7 @@ luci-lib-base luci-lib-ip luci-lib-jsonc luci-lib-nixio +mkf2fs mtd netifd nftables-json @@ -114,8 +159,10 @@ olsrd-mod-txtinfo olsrd-mod-watchdog openwrt-keyring opkg +partx-utils procd prometheus-exporter +r8169-firmware rpcd rpcd-mod-file rpcd-mod-luci @@ -130,8 +177,11 @@ uci uclient-fetch ucode ucode-mod-fs +ucode-mod-nl80211 +ucode-mod-rtnl ucode-mod-ubus ucode-mod-uci +ucode-mod-uloop uhttpd urandom-seed urngd diff --git a/files/etc/radios.json b/files/etc/radios.json index 215c2c23..176e4996 100644 --- a/files/etc/radios.json +++ b/files/etc/radios.json @@ -20,6 +20,16 @@ "gl.inet gl-ar750s (nor/nand)": { "maxpower": "23" }, + "gl.inet gl-b1300": { + }, + "gl.inet gl-mt1300": { + "wlan0": { + "bandwidths": [ 20 ] + }, + "wlan1": { + "bandwidths": [ 20 ] + } + }, "tp-link cpe210 v1": { "maxpower": "23", "chanpower": { @@ -555,6 +565,14 @@ "maxpower": "22", "pwroffset": "4" }, + "0xe4f2": { + "name": "Ubiquiti NanoBeam 2AC 13 (2WA)", + "wlan0": { + "bandwidths": [ 10, 20 ], + "maxpower": 21, + "pwroffset": 6 + } + }, "0xe4f5": { "name": "Ubiquiti NanoBeam AC (XC)", "maxpower": "23", diff --git a/files/etc/uci-defaults/11_compat_version b/files/etc/uci-defaults/11_compat_version index ad2ed533..a8c86eba 100644 --- a/files/etc/uci-defaults/11_compat_version +++ b/files/etc/uci-defaults/11_compat_version @@ -1,15 +1,8 @@ #! /bin/sh -case "$(/usr/local/bin/get_boardid)" in - MikroTik\ hAP\ ac2|\ - MikroTik\ hAP\ ac3|\ - MikroTik\ SXTsq\ 5\ ac*|\ - MikroTik\ LDF\ 5\ ac*|\ - MikroTik\ LHG\ 5\ ac*) - sed -i "s/^compat_version = 1.0/compat_version = 1.1/" /etc/config.mesh/_setup - sed -i "s/^compat_version = 1.0/compat_version = 1.1/" /etc/config.mesh/_setup.default - /sbin/uci -q set system.@system[0].compat_version=1.1 - /sbin/uci -q commit system - ;; - *) - ;; -esac +VER=$(jsonfilter -e '@.system.compat_version' < /etc/board.json) +if [ "${VER}" != "" ]; then + sed -i "s/^compat_version = 1.0/compat_version = ${VER}/" /etc/config.mesh/_setup + sed -i "s/^compat_version = 1.0/compat_version = ${VER}/" /etc/config.mesh/_setup.default + uci -q set system.@system[0].compat_version=${VER} + uci -q commit system +fi diff --git a/files/etc/uci-defaults/94_update_permpkg b/files/etc/uci-defaults/94_update_permpkg new file mode 100755 index 00000000..76622a2e --- /dev/null +++ b/files/etc/uci-defaults/94_update_permpkg @@ -0,0 +1,4 @@ +#! /bin/sh +# Update the permanent package list so we can't uninstall any of the standard system + +opkg list-installed | sed s/\ .*// > /etc/permpkg diff --git a/files/usr/lib/lua/aredn/hardware.lua b/files/usr/lib/lua/aredn/hardware.lua index 44774527..0ede5101 100644 --- a/files/usr/lib/lua/aredn/hardware.lua +++ b/files/usr/lib/lua/aredn/hardware.lua @@ -71,6 +71,28 @@ function hardware.get_radio() return radio_json end +function hardware.get_radio_count() + local radio = hardware.get_radio() + if not radio then + return 0 + elseif radio.wlan0 then + if radio.wlan1 then + return 2 + else + return 1 + end + else + local count = 0 + if nixio.fs.stat("/sys/class/ieee80211") then + for file in nixio.fs.dir("/sys/class/ieee80211") + do + count = count + 1 + end + end + return count + end +end + function hardware.get_radio_intf(wifiintf) local radio = hardware.get_radio() if radio and radio[wifiintf] then @@ -277,19 +299,25 @@ function hardware.get_default_channel(wifiintf) for _, channel in ipairs(hardware.get_rfchannels(wifiintf)) do if channel.frequency == 912 then - return { channel = 5, bandwidth = 5, rfband = "900MHz" } + return { channel = 5, bandwidth = 5, band = "900MHz" } end + local bws = {} + for _, v in ipairs(hardware.get_rfbandwidths(wifiintf)) + do + bws[v] = v + end + local bw = bws[10] or bws[20] or bws[5] or 0 if channel.frequency == 2397 then - return { channel = -2, bandwidth = 10, rfband = "2.4GHz" } + return { channel = -2, bandwidth = bw, band = "2.4GHz" } end if channel.frequency == 2412 then - return { channel = 1, bandwidth = 10, rfband = "2.4GHz" } + return { channel = 1, bandwidth = bw, band = "2.4GHz" } end if channel.frequency == 3420 then - return { channel = 84, bandwidth = 10, rfband = "3GHz" } + return { channel = 84, bandwidth = bw, band = "3GHz" } end if channel.frequency == 5745 then - return { channel = 149, bandwidth = 10, rfband = "5GHz" } + return { channel = 149, bandwidth = bw, band = "5GHz" } end end return nil @@ -320,7 +348,7 @@ function hardware.get_rfchannels(wifiintf) end for line in f:lines() do - local freq, num = line:match("(%d+%.%d+) GHz %(Channel (%-?%d+)%)") + local freq, num = line:match("(%d+%.%d+) GHz %(Band: .*, Channel (%-?%d+)%)") if freq and not line:match("restricted") and not line:match("disabled") then freq = tonumber("" .. freq:gsub("%.", "")) + freq_adjust if freq >= freq_min and freq <= freq_max then diff --git a/files/usr/lib/lua/aredn/utils.lua b/files/usr/lib/lua/aredn/utils.lua index 10889003..d2650caa 100755 --- a/files/usr/lib/lua/aredn/utils.lua +++ b/files/usr/lib/lua/aredn/utils.lua @@ -37,7 +37,7 @@ local nxo = require("nixio") local ipc = require("luci.ip") -require("luci.http") +require('luci.ohttp') require("uci") function round2(num, idp) diff --git a/files/usr/lib/lua/luci/ohttp.lua b/files/usr/lib/lua/luci/ohttp.lua new file mode 100755 index 00000000..20b55f28 --- /dev/null +++ b/files/usr/lib/lua/luci/ohttp.lua @@ -0,0 +1,554 @@ +-- Copyright 2008 Steven Barth +-- Copyright 2010-2018 Jo-Philipp Wich +-- Licensed to the public under the Apache License 2.0. + +local util = require "luci.util" +local coroutine = require "coroutine" +local table = require "table" +local lhttp = require "lucihttp" +local nixio = require "nixio" +local ltn12 = require "luci.ltn12" + +local table, ipairs, pairs, type, tostring, tonumber, error = + table, ipairs, pairs, type, tostring, tonumber, error + +module "luci.http" + +HTTP_MAX_CONTENT = 1024*100 -- 100 kB maximum content size + +context = util.threadlocal() + +Request = util.class() +function Request.__init__(self, env, sourcein, sinkerr) + self.input = sourcein + self.error = sinkerr + + + -- File handler nil by default to let .content() work + self.filehandler = nil + + -- HTTP-Message table + self.message = { + env = env, + headers = {}, + params = urldecode_params(env.QUERY_STRING or ""), + } + + self.parsed_input = false +end + +function Request.formvalue(self, name, noparse) + if not noparse and not self.parsed_input then + self:_parse_input() + end + + if name then + return self.message.params[name] + else + return self.message.params + end +end + +function Request.formvaluetable(self, prefix) + local vals = {} + prefix = prefix and prefix .. "." or "." + + if not self.parsed_input then + self:_parse_input() + end + + local void = self.message.params[nil] + for k, v in pairs(self.message.params) do + if k:find(prefix, 1, true) == 1 then + vals[k:sub(#prefix + 1)] = tostring(v) + end + end + + return vals +end + +function Request.content(self) + if not self.parsed_input then + self:_parse_input() + end + + return self.message.content, self.message.content_length +end + +function Request.getcookie(self, name) + return lhttp.header_attribute("cookie; " .. (self:getenv("HTTP_COOKIE") or ""), name) +end + +function Request.getenv(self, name) + if name then + return self.message.env[name] + else + return self.message.env + end +end + +function Request.setfilehandler(self, callback) + self.filehandler = callback + + if not self.parsed_input then + return + end + + -- If input has already been parsed then uploads are stored as unlinked + -- temporary files pointed to by open file handles in the parameter + -- value table. Loop all params, and invoke the file callback for any + -- param with an open file handle. + local name, value + for name, value in pairs(self.message.params) do + if type(value) == "table" then + while value.fd do + local data = value.fd:read(1024) + local eof = (not data or data == "") + + callback(value, data, eof) + + if eof then + value.fd:close() + value.fd = nil + end + end + end + end +end + +function Request._parse_input(self) + parse_message_body( + self.input, + self.message, + self.filehandler + ) + self.parsed_input = true +end + +function close() + if not context.eoh then + context.eoh = true + coroutine.yield(3) + end + + if not context.closed then + context.closed = true + coroutine.yield(5) + end +end + +function content() + return context.request:content() +end + +function formvalue(name, noparse) + return context.request:formvalue(name, noparse) +end + +function formvaluetable(prefix) + return context.request:formvaluetable(prefix) +end + +function getcookie(name) + return context.request:getcookie(name) +end + +-- or the environment table itself. +function getenv(name) + return context.request:getenv(name) +end + +function setfilehandler(callback) + return context.request:setfilehandler(callback) +end + +function header(key, value) + if not context.headers then + context.headers = {} + end + context.headers[key:lower()] = value + coroutine.yield(2, key, value) +end + +function prepare_content(mime) + if not context.headers or not context.headers["content-type"] then + if mime == "application/xhtml+xml" then + if not getenv("HTTP_ACCEPT") or + not getenv("HTTP_ACCEPT"):find("application/xhtml+xml", nil, true) then + mime = "text/html; charset=UTF-8" + end + header("Vary", "Accept") + end + header("Content-Type", mime) + end +end + +function source() + return context.request.input +end + +function status(code, message) + code = code or 200 + message = message or "OK" + context.status = code + coroutine.yield(1, code, message) +end + +-- This function is as a valid LTN12 sink. +-- If the content chunk is nil this function will automatically invoke close. +function write(content, src_err) + if not content then + if src_err then + error(src_err) + else + close() + end + return true + elseif #content == 0 then + return true + else + if not context.eoh then + if not context.status then + status() + end + if not context.headers or not context.headers["content-type"] then + header("Content-Type", "text/html; charset=utf-8") + end + if not context.headers["cache-control"] then + header("Cache-Control", "no-cache") + header("Expires", "0") + end + if not context.headers["x-frame-options"] then + header("X-Frame-Options", "SAMEORIGIN") + end + if not context.headers["x-xss-protection"] then + header("X-XSS-Protection", "1; mode=block") + end + if not context.headers["x-content-type-options"] then + header("X-Content-Type-Options", "nosniff") + end + + context.eoh = true + coroutine.yield(3) + end + coroutine.yield(4, content) + return true + end +end + +function splice(fd, size) + coroutine.yield(6, fd, size) +end + +function redirect(url) + if url == "" then url = "/" end + status(302, "Found") + header("Location", url) + close() +end + +function build_querystring(q) + local s, n, k, v = {}, 1, nil, nil + + for k, v in pairs(q) do + s[n+0] = (n == 1) and "?" or "&" + s[n+1] = util.urlencode(k) + s[n+2] = "=" + s[n+3] = util.urlencode(v) + n = n + 4 + end + + return table.concat(s, "") +end + +urldecode = util.urldecode + +urlencode = util.urlencode + +function write_json(x) + util.serialize_json(x, write) +end + +-- from given url or string. Returns a table with urldecoded values. +-- Simple parameters are stored as string values associated with the parameter +-- name within the table. Parameters with multiple values are stored as array +-- containing the corresponding values. +function urldecode_params(url, tbl) + local parser, name + local params = tbl or { } + + parser = lhttp.urlencoded_parser(function (what, buffer, length) + if what == parser.TUPLE then + name, value = nil, nil + elseif what == parser.NAME then + name = lhttp.urldecode(buffer) + elseif what == parser.VALUE and name then + params[name] = lhttp.urldecode(buffer) or "" + end + + return true + end) + + if parser then + parser:parse((url or ""):match("[^?]*$")) + parser:parse(nil) + end + + return params +end + +-- separated by "&". Tables are encoded as parameters with multiple values by +-- repeating the parameter name with each value. +function urlencode_params(tbl) + local k, v + local n, enc = 1, {} + for k, v in pairs(tbl) do + if type(v) == "table" then + local i, v2 + for i, v2 in ipairs(v) do + if enc[1] then + enc[n] = "&" + n = n + 1 + end + + enc[n+0] = lhttp.urlencode(k) + enc[n+1] = "=" + enc[n+2] = lhttp.urlencode(v2) + n = n + 3 + end + else + if enc[1] then + enc[n] = "&" + n = n + 1 + end + + enc[n+0] = lhttp.urlencode(k) + enc[n+1] = "=" + enc[n+2] = lhttp.urlencode(v) + n = n + 3 + end + end + + return table.concat(enc, "") +end + +-- Content-Type. Stores all extracted data associated with its parameter name +-- in the params table within the given message object. Multiple parameter +-- values are stored as tables, ordinary ones as strings. +-- If an optional file callback function is given then it is fed with the +-- file contents chunk by chunk and only the extracted file name is stored +-- within the params table. The callback function will be called subsequently +-- with three arguments: +-- o Table containing decoded (name, file) and raw (headers) mime header data +-- o String value containing a chunk of the file data +-- o Boolean which indicates whether the current chunk is the last one (eof) +function mimedecode_message_body(src, msg, file_cb) + local parser, header, field + local len, maxlen = 0, tonumber(msg.env.CONTENT_LENGTH or nil) + + parser, err = lhttp.multipart_parser(msg.env.CONTENT_TYPE, function (what, buffer, length) + if what == parser.PART_INIT then + field = { } + + elseif what == parser.HEADER_NAME then + header = buffer:lower() + + elseif what == parser.HEADER_VALUE and header then + if header:lower() == "content-disposition" and + lhttp.header_attribute(buffer, nil) == "form-data" + then + field.name = lhttp.header_attribute(buffer, "name") + field.file = lhttp.header_attribute(buffer, "filename") + field[1] = field.file + end + + if field.headers then + field.headers[header] = buffer + else + field.headers = { [header] = buffer } + end + + elseif what == parser.PART_BEGIN then + return not field.file + + elseif what == parser.PART_DATA and field.name and length > 0 then + if field.file then + if file_cb then + file_cb(field, buffer, false) + msg.params[field.name] = msg.params[field.name] or field + else + if not field.fd then + field.fd = nixio.mkstemp(field.name) + end + + if field.fd then + field.fd:write(buffer) + msg.params[field.name] = msg.params[field.name] or field + end + end + else + field.value = buffer + end + + elseif what == parser.PART_END and field.name then + if field.file and msg.params[field.name] then + if file_cb then + file_cb(field, "", true) + elseif field.fd then + field.fd:seek(0, "set") + end + else + local val = msg.params[field.name] + + if type(val) == "table" then + val[#val+1] = field.value or "" + elseif val ~= nil then + msg.params[field.name] = { val, field.value or "" } + else + msg.params[field.name] = field.value or "" + end + end + + field = nil + + elseif what == parser.ERROR then + err = buffer + end + + return true + end, HTTP_MAX_CONTENT) + + return ltn12.pump.all(src, function (chunk) + len = len + (chunk and #chunk or 0) + + if maxlen and len > maxlen + 2 then + return nil, "Message body size exceeds Content-Length" + end + + if not parser or not parser:parse(chunk) then + return nil, err + end + + return true + end) +end + +-- Content-Type. Stores all extracted data associated with its parameter name +-- in the params table within the given message object. Multiple parameter +-- values are stored as tables, ordinary ones as strings. +function urldecode_message_body(src, msg) + local err, name, value, parser + local len, maxlen = 0, tonumber(msg.env.CONTENT_LENGTH or nil) + + parser = lhttp.urlencoded_parser(function (what, buffer, length) + if what == parser.TUPLE then + name, value = nil, nil + elseif what == parser.NAME then + name = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) + elseif what == parser.VALUE and name then + local val = msg.params[name] + + if type(val) == "table" then + val[#val+1] = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or "" + elseif val ~= nil then + msg.params[name] = { val, lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or "" } + else + msg.params[name] = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or "" + end + elseif what == parser.ERROR then + err = buffer + end + + return true + end, HTTP_MAX_CONTENT) + + return ltn12.pump.all(src, function (chunk) + len = len + (chunk and #chunk or 0) + + if maxlen and len > maxlen + 2 then + return nil, "Message body size exceeds Content-Length" + elseif len > HTTP_MAX_CONTENT then + return nil, "Message body size exceeds maximum allowed length" + end + + if not parser or not parser:parse(chunk) then + return nil, err + end + + return true + end) +end + +-- This function will examine the Content-Type within the given message object +-- to select the appropriate content decoder. +-- Currently the application/x-www-urlencoded and application/form-data +-- mime types are supported. If the encountered content encoding can't be +-- handled then the whole message body will be stored unaltered as "content" +-- property within the given message object. +function parse_message_body(src, msg, filecb) + if msg.env.CONTENT_LENGTH or msg.env.REQUEST_METHOD == "POST" then + local ctype = lhttp.header_attribute(msg.env.CONTENT_TYPE, nil) + + -- Is it multipart/mime ? + if ctype == "multipart/form-data" then + return mimedecode_message_body(src, msg, filecb) + + -- Is it application/x-www-form-urlencoded ? + elseif ctype == "application/x-www-form-urlencoded" then + return urldecode_message_body(src, msg) + + end + + -- Unhandled encoding + -- If a file callback is given then feed it chunk by chunk, else + -- store whole buffer in message.content + local sink + + -- If we have a file callback then feed it + if type(filecb) == "function" then + local meta = { + name = "raw", + encoding = msg.env.CONTENT_TYPE + } + sink = function( chunk ) + if chunk then + return filecb(meta, chunk, false) + else + return filecb(meta, nil, true) + end + end + -- ... else append to .content + else + msg.content = "" + msg.content_length = 0 + + sink = function( chunk ) + if chunk then + if ( msg.content_length + #chunk ) <= HTTP_MAX_CONTENT then + msg.content = msg.content .. chunk + msg.content_length = msg.content_length + #chunk + return true + else + return nil, "POST data exceeds maximum allowed length" + end + end + return true + end + end + + -- Pump data... + while true do + local ok, err = ltn12.pump.step( src, sink ) + + if not ok and err then + return nil, err + elseif not ok then -- eof + return true + end + end + + return true + end + + return false +end diff --git a/files/usr/local/bin/mgr/watchdog.lua b/files/usr/local/bin/mgr/watchdog.lua index 4fbd7b42..42c0f9a9 100644 --- a/files/usr/local/bin/mgr/watchdog.lua +++ b/files/usr/local/bin/mgr/watchdog.lua @@ -65,7 +65,7 @@ end function watchdog() while true do - wait_for_ticks(21) + wait_for_ticks(223) local pid = read_all(pidfile) if pid and nixio.fs.stat("/proc/" .. pid) then diff --git a/files/usr/local/bin/mgr/wireless_monitor.lua b/files/usr/local/bin/mgr/wireless_monitor.lua index 89f5e452..14c53c1d 100755 --- a/files/usr/local/bin/mgr/wireless_monitor.lua +++ b/files/usr/local/bin/mgr/wireless_monitor.lua @@ -104,12 +104,6 @@ function M.reset_network(mode) elseif mode == "scan-all" then os.execute(IW .. " " .. wifi .. " scan > /dev/null 2>&1") os.execute(IW .. " " .. wifi .. " scan passive > /dev/null 2>&1") - elseif mode == "reset" then - if chipset == "ath9k" then - write_all("/sys/kernel/debug/ieee80211/" .. phy .. "/ath9k/reset", "1") - else - write_all("/sys/kernel/debug/ieee80211/" .. phy .. "/ath10k/simulate_fw_crash", "hw-restart") - end else log:write("-- unknown") end diff --git a/files/usr/local/bin/node-setup b/files/usr/local/bin/node-setup index 55f01a6d..00b47dbd 100755 --- a/files/usr/local/bin/node-setup +++ b/files/usr/local/bin/node-setup @@ -764,6 +764,7 @@ c:commit("dhcp") local config = "" local ifacenum = 0 local ifacecount = 0 +local devpaths = {} if nixio.fs.stat(ieee80211) then for devname in nixio.fs.dir(ieee80211) do @@ -778,6 +779,11 @@ if nixio.fs.stat(ieee80211) then if devpath:match("^platform.*/pci.*") then devpath = devpath:match("^platform/(.*)") end + local devpathc = devpaths[devpath] or 0 + devpaths[devpath] = devpathc + 1 + if devpathc > 0 then + devpath = devpath .. "+" .. devpathc + end local is_mesh_rf = false local htmode = "HT20" local disabled = "0" diff --git a/files/www/cgi-bin/admin b/files/www/cgi-bin/admin index 75ab656b..8b621a71 100755 --- a/files/www/cgi-bin/admin +++ b/files/www/cgi-bin/admin @@ -169,7 +169,7 @@ end local parms = {} local firmfile = "" if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.http') + require('luci.ohttp') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/files/www/cgi-bin/advancedconfig b/files/www/cgi-bin/advancedconfig index 04554824..f576ed0f 100755 --- a/files/www/cgi-bin/advancedconfig +++ b/files/www/cgi-bin/advancedconfig @@ -765,7 +765,7 @@ end -- read_postdata local parms = {} if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.http') + require('luci.ohttp') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/files/www/cgi-bin/advancednetwork b/files/www/cgi-bin/advancednetwork index ddac3722..19296ccf 100755 --- a/files/www/cgi-bin/advancednetwork +++ b/files/www/cgi-bin/advancednetwork @@ -300,7 +300,7 @@ local layout = layouts[get_board_type] local configs = {} if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.http') + require('luci.ohttp') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/files/www/cgi-bin/mesh b/files/www/cgi-bin/mesh index 753b0a7d..a761877d 100755 --- a/files/www/cgi-bin/mesh +++ b/files/www/cgi-bin/mesh @@ -90,7 +90,7 @@ end -- post data if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.http') + require('luci.ohttp') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/files/www/cgi-bin/ports b/files/www/cgi-bin/ports index bddfd204..94515080 100755 --- a/files/www/cgi-bin/ports +++ b/files/www/cgi-bin/ports @@ -60,7 +60,7 @@ end -- post_data local parms = {} if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.http') + require('luci.ohttp') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/files/www/cgi-bin/scan b/files/www/cgi-bin/scan index f1e62e74..a97263fd 100755 --- a/files/www/cgi-bin/scan +++ b/files/www/cgi-bin/scan @@ -149,7 +149,7 @@ end -- scan end if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.http') + require('luci.ohttp') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/files/www/cgi-bin/setup b/files/www/cgi-bin/setup index f386b51a..207d0cf1 100755 --- a/files/www/cgi-bin/setup +++ b/files/www/cgi-bin/setup @@ -41,7 +41,7 @@ require("aredn.http") require("aredn.utils") require("aredn.hardware") require("uci") -require('luci.http') +require('luci.ohttp') local html = require("aredn.html") local aredn_info = require("aredn.info") @@ -176,7 +176,7 @@ passwd1 = "" passwd2 = "" wifi_intf = "" -local phycount = tonumber(capture("ls -1d /sys/class/ieee80211/* | wc -l"):chomp()) +local phycount = aredn.hardware.get_radio_count() local radio_name = (aredn.hardware.get_radio() or {}).name or "" local M9model = radio_name:match("M9") local M3model = radio_name:match("M3") @@ -428,48 +428,53 @@ if (parms.button_apply or parms.button_save) and wifi_enable == "1" then os.execute("iw dev " .. wifi_intf .. " set txpower fixed " .. wifi_txpower .. "00 >/dev/null 2>&1") end -if parms.button_updatelocation then +if (parms.button_updatelocation or parms.button_save) then -- process gridsquare local cursora = uci.cursor(); local cursorb = uci.cursor("/etc/config.mesh") - if parms.gridsquare ~= "" then - if parms.gridsquare:match("^[A-Z][A-Z]%d%d[a-z][a-z]$") then - cursora:set("aredn", "@location[0]", "gridsquare", parms.gridsquare) - cursorb:set("aredn", "@location[0]", "gridsquare", parms.gridsquare) - out("Gridsquare updated.") + if (cursora:get("aredn", "@location[0]", "gridsquare") or "") ~= parms.gridsquare then + if parms.gridsquare ~= "" then + if parms.gridsquare:match("^[A-Z][A-Z]%d%d[a-z][a-z]$") then + cursora:set("aredn", "@location[0]", "gridsquare", parms.gridsquare) + cursorb:set("aredn", "@location[0]", "gridsquare", parms.gridsquare) + out("Gridsquare updated.") + else + err("ERROR: Gridsquare format is: 2-uppercase letters, 2-digits, 2-lowercase letters. (AB12cd)") + end else - err("ERROR: Gridsquare format is: 2-uppercase letters, 2-digits, 2-lowercase letters. (AB12cd)") + cursora:set("aredn", "@location[0]", "gridsquare", "") + cursorb:set("aredn", "@location[0]", "gridsquare", "") + out("Gridsquare purged.") end - else - cursora:set("aredn", "@location[0]", "gridsquare", "") - cursorb:set("aredn", "@location[0]", "gridsquare", "") - out("Gridsquare purged.") end -- process lat/lng - if parms.latitude ~= "" and parms.longitude ~= "" then - if parms.latitude:match("^[-+]?%d%d?%.%d+$") and parms.longitude:match("^[-+]?%d%d?%d?%.%d+$") then - if tonumber(parms.latitude) >= -90 and tonumber(parms.latitude) <= 90 and tonumber(parms.longitude) >= -180 and tonumber(parms.longitude) <= 180 then - cursora:set("aredn", "@location[0]", "lat", parms.latitude) - cursorb:set("aredn", "@location[0]", "lat", parms.latitude) - cursora:set("aredn", "@location[0]", "lon", parms.longitude) - cursorb:set("aredn", "@location[0]", "lon", parms.longitude) - out("Lat/lon updated.") + if (cursora:get("aredn", "@location[0]", "lat") or "") ~= parms.latitude or (cursora:get("aredn", "@location[0]", "lon") or "") ~= parms.longitude then + if parms.latitude ~= "" and parms.longitude ~= "" then + if parms.latitude:match("^[-+]?%d%d?%.%d+$") and parms.longitude:match("^[-+]?%d%d?%d?%.%d+$") then + if tonumber(parms.latitude) >= -90 and tonumber(parms.latitude) <= 90 and tonumber(parms.longitude) >= -180 and tonumber(parms.longitude) <= 180 then + cursora:set("aredn", "@location[0]", "lat", parms.latitude) + cursorb:set("aredn", "@location[0]", "lat", parms.latitude) + cursora:set("aredn", "@location[0]", "lon", parms.longitude) + cursorb:set("aredn", "@location[0]", "lon", parms.longitude) + out("Lat/lon updated.") + else + err("ERROR: Lat/lon values must be between -90/90 and -180/180, respectively.") + end else - err("ERROR: Lat/lon values must be between -90/90 and -180/180, respectively.") + err("ERROR: Lat/lon format is decimal: (ex. 30.121456 or -95.911154).") end else - err("ERROR: Lat/lon format is decimal: (ex. 30.121456 or -95.911154).") + cursora:set("aredn", "@location[0]", "lat", "") + cursorb:set("aredn", "@location[0]", "lat", "") + cursora:set("aredn", "@location[0]", "lon", "") + cursorb:set("aredn", "@location[0]", "lon", "") + out("Lat/lon purged.") end - else - cursora:set("aredn", "@location[0]", "lat", "") - cursorb:set("aredn", "@location[0]", "lat", "") - cursora:set("aredn", "@location[0]", "lon", "") - cursorb:set("aredn", "@location[0]", "lon", "") - out("Lat/lon purged.") end cursora:commit("aredn") cursorb:commit("aredn") + cursor = cursora end -- retrieve location data @@ -909,7 +914,19 @@ function foundLocation(position) { } function noLocation() { - alert('Could not find location. Try pinning it on the map.'); + const req = new XMLHttpRequest(); + req.addEventListener("load", function() { + try { + const json = JSON.parse(this.responseText); + foundLocation({ coords: { latitude: json.lat, longitude: json.lon }}) + return; + } + catch (_) { + } + alert('Could not find location. Try pinning it on the map.'); + }); + req.open("GET", "http://ip-api.com/json"); + req.send(); } function updDist(x) { @@ -1441,14 +1458,11 @@ html.print("") html.print("") html.print("") html.print("
Optional Settings
Latitude") -html.print(" ") +local locdisabled = pingOK and "" or "disabled" +html.print(" ") html.print("") -html.print("  ") -if pingOK then - html.print(" ") -else - html.print(" ") -end +html.print("  ") +html.print(" ") html.print("
LongitudeGrid Square

Timezone