diff --git a/Makefile b/Makefile index a9849104..34343356 100644 --- a/Makefile +++ b/Makefile @@ -103,6 +103,13 @@ endef list-targets: FORCE @$(foreach target,$(GLUON_TARGETS),echo '$(target)';) +lint: lint-lua lint-sh + +lint-lua: FORCE + @scripts/lint-lua.sh + +lint-sh: FORCE + @scripts/lint-sh.sh GLUON_DEFAULT_PACKAGES := hostapd-mini diff --git a/README.md b/README.md index 4917e82d..676d580b 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ the future development of Gluon. Please refrain from using the `master` branch for anything else but development purposes! Use the most recent release instead. You can list all releases by running `git tag` -and switch to one by running `git checkout v2019.1 && make update`. +and switch to one by running `git checkout v2020.1 && make update`. If you're using the autoupdater, do not autoupdate nodes with anything but releases. If you upgrade using random master commits the nodes *will break* eventually. diff --git a/contrib/Dockerfile b/contrib/Dockerfile index 18868378..50d7ff89 100644 --- a/contrib/Dockerfile +++ b/contrib/Dockerfile @@ -17,6 +17,7 @@ RUN apt update && apt install -y --no-install-recommends \ time \ ecdsautils \ lua-check \ + shellcheck \ && rm -rf /var/lib/apt/lists/* RUN useradd -d /gluon gluon diff --git a/contrib/ci/Jenkinsfile b/contrib/ci/Jenkinsfile index 5ecbe203..4a4cbc4c 100644 --- a/contrib/ci/Jenkinsfile +++ b/contrib/ci/Jenkinsfile @@ -1,27 +1,52 @@ pipeline { - agent { label 'gluon-docker' } - environment { - GLUON_SITEDIR = "contrib/ci/minimal-site" - GLUON_TARGET = "x86-64" - BUILD_LOG = "1" - } - stages { - stage('lint') { - steps { - sh 'luacheck package scripts targets' - } - } - stage('docs') { - steps { - sh 'make -C docs html' - } - } - stage('build') { - steps { - sh 'make update' - sh 'test -d /dl_cache && ln -s /dl_cache openwrt/dl || true' - sh 'make -j$(nproc) V=s' - } - } - } + agent none + environment { + GLUON_SITEDIR = "contrib/ci/minimal-site" + GLUON_TARGET = "x86-64" + BUILD_LOG = "1" + } + stages { + stage('lint') { + parallel { + stage('lint-lua') { + agent { label 'gluon-docker' } + steps { + sh 'make lint-lua' + } + } + stage('lint-sh') { + agent { label 'gluon-docker-v1' } + steps { + sh 'make lint-sh' + } + } + } + } + stage('docs') { + agent { label 'gluon-docker' } + steps { + sh 'make -C docs html' + } + } + stage('build') { + agent { label 'gluon-docker' } + steps { + sh 'make update' + sh 'test -d /dl_cache && ln -s /dl_cache openwrt/dl || true' + sh 'make -j$(nproc) V=s' + } + } + } } + +/* + api-history: + + Every time the build dependencies of gluon change, the version + every container has to be rebuilt. Therefore, we use Jenkins + labels which intoduce a version number which is documented here. + As soon, as you properly rebuilt your docker container, you + can notify lemoer, that you have updated your node. + + - gluon-docker-v1: add shellcheck binary to the build environment +*/ diff --git a/contrib/ci/jenkins-community-slave/README.md b/contrib/ci/jenkins-community-slave/README.md index aebc78e8..7d049133 100644 --- a/contrib/ci/jenkins-community-slave/README.md +++ b/contrib/ci/jenkins-community-slave/README.md @@ -26,7 +26,7 @@ docker run --detach --restart always \ - Your node should appear [here](https://build.ffh.zone/label/gluon-docker/). - When clicking on it, Jenkins should state "Agent is connected." like here: ![Screenshot from 2019-09-24 01-00-52](https://user-images.githubusercontent.com/601153/65469209-dac6c180-de66-11e9-9d62-0d1c3b6b940b.png) -5. **Your docker container needs to be rebuilt, when the build dependencies of gluon change. So please be aware of that and update your docker container in that case.** +5. **Your docker container needs to be rebuilt, when the build dependencies of gluon change. As soon as build dependencies have changed, the build dependency api level has to be raised.** After you rebuilt your docker container, notifiy @lemoer, so he can bump the versioning number. ## Backoff - If @lemoer is not reachable, please be patient at first if possible. Otherwise contact info@hannover.freifunk.net or join the channel `#freifunkh` on hackint. diff --git a/contrib/depdot.sh b/contrib/depdot.sh index c065ea57..4e0a9406 100755 --- a/contrib/depdot.sh +++ b/contrib/depdot.sh @@ -5,8 +5,7 @@ # * Works only if directory names and package names are the same (true for all Gluon packages) # * Doesn't show dependencies through virtual packages correctly - - +set -e shopt -s nullglob diff --git a/contrib/lsupgrade.sh b/contrib/lsupgrade.sh index eca7a852..f8e28f9a 100755 --- a/contrib/lsupgrade.sh +++ b/contrib/lsupgrade.sh @@ -1,5 +1,6 @@ #!/bin/bash +set -e # Script to list all upgrade scripts in a clear manner # Limitations: # * Does only show scripts of packages whose `files'/`luasrc' directories represent the whole image filesystem (which are all Gluon packages) @@ -27,7 +28,7 @@ fi pushd "$(dirname "$0")/.." >/dev/null -find ./package packages -name Makefile | while read makefile; do +find ./package packages -name Makefile | while read -r makefile; do dir="$(dirname "$makefile")" pushd "$dir" >/dev/null diff --git a/contrib/sign.sh b/contrib/sign.sh index c04854e8..d88bc345 100755 --- a/contrib/sign.sh +++ b/contrib/sign.sh @@ -2,7 +2,7 @@ set -e -if [ $# -ne 2 -o "-h" = "$1" -o "--help" = "$1" -o ! -r "$1" -o ! -r "$2" ]; then +if [ $# -ne 2 ] || [ "-h" = "$1" ] || [ "--help" = "$1" ] || [ ! -r "$1" ] || [ ! -r "$2" ]; then cat < diff --git a/contrib/sigtest.sh b/contrib/sigtest.sh index 2a0faf2c..0fa19f90 100755 --- a/contrib/sigtest.sh +++ b/contrib/sigtest.sh @@ -1,6 +1,6 @@ #!/bin/sh -if [ $# -eq 0 -o "-h" = "$1" -o "-help" = "$1" -o "--help" = "$1" ]; then +if [ $# -eq 0 ] || [ "-h" = "$1" ] || [ "-help" = "$1" ] || [ "--help" = "$1" ]; then cat < @@ -27,7 +27,7 @@ awk "BEGIN { sep=0 } else print > \"$lower\"}" \ "$manifest" -while read line +while read -r line do if ecdsaverify -s "$line" -p "$public" "$upper"; then ret=0 diff --git a/docs/conf.py b/docs/conf.py index bbc9fa70..4f7e5191 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -20,11 +20,11 @@ # -- Project information ----------------------------------------------------- project = 'Gluon' -copyright = '2015-2019, Project Gluon' +copyright = '2015-2020, Project Gluon' author = 'Project Gluon' # The short X.Y version -version = '2019.1+' +version = '2020.1+' # The full version, including alpha/beta/rc tags release = version diff --git a/docs/dev/hardware.rst b/docs/dev/hardware.rst index dae2bbb3..986a88bf 100644 --- a/docs/dev/hardware.rst +++ b/docs/dev/hardware.rst @@ -5,7 +5,7 @@ for new hardware to Gluon. Hardware requirements --------------------- -Having an ath9k (or ath10k) based WLAN adapter is highly recommended, +Having an ath9k, ath10k or mt76 based WLAN adapter is highly recommended, although other chipsets may also work. VAP (multiple SSID) support is a requirement. diff --git a/docs/dev/wan.rst b/docs/dev/wan.rst index 86455e91..b992146a 100644 --- a/docs/dev/wan.rst +++ b/docs/dev/wan.rst @@ -11,6 +11,11 @@ There are two cases in which the WAN port is used: After the VPN connection has been established, the node should be able to reach the mesh's DNS servers and use these for all other name resolution. +If the device does not feature a WAN port, the LAN port is configured as WAN port. +In case such a device has multiple LAN ports, all these can be used as WAN. +Devices, which feature a "hybrid" port (labled as WAN/LAN), this port is used as WAN. + +This behavior can be reversed using the ``single_as_lan`` site.conf option. Routing tables ~~~~~~~~~~~~~~ diff --git a/docs/index.rst b/docs/index.rst index ae4a4df0..261b4f52 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -74,7 +74,11 @@ Several Freifunk communities in Germany use Gluon as the foundation of their Fre :caption: Releases :maxdepth: 1 + releases/v2020.1 + releases/v2019.1.2 + releases/v2019.1.1 releases/v2019.1 + releases/v2018.2.4 releases/v2018.2.3 releases/v2018.2.2 releases/v2018.2.1 diff --git a/docs/package/gluon-radv-filterd.rst b/docs/package/gluon-radv-filterd.rst index 509599d0..7b07ff9c 100644 --- a/docs/package/gluon-radv-filterd.rst +++ b/docs/package/gluon-radv-filterd.rst @@ -13,29 +13,32 @@ Selected router The router selection mechanism is independent from the batman-adv gateway mode. In contrast, the device originating the router advertisement could be any router or client connected to the mesh, as radv-filterd captures all router -advertisements originating from it. All nodes announcing router advertisement +advertisements originating from it. All nodes announcing router advertisement **with** a default lifetime greater than 0 are being considered as candidates. In case a router is not a batman-adv originator itself, its TQ is defined by the originator it is connected to. This lookup uses the batman-adv global translation table. -Initially the router is the selected by choosing the candidate with the -strongest TQ. When another candidate can provide a better TQ metric it is not -picked up as the selected router until it will outperform the currently -selected router by X metric units. The hysteresis threshold is configurable -and prevents excessive flapping of the gateway. +Initially the router is selected by choosing the candidate with the strongest +TQ. When another candidate can provide a better TQ metric, that outperforms the +currently selected router by X metric units, it will be picked as the new +selected router. The hysteresis threshold is configurable and prevents excessive +flapping of the gateway. -"Local" routers ---------------- +Local routers +------------- -The package has functionality to select "local" routers, i.e. those connected -via cable or WLAN instead of via the mesh (technically: appearing in the -``transtable_local``), a fake TQ of 512 so that they are always preferred. -However, if used together with the :doc:`gluon-ebtables-filter-ra-dhcp` -package, these router advertisements are filtered anyway and reach neither the -node nor any other client. You currently have to disable the package or insert -custom ebtables rules in order to use local routers. +Local routers (i.e. local internet gateways connected to some nodes) that are +connected to the client interface via cable or WLAN instead of via the mesh +(technically: appearing in the transtable_local) are taken into account with a +fake TQ of 512, so that they are always preferred. + +Be aware of problems if you plan to use local routers together with the +:doc:`gluon-ebtables-filter-ra-dhcp` package. These router advertisements are +filtered anyway and reach neither the node nor any other client. Therefore the +use of local routers is not possible as long as the package +``gluon-radv-filterd`` is used. respondd module --------------- diff --git a/docs/releases/v2018.2.4.rst b/docs/releases/v2018.2.4.rst new file mode 100644 index 00000000..bddae46d --- /dev/null +++ b/docs/releases/v2018.2.4.rst @@ -0,0 +1,53 @@ +Gluon 2018.2.4 +============== + +End of life +~~~~~~~~~~~~~~ + +This will be the final release of the v2018.2.x series. Updating to the v2019.1.x release series is the recommended course of action, which should be fairly easy. + +Bugfixes +~~~~~~~~ + +* Fixes device alias for Ubiquiti UniFi AC LR. (`#1834 `_) + Autoupdates on this model were impossible before, since we were missing the proper device alias. + +* Add correct ath10k firmware package for OCEDO Koala. (`#1838 `_) + +* Fixes various batman-adv bugs with backports from 2019.4 and 2019.5 by updating the openwrt-routing packages feed + +Other changes +~~~~~~~~~~~~~ + +* Linux kernel has been updated to either + + - 4.9.207 (ar71xx, brcm2708, mpc85xx) or + - 4.14.160 (ipq40xx, ipq806x, mvebu, ramips, sunxi, x86). + +Known issues +~~~~~~~~~~~~ + +* Default TX power on many Ubiquiti devices is too high, correct offsets are + unknown (`#94 `_) + + Reducing the TX power in the Advanced Settings is recommended. + +* The MAC address of the WAN interface is modified even when Mesh-on-WAN is + disabled (`#496 `_) + + This may lead to issues in environments where a fixed MAC address is expected + (like VMware when promiscuous mode is disallowed). + +* Inconsistent respondd API + (`#522 `_) + + The current API is inconsistent and will be replaced eventually. The old API + will still be supported for a while. + +* Frequent reboots due to out-of-memory or high load due to memory pressure on + weak hardware especially in larger meshes + (`#1243 `_) + + Optimizations in Gluon 2018.1 have significantly improved memory usage. + There are still known bugs leading to unreasonably high load that we hope to + solve in future releases. diff --git a/docs/releases/v2019.1.1.rst b/docs/releases/v2019.1.1.rst new file mode 100644 index 00000000..0385e8bf --- /dev/null +++ b/docs/releases/v2019.1.1.rst @@ -0,0 +1,62 @@ +Gluon 2019.1.1 +############## + +Bugfixes +******** + +* Fixes device alias for Ubiquiti UniFi AC LR. (`#1834 `_) + Autoupdates on this model were impossible before, since we were missing the proper device alias. + +* Add correct ath10k firmware package for OCEDO Koala. (`#1838 `_) + +* Fixes various batman-adv bugs with backports from 2019.4 and 2019.5 by updating the openwrt-routing packages feed. + +* Fixes node role list. (`#1851 `_) + With Gluon v2019.1 it became impossible to change the role of a node via the config mode. + +Other Changes +************* + +* Linux kernel has been updated to either + + - 4.9.207 (ar71xx, brcm2708, mpc85xx) or + - 4.14.160 (ipq40xx, ipq806x, mvebu, ramips, sunxi, x86). + +Known issues +************ + +* Out of memory situations with high client count on ath9k. + (`#1768 `_) + +* The integration of the BATMAN_V routing algorithm is incomplete. + + - | Mesh neighbors don't appear on the status page. (`#1726 `_) + | Many tools have the BATMAN_IV metric hardcoded, these need to be updated to account for the new throughput + | metric. + + - | Throughput values are not correctly acquired for different interface types. + | (`#1728 `_) + | This affects virtual interface types like bridges and VXLAN. + +* Default TX power on many Ubiquiti devices is too high, correct offsets are unknown + (`#94 `_) + + Reducing the TX power in the Advanced Settings is recommended. + +* The MAC address of the WAN interface is modified even when Mesh-on-WAN is disabled + (`#496 `_) + + This may lead to issues in environments where a fixed MAC address is expected (like VMware when promiscuous mode is + disallowed). + +* Inconsistent respondd API (`#522 `_) + + The current API is inconsistent and will be replaced eventually. The old API will still be supported for a while. + +* Frequent reboots due to out-of-memory or high load due to memory pressure on weak hardware especially in larger + meshes (`#1243 `_) + + Optimizations in Gluon 2018.1 have significantly improved memory usage. + There are still known bugs leading to unreasonably high load that we hope to + solve in future releases. + diff --git a/docs/releases/v2019.1.2.rst b/docs/releases/v2019.1.2.rst new file mode 100644 index 00000000..7d44fd49 --- /dev/null +++ b/docs/releases/v2019.1.2.rst @@ -0,0 +1,58 @@ +Gluon 2019.1.2 +############## + +Bugfixes +******** + +* Fixes a buffer-overflow vulnerability in libubox, a core component of OpenWrt + (CVE-2020-7248) + +* Fixes a vulnerability in the OpenWrt package manager (opkg). By using this vulnerability, + an attacker could bypass the integrity check of the package artifacts. (CVE-2020-7982) + +Other Changes +************* + +* Linux kernel has been updated to either + + - 4.9.211 (ar71xx, brcm2708, mpc85xx) or + - 4.14.167 (ipq40xx, ipq806x, mvebu, ramips, sunxi, x86). + +Known issues +************ + +* Out of memory situations with high client count on ath9k. + (`#1768 `_) + +* The integration of the BATMAN_V routing algorithm is incomplete. + + - | Mesh neighbors don't appear on the status page. (`#1726 `_) + | Many tools have the BATMAN_IV metric hardcoded, these need to be updated to account for the new throughput + | metric. + + - | Throughput values are not correctly acquired for different interface types. + | (`#1728 `_) + | This affects virtual interface types like bridges and VXLAN. + +* Default TX power on many Ubiquiti devices is too high, correct offsets are unknown + (`#94 `_) + + Reducing the TX power in the Advanced Settings is recommended. + +* The MAC address of the WAN interface is modified even when Mesh-on-WAN is disabled + (`#496 `_) + + This may lead to issues in environments where a fixed MAC address is expected (like VMware when promiscuous mode is + disallowed). + +* Inconsistent respondd API (`#522 `_) + + The current API is inconsistent and will be replaced eventually. The old API will still be supported for a while. + +* Frequent reboots due to out-of-memory or high load due to memory pressure on weak hardware especially in larger + meshes (`#1243 `_) + + Optimizations in Gluon 2018.1 have significantly improved memory usage. + There are still known bugs leading to unreasonably high load that we hope to + solve in future releases. + diff --git a/docs/releases/v2019.1.rst b/docs/releases/v2019.1.rst index 9c1ce60b..a9e0a829 100644 --- a/docs/releases/v2019.1.rst +++ b/docs/releases/v2019.1.rst @@ -15,6 +15,7 @@ possible. With Gluon v2019.1, nodes will not answer respondd queries on ``[ff02::2:1001]:1001`` anymore. Respondd querier setups still using this address must be updated to the new address ``[ff05::2:1001]:1001`` (supported since Gluon v2017.1). This change was required due to cross-domain leakage of respondd data. +If you are using hopglass-server to query respondd data, you need to update it to at least commit f0e2c0a5. If you are upgrading from a version prior to v2018.1, please note that the flash layout on some devices (TP-Link CPE/WBS 210/510) was changed. To avoid upgrade failures, make sure to upgrade diff --git a/docs/releases/v2020.1.rst b/docs/releases/v2020.1.rst new file mode 100644 index 00000000..9fc8566e --- /dev/null +++ b/docs/releases/v2020.1.rst @@ -0,0 +1,191 @@ +Gluon 2020.1 +============ + +This is the first release of Gluon in 2020, based on OpenWrt 19.07. It +introduces the ath79 target, which will replace ar71xx in the short +term. + +Added hardware support +---------------------- + +ath79-generic +~~~~~~~~~~~~~ + +- devolo WiFi pro 1200e +- devolo WiFi pro 1200i +- devolo WiFi pro 1750c +- devolo WiFi pro 1750e +- devolo WiFi pro 1750i +- devolo WiFi pro 1750x +- GL.iNet GL-AR300M-Lite +- OCEDO Raccoon +- TP-Link Archer C6 v2 + +ipq40xx-generic +~~~~~~~~~~~~~~~ + +- Aruba AP-303 +- Aruba Instant On AP11 +- AVM FRITZ!Repeater 1200 + +ipq806x-generic +~~~~~~~~~~~~~~~ + +- Netgear R7800 + +lantiq-xway +~~~~~~~~~~~ + +- AVM FRITZ!Box 7312 +- AVM FRITZ!Box 7320 +- AVM FRITZ!Box 7330 +- AVM FRITZ!Box 7330 SL + +lantiq-xrx200 +~~~~~~~~~~~~~ + +- AVM FRITZ!Box 7360 (v1, v2) +- AVM FRITZ!Box 7360 SL +- AVM FRITZ!Box 7362 SL +- AVM FRITZ!Box 7412 + +mpc85xx-p1020 +~~~~~~~~~~~~~ + +- Enterasys WS-AP3710i +- OCEDO Panda + +ramips-mt7620 +~~~~~~~~~~~~~ + +- TP-Link Archer C2 (v1) +- TP-Link Archer C20 (v1) +- TP-Link Archer C20i +- TP-Link Archer C50 (v1) +- Xiaomi MiWifi Mini + +ramips-mt7621 +~~~~~~~~~~~~~ + +- Netgear EX6150 (v1) +- Netgear R6220 + +ramips-mt76x8 +~~~~~~~~~~~~~ + +- GL.iNet VIXMINI +- TP-Link TL-MR3020 (v3) +- TP-Link TL-WA801ND (v5) +- TP-Link TL-WR902AC (v3) + +Removed hardware support +------------------------ + +- ALFA Network Hornet-UB [#kernelpartition_too_small]_ +- ALFA Network Tube2H [#kernelpartition_too_small]_ +- ALFA Network N2 [#kernelpartition_too_small]_ +- ALFA Network N5 [#kernelpartition_too_small]_ + +.. [#kernelpartition_too_small] + The kernel partition on this device is too small to build a working image. + +Major changes +------------- + +OpenWrt 19.07 +~~~~~~~~~~~~~ + +Gluon v2020.1 is the first release to use OpenWrt 19.07. All targets +therefore use Linux 4.14.166. + +batman-adv compat v14 removal +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Support for the long deprecated compat 14 version of batman-adv has been +dropped. Communities still using this version should migrate to batman-adv +using the scheduled domain switch. + +IBSS wireless mesh removal +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Support for the IBSS wireless protocol has been dropped. Communities +still using IBSS are suggested to migrate to 802.11s using the scheduled +domain switch. + +Performance enhancements +~~~~~~~~~~~~~~~~~~~~~~~~ + +We install zram-swap by default on ``ar71xx`` devices with 8MB of flash +and 32MB of RAM. + +Renamed targets +~~~~~~~~~~~~~~~ + +- The ``ipq40xx`` target was renamed to ``ipq40xx-generic``. +- The ``ipq806x`` target was renamed to ``ipq806x-generic``. + +Status Page +~~~~~~~~~~~ + +- Gateway nexthop information has been added to the statuspage when batman-adv + is used. This includes its MAC address and prettyname as well as the interface + name towards the selected gateway. +- The site name has been added to the statuspage. If the node is in a multidomain + setup it will also show the domain name. + +DECT button to enter config mode +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Many AVM devices don't feature a separate RESET/WPS button, therefore +starting this release we support entering the config mode via DECT buttons. + +X86 partition size +~~~~~~~~~~~~~~~~~~ + +The x86 partition size has been reduced to fit on disks with a capacity of 128 MB. + +Bugfixes +-------- + +Autoupdater aliases +~~~~~~~~~~~~~~~~~~~ + +We have added several new aliases for autoupdater compatibility on +the following devices: + +- Ubiquiti UniFi AC LR +- Raspberry Pi + +Site changes +------------ + +site.mk +~~~~~~~ + +- The ``GLUON_WLAN_MESH`` variable can be dropped, as 802.11s is + the only supported wireless transport from now on. + +Internals +--------- + +Linting Targets +~~~~~~~~~~~~~~~ + +Support for linter make targets was added. + +- ``make lint`` +- ``make lint-sh`` to only check shell scripts +- ``make lint-lua`` to only check lua scripts + +These require the shellcheck and luacheck tools. The docker image has +been updated accordingly. + +Continuous integration +~~~~~~~~~~~~~~~~~~~~~~ + +We have implemented continuous integration testing using Jenkins and thereby +ensure that all lua and shell scripts are linted, that the documentation +still builds and warnings are highlighted, and that Gluon still +compiles, by testing a build on the ``x86_64`` target. We expect this to +significantly improve the feedback cycle and quality of contributions. + diff --git a/docs/site-example/site.conf b/docs/site-example/site.conf index 2b9c9584..405daca3 100644 --- a/docs/site-example/site.conf +++ b/docs/site-example/site.conf @@ -1,4 +1,4 @@ --- This is an example site configuration for Gluon v2019.1 +-- This is an example site configuration for Gluon v2020.1 -- -- Take a look at the documentation located at -- https://gluon.readthedocs.io/ for details. diff --git a/docs/user/getting_started.rst b/docs/user/getting_started.rst index 95c4407a..57996a56 100644 --- a/docs/user/getting_started.rst +++ b/docs/user/getting_started.rst @@ -8,7 +8,7 @@ Gluon's releases are managed using `Git tags`_. If you are just getting started with Gluon we recommend to use the latest stable release of Gluon. Take a look at the `list of gluon releases`_ and notice the latest release, -e.g. *v2019.1*. Always get Gluon using git and don't try to download it +e.g. *v2020.1*. Always get Gluon using git and don't try to download it as a Zip archive as the archive will be missing version information. Please keep in mind that there is no "default Gluon" build; a site configuration @@ -44,7 +44,7 @@ Building the images ------------------- To build Gluon, first check out the repository. Replace *RELEASE* with the -version you'd like to checkout, e.g. *v2019.1*. +version you'd like to checkout, e.g. *v2020.1*. :: @@ -120,7 +120,7 @@ There are two levels of `make clean`:: make clean GLUON_TARGET=ar71xx-generic -will ensure all packages are rebuilt for a single target. This normally not +will ensure all packages are rebuilt for a single target. This is usually not necessary, but may fix certain kinds of build failures. :: diff --git a/docs/user/supported_devices.rst b/docs/user/supported_devices.rst index 250d51d6..3c23eda0 100644 --- a/docs/user/supported_devices.rst +++ b/docs/user/supported_devices.rst @@ -37,13 +37,13 @@ ar71xx-generic - DIR-505 (A1, A2) - DIR-825 (B1) -* GL Innovations +* GL.iNet + - 6408A + - 6416A - GL-AR150 - GL-AR300M - GL-AR750 - - GL-iNet 6408A (v1) - - GL-iNet 6416A (v1) * Linksys @@ -82,7 +82,7 @@ ar71xx-generic - CPE220 (v1.1) - CPE510 (v1.0, v1.1) - CPE520 (v1.1) - - RE450 + - RE450 (v1) - TL-WDR3500 (v1) - TL-WDR3600 (v1) - TL-WDR4300 (v1) @@ -183,6 +183,23 @@ ar71xx-tiny [#deprecated]_ ath79-generic -------------- +* devolo + + - WiFi pro 1200e [#lan_as_wan]_ + - WiFi pro 1200i + - WiFi pro 1750c + - WiFi pro 1750e [#lan_as_wan]_ + - WiFi pro 1750i + - WiFi pro 1750x + +* GL.iNet + + - GL-AR300M-Lite + +* OCEDO + + - Raccoon + * TP-Link - Archer C6 (v2) @@ -212,8 +229,8 @@ ipq40xx-generic * NETGEAR - - EX6100v2 - - EX6150v2 + - EX6100 (v2) + - EX6150 (v2) * OpenMesh @@ -237,6 +254,9 @@ lantiq-xrx200 * AVM + - FRITZ!Box 7360 (v1, v2) [#avmflash]_ [#lan_as_wan]_ + - FRITZ!Box 7360 SL [#avmflash]_ [#lan_as_wan]_ + - FRITZ!Box 7362 SL [#eva_ramboot]_ [#lan_as_wan]_ - FRITZ!Box 7412 [#eva_ramboot]_ lantiq-xway @@ -245,6 +265,9 @@ lantiq-xway * AVM - FRITZ!Box 7312 [#avmflash]_ + - FRITZ!Box 7320 [#avmflash]_ [#lan_as_wan]_ + - FRITZ!Box 7330 [#avmflash]_ [#lan_as_wan]_ + - FRITZ!Box 7330 SL [#avmflash]_ [#lan_as_wan]_ mpc85xx-generic --------------- @@ -260,6 +283,10 @@ mpc85xx-p1020 - HiveAP 330 +* Enterasys + + - WS-AP3710i + * OCEDO - Panda @@ -267,7 +294,7 @@ mpc85xx-p1020 ramips-mt7620 ------------- -* GL Innovations +* GL.iNet - GL-MT300A - GL-MT300N @@ -277,6 +304,17 @@ ramips-mt7620 - WT3020AD/F/H +* TP-Link + + - Archer C2 v1 + - Archer C20 (v1) + - Archer C20i + - Archer C50 v1 + +* Xiaomi + + - MiWiFi Mini + ramips-mt7621 ------------- @@ -290,6 +328,7 @@ ramips-mt7621 * NETGEAR + - EX6150 (v1) - R6220 * Ubiquiti @@ -316,10 +355,13 @@ ramips-mt76x8 * TP-Link - - TL-MR3420 v5 - - TL-WR841N v13 - Archer C50 v3 - Archer C50 v4 + - TL-MR3020 v3 + - TL-MR3420 v5 + - TL-WA801ND v5 + - TL-WR841N v13 + - TL-WR902AC v3 * VoCore @@ -382,4 +424,7 @@ Footnotes .. [#eva_ramboot] For instructions on how to flash AVM NAND devices, see the respective - commit which added support in OpenWrt. \ No newline at end of file + commit which added support in OpenWrt. + +.. [#lan_as_wan] + All LAN ports on this device are used as WAN. diff --git a/modules b/modules index cfd3a689..650f294b 100644 --- a/modules +++ b/modules @@ -1,20 +1,16 @@ -GLUON_FEEDS='packages routing luci gluon' +GLUON_FEEDS='packages routing gluon' OPENWRT_REPO=https://git.openwrt.org/openwrt/openwrt.git OPENWRT_BRANCH=openwrt-19.07 -OPENWRT_COMMIT=a8b293598f181f358ba8ac988ef75a97064792e0 +OPENWRT_COMMIT=17137076732b18442202e75c7edf10bccbc5f2a2 PACKAGES_PACKAGES_REPO=https://github.com/openwrt/packages.git PACKAGES_PACKAGES_BRANCH=openwrt-19.07 -PACKAGES_PACKAGES_COMMIT=702c655874db358706b7858445b06dba09c90cd6 +PACKAGES_PACKAGES_COMMIT=99efce0cd27adfcc53384fba93f37e5ee2e517de PACKAGES_ROUTING_REPO=https://github.com/openwrt-routing/packages.git PACKAGES_ROUTING_BRANCH=openwrt-19.07 -PACKAGES_ROUTING_COMMIT=8d5ee29f088e9dfaa49dc74573edb1919f14dbf4 - -PACKAGES_LUCI_REPO=https://github.com/openwrt/luci.git -PACKAGES_LUCI_BRANCH=openwrt-19.07 -PACKAGES_LUCI_COMMIT=7542d02cd23208ca2ed89ea5341d323ca3dc4e58 +PACKAGES_ROUTING_COMMIT=efa6e5445adda9c6545f551808829ec927cbade8 PACKAGES_GLUON_REPO=https://github.com/freifunk-gluon/packages.git -PACKAGES_GLUON_COMMIT=de7b228cae72e87f2dfb3eed5b0354bd7cec4ca7 +PACKAGES_GLUON_COMMIT=12e41d0ff07ec54bbd67a31ab50d12ca04f2238c diff --git a/package/gluon-core/files/lib/netifd/proto/gluon_wired.sh b/package/gluon-core/files/lib/netifd/proto/gluon_wired.sh index 0778b354..708e9743 100755 --- a/package/gluon-core/files/lib/netifd/proto/gluon_wired.sh +++ b/package/gluon-core/files/lib/netifd/proto/gluon_wired.sh @@ -14,6 +14,7 @@ xor2() { echo -n "${1:1:1}" | tr '0123456789abcdef' '23016745ab89efcd' } +# shellcheck disable=SC2086 interface_linklocal() { local macaddr="$(ubus call network.device status '{"name": "'"$1"'"}' | jsonfilter -e '@.macaddr')" local oldIFS="$IFS"; IFS=':'; set -- $macaddr; IFS="$oldIFS" diff --git a/package/gluon-core/luasrc/lib/gluon/upgrade/010-primary-mac b/package/gluon-core/luasrc/lib/gluon/upgrade/010-primary-mac index 600a147f..f4ad37a9 100755 --- a/package/gluon-core/luasrc/lib/gluon/upgrade/010-primary-mac +++ b/package/gluon-core/luasrc/lib/gluon/upgrade/010-primary-mac @@ -50,6 +50,8 @@ elseif platform.match('ar71xx', 'generic', {'archer-c5', 'archer-c58-v1', table.insert(try_files, 1, '/sys/class/net/eth1/address') elseif platform.match('ar71xx', 'nand', {'hiveap-121'}) then table.insert(try_files, 1, '/sys/class/net/eth0/address') +elseif platform.match('ath79', 'generic', {'ocedo,raccoon'}) then + table.insert(try_files, 1, '/sys/class/net/eth0/address') elseif platform.match('ipq40xx', 'generic', {'avm,fritzbox-4040', 'openmesh,a42', 'openmesh,a62'}) then table.insert(try_files, 1, '/sys/class/net/eth0/address') @@ -59,7 +61,7 @@ elseif platform.match('mpc85xx', 'p1020', {'aerohive,hiveap-330'}) then table.insert(try_files, 1, '/sys/class/net/eth0/address') elseif platform.match('mpc85xx', 'p1020', {'ocedo,panda'}) then table.insert(try_files, 1, '/sys/class/net/eth1/address') -elseif platform.match('ramips', 'mt7620', {'miwifi-mini'}) then +elseif platform.match('ramips', 'mt7620', {'miwifi-mini', 'tplink,c2-v1', 'c20-v1', 'c20i', 'c50'}) then table.insert(try_files, 1, '/sys/class/net/eth0/address') elseif platform.match('ramips', 'mt7621', {'dir-860l-b1'}) then table.insert(try_files, 1, '/sys/class/ieee80211/phy1/macaddress') diff --git a/package/gluon-core/luasrc/usr/lib/lua/gluon/platform.lua b/package/gluon-core/luasrc/usr/lib/lua/gluon/platform.lua index d87218e6..a16c7036 100644 --- a/package/gluon-core/luasrc/usr/lib/lua/gluon/platform.lua +++ b/package/gluon-core/luasrc/usr/lib/lua/gluon/platform.lua @@ -44,6 +44,9 @@ function M.is_outdoor_device() elseif M.match('ar71xx', 'generic', {'unifiac-pro'}) and M.get_model() == 'Ubiquiti UniFi-AC-MESH-PRO' then return true + + elseif M.match('ath79', 'generic', {'devolo,dvl1750x'}) then + return true end return false diff --git a/package/gluon-mesh-babel/Makefile b/package/gluon-mesh-babel/Makefile index 4d5f1197..bdc3d4bc 100644 --- a/package/gluon-mesh-babel/Makefile +++ b/package/gluon-mesh-babel/Makefile @@ -10,7 +10,7 @@ include ../gluon.mk define Package/gluon-mesh-babel TITLE:=Babel mesh - DEPENDS:=+gluon-core +babeld +mmfd +libiwinfo +libgluonutil +firewall +libjson-c +libnl-tiny +libubus +libubox +libblobmsg-json +libbabelhelper +luabitop +gluon-l3roamd + DEPENDS:=+gluon-core +babeld +gluon-mmfd +libiwinfo +libgluonutil +firewall +libjson-c +libnl-tiny +libubus +libubox +libblobmsg-json +libbabelhelper +luabitop PROVIDES:=gluon-mesh-provider endef diff --git a/package/gluon-mesh-babel/luasrc/lib/gluon/upgrade/300-gluon-mesh-babel-mkconfig b/package/gluon-mesh-babel/luasrc/lib/gluon/upgrade/300-gluon-mesh-babel-mkconfig index 43eaa428..e9a62dbe 100755 --- a/package/gluon-mesh-babel/luasrc/lib/gluon/upgrade/300-gluon-mesh-babel-mkconfig +++ b/package/gluon-mesh-babel/luasrc/lib/gluon/upgrade/300-gluon-mesh-babel-mkconfig @@ -1,6 +1,8 @@ #!/usr/bin/lua local site = require 'gluon.site' +local uci = require('simple-uci').cursor() +local nodeip = uci:get('network', 'loopback', 'ip6addr'):match('^[^/]+') local babelconf='/etc/gluon-babeld.conf' local file = io.open(babelconf, "w") @@ -15,7 +17,7 @@ file:write("redistribute ip " .. site.prefix6() .. " eq 128 allow\n") file:write("redistribute ip " .. site.node_client_prefix6() .. " eq 128 allow\n") file:write("redistribute ip " .. site.node_prefix6() .. " eq 128 allow\n") file:write("redistribute ip 2000::/3 allow\n") - file:write("redistribute local if br-wan deny\n") file:write("redistribute local ip 0.0.0.0/0 deny\n") +file:write("install pref-src " .. nodeip .."\n") file:close() diff --git a/package/gluon-mesh-babel/src/Makefile b/package/gluon-mesh-babel/src/Makefile index 98a22d5e..80d29fa9 100644 --- a/package/gluon-mesh-babel/src/Makefile +++ b/package/gluon-mesh-babel/src/Makefile @@ -25,7 +25,7 @@ LDFLAGS_JSONC = $(shell pkg-config --libs json-c) respondd.so: respondd.c handle_neighbour.c - $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -shared $(LDFLAGS_JSONC) -o $@ $^ -lgluonutil -lblobmsg_json -lubox -lubus -liwinfo -luci + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -shared $(LDFLAGS_JSONC) -o $@ $^ -lgluonutil -lblobmsg_json -lubox -lubus -luci neighbours-babel: neighbours-babel.c handle_neighbour.c $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_JSONC) $(LDFLAGS) $(LDLIBS) $(LDFLAGS_JSONC) -o $@ $^ diff --git a/package/gluon-mesh-babel/src/respondd.c b/package/gluon-mesh-babel/src/respondd.c index d82ce6af..96195d89 100644 --- a/package/gluon-mesh-babel/src/respondd.c +++ b/package/gluon-mesh-babel/src/respondd.c @@ -26,17 +26,15 @@ #include -#include #include #include #include -#include -#include #include #include #include #include +#include #include #include @@ -49,33 +47,18 @@ #include #include -#include -#include -#include - #include -#include "errno.h" +#include #include #include -#include "libubus.h" - -#define _STRINGIFY(s) #s -#define STRINGIFY(s) _STRINGIFY(s) -#include - -#define MAX_INACTIVITY 60000 +#include #define SOCKET_INPUT_BUFFER_SIZE 255 -#define BABEL_PORT 33123 -#define VPN_INTERFACE "mesh-vpn" -#define l3rdctl "/var/run/l3roamd.sock" -#define IFNAMELEN 32 #define PROTOLEN 32 -#define UBUS_TIMEOUT 30 -#define UBUS_SOCKET "/var/run/ubus.sock" +#define UBUS_TIMEOUT 30000 static struct babelhelper_ctx bhelper_ctx = {}; @@ -241,7 +224,7 @@ static struct json_object * get_babel_neighbours(void) { if (!neighbours) return NULL; - babelhelper_readbabeldata(&bhelper_ctx, (void*)neighbours, handle_neighbour); + babelhelper_readbabeldata(&bhelper_ctx, "dump", (void*)neighbours, handle_neighbour); return(neighbours); } @@ -258,9 +241,9 @@ static void blobmsg_handle_element(struct blob_attr *attr, bool head, char **ifn switch (blob_id(attr)) { case BLOBMSG_TYPE_STRING: - if (!strncmp(blobmsg_name(attr),"device", 6)) { + if (!strncmp(blobmsg_name(attr), "device", 6)) { free(*ifname); - *ifname = strndup(data, IFNAMELEN); + *ifname = strndup(data, IF_NAMESIZE); } else if (!strncmp(blobmsg_name(attr), "proto", 5)) { free(*proto); *proto = strndup(data, PROTOLEN); @@ -330,7 +313,7 @@ static struct json_object * get_mesh_ifs() { unsigned int id=8; - ubus_ctx = ubus_connect(UBUS_SOCKET); + ubus_ctx = ubus_connect(NULL); if (!ubus_ctx) { fprintf(stderr,"could not connect to ubus, not providing mesh-data\n"); goto end; @@ -338,7 +321,7 @@ static struct json_object * get_mesh_ifs() { blob_buf_init(&b, 0); ubus_lookup_id(ubus_ctx, "network.interface", &id); - int uret = ubus_invoke(ubus_ctx, id, "dump", b.head, receive_call_result_data, &ret, UBUS_TIMEOUT * 1000); + int uret = ubus_invoke(ubus_ctx, id, "dump", b.head, receive_call_result_data, &ret, UBUS_TIMEOUT); if (uret > 0) fprintf(stderr, "ubus command failed: %s\n", ubus_strerror(uret)); @@ -386,34 +369,40 @@ static struct json_object * respondd_provider_nodeinfo(void) { return ret; } -static uint64_t getnumber(const char *ifname, const char *stat) { +static struct json_object * read_number(const char *ifname, const char *stat) { const char *format = "/sys/class/net/%s/statistics/%s"; + + struct json_object *ret = NULL; + int64_t i; + char path[strlen(format) + strlen(ifname) + strlen(stat) + 1]; snprintf(path, sizeof(path), format, ifname, stat); - if (! access(path, F_OK)) { - char *line=gluonutil_read_line(path); - long long i = atoll(line); - free(line); - return(i); - } - return 0; + + FILE *f = fopen(path, "r"); + if (!f) + return NULL; + + if (fscanf(f, "%"SCNd64, &i) == 1) + ret = json_object_new_int64(i); + + fclose(f); + + return ret; } static struct json_object * get_traffic(void) { - char ifname[16]; - - strncpy(ifname, "br-client", 16); + const char *ifname = "br-client"; struct json_object *ret = NULL; struct json_object *rx = json_object_new_object(); struct json_object *tx = json_object_new_object(); - json_object_object_add(rx, "packets", json_object_new_int64(getnumber(ifname, "rx_packets"))); - json_object_object_add(rx, "bytes", json_object_new_int64(getnumber(ifname, "rx_bytes"))); - json_object_object_add(rx, "dropped", json_object_new_int64(getnumber(ifname, "rx_dropped"))); - json_object_object_add(tx, "packets", json_object_new_int64(getnumber(ifname, "tx_packets"))); - json_object_object_add(tx, "dropped", json_object_new_int64(getnumber(ifname, "tx_dropped"))); - json_object_object_add(tx, "bytes", json_object_new_int64(getnumber(ifname, "tx_bytes"))); + json_object_object_add(rx, "packets", read_number(ifname, "rx_packets")); + json_object_object_add(rx, "bytes", read_number(ifname, "rx_bytes")); + json_object_object_add(rx, "dropped", read_number(ifname, "rx_dropped")); + json_object_object_add(tx, "packets", read_number(ifname, "tx_packets")); + json_object_object_add(tx, "dropped", read_number(ifname, "tx_dropped")); + json_object_object_add(tx, "bytes", read_number(ifname, "tx_bytes")); ret = json_object_new_object(); json_object_object_add(ret, "rx", rx); @@ -422,72 +411,6 @@ static struct json_object * get_traffic(void) { return ret; } -static void count_iface_stations(size_t *wifi24, size_t *wifi5, const char *ifname) { - const struct iwinfo_ops *iw = iwinfo_backend(ifname); - if (!iw) - return; - - int freq; - if (iw->frequency(ifname, &freq) < 0) - return; - - size_t *wifi; - if (freq >= 2400 && freq < 2500) - wifi = wifi24; - else if (freq >= 5000 && freq < 6000) - wifi = wifi5; - else - return; - - int len; - char buf[IWINFO_BUFSIZE]; - if (iw->assoclist(ifname, buf, &len) < 0) - return; - - struct iwinfo_assoclist_entry *entry; - for (entry = (struct iwinfo_assoclist_entry *)buf; (char*)(entry+1) <= buf + len; entry++) { - if (entry->inactive > MAX_INACTIVITY) - continue; - - (*wifi)++; - } -} - -static void count_stations(size_t *wifi24, size_t *wifi5) { - struct uci_context *ctx = uci_alloc_context(); - ctx->flags &= ~UCI_FLAG_STRICT; - - - struct uci_package *p; - if (uci_load(ctx, "wireless", &p)) - goto end; - - - struct uci_element *e; - uci_foreach_element(&p->sections, e) { - struct uci_section *s = uci_to_section(e); - if (strcmp(s->type, "wifi-iface")) - continue; - - const char *network = uci_lookup_option_string(ctx, s, "network"); - if (!network || strcmp(network, "client")) - continue; - - const char *mode = uci_lookup_option_string(ctx, s, "mode"); - if (!mode || strcmp(mode, "ap")) - continue; - - const char *ifname = uci_lookup_option_string(ctx, s, "ifname"); - if (!ifname) - continue; - - count_iface_stations(wifi24, wifi5, ifname); - } - -end: - uci_free_context(ctx); -} - static bool handle_route_addgw_nexthop(char **data, void *arg) { struct json_object *obj = (struct json_object*) arg; if (data[PREFIX] && data[FROM] && data[VIA] && data[IF]) { @@ -569,21 +492,12 @@ end: } static struct json_object * get_clients(void) { - size_t wifi24 = 0, wifi5 = 0; - - count_stations(&wifi24, &wifi5); - - int total = ask_l3roamd_for_client_count(); - - size_t wifi = wifi24 + wifi5; struct json_object *ret = json_object_new_object(); + int total = ask_l3roamd_for_client_count(); if (total >= 0) json_object_object_add(ret, "total", json_object_new_int(total)); - json_object_object_add(ret, "wifi", json_object_new_int(wifi)); - json_object_object_add(ret, "wifi24", json_object_new_int(wifi24)); - json_object_object_add(ret, "wifi5", json_object_new_int(wifi5)); return ret; } @@ -593,94 +507,11 @@ static struct json_object * respondd_provider_statistics(void) { json_object_object_add(ret, "clients", get_clients()); json_object_object_add(ret, "traffic", get_traffic()); - babelhelper_readbabeldata(&bhelper_ctx, (void*)ret, handle_route_addgw_nexthop ); + babelhelper_readbabeldata(&bhelper_ctx, "dump", (void*)ret, handle_route_addgw_nexthop ); return ret; } -static struct json_object * get_wifi_neighbours(const char *ifname) { - const struct iwinfo_ops *iw = iwinfo_backend(ifname); - if (!iw) - return NULL; - - int len; - char buf[IWINFO_BUFSIZE]; - if (iw->assoclist(ifname, buf, &len) < 0) - return NULL; - - struct json_object *neighbours = json_object_new_object(); - - struct iwinfo_assoclist_entry *entry; - for (entry = (struct iwinfo_assoclist_entry *)buf; (char*)(entry+1) <= buf + len; entry++) { - if (entry->inactive > MAX_INACTIVITY) - continue; - - struct json_object *obj = json_object_new_object(); - - json_object_object_add(obj, "signal", json_object_new_int(entry->signal)); - json_object_object_add(obj, "noise", json_object_new_int(entry->noise)); - json_object_object_add(obj, "inactive", json_object_new_int(entry->inactive)); - - char mac[18]; - snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x", - entry->mac[0], entry->mac[1], entry->mac[2], - entry->mac[3], entry->mac[4], entry->mac[5]); - - json_object_object_add(neighbours, mac, obj); - } - - struct json_object *ret = json_object_new_object(); - - if (json_object_object_length(neighbours)) - json_object_object_add(ret, "neighbours", neighbours); - else - json_object_put(neighbours); - - return ret; -} - -static struct json_object * get_wifi(void) { - - struct uci_context *ctx = uci_alloc_context(); - ctx->flags &= ~UCI_FLAG_STRICT; - - struct json_object *ret = json_object_new_object(); - - struct uci_package *p; - if (uci_load(ctx, "network", &p)) - goto end; - - - struct uci_element *e; - uci_foreach_element(&p->sections, e) { - struct uci_section *s = uci_to_section(e); - if (strcmp(s->type, "interface")) - continue; - - const char *proto = uci_lookup_option_string(ctx, s, "proto"); - if (!proto || strcmp(proto, "gluon_mesh")) - continue; - - const char *ifname = uci_lookup_option_string(ctx, s, "ifname"); - if (!ifname) - continue; - - char *ifaddr = gluonutil_get_interface_address(ifname); - if (!ifaddr) - continue; - - struct json_object *neighbours = get_wifi_neighbours(ifname); - if (neighbours) - json_object_object_add(ret, ifaddr, neighbours); - - free(ifaddr); - } - -end: - uci_free_context(ctx); - return ret; -} - static struct json_object * respondd_provider_neighbours(void) { struct json_object *ret = json_object_new_object(); @@ -689,10 +520,6 @@ static struct json_object * respondd_provider_neighbours(void) { json_object_object_add(ret, "babel", babel); - struct json_object *wifi = get_wifi(); - if (wifi) - json_object_object_add(ret, "wifi", wifi); - return ret; } diff --git a/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/teardown.d/70-gluon-mesh-batman-adv b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/teardown.d/70-gluon-mesh-batman-adv index 355b89b0..a8850f18 100755 --- a/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/teardown.d/70-gluon-mesh-batman-adv +++ b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/teardown.d/70-gluon-mesh-batman-adv @@ -1,5 +1,5 @@ #!/bin/sh lock /var/lock/gluon_bat0.lock -(echo 'none' > "/sys/class/net/$IFNAME/batman_adv/mesh_iface") 2>/dev/null +batctl interface del "$IFNAME" 2>/dev/null lock -u /var/lock/gluon_bat0.lock diff --git a/package/gluon-mesh-batman-adv/files/lib/netifd/proto/gluon_bat0.sh b/package/gluon-mesh-batman-adv/files/lib/netifd/proto/gluon_bat0.sh index aaf9c908..f5c54ea3 100755 --- a/package/gluon-mesh-batman-adv/files/lib/netifd/proto/gluon_bat0.sh +++ b/package/gluon-mesh-batman-adv/files/lib/netifd/proto/gluon_bat0.sh @@ -22,20 +22,9 @@ proto_gluon_bat0_renew() { lock /var/lock/gluon_bat0.lock - local ifdump="$(ubus call network.interface dump)" - - echo "$ifdump" | jsonfilter \ - -e "@.interface[@.proto='gluon_mesh' && @.up=true]['device','data']" \ - | while read dev; do - read data - - echo bat0 > "/sys/class/net/$dev/batman_adv/mesh_iface" - - ! [ "$(echo "$data" | jsonfilter -e "@.transitive")" = 'true' ] - transitive=$? - - (echo "$transitive" > "/sys/class/net/$dev/batman_adv/no_rebroadcast") 2>/dev/null - done + ubus call network.interface dump | jsonfilter \ + -e "@.interface[@.proto='gluon_mesh' && @.up=true].device" \ + | xargs -r -n 1 batctl interface add lock -u /var/lock/gluon_bat0.lock } diff --git a/package/gluon-mesh-batman-adv/src/Makefile b/package/gluon-mesh-batman-adv/src/Makefile index 0974669b..e72dce56 100644 --- a/package/gluon-mesh-batman-adv/src/Makefile +++ b/package/gluon-mesh-batman-adv/src/Makefile @@ -31,5 +31,8 @@ endif CFLAGS += $(LIBBATADV_CFLAGS) LDLIBS += $(LIBBATADV_LDLIBS) -respondd.so: respondd.c - $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -o $@ $^ $(LDLIBS) -lgluonutil -liwinfo -luci + +SOURCES = respondd.c respondd-nodeinfo.c respondd-statistics.c respondd-neighbours.c + +respondd.so: $(SOURCES) respondd-common.h + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -fvisibility=hidden -D_GNU_SOURCE -o $@ $(SOURCES) $(LDLIBS) -lgluonutil diff --git a/package/gluon-mesh-batman-adv/src/respondd-common.h b/package/gluon-mesh-batman-adv/src/respondd-common.h new file mode 100644 index 00000000..54145ff9 --- /dev/null +++ b/package/gluon-mesh-batman-adv/src/respondd-common.h @@ -0,0 +1,30 @@ +/* + Copyright (c) 2016-2019, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#pragma once + +struct json_object * respondd_provider_nodeinfo(void); +struct json_object * respondd_provider_statistics(void); +struct json_object * respondd_provider_neighbours(void); diff --git a/package/gluon-mesh-batman-adv/src/respondd-neighbours.c b/package/gluon-mesh-batman-adv/src/respondd-neighbours.c new file mode 100644 index 00000000..bf5b0315 --- /dev/null +++ b/package/gluon-mesh-batman-adv/src/respondd-neighbours.c @@ -0,0 +1,176 @@ +/* + Copyright (c) 2016-2019, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "respondd-common.h" + +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#include + + +struct neigh_netlink_opts { + struct json_object *interfaces; + struct batadv_nlquery_opts query_opts; +}; + + +static struct json_object * ifnames2addrs(struct json_object *interfaces) { + struct json_object *ret = json_object_new_object(); + + json_object_object_foreach(interfaces, ifname, interface) { + char *ifaddr = gluonutil_get_interface_address(ifname); + if (!ifaddr) + continue; + + struct json_object *obj = json_object_new_object(); + json_object_object_add(obj, "neighbours", json_object_get(interface)); + json_object_object_add(ret, ifaddr, obj); + + free(ifaddr); + } + + json_object_put(interfaces); + + return ret; +} + +static const enum batadv_nl_attrs parse_orig_list_mandatory[] = { + BATADV_ATTR_ORIG_ADDRESS, + BATADV_ATTR_NEIGH_ADDRESS, + BATADV_ATTR_TQ, + BATADV_ATTR_HARD_IFINDEX, + BATADV_ATTR_LAST_SEEN_MSECS, +}; + +static int parse_orig_list_netlink_cb(struct nl_msg *msg, void *arg) +{ + struct nlattr *attrs[BATADV_ATTR_MAX+1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct batadv_nlquery_opts *query_opts = arg; + struct genlmsghdr *ghdr; + uint8_t *orig; + uint8_t *dest; + uint8_t tq; + uint32_t hardif; + uint32_t lastseen; + char ifname_buf[IF_NAMESIZE], *ifname; + struct neigh_netlink_opts *opts; + char mac1[18]; + + opts = batadv_container_of(query_opts, struct neigh_netlink_opts, + query_opts); + + if (!genlmsg_valid_hdr(nlh, 0)) + return NL_OK; + + ghdr = nlmsg_data(nlh); + + if (ghdr->cmd != BATADV_CMD_GET_ORIGINATORS) + return NL_OK; + + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_genl_policy)) + return NL_OK; + + if (batadv_genl_missing_attrs(attrs, parse_orig_list_mandatory, + BATADV_ARRAY_SIZE(parse_orig_list_mandatory))) + return NL_OK; + + orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); + dest = nla_data(attrs[BATADV_ATTR_NEIGH_ADDRESS]); + tq = nla_get_u8(attrs[BATADV_ATTR_TQ]); + hardif = nla_get_u32(attrs[BATADV_ATTR_HARD_IFINDEX]); + lastseen = nla_get_u32(attrs[BATADV_ATTR_LAST_SEEN_MSECS]); + + if (memcmp(orig, dest, 6) != 0) + return NL_OK; + + ifname = if_indextoname(hardif, ifname_buf); + if (!ifname) + return NL_OK; + + sprintf(mac1, "%02x:%02x:%02x:%02x:%02x:%02x", + orig[0], orig[1], orig[2], orig[3], orig[4], orig[5]); + + struct json_object *obj = json_object_new_object(); + if (!obj) + return NL_OK; + + struct json_object *interface; + if (!json_object_object_get_ex(opts->interfaces, ifname, &interface)) { + interface = json_object_new_object(); + json_object_object_add(opts->interfaces, ifname, interface); + } + + json_object_object_add(obj, "tq", json_object_new_int(tq)); + json_object_object_add(obj, "lastseen", json_object_new_double(lastseen / 1000.)); + json_object_object_add(obj, "best", json_object_new_boolean(!!attrs[BATADV_ATTR_FLAG_BEST])); + json_object_object_add(interface, mac1, obj); + + return NL_OK; +} + +static struct json_object * get_batadv(void) { + struct neigh_netlink_opts opts = { + .query_opts = { + .err = 0, + }, + }; + int ret; + + opts.interfaces = json_object_new_object(); + if (!opts.interfaces) + return NULL; + + ret = batadv_genl_query("bat0", BATADV_CMD_GET_ORIGINATORS, + parse_orig_list_netlink_cb, NLM_F_DUMP, + &opts.query_opts); + if (ret < 0) { + json_object_put(opts.interfaces); + return NULL; + } + + return ifnames2addrs(opts.interfaces); +} + +struct json_object * respondd_provider_neighbours(void) { + struct json_object *ret = json_object_new_object(); + + struct json_object *batadv = get_batadv(); + if (batadv) + json_object_object_add(ret, "batadv", batadv); + + return ret; +} diff --git a/package/gluon-mesh-batman-adv/src/respondd-nodeinfo.c b/package/gluon-mesh-batman-adv/src/respondd-nodeinfo.c new file mode 100644 index 00000000..36e330f9 --- /dev/null +++ b/package/gluon-mesh-batman-adv/src/respondd-nodeinfo.c @@ -0,0 +1,219 @@ +/* + Copyright (c) 2016-2019, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "respondd-common.h" + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +struct ip_address_information { + unsigned int ifindex; + struct json_object *addresses; +}; + +static int get_addresses_cb(struct nl_msg *msg, void *arg) { + struct ip_address_information *info = (struct ip_address_information*) arg; + + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct ifaddrmsg *msg_content = NLMSG_DATA(nlh); + int remaining = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg)); + struct rtattr *hdr; + + for (hdr = IFA_RTA(msg_content); RTA_OK(hdr, remaining); hdr = RTA_NEXT(hdr, remaining)) { + char addr_str_buf[INET6_ADDRSTRLEN]; + + /* We are only interested in IP-addresses of br-client */ + if (hdr->rta_type != IFA_ADDRESS || + msg_content->ifa_index != info->ifindex || + msg_content->ifa_flags & (IFA_F_TENTATIVE|IFA_F_DEPRECATED)) { + continue; + } + + if (inet_ntop(AF_INET6, (struct in6_addr *) RTA_DATA(hdr), addr_str_buf, INET6_ADDRSTRLEN)) { + json_object_array_add(info->addresses, json_object_new_string(addr_str_buf)); + } + } + + return NL_OK; +} + +static struct json_object *get_addresses(void) { + struct ip_address_information info = { + .ifindex = if_nametoindex("br-client"), + .addresses = json_object_new_array(), + }; + int err; + + /* Open socket */ + struct nl_sock *socket = nl_socket_alloc(); + if (!socket) { + return info.addresses; + } + + err = nl_connect(socket, NETLINK_ROUTE); + if (err < 0) { + goto out_free; + } + + /* Send message */ + struct ifaddrmsg rt_hdr = { .ifa_family = AF_INET6, }; + err = nl_send_simple(socket, RTM_GETADDR, NLM_F_REQUEST | NLM_F_ROOT, &rt_hdr, sizeof(struct ifaddrmsg)); + if (err < 0) { + goto out_free; + } + + /* Retrieve answer. Message is handled by get_addresses_cb */ + nl_socket_modify_cb(socket, NL_CB_VALID, NL_CB_CUSTOM, get_addresses_cb, &info); + nl_recvmsgs_default(socket); + +out_free: + nl_socket_free(socket); + return info.addresses; +} + +static void add_if_not_empty(struct json_object *obj, const char *key, struct json_object *val) { + if (json_object_array_length(val)) + json_object_object_add(obj, key, val); + else + json_object_put(val); +} + +static bool interface_file_exists(const char *ifname, const char *name) { + const char *format = "/sys/class/net/%s/%s"; + char path[strlen(format) + strlen(ifname) + strlen(name)]; + snprintf(path, sizeof(path), format, ifname, name); + + return !access(path, F_OK); +} + +static void mesh_add_subif(const char *ifname, struct json_object *wireless, + struct json_object *tunnel, struct json_object *other) { + struct json_object *address = gluonutil_wrap_and_free_string(gluonutil_get_interface_address(ifname)); + + char lowername[IFNAMSIZ]; + strncpy(lowername, ifname, sizeof(lowername)-1); + lowername[sizeof(lowername)-1] = 0; + + const char *format = "/sys/class/net/%s/lower_*"; + char pattern[strlen(format) + IFNAMSIZ]; + + /* In case of VLAN and bridge interfaces, we want the lower interface + * to determine the interface type (but not for the interface address) */ + while (true) { + snprintf(pattern, sizeof(pattern), format, lowername); + size_t pattern_len = strlen(pattern); + + glob_t lower; + if (glob(pattern, GLOB_NOSORT, NULL, &lower)) + break; + + strncpy(lowername, lower.gl_pathv[0] + pattern_len - 1, sizeof(lowername)-1); + + globfree(&lower); + } + + if (interface_file_exists(lowername, "wireless")) + json_object_array_add(wireless, address); + else if (interface_file_exists(lowername, "tun_flags")) + json_object_array_add(tunnel, address); + else + json_object_array_add(other, address); + +} + +static struct json_object * get_mesh_subifs(const char *ifname) { + struct json_object *wireless = json_object_new_array(); + struct json_object *tunnel = json_object_new_array(); + struct json_object *other = json_object_new_array(); + + const char *format = "/sys/class/net/%s/lower_*"; + char pattern[strlen(format) + strlen(ifname) - 1]; + snprintf(pattern, sizeof(pattern), format, ifname); + + size_t pattern_len = strlen(pattern); + + glob_t lower; + if (!glob(pattern, GLOB_NOSORT, NULL, &lower)) { + size_t i; + for (i = 0; i < lower.gl_pathc; i++) { + mesh_add_subif(lower.gl_pathv[i] + pattern_len - 1, + wireless, tunnel, other); + } + + globfree(&lower); + } + + struct json_object *ret = json_object_new_object(); + add_if_not_empty(ret, "wireless", wireless); + add_if_not_empty(ret, "tunnel", tunnel); + add_if_not_empty(ret, "other", other); + return ret; +} + +static struct json_object * get_mesh(void) { + struct json_object *ret = json_object_new_object(); + struct json_object *bat0_interfaces = json_object_new_object(); + json_object_object_add(bat0_interfaces, "interfaces", get_mesh_subifs("bat0")); + json_object_object_add(ret, "bat0", bat0_interfaces); + return ret; +} + +struct json_object * respondd_provider_nodeinfo(void) { + struct json_object *ret = json_object_new_object(); + + struct json_object *network = json_object_new_object(); + json_object_object_add(network, "addresses", get_addresses()); + json_object_object_add(network, "mesh", get_mesh()); + json_object_object_add(ret, "network", network); + + struct json_object *software = json_object_new_object(); + struct json_object *software_batman_adv = json_object_new_object(); + json_object_object_add(software_batman_adv, "version", + gluonutil_wrap_and_free_string(gluonutil_read_line("/sys/module/batman_adv/version"))); + json_object_object_add(software_batman_adv, "compat", json_object_new_int(15)); + json_object_object_add(software, "batman-adv", software_batman_adv); + json_object_object_add(ret, "software", software); + + return ret; +} diff --git a/package/gluon-mesh-batman-adv/src/respondd-statistics.c b/package/gluon-mesh-batman-adv/src/respondd-statistics.c new file mode 100644 index 00000000..c9394d87 --- /dev/null +++ b/package/gluon-mesh-batman-adv/src/respondd-statistics.c @@ -0,0 +1,322 @@ +/* + Copyright (c) 2016-2019, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "respondd-common.h" + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +#define MAX_INACTIVITY 60000 + + +struct clients_netlink_opts { + size_t clients; + struct batadv_nlquery_opts query_opts; +}; + +struct gw_netlink_opts { + struct json_object *obj; + struct batadv_nlquery_opts query_opts; +}; + + +static const enum batadv_nl_attrs gateways_mandatory[] = { + BATADV_ATTR_ORIG_ADDRESS, + BATADV_ATTR_ROUTER, +}; + +static int parse_gw_list_netlink_cb(struct nl_msg *msg, void *arg) +{ + struct nlattr *attrs[BATADV_ATTR_MAX+1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct batadv_nlquery_opts *query_opts = arg; + struct genlmsghdr *ghdr; + uint8_t *orig; + uint8_t *router; + struct gw_netlink_opts *opts; + char addr[18]; + + opts = batadv_container_of(query_opts, struct gw_netlink_opts, + query_opts); + + if (!genlmsg_valid_hdr(nlh, 0)) + return NL_OK; + + ghdr = nlmsg_data(nlh); + + if (ghdr->cmd != BATADV_CMD_GET_GATEWAYS) + return NL_OK; + + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_genl_policy)) + return NL_OK; + + if (batadv_genl_missing_attrs(attrs, gateways_mandatory, + BATADV_ARRAY_SIZE(gateways_mandatory))) + return NL_OK; + + if (!attrs[BATADV_ATTR_FLAG_BEST]) + return NL_OK; + + orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); + router = nla_data(attrs[BATADV_ATTR_ROUTER]); + + sprintf(addr, "%02x:%02x:%02x:%02x:%02x:%02x", + orig[0], orig[1], orig[2], orig[3], orig[4], orig[5]); + + json_object_object_add(opts->obj, "gateway", json_object_new_string(addr)); + + sprintf(addr, "%02x:%02x:%02x:%02x:%02x:%02x", + router[0], router[1], router[2], router[3], router[4], router[5]); + + json_object_object_add(opts->obj, "gateway_nexthop", json_object_new_string(addr)); + + return NL_STOP; +} + +static void add_gateway(struct json_object *obj) { + struct gw_netlink_opts opts = { + .obj = obj, + .query_opts = { + .err = 0, + }, + }; + + batadv_genl_query("bat0", BATADV_CMD_GET_GATEWAYS, + parse_gw_list_netlink_cb, NLM_F_DUMP, + &opts.query_opts); +} + +static inline bool ethtool_ioctl(int fd, struct ifreq *ifr, void *data) { + ifr->ifr_data = data; + + return (ioctl(fd, SIOCETHTOOL, ifr) >= 0); +} + +static uint32_t ethtool_get_stats_length(int fd, struct ifreq *ifr) { + struct { + struct ethtool_sset_info info; + uint32_t buf; + } sset = {}; + + sset.info.cmd = ETHTOOL_GSSET_INFO; + sset.info.sset_mask = (uint64_t)1 << ETH_SS_STATS; + + if (!ethtool_ioctl(fd, ifr, &sset.info)) + return 0; + + return sset.info.sset_mask ? sset.info.data[0] : 0; +} + +static struct ethtool_gstrings * ethtool_get_stats_strings(int fd, struct ifreq *ifr) { + uint32_t n_stats = ethtool_get_stats_length(fd, ifr); + + if (!n_stats) + return NULL; + + struct ethtool_gstrings *strings = calloc(1, sizeof(*strings) + n_stats * ETH_GSTRING_LEN); + + strings->cmd = ETHTOOL_GSTRINGS; + strings->string_set = ETH_SS_STATS; + strings->len = n_stats; + + if (!ethtool_ioctl(fd, ifr, strings)) { + free(strings); + return NULL; + } + + return strings; +} + + +static struct json_object * get_traffic(void) { + struct ethtool_gstrings *strings = NULL; + struct ethtool_stats *stats = NULL; + + struct ifreq ifr = {}; + strncpy(ifr.ifr_name, "bat0", IF_NAMESIZE); + + struct json_object *ret = NULL; + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) + return NULL; + + strings = ethtool_get_stats_strings(fd, &ifr); + if (!strings) + goto out; + + stats = calloc(1, sizeof(struct ethtool_stats) + strings->len * sizeof(uint64_t)); + stats->cmd = ETHTOOL_GSTATS; + stats->n_stats = strings->len; + + if (!ethtool_ioctl(fd, &ifr, stats)) + goto out; + + struct json_object *rx = json_object_new_object(); + struct json_object *tx = json_object_new_object(); + struct json_object *forward = json_object_new_object(); + struct json_object *mgmt_rx = json_object_new_object(); + struct json_object *mgmt_tx = json_object_new_object(); + + size_t i; + for (i = 0; i < strings->len; i++) { + if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "rx", ETH_GSTRING_LEN)) + json_object_object_add(rx, "packets", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "rx_bytes", ETH_GSTRING_LEN)) + json_object_object_add(rx, "bytes", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "tx", ETH_GSTRING_LEN)) + json_object_object_add(tx, "packets", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "tx_dropped", ETH_GSTRING_LEN)) + json_object_object_add(tx, "dropped", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "tx_bytes", ETH_GSTRING_LEN)) + json_object_object_add(tx, "bytes", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "forward", ETH_GSTRING_LEN)) + json_object_object_add(forward, "packets", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "forward_bytes", ETH_GSTRING_LEN)) + json_object_object_add(forward, "bytes", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "mgmt_rx", ETH_GSTRING_LEN)) + json_object_object_add(mgmt_rx, "packets", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "mgmt_rx_bytes", ETH_GSTRING_LEN)) + json_object_object_add(mgmt_rx, "bytes", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "mgmt_tx", ETH_GSTRING_LEN)) + json_object_object_add(mgmt_tx, "packets", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "mgmt_tx_bytes", ETH_GSTRING_LEN)) + json_object_object_add(mgmt_tx, "bytes", json_object_new_int64(stats->data[i])); + } + + ret = json_object_new_object(); + json_object_object_add(ret, "rx", rx); + json_object_object_add(ret, "tx", tx); + json_object_object_add(ret, "forward", forward); + json_object_object_add(ret, "mgmt_rx", mgmt_rx); + json_object_object_add(ret, "mgmt_tx", mgmt_tx); + + out: + free(stats); + free(strings); + close(fd); + return ret; +} + +static const enum batadv_nl_attrs clients_mandatory[] = { + BATADV_ATTR_TT_FLAGS, + /* Entries without the BATADV_TT_CLIENT_NOPURGE flag do not have a + * BATADV_ATTR_LAST_SEEN_MSECS attribute. We can still make this attr + * mandatory here, as entries without BATADV_TT_CLIENT_NOPURGE are + * ignored anyways. + */ + BATADV_ATTR_LAST_SEEN_MSECS, +}; + +static int parse_clients_list_netlink_cb(struct nl_msg *msg, void *arg) +{ + struct nlattr *attrs[BATADV_ATTR_MAX+1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct batadv_nlquery_opts *query_opts = arg; + struct genlmsghdr *ghdr; + struct clients_netlink_opts *opts; + uint32_t flags, lastseen; + + opts = batadv_container_of(query_opts, struct clients_netlink_opts, + query_opts); + + if (!genlmsg_valid_hdr(nlh, 0)) + return NL_OK; + + ghdr = nlmsg_data(nlh); + + if (ghdr->cmd != BATADV_CMD_GET_TRANSTABLE_LOCAL) + return NL_OK; + + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_genl_policy)) + return NL_OK; + + if (batadv_genl_missing_attrs(attrs, clients_mandatory, + BATADV_ARRAY_SIZE(clients_mandatory))) + return NL_OK; + + flags = nla_get_u32(attrs[BATADV_ATTR_TT_FLAGS]); + + if (flags & (BATADV_TT_CLIENT_NOPURGE)) + return NL_OK; + + lastseen = nla_get_u32(attrs[BATADV_ATTR_LAST_SEEN_MSECS]); + if (lastseen > MAX_INACTIVITY) + return NL_OK; + + opts->clients++; + + return NL_OK; +} + +static struct json_object * get_clients(void) { + struct clients_netlink_opts opts = { + .clients = 0, + .query_opts = { + .err = 0, + }, + }; + + batadv_genl_query("bat0", BATADV_CMD_GET_TRANSTABLE_LOCAL, + parse_clients_list_netlink_cb, NLM_F_DUMP, + &opts.query_opts); + + struct json_object *ret = json_object_new_object(); + + json_object_object_add(ret, "total", json_object_new_int(opts.clients)); + + return ret; +} + +struct json_object * respondd_provider_statistics(void) { + struct json_object *ret = json_object_new_object(); + + json_object_object_add(ret, "clients", get_clients()); + json_object_object_add(ret, "traffic", get_traffic()); + + add_gateway(ret); + + return ret; +} diff --git a/package/gluon-mesh-batman-adv/src/respondd.c b/package/gluon-mesh-batman-adv/src/respondd.c index c2b20399..36188e46 100644 --- a/package/gluon-mesh-batman-adv/src/respondd.c +++ b/package/gluon-mesh-batman-adv/src/respondd.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2016, Matthias Schiffer + Copyright (c) 2016-2019, Matthias Schiffer All rights reserved. Redistribution and use in source and binary forms, with or without @@ -23,780 +23,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "respondd-common.h" #include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include - - -#define _STRINGIFY(s) #s -#define STRINGIFY(s) _STRINGIFY(s) - -#define MAX_INACTIVITY 60000 - - -struct neigh_netlink_opts { - struct json_object *interfaces; - struct batadv_nlquery_opts query_opts; -}; - -struct gw_netlink_opts { - struct json_object *obj; - struct batadv_nlquery_opts query_opts; -}; - -struct clients_netlink_opts { - size_t non_wifi; - struct batadv_nlquery_opts query_opts; -}; - -struct ip_address_information { - unsigned int ifindex; - struct json_object *addresses; -}; - -static int get_addresses_cb(struct nl_msg *msg, void *arg) { - struct ip_address_information *info = (struct ip_address_information*) arg; - - struct nlmsghdr *nlh = nlmsg_hdr(msg); - struct ifaddrmsg *msg_content = NLMSG_DATA(nlh); - int remaining = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg)); - struct rtattr *hdr; - - for (hdr = IFA_RTA(msg_content); RTA_OK(hdr, remaining); hdr = RTA_NEXT(hdr, remaining)) { - char addr_str_buf[INET6_ADDRSTRLEN]; - - /* We are only interested in IP-addresses of br-client */ - if (hdr->rta_type != IFA_ADDRESS || - msg_content->ifa_index != info->ifindex || - msg_content->ifa_flags & (IFA_F_TENTATIVE|IFA_F_DEPRECATED)) { - continue; - } - - if (inet_ntop(AF_INET6, (struct in6_addr *) RTA_DATA(hdr), addr_str_buf, INET6_ADDRSTRLEN)) { - json_object_array_add(info->addresses, json_object_new_string(addr_str_buf)); - } - } - - return NL_OK; -} - -static struct json_object *get_addresses(void) { - struct ip_address_information info = { - .ifindex = if_nametoindex("br-client"), - .addresses = json_object_new_array(), - }; - int err; - - /* Open socket */ - struct nl_sock *socket = nl_socket_alloc(); - if (!socket) { - return info.addresses; - } - - err = nl_connect(socket, NETLINK_ROUTE); - if (err < 0) { - goto out_free; - } - - /* Send message */ - struct ifaddrmsg rt_hdr = { .ifa_family = AF_INET6, }; - err = nl_send_simple(socket, RTM_GETADDR, NLM_F_REQUEST | NLM_F_ROOT, &rt_hdr, sizeof(struct ifaddrmsg)); - if (err < 0) { - goto out_free; - } - - /* Retrieve answer. Message is handled by get_addresses_cb */ - nl_socket_modify_cb(socket, NL_CB_VALID, NL_CB_CUSTOM, get_addresses_cb, &info); - nl_recvmsgs_default(socket); - -out_free: - nl_socket_free(socket); - return info.addresses; -} - -static void add_if_not_empty(struct json_object *obj, const char *key, struct json_object *val) { - if (json_object_array_length(val)) - json_object_object_add(obj, key, val); - else - json_object_put(val); -} - -static bool interface_file_exists(const char *ifname, const char *name) { - const char *format = "/sys/class/net/%s/%s"; - char path[strlen(format) + strlen(ifname) + strlen(name)]; - snprintf(path, sizeof(path), format, ifname, name); - - return !access(path, F_OK); -} - -static void mesh_add_subif(const char *ifname, struct json_object *wireless, - struct json_object *tunnel, struct json_object *other) { - struct json_object *address = gluonutil_wrap_and_free_string(gluonutil_get_interface_address(ifname)); - - char lowername[IFNAMSIZ]; - strncpy(lowername, ifname, sizeof(lowername)-1); - lowername[sizeof(lowername)-1] = 0; - - const char *format = "/sys/class/net/%s/lower_*"; - char pattern[strlen(format) + IFNAMSIZ]; - - /* In case of VLAN and bridge interfaces, we want the lower interface - * to determine the interface type (but not for the interface address) */ - while (true) { - snprintf(pattern, sizeof(pattern), format, lowername); - size_t pattern_len = strlen(pattern); - - glob_t lower; - if (glob(pattern, GLOB_NOSORT, NULL, &lower)) - break; - - strncpy(lowername, lower.gl_pathv[0] + pattern_len - 1, sizeof(lowername)-1); - - globfree(&lower); - } - - if (interface_file_exists(lowername, "wireless")) - json_object_array_add(wireless, address); - else if (interface_file_exists(lowername, "tun_flags")) - json_object_array_add(tunnel, address); - else - json_object_array_add(other, address); - -} - -static struct json_object * get_mesh_subifs(const char *ifname) { - struct json_object *wireless = json_object_new_array(); - struct json_object *tunnel = json_object_new_array(); - struct json_object *other = json_object_new_array(); - - const char *format = "/sys/class/net/%s/lower_*"; - char pattern[strlen(format) + strlen(ifname) - 1]; - snprintf(pattern, sizeof(pattern), format, ifname); - - size_t pattern_len = strlen(pattern); - - glob_t lower; - if (!glob(pattern, GLOB_NOSORT, NULL, &lower)) { - size_t i; - for (i = 0; i < lower.gl_pathc; i++) { - mesh_add_subif(lower.gl_pathv[i] + pattern_len - 1, - wireless, tunnel, other); - } - - globfree(&lower); - } - - struct json_object *ret = json_object_new_object(); - add_if_not_empty(ret, "wireless", wireless); - add_if_not_empty(ret, "tunnel", tunnel); - add_if_not_empty(ret, "other", other); - return ret; -} - -static struct json_object * get_mesh(void) { - struct json_object *ret = json_object_new_object(); - struct json_object *bat0_interfaces = json_object_new_object(); - json_object_object_add(bat0_interfaces, "interfaces", get_mesh_subifs("bat0")); - json_object_object_add(ret, "bat0", bat0_interfaces); - return ret; -} - -static struct json_object * respondd_provider_nodeinfo(void) { - struct json_object *ret = json_object_new_object(); - - struct json_object *network = json_object_new_object(); - json_object_object_add(network, "addresses", get_addresses()); - json_object_object_add(network, "mesh", get_mesh()); - json_object_object_add(ret, "network", network); - - struct json_object *software = json_object_new_object(); - struct json_object *software_batman_adv = json_object_new_object(); - json_object_object_add(software_batman_adv, "version", - gluonutil_wrap_and_free_string(gluonutil_read_line("/sys/module/batman_adv/version"))); - json_object_object_add(software_batman_adv, "compat", json_object_new_int(15)); - json_object_object_add(software, "batman-adv", software_batman_adv); - json_object_object_add(ret, "software", software); - - return ret; -} - -static const enum batadv_nl_attrs gateways_mandatory[] = { - BATADV_ATTR_ORIG_ADDRESS, - BATADV_ATTR_ROUTER, -}; - -static int parse_gw_list_netlink_cb(struct nl_msg *msg, void *arg) -{ - struct nlattr *attrs[BATADV_ATTR_MAX+1]; - struct nlmsghdr *nlh = nlmsg_hdr(msg); - struct batadv_nlquery_opts *query_opts = arg; - struct genlmsghdr *ghdr; - uint8_t *orig; - uint8_t *router; - struct gw_netlink_opts *opts; - char addr[18]; - - opts = batadv_container_of(query_opts, struct gw_netlink_opts, - query_opts); - - if (!genlmsg_valid_hdr(nlh, 0)) - return NL_OK; - - ghdr = nlmsg_data(nlh); - - if (ghdr->cmd != BATADV_CMD_GET_GATEWAYS) - return NL_OK; - - if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), - genlmsg_len(ghdr), batadv_genl_policy)) - return NL_OK; - - if (batadv_genl_missing_attrs(attrs, gateways_mandatory, - BATADV_ARRAY_SIZE(gateways_mandatory))) - return NL_OK; - - if (!attrs[BATADV_ATTR_FLAG_BEST]) - return NL_OK; - - orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); - router = nla_data(attrs[BATADV_ATTR_ROUTER]); - - sprintf(addr, "%02x:%02x:%02x:%02x:%02x:%02x", - orig[0], orig[1], orig[2], orig[3], orig[4], orig[5]); - - json_object_object_add(opts->obj, "gateway", json_object_new_string(addr)); - - sprintf(addr, "%02x:%02x:%02x:%02x:%02x:%02x", - router[0], router[1], router[2], router[3], router[4], router[5]); - - json_object_object_add(opts->obj, "gateway_nexthop", json_object_new_string(addr)); - - return NL_STOP; -} - -static void add_gateway(struct json_object *obj) { - struct gw_netlink_opts opts = { - .obj = obj, - .query_opts = { - .err = 0, - }, - }; - - batadv_genl_query("bat0", BATADV_CMD_GET_GATEWAYS, - parse_gw_list_netlink_cb, NLM_F_DUMP, - &opts.query_opts); -} - -static inline bool ethtool_ioctl(int fd, struct ifreq *ifr, void *data) { - ifr->ifr_data = data; - - return (ioctl(fd, SIOCETHTOOL, ifr) >= 0); -} - -static uint32_t ethtool_get_stats_length(int fd, struct ifreq *ifr) { - const size_t sset_info_len = sizeof(struct ethtool_sset_info) + sizeof(uint32_t); - struct ethtool_sset_info *sset_info = alloca(sset_info_len); - memset(sset_info, 0, sset_info_len); - - sset_info->cmd = ETHTOOL_GSSET_INFO; - sset_info->sset_mask = 1ull << ETH_SS_STATS; - - if (!ethtool_ioctl(fd, ifr, sset_info)) - return 0; - - return sset_info->sset_mask ? sset_info->data[0] : 0; -} - -static struct ethtool_gstrings * ethtool_get_stats_strings(int fd, struct ifreq *ifr) { - uint32_t n_stats = ethtool_get_stats_length(fd, ifr); - - if (!n_stats) - return NULL; - - struct ethtool_gstrings *strings = calloc(1, sizeof(*strings) + n_stats * ETH_GSTRING_LEN); - - strings->cmd = ETHTOOL_GSTRINGS; - strings->string_set = ETH_SS_STATS; - strings->len = n_stats; - - if (!ethtool_ioctl(fd, ifr, strings)) { - free(strings); - return NULL; - } - - return strings; -} - - -static struct json_object * get_traffic(void) { - struct ethtool_gstrings *strings = NULL; - struct ethtool_stats *stats = NULL; - - struct ifreq ifr = {}; - strncpy(ifr.ifr_name, "bat0", IF_NAMESIZE); - - struct json_object *ret = NULL; - - int fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd < 0) - return NULL; - - strings = ethtool_get_stats_strings(fd, &ifr); - if (!strings) - goto out; - - stats = calloc(1, sizeof(struct ethtool_stats) + strings->len * sizeof(uint64_t)); - stats->cmd = ETHTOOL_GSTATS; - stats->n_stats = strings->len; - - if (!ethtool_ioctl(fd, &ifr, stats)) - goto out; - - struct json_object *rx = json_object_new_object(); - struct json_object *tx = json_object_new_object(); - struct json_object *forward = json_object_new_object(); - struct json_object *mgmt_rx = json_object_new_object(); - struct json_object *mgmt_tx = json_object_new_object(); - - size_t i; - for (i = 0; i < strings->len; i++) { - if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "rx", ETH_GSTRING_LEN)) - json_object_object_add(rx, "packets", json_object_new_int64(stats->data[i])); - else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "rx_bytes", ETH_GSTRING_LEN)) - json_object_object_add(rx, "bytes", json_object_new_int64(stats->data[i])); - else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "tx", ETH_GSTRING_LEN)) - json_object_object_add(tx, "packets", json_object_new_int64(stats->data[i])); - else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "tx_dropped", ETH_GSTRING_LEN)) - json_object_object_add(tx, "dropped", json_object_new_int64(stats->data[i])); - else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "tx_bytes", ETH_GSTRING_LEN)) - json_object_object_add(tx, "bytes", json_object_new_int64(stats->data[i])); - else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "forward", ETH_GSTRING_LEN)) - json_object_object_add(forward, "packets", json_object_new_int64(stats->data[i])); - else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "forward_bytes", ETH_GSTRING_LEN)) - json_object_object_add(forward, "bytes", json_object_new_int64(stats->data[i])); - else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "mgmt_rx", ETH_GSTRING_LEN)) - json_object_object_add(mgmt_rx, "packets", json_object_new_int64(stats->data[i])); - else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "mgmt_rx_bytes", ETH_GSTRING_LEN)) - json_object_object_add(mgmt_rx, "bytes", json_object_new_int64(stats->data[i])); - else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "mgmt_tx", ETH_GSTRING_LEN)) - json_object_object_add(mgmt_tx, "packets", json_object_new_int64(stats->data[i])); - else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "mgmt_tx_bytes", ETH_GSTRING_LEN)) - json_object_object_add(mgmt_tx, "bytes", json_object_new_int64(stats->data[i])); - } - - ret = json_object_new_object(); - json_object_object_add(ret, "rx", rx); - json_object_object_add(ret, "tx", tx); - json_object_object_add(ret, "forward", forward); - json_object_object_add(ret, "mgmt_rx", mgmt_rx); - json_object_object_add(ret, "mgmt_tx", mgmt_tx); - - out: - free(stats); - free(strings); - close(fd); - return ret; -} - -static void count_iface_stations(size_t *wifi24, size_t *wifi5, const char *ifname) { - const struct iwinfo_ops *iw = iwinfo_backend(ifname); - if (!iw) - return; - - int freq; - if (iw->frequency(ifname, &freq) < 0) - return; - - size_t *wifi; - if (freq >= 2400 && freq < 2500) - wifi = wifi24; - else if (freq >= 5000 && freq < 6000) - wifi = wifi5; - else - return; - - int len; - char buf[IWINFO_BUFSIZE]; - if (iw->assoclist(ifname, buf, &len) < 0) - return; - - struct iwinfo_assoclist_entry *entry; - for (entry = (struct iwinfo_assoclist_entry *)buf; (char*)(entry+1) <= buf + len; entry++) { - if (entry->inactive > MAX_INACTIVITY) - continue; - - (*wifi)++; - } -} - -static void count_stations(size_t *wifi24, size_t *wifi5) { - struct uci_context *ctx = uci_alloc_context(); - if (!ctx) - return; - ctx->flags &= ~UCI_FLAG_STRICT; - - - struct uci_package *p; - if (uci_load(ctx, "wireless", &p)) - goto end; - - - struct uci_element *e; - uci_foreach_element(&p->sections, e) { - struct uci_section *s = uci_to_section(e); - if (strcmp(s->type, "wifi-iface")) - continue; - - const char *network = uci_lookup_option_string(ctx, s, "network"); - if (!network || strcmp(network, "client")) - continue; - - const char *mode = uci_lookup_option_string(ctx, s, "mode"); - if (!mode || strcmp(mode, "ap")) - continue; - - const char *ifname = uci_lookup_option_string(ctx, s, "ifname"); - if (!ifname) - continue; - - count_iface_stations(wifi24, wifi5, ifname); - } - - end: - uci_free_context(ctx); -} - -static const enum batadv_nl_attrs clients_mandatory[] = { - BATADV_ATTR_TT_FLAGS, - /* Entries without the BATADV_TT_CLIENT_NOPURGE flag do not have a - * BATADV_ATTR_LAST_SEEN_MSECS attribute. We can still make this attr - * mandatory here, as entries without BATADV_TT_CLIENT_NOPURGE are - * ignored anyways. - */ - BATADV_ATTR_LAST_SEEN_MSECS, -}; - -static int parse_clients_list_netlink_cb(struct nl_msg *msg, void *arg) -{ - struct nlattr *attrs[BATADV_ATTR_MAX+1]; - struct nlmsghdr *nlh = nlmsg_hdr(msg); - struct batadv_nlquery_opts *query_opts = arg; - struct genlmsghdr *ghdr; - struct clients_netlink_opts *opts; - uint32_t flags, lastseen; - - opts = batadv_container_of(query_opts, struct clients_netlink_opts, - query_opts); - - if (!genlmsg_valid_hdr(nlh, 0)) - return NL_OK; - - ghdr = nlmsg_data(nlh); - - if (ghdr->cmd != BATADV_CMD_GET_TRANSTABLE_LOCAL) - return NL_OK; - - if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), - genlmsg_len(ghdr), batadv_genl_policy)) - return NL_OK; - - if (batadv_genl_missing_attrs(attrs, clients_mandatory, - BATADV_ARRAY_SIZE(clients_mandatory))) - return NL_OK; - - flags = nla_get_u32(attrs[BATADV_ATTR_TT_FLAGS]); - - if (flags & (BATADV_TT_CLIENT_NOPURGE | BATADV_TT_CLIENT_WIFI)) - return NL_OK; - - lastseen = nla_get_u32(attrs[BATADV_ATTR_LAST_SEEN_MSECS]); - if (lastseen > MAX_INACTIVITY) - return NL_OK; - - opts->non_wifi++; - - return NL_OK; -} - -static struct json_object * get_clients(void) { - size_t wifi24 = 0, wifi5 = 0; - size_t total; - size_t wifi; - struct clients_netlink_opts opts = { - .non_wifi = 0, - .query_opts = { - .err = 0, - }, - }; - - batadv_genl_query("bat0", BATADV_CMD_GET_TRANSTABLE_LOCAL, - parse_clients_list_netlink_cb, NLM_F_DUMP, - &opts.query_opts); - - count_stations(&wifi24, &wifi5); - wifi = wifi24 + wifi5; - total = wifi + opts.non_wifi; - - struct json_object *ret = json_object_new_object(); - json_object_object_add(ret, "total", json_object_new_int(total)); - json_object_object_add(ret, "wifi", json_object_new_int(wifi)); - json_object_object_add(ret, "wifi24", json_object_new_int(wifi24)); - json_object_object_add(ret, "wifi5", json_object_new_int(wifi5)); - return ret; -} - - -static struct json_object * respondd_provider_statistics(void) { - struct json_object *ret = json_object_new_object(); - - json_object_object_add(ret, "clients", get_clients()); - json_object_object_add(ret, "traffic", get_traffic()); - - add_gateway(ret); - - return ret; -} - - -static struct json_object * ifnames2addrs(struct json_object *interfaces) { - struct json_object *ret = json_object_new_object(); - - json_object_object_foreach(interfaces, ifname, interface) { - char *ifaddr = gluonutil_get_interface_address(ifname); - if (!ifaddr) - continue; - - struct json_object *obj = json_object_new_object(); - json_object_object_add(obj, "neighbours", json_object_get(interface)); - json_object_object_add(ret, ifaddr, obj); - - free(ifaddr); - } - - json_object_put(interfaces); - - return ret; -} - -static const enum batadv_nl_attrs parse_orig_list_mandatory[] = { - BATADV_ATTR_ORIG_ADDRESS, - BATADV_ATTR_NEIGH_ADDRESS, - BATADV_ATTR_TQ, - BATADV_ATTR_HARD_IFINDEX, - BATADV_ATTR_LAST_SEEN_MSECS, -}; - -static int parse_orig_list_netlink_cb(struct nl_msg *msg, void *arg) -{ - struct nlattr *attrs[BATADV_ATTR_MAX+1]; - struct nlmsghdr *nlh = nlmsg_hdr(msg); - struct batadv_nlquery_opts *query_opts = arg; - struct genlmsghdr *ghdr; - uint8_t *orig; - uint8_t *dest; - uint8_t tq; - uint32_t hardif; - uint32_t lastseen; - char ifname_buf[IF_NAMESIZE], *ifname; - struct neigh_netlink_opts *opts; - char mac1[18]; - - opts = batadv_container_of(query_opts, struct neigh_netlink_opts, - query_opts); - - if (!genlmsg_valid_hdr(nlh, 0)) - return NL_OK; - - ghdr = nlmsg_data(nlh); - - if (ghdr->cmd != BATADV_CMD_GET_ORIGINATORS) - return NL_OK; - - if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), - genlmsg_len(ghdr), batadv_genl_policy)) - return NL_OK; - - if (batadv_genl_missing_attrs(attrs, parse_orig_list_mandatory, - BATADV_ARRAY_SIZE(parse_orig_list_mandatory))) - return NL_OK; - - orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); - dest = nla_data(attrs[BATADV_ATTR_NEIGH_ADDRESS]); - tq = nla_get_u8(attrs[BATADV_ATTR_TQ]); - hardif = nla_get_u32(attrs[BATADV_ATTR_HARD_IFINDEX]); - lastseen = nla_get_u32(attrs[BATADV_ATTR_LAST_SEEN_MSECS]); - - if (memcmp(orig, dest, 6) != 0) - return NL_OK; - - ifname = if_indextoname(hardif, ifname_buf); - if (!ifname) - return NL_OK; - - sprintf(mac1, "%02x:%02x:%02x:%02x:%02x:%02x", - orig[0], orig[1], orig[2], orig[3], orig[4], orig[5]); - - struct json_object *obj = json_object_new_object(); - if (!obj) - return NL_OK; - - struct json_object *interface; - if (!json_object_object_get_ex(opts->interfaces, ifname, &interface)) { - interface = json_object_new_object(); - json_object_object_add(opts->interfaces, ifname, interface); - } - - json_object_object_add(obj, "tq", json_object_new_int(tq)); - json_object_object_add(obj, "lastseen", json_object_new_double(lastseen / 1000.)); - json_object_object_add(obj, "best", json_object_new_boolean(attrs[BATADV_ATTR_FLAG_BEST])); - json_object_object_add(interface, mac1, obj); - - return NL_OK; -} - -static struct json_object * get_batadv(void) { - struct neigh_netlink_opts opts = { - .query_opts = { - .err = 0, - }, - }; - int ret; - - opts.interfaces = json_object_new_object(); - if (!opts.interfaces) - return NULL; - - ret = batadv_genl_query("bat0", BATADV_CMD_GET_ORIGINATORS, - parse_orig_list_netlink_cb, NLM_F_DUMP, - &opts.query_opts); - if (ret < 0) { - json_object_put(opts.interfaces); - return NULL; - } - - return ifnames2addrs(opts.interfaces); -} - -static struct json_object * get_wifi_neighbours(const char *ifname) { - const struct iwinfo_ops *iw = iwinfo_backend(ifname); - if (!iw) - return NULL; - - int len; - char buf[IWINFO_BUFSIZE]; - if (iw->assoclist(ifname, buf, &len) < 0) - return NULL; - - struct json_object *neighbours = json_object_new_object(); - - struct iwinfo_assoclist_entry *entry; - for (entry = (struct iwinfo_assoclist_entry *)buf; (char*)(entry+1) <= buf + len; entry++) { - if (entry->inactive > MAX_INACTIVITY) - continue; - - struct json_object *obj = json_object_new_object(); - - json_object_object_add(obj, "signal", json_object_new_int(entry->signal)); - json_object_object_add(obj, "noise", json_object_new_int(entry->noise)); - json_object_object_add(obj, "inactive", json_object_new_int(entry->inactive)); - - char mac[18]; - snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x", - entry->mac[0], entry->mac[1], entry->mac[2], - entry->mac[3], entry->mac[4], entry->mac[5]); - - json_object_object_add(neighbours, mac, obj); - } - - struct json_object *ret = json_object_new_object(); - - if (json_object_object_length(neighbours)) - json_object_object_add(ret, "neighbours", neighbours); - else - json_object_put(neighbours); - - return ret; -} - -static struct json_object * get_wifi(void) { - const char *mesh = "bat0"; - - struct json_object *ret = json_object_new_object(); - - const char *format = "/sys/class/net/%s/lower_*"; - char pattern[strlen(format) + strlen(mesh)]; - snprintf(pattern, sizeof(pattern), format, mesh); - - size_t pattern_len = strlen(pattern); - - glob_t lower; - if (!glob(pattern, GLOB_NOSORT, NULL, &lower)) { - size_t i; - for (i = 0; i < lower.gl_pathc; i++) { - const char *ifname = lower.gl_pathv[i] + pattern_len - 1; - char *ifaddr = gluonutil_get_interface_address(ifname); - if (!ifaddr) - continue; - - struct json_object *neighbours = get_wifi_neighbours(ifname); - if (neighbours) - json_object_object_add(ret, ifaddr, neighbours); - - free(ifaddr); - } - - globfree(&lower); - } - - return ret; -} - -static struct json_object * respondd_provider_neighbours(void) { - struct json_object *ret = json_object_new_object(); - - struct json_object *batadv = get_batadv(); - if (batadv) - json_object_object_add(ret, "batadv", batadv); - - struct json_object *wifi = get_wifi(); - if (wifi) - json_object_object_add(ret, "wifi", wifi); - - return ret; -} - +__attribute__ ((visibility ("default"))) const struct respondd_provider_info respondd_providers[] = { {"nodeinfo", respondd_provider_nodeinfo}, {"statistics", respondd_provider_statistics}, diff --git a/package/gluon-neighbour-info/src/gluon-neighbour-info.c b/package/gluon-neighbour-info/src/gluon-neighbour-info.c index 24237bfe..6e255d87 100644 --- a/package/gluon-neighbour-info/src/gluon-neighbour-info.c +++ b/package/gluon-neighbour-info/src/gluon-neighbour-info.c @@ -37,8 +37,8 @@ void usage() { puts("Usage: gluon-neighbour-info [-h] [-s] [-l] [-c ] [-t ] -d -p -i -r "); - puts(" -p UDP port"); - puts(" -d destination address (unicast ip6 or multicast group, e.g. ff02:0:0:0:0:0:2:1001)"); + puts(" -p UDP port (default: 1001)"); + puts(" -d destination address (unicast ip6 or multicast group, e.g. ff02:0:0:0:0:0:2:1001, default: ::1)"); puts(" -i interface, e.g. eth0 "); puts(" -r request, e.g. nodeinfo"); puts(" -t timeout in seconds (default: 3)"); @@ -144,6 +144,8 @@ int main(int argc, char **argv) { exit(EXIT_FAILURE); } + client_addr.sin6_addr = in6addr_loopback; + client_addr.sin6_port = htons(1001); client_addr.sin6_family = AF_INET6; opterr = 0; diff --git a/package/gluon-respondd/src/Makefile b/package/gluon-respondd/src/Makefile index f26b59a2..9e1e831d 100644 --- a/package/gluon-respondd/src/Makefile +++ b/package/gluon-respondd/src/Makefile @@ -2,5 +2,7 @@ all: respondd.so CFLAGS += -Wall -respondd.so: respondd.c - $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -o $@ $^ $(LDLIBS) -lgluonutil -lplatforminfo -luci +SOURCES = respondd.c respondd-nodeinfo.c respondd-statistics.c respondd-neighbours.c + +respondd.so: $(SOURCES) respondd-common.h + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -fvisibility=hidden -D_GNU_SOURCE -o $@ $(SOURCES) $(LDLIBS) -lgluonutil -lplatforminfo -luci -liwinfo diff --git a/package/gluon-respondd/src/respondd-common.h b/package/gluon-respondd/src/respondd-common.h new file mode 100644 index 00000000..db40cbaf --- /dev/null +++ b/package/gluon-respondd/src/respondd-common.h @@ -0,0 +1,32 @@ +/* + Copyright (c) 2016-2019, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#pragma once + +#define MAX_INACTIVITY 60000 + +struct json_object * respondd_provider_nodeinfo(void); +struct json_object * respondd_provider_statistics(void); +struct json_object * respondd_provider_neighbours(void); diff --git a/package/gluon-respondd/src/respondd-neighbours.c b/package/gluon-respondd/src/respondd-neighbours.c new file mode 100644 index 00000000..2a07634f --- /dev/null +++ b/package/gluon-respondd/src/respondd-neighbours.c @@ -0,0 +1,130 @@ +/* + Copyright (c) 2016-2019, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "respondd-common.h" + +#include + +#include +#include + + +static struct json_object * get_wifi_neighbours(const char *ifname) { + const struct iwinfo_ops *iw = iwinfo_backend(ifname); + if (!iw) + return NULL; + + int len; + char buf[IWINFO_BUFSIZE]; + if (iw->assoclist(ifname, buf, &len) < 0) + return NULL; + + struct json_object *neighbours = json_object_new_object(); + + struct iwinfo_assoclist_entry *entry; + for (entry = (struct iwinfo_assoclist_entry *)buf; (char*)(entry+1) <= buf + len; entry++) { + if (entry->inactive > MAX_INACTIVITY) + continue; + + struct json_object *obj = json_object_new_object(); + + json_object_object_add(obj, "signal", json_object_new_int(entry->signal)); + json_object_object_add(obj, "noise", json_object_new_int(entry->noise)); + json_object_object_add(obj, "inactive", json_object_new_int(entry->inactive)); + + char mac[18]; + snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x", + entry->mac[0], entry->mac[1], entry->mac[2], + entry->mac[3], entry->mac[4], entry->mac[5]); + + json_object_object_add(neighbours, mac, obj); + } + + struct json_object *ret = json_object_new_object(); + + if (json_object_object_length(neighbours)) + json_object_object_add(ret, "neighbours", neighbours); + else + json_object_put(neighbours); + + return ret; +} + +static struct json_object * get_wifi(void) { + struct uci_context *ctx = uci_alloc_context(); + if (!ctx) + return NULL; + + ctx->flags &= ~UCI_FLAG_STRICT; + + struct json_object *ret = json_object_new_object(); + + struct uci_package *p; + if (uci_load(ctx, "network", &p)) + goto end; + + + struct uci_element *e; + uci_foreach_element(&p->sections, e) { + struct uci_section *s = uci_to_section(e); + if (strcmp(s->type, "interface")) + continue; + + const char *proto = uci_lookup_option_string(ctx, s, "proto"); + if (!proto || strcmp(proto, "gluon_mesh")) + continue; + + const char *ifname = uci_lookup_option_string(ctx, s, "ifname"); + if (!ifname) + continue; + + char *ifaddr = gluonutil_get_interface_address(ifname); + if (!ifaddr) + continue; + + struct json_object *neighbours = get_wifi_neighbours(ifname); + if (neighbours) + json_object_object_add(ret, ifaddr, neighbours); + + free(ifaddr); + } + +end: + uci_free_context(ctx); + return ret; +} + +struct json_object * respondd_provider_neighbours(void) { + struct json_object *ret = json_object_new_object(); + + json_object_object_add(ret, "node_id", gluonutil_wrap_and_free_string(gluonutil_get_node_id())); + + struct json_object *wifi = get_wifi(); + if (wifi) + json_object_object_add(ret, "wifi", wifi); + + + return ret; +} diff --git a/package/gluon-respondd/src/respondd-nodeinfo.c b/package/gluon-respondd/src/respondd-nodeinfo.c new file mode 100644 index 00000000..f70abc9a --- /dev/null +++ b/package/gluon-respondd/src/respondd-nodeinfo.c @@ -0,0 +1,132 @@ +/* + Copyright (c) 2016-2019, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "respondd-common.h" + +#include +#include + +#include +#include + +#include +#include +#include + + +static struct json_object * gluon_version(void) { + char *version = gluonutil_read_line("/lib/gluon/gluon-version"); + if (!version) + return NULL; + + char full_version[6 + strlen(version) + 1]; + snprintf(full_version, sizeof(full_version), "gluon-%s", version); + + free(version); + + + return json_object_new_string(full_version); +} + +static struct json_object * get_site_code(void) { + struct json_object *site = gluonutil_load_site_config(); + if (!site) + return NULL; + + struct json_object *ret = NULL; + json_object_object_get_ex(site, "site_code", &ret); + if (ret) + json_object_get(ret); + + json_object_put(site); + return ret; +} + +static struct json_object * get_domain_code(void) { + return gluonutil_wrap_and_free_string(gluonutil_get_domain()); +} + +static struct json_object * get_hostname(void) { + struct json_object *ret = NULL; + + struct uci_context *ctx = uci_alloc_context(); + if (!ctx) + return NULL; + ctx->flags &= ~UCI_FLAG_STRICT; + + char section[] = "system.@system[0]"; + struct uci_ptr ptr; + if (uci_lookup_ptr(ctx, &ptr, section, true)) + goto error; + + struct uci_section *s = ptr.s; + + const char *hostname = uci_lookup_option_string(ctx, s, "pretty_hostname"); + + if (!hostname) + hostname = uci_lookup_option_string(ctx, s, "hostname"); + + ret = gluonutil_wrap_string(hostname); + +error: + uci_free_context(ctx); + + return ret; +} + +struct json_object * respondd_provider_nodeinfo(void) { + struct json_object *ret = json_object_new_object(); + + json_object_object_add(ret, "node_id", gluonutil_wrap_and_free_string(gluonutil_get_node_id())); + json_object_object_add(ret, "hostname", get_hostname()); + + struct json_object *hardware = json_object_new_object(); + + const char *model = platforminfo_get_model(); + if (model) + json_object_object_add(hardware, "model", json_object_new_string(model)); + + json_object_object_add(hardware, "nproc", json_object_new_int(sysconf(_SC_NPROCESSORS_ONLN))); + json_object_object_add(ret, "hardware", hardware); + + struct json_object *network = json_object_new_object(); + json_object_object_add(network, "mac", gluonutil_wrap_and_free_string(gluonutil_get_sysconfig("primary_mac"))); + json_object_object_add(ret, "network", network); + + struct json_object *software = json_object_new_object(); + struct json_object *software_firmware = json_object_new_object(); + json_object_object_add(software_firmware, "base", gluon_version()); + json_object_object_add(software_firmware, "release", gluonutil_wrap_and_free_string(gluonutil_read_line("/lib/gluon/release"))); + json_object_object_add(software, "firmware", software_firmware); + json_object_object_add(ret, "software", software); + + struct json_object *system = json_object_new_object(); + json_object_object_add(system, "site_code", get_site_code()); + if (gluonutil_has_domains()) + json_object_object_add(system, "domain_code", get_domain_code()); + json_object_object_add(ret, "system", system); + + return ret; +} diff --git a/package/gluon-respondd/src/respondd-statistics.c b/package/gluon-respondd/src/respondd-statistics.c new file mode 100644 index 00000000..634b2942 --- /dev/null +++ b/package/gluon-respondd/src/respondd-statistics.c @@ -0,0 +1,309 @@ +/* + Copyright (c) 2016-2019, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "respondd-common.h" + +#include + +#include +#include + +#include +#include +#include +#include + +#include + + +static void add_uptime(struct json_object *obj) { + FILE *f = fopen("/proc/uptime", "r"); + struct json_object* jso; + if (!f) + return; + + double uptime, idletime; + if (fscanf(f, "%lf %lf", &uptime, &idletime) == 2) { + jso = json_object_new_double(uptime); + json_object_set_serializer(jso, json_object_double_to_json_string, "%.2f", NULL); + json_object_object_add(obj, "uptime", jso); + jso = json_object_new_double(idletime); + json_object_set_serializer(jso, json_object_double_to_json_string, "%.2f", NULL); + json_object_object_add(obj, "idletime", jso); + } + + fclose(f); +} + +static void add_loadavg(struct json_object *obj) { + FILE *f = fopen("/proc/loadavg", "r"); + if (!f) + return; + + double loadavg; + unsigned proc_running, proc_total; + if (fscanf(f, "%lf %*f %*f %u/%u", &loadavg, &proc_running, &proc_total) == 3) { + struct json_object *jso = json_object_new_double(loadavg); + json_object_set_serializer(jso, json_object_double_to_json_string, "%.2f", NULL); + json_object_object_add(obj, "loadavg", jso); + + struct json_object *processes = json_object_new_object(); + json_object_object_add(processes, "running", json_object_new_int(proc_running)); + json_object_object_add(processes, "total", json_object_new_int(proc_total)); + json_object_object_add(obj, "processes", processes); + } + + fclose(f); +} + +static struct json_object * get_memory(void) { + FILE *f = fopen("/proc/meminfo", "r"); + if (!f) + return NULL; + + struct json_object *ret = json_object_new_object(); + + char *line = NULL; + size_t len = 0; + + while (getline(&line, &len, f) >= 0) { + char label[32]; + unsigned value; + + if (sscanf(line, "%31[^:]: %u", label, &value) != 2) + continue; + + if (!strcmp(label, "MemTotal")) + json_object_object_add(ret, "total", json_object_new_int(value)); + else if (!strcmp(label, "MemFree")) + json_object_object_add(ret, "free", json_object_new_int(value)); + else if (!strcmp(label, "MemAvailable")) + json_object_object_add(ret, "available", json_object_new_int(value)); + else if (!strcmp(label, "Buffers")) + json_object_object_add(ret, "buffers", json_object_new_int(value)); + else if (!strcmp(label, "Cached")) + json_object_object_add(ret, "cached", json_object_new_int(value)); + } + + free(line); + fclose(f); + + return ret; +} + +static struct json_object * get_stat(void) { + FILE *f = fopen("/proc/stat", "r"); + if (!f) + return NULL; + + struct json_object *stat = json_object_new_object(); + struct json_object *ret = NULL; + + char *line = NULL; + size_t len = 0; + + while (getline(&line, &len, f) >= 0) { + char label[32]; + + if (sscanf(line, "%31s", label) != 1){ + goto invalid_stat_format; + } + + if (!strcmp(label, "cpu")) { + int64_t user, nice, system, idle, iowait, irq, softirq; + if (sscanf(line, "%*s %"SCNd64" %"SCNd64" %"SCNd64" %"SCNd64" %"SCNd64" %"SCNd64" %"SCNd64, + &user, &nice, &system, &idle, &iowait, &irq, &softirq) != 7) + goto invalid_stat_format; + + struct json_object *cpu = json_object_new_object(); + + json_object_object_add(cpu, "user", json_object_new_int64(user)); + json_object_object_add(cpu, "nice", json_object_new_int64(nice)); + json_object_object_add(cpu, "system", json_object_new_int64(system)); + json_object_object_add(cpu, "idle", json_object_new_int64(idle)); + json_object_object_add(cpu, "iowait", json_object_new_int64(iowait)); + json_object_object_add(cpu, "irq", json_object_new_int64(irq)); + json_object_object_add(cpu, "softirq", json_object_new_int64(softirq)); + + json_object_object_add(stat, "cpu", cpu); + } else if (!strcmp(label, "ctxt")) { + int64_t ctxt; + if (sscanf(line, "%*s %"SCNd64, &ctxt) != 1) + goto invalid_stat_format; + + json_object_object_add(stat, "ctxt", json_object_new_int64(ctxt)); + } else if (!strcmp(label, "intr")) { + int64_t total_intr; + if (sscanf(line, "%*s %"SCNd64, &total_intr) != 1) + goto invalid_stat_format; + + json_object_object_add(stat, "intr", json_object_new_int64(total_intr)); + } else if (!strcmp(label, "softirq")) { + int64_t total_softirq; + if (sscanf(line, "%*s %"SCNd64, &total_softirq) != 1) + goto invalid_stat_format; + + json_object_object_add(stat, "softirq", json_object_new_int64(total_softirq)); + } else if (!strcmp(label, "processes")) { + int64_t processes; + if (sscanf(line, "%*s %"SCNd64, &processes) != 1) + goto invalid_stat_format; + + json_object_object_add(stat, "processes", json_object_new_int64(processes)); + } + + } + + ret = stat; + +invalid_stat_format: + if (!ret) + json_object_put(stat); + + free(line); + fclose(f); + + return ret; +} + + +static struct json_object * get_rootfs_usage(void) { + struct statfs s; + if (statfs("/", &s)) + return NULL; + + struct json_object *jso = json_object_new_double(1 - (double)s.f_bfree / s.f_blocks); + json_object_set_serializer(jso, json_object_double_to_json_string, "%.4f", NULL); + return jso; +} + +static struct json_object * get_time(void) { + struct timespec now; + + if (clock_gettime(CLOCK_REALTIME, &now) != 0) + return NULL; + + return json_object_new_int64(now.tv_sec); +} + +static void count_iface_stations(size_t *wifi24, size_t *wifi5, const char *ifname) { + const struct iwinfo_ops *iw = iwinfo_backend(ifname); + if (!iw) + return; + + int freq; + if (iw->frequency(ifname, &freq) < 0) + return; + + size_t *wifi; + if (freq >= 2400 && freq < 2500) + wifi = wifi24; + else if (freq >= 5000 && freq < 6000) + wifi = wifi5; + else + return; + + int len; + char buf[IWINFO_BUFSIZE]; + if (iw->assoclist(ifname, buf, &len) < 0) + return; + + struct iwinfo_assoclist_entry *entry; + for (entry = (struct iwinfo_assoclist_entry *)buf; (char*)(entry+1) <= buf + len; entry++) { + if (entry->inactive > MAX_INACTIVITY) + continue; + + (*wifi)++; + } +} + +static void count_stations(size_t *wifi24, size_t *wifi5) { + struct uci_context *ctx = uci_alloc_context(); + if (!ctx) + return; + ctx->flags &= ~UCI_FLAG_STRICT; + + + struct uci_package *p; + if (uci_load(ctx, "wireless", &p)) + goto end; + + + struct uci_element *e; + uci_foreach_element(&p->sections, e) { + struct uci_section *s = uci_to_section(e); + if (strcmp(s->type, "wifi-iface")) + continue; + + const char *network = uci_lookup_option_string(ctx, s, "network"); + if (!network || strcmp(network, "client")) + continue; + + const char *mode = uci_lookup_option_string(ctx, s, "mode"); + if (!mode || strcmp(mode, "ap")) + continue; + + const char *ifname = uci_lookup_option_string(ctx, s, "ifname"); + if (!ifname) + continue; + + count_iface_stations(wifi24, wifi5, ifname); + } + + end: + uci_free_context(ctx); +} + +static struct json_object * get_clients(void) { + size_t wifi24 = 0, wifi5 = 0; + + count_stations(&wifi24, &wifi5); + + struct json_object *ret = json_object_new_object(); + + json_object_object_add(ret, "wifi", json_object_new_int(wifi24 + wifi5)); + json_object_object_add(ret, "wifi24", json_object_new_int(wifi24)); + json_object_object_add(ret, "wifi5", json_object_new_int(wifi5)); + + return ret; +} + +struct json_object * respondd_provider_statistics(void) { + struct json_object *ret = json_object_new_object(); + + json_object_object_add(ret, "node_id", gluonutil_wrap_and_free_string(gluonutil_get_node_id())); + + json_object_object_add(ret, "time", get_time()); + json_object_object_add(ret, "rootfs_usage", get_rootfs_usage()); + json_object_object_add(ret, "memory", get_memory()); + json_object_object_add(ret, "stat", get_stat()); + + json_object_object_add(ret, "clients", get_clients()); + + add_uptime(ret); + add_loadavg(ret); + + return ret; +} diff --git a/package/gluon-respondd/src/respondd.c b/package/gluon-respondd/src/respondd.c index b0b74936..36188e46 100644 --- a/package/gluon-respondd/src/respondd.c +++ b/package/gluon-respondd/src/respondd.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2016, Matthias Schiffer + Copyright (c) 2016-2019, Matthias Schiffer All rights reserved. Redistribution and use in source and binary forms, with or without @@ -23,316 +23,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "respondd-common.h" #include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - - -static struct json_object * gluon_version(void) { - char *version = gluonutil_read_line("/lib/gluon/gluon-version"); - if (!version) - return NULL; - - char full_version[6 + strlen(version) + 1]; - snprintf(full_version, sizeof(full_version), "gluon-%s", version); - - free(version); - - - return json_object_new_string(full_version); -} - -static struct json_object * get_site_code(void) { - struct json_object *site = gluonutil_load_site_config(); - if (!site) - return NULL; - - struct json_object *ret = NULL; - json_object_object_get_ex(site, "site_code", &ret); - if (ret) - json_object_get(ret); - - json_object_put(site); - return ret; -} - -static struct json_object * get_domain_code(void) { - return gluonutil_wrap_and_free_string(gluonutil_get_domain()); -} - -static struct json_object * get_hostname(void) { - struct json_object *ret = NULL; - - struct uci_context *ctx = uci_alloc_context(); - if (!ctx) - return NULL; - ctx->flags &= ~UCI_FLAG_STRICT; - - char section[] = "system.@system[0]"; - struct uci_ptr ptr; - if (uci_lookup_ptr(ctx, &ptr, section, true)) - goto error; - - struct uci_section *s = ptr.s; - - const char *hostname = uci_lookup_option_string(ctx, s, "pretty_hostname"); - - if (!hostname) - hostname = uci_lookup_option_string(ctx, s, "hostname"); - - ret = gluonutil_wrap_string(hostname); - -error: - uci_free_context(ctx); - - return ret; -} - -static struct json_object * respondd_provider_nodeinfo(void) { - struct json_object *ret = json_object_new_object(); - - json_object_object_add(ret, "node_id", gluonutil_wrap_and_free_string(gluonutil_get_node_id())); - json_object_object_add(ret, "hostname", get_hostname()); - - struct json_object *hardware = json_object_new_object(); - - const char *model = platforminfo_get_model(); - if (model) - json_object_object_add(hardware, "model", json_object_new_string(model)); - - json_object_object_add(hardware, "nproc", json_object_new_int(sysconf(_SC_NPROCESSORS_ONLN))); - json_object_object_add(ret, "hardware", hardware); - - struct json_object *network = json_object_new_object(); - json_object_object_add(network, "mac", gluonutil_wrap_and_free_string(gluonutil_get_sysconfig("primary_mac"))); - json_object_object_add(ret, "network", network); - - struct json_object *software = json_object_new_object(); - struct json_object *software_firmware = json_object_new_object(); - json_object_object_add(software_firmware, "base", gluon_version()); - json_object_object_add(software_firmware, "release", gluonutil_wrap_and_free_string(gluonutil_read_line("/lib/gluon/release"))); - json_object_object_add(software, "firmware", software_firmware); - json_object_object_add(ret, "software", software); - - struct json_object *system = json_object_new_object(); - json_object_object_add(system, "site_code", get_site_code()); - if (gluonutil_has_domains()) - json_object_object_add(system, "domain_code", get_domain_code()); - json_object_object_add(ret, "system", system); - - return ret; -} - - -static void add_uptime(struct json_object *obj) { - FILE *f = fopen("/proc/uptime", "r"); - struct json_object* jso; - if (!f) - return; - - double uptime, idletime; - if (fscanf(f, "%lf %lf", &uptime, &idletime) == 2) { - jso = json_object_new_double(uptime); - json_object_set_serializer(jso, json_object_double_to_json_string, "%.2f", NULL); - json_object_object_add(obj, "uptime", jso); - jso = json_object_new_double(idletime); - json_object_set_serializer(jso, json_object_double_to_json_string, "%.2f", NULL); - json_object_object_add(obj, "idletime", jso); - } - - fclose(f); -} - -static void add_loadavg(struct json_object *obj) { - FILE *f = fopen("/proc/loadavg", "r"); - if (!f) - return; - - double loadavg; - unsigned proc_running, proc_total; - if (fscanf(f, "%lf %*f %*f %u/%u", &loadavg, &proc_running, &proc_total) == 3) { - struct json_object *jso = json_object_new_double(loadavg); - json_object_set_serializer(jso, json_object_double_to_json_string, "%.2f", NULL); - json_object_object_add(obj, "loadavg", jso); - - struct json_object *processes = json_object_new_object(); - json_object_object_add(processes, "running", json_object_new_int(proc_running)); - json_object_object_add(processes, "total", json_object_new_int(proc_total)); - json_object_object_add(obj, "processes", processes); - } - - fclose(f); -} - -static struct json_object * get_memory(void) { - FILE *f = fopen("/proc/meminfo", "r"); - if (!f) - return NULL; - - struct json_object *ret = json_object_new_object(); - - char *line = NULL; - size_t len = 0; - - while (getline(&line, &len, f) >= 0) { - char label[32]; - unsigned value; - - if (sscanf(line, "%31[^:]: %u", label, &value) != 2) - continue; - - if (!strcmp(label, "MemTotal")) - json_object_object_add(ret, "total", json_object_new_int(value)); - else if (!strcmp(label, "MemFree")) - json_object_object_add(ret, "free", json_object_new_int(value)); - else if (!strcmp(label, "MemAvailable")) - json_object_object_add(ret, "available", json_object_new_int(value)); - else if (!strcmp(label, "Buffers")) - json_object_object_add(ret, "buffers", json_object_new_int(value)); - else if (!strcmp(label, "Cached")) - json_object_object_add(ret, "cached", json_object_new_int(value)); - } - - free(line); - fclose(f); - - return ret; -} - -static struct json_object * get_stat(void) { - FILE *f = fopen("/proc/stat", "r"); - if (!f) - return NULL; - - struct json_object *stat = json_object_new_object(); - struct json_object *ret = NULL; - - char *line = NULL; - size_t len = 0; - - while (getline(&line, &len, f) >= 0) { - char label[32]; - - if (sscanf(line, "%31s", label) != 1){ - goto invalid_stat_format; - } - - if (!strcmp(label, "cpu")) { - unsigned long long user, nice, system, idle, iowait, irq, softirq; - if (sscanf(line, "%*s %"SCNu64" %"SCNu64" %"SCNu64" %"SCNu64" %"SCNu64" %"SCNu64" %"SCNu64, - &user, &nice, &system, &idle, &iowait, &irq, &softirq) != 7) - goto invalid_stat_format; - - struct json_object *cpu = json_object_new_object(); - - json_object_object_add(cpu, "user", json_object_new_int64(user)); - json_object_object_add(cpu, "nice", json_object_new_int64(nice)); - json_object_object_add(cpu, "system", json_object_new_int64(system)); - json_object_object_add(cpu, "idle", json_object_new_int64(idle)); - json_object_object_add(cpu, "iowait", json_object_new_int64(iowait)); - json_object_object_add(cpu, "irq", json_object_new_int64(irq)); - json_object_object_add(cpu, "softirq", json_object_new_int64(softirq)); - - json_object_object_add(stat, "cpu", cpu); - } else if (!strcmp(label, "ctxt")) { - unsigned long long ctxt; - if (sscanf(line, "%*s %"SCNu64, &ctxt) != 1) - goto invalid_stat_format; - - json_object_object_add(stat, "ctxt", json_object_new_int64(ctxt)); - } else if (!strcmp(label, "intr")) { - unsigned long long total_intr; - if (sscanf(line, "%*s %"SCNu64, &total_intr) != 1) - goto invalid_stat_format; - - json_object_object_add(stat, "intr", json_object_new_int64(total_intr)); - } else if (!strcmp(label, "softirq")) { - unsigned long long total_softirq; - if (sscanf(line, "%*s %"SCNu64, &total_softirq) != 1) - goto invalid_stat_format; - - json_object_object_add(stat, "softirq", json_object_new_int64(total_softirq)); - } else if (!strcmp(label, "processes")) { - unsigned long long processes; - if (sscanf(line, "%*s %"SCNu64, &processes) != 1) - goto invalid_stat_format; - - json_object_object_add(stat, "processes", json_object_new_int64(processes)); - } - - } - - ret = stat; - -invalid_stat_format: - if (!ret) - json_object_put(stat); - - free(line); - fclose(f); - - return ret; -} - - -static struct json_object * get_rootfs_usage(void) { - struct statfs s; - if (statfs("/", &s)) - return NULL; - - struct json_object *jso = json_object_new_double(1 - (double)s.f_bfree / s.f_blocks); - json_object_set_serializer(jso, json_object_double_to_json_string, "%.4f", NULL); - return jso; -} - -static struct json_object * get_time(void) { - struct timespec now; - - if (clock_gettime(CLOCK_REALTIME, &now) != 0) - return NULL; - - return json_object_new_int64(now.tv_sec); -} - -static struct json_object * respondd_provider_statistics(void) { - struct json_object *ret = json_object_new_object(); - - json_object_object_add(ret, "node_id", gluonutil_wrap_and_free_string(gluonutil_get_node_id())); - - json_object *time = get_time(); - if (time != NULL) - json_object_object_add(ret, "time", time); - - json_object_object_add(ret, "rootfs_usage", get_rootfs_usage()); - json_object_object_add(ret, "memory", get_memory()); - json_object_object_add(ret, "stat", get_stat()); - - add_uptime(ret); - add_loadavg(ret); - - return ret; -} - - -static struct json_object * respondd_provider_neighbours(void) { - struct json_object *ret = json_object_new_object(); - json_object_object_add(ret, "node_id", gluonutil_wrap_and_free_string(gluonutil_get_node_id())); - return ret; -} - +__attribute__ ((visibility ("default"))) const struct respondd_provider_info respondd_providers[] = { {"nodeinfo", respondd_provider_nodeinfo}, {"statistics", respondd_provider_statistics}, diff --git a/package/gluon-setup-mode/files/etc/hotplug.d/button/50-gluon-setup-mode b/package/gluon-setup-mode/files/etc/hotplug.d/button/50-gluon-setup-mode index 3a3cb20f..314f8a43 100755 --- a/package/gluon-setup-mode/files/etc/hotplug.d/button/50-gluon-setup-mode +++ b/package/gluon-setup-mode/files/etc/hotplug.d/button/50-gluon-setup-mode @@ -12,7 +12,7 @@ wait_setup_mode() { } -if [ "$BUTTON" = wps -o "$BUTTON" = reset -o "$BUTTON" = phone ]; then +if [ "$BUTTON" = wps ] || [ "$BUTTON" = reset ] || [ "$BUTTON" = phone ]; then case "$ACTION" in pressed) wait_setup_mode & @@ -21,7 +21,7 @@ if [ "$BUTTON" = wps -o "$BUTTON" = reset -o "$BUTTON" = phone ]; then ;; released) if [ -r /tmp/.wait_setup_mode ]; then - kill $(cat /tmp/.wait_setup_mode) + kill "$(cat /tmp/.wait_setup_mode)" rm /tmp/.wait_setup_mode fi ;; diff --git a/package/gluon-setup-mode/files/lib/preinit/90_setup_mode b/package/gluon-setup-mode/files/lib/preinit/90_setup_mode index 396b4f76..c38ac281 100644 --- a/package/gluon-setup-mode/files/lib/preinit/90_setup_mode +++ b/package/gluon-setup-mode/files/lib/preinit/90_setup_mode @@ -5,7 +5,7 @@ setup_mode_enable() { local enabled="$(uci -q get 'gluon-setup-mode.@setup_mode[0].enabled')" local configured="$(uci -q get 'gluon-setup-mode.@setup_mode[0].configured')" - if [ "$enabled" = 1 -o "$configured" != 1 ]; then + if [ "$enabled" = 1 ] || [ "$configured" != 1 ]; then echo '/lib/gluon/setup-mode/rc.d' > /tmp/rc_d_path fi } diff --git a/package/gluon-site/Makefile b/package/gluon-site/Makefile index b1d2d91b..b81ed103 100644 --- a/package/gluon-site/Makefile +++ b/package/gluon-site/Makefile @@ -8,7 +8,7 @@ PKG_VERSION:=$(if $(DUMP),x,$(GLUON_SITE_VERSION)) PKG_CONFIG_DEPENDS := CONFIG_GLUON_RELEASE CONFIG_GLUON_SITEDIR CONFIG_GLUON_MULTIDOMAIN PKG_FILE_DEPENDS := $(GLUON_SITEDIR)/site.conf $(GLUON_SITEDIR)/domains/ $(GLUON_SITEDIR)/i18n/ -PKG_BUILD_DEPENDS := lua-cjson/host +PKG_BUILD_DEPENDS := lua-cjson/host gluon-web/host PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) diff --git a/package/gluon-status-page/files/lib/gluon/status-page/view/status-page.html b/package/gluon-status-page/files/lib/gluon/status-page/view/status-page.html index 6e18b010..cb7aaa11 100644 --- a/package/gluon-status-page/files/lib/gluon/status-page/view/status-page.html +++ b/package/gluon-status-page/files/lib/gluon/status-page/view/status-page.html @@ -135,7 +135,7 @@ <%:Load average%><%= statistics('loadavg', 'decimal') %> <%:RAM%><%= statistics('memory', 'memory') %> <%:Filesystem%><%= statistics('rootfs_usage', 'percent') %> - <%:Gateway%><%= statistics('gateway') %> + <%:Gateway%><%= statistics('gateway') %>
<%= statistics('gateway_nexthop', 'neighbour') %> <%:Clients%><%= statistics('clients/total') %> diff --git a/package/gluon-status-page/files/lib/gluon/status-page/www/static/status-page.js b/package/gluon-status-page/files/lib/gluon/status-page/www/static/status-page.js index 37bda815..87e33789 100644 --- a/package/gluon-status-page/files/lib/gluon/status-page/www/static/status-page.js +++ b/package/gluon-status-page/files/lib/gluon/status-page/www/static/status-page.js @@ -1 +1 @@ -"use strict";!function(){var a=JSON.parse(document.body.getAttribute("data-translations"));function r(t,e){return t.toFixed(e).replace(/\./,a["."])}function o(t,e){e--;for(var n=t;10<=n&&0e[0]?-1:t[1]e[1]?1:0});var e=t[0][2];return e&&!/^fe80:/i.test(e)?e:void 0}}(t.network.addresses);if(u){if("span"===h.nodeName.toLowerCase()){var l=h;h=document.createElement("a"),l.parentNode.replaceChild(h,l)}h.href="http://["+u+"]/"}if(h.textContent=t.hostname,y&&t.location){var f=(e=y.latitude,n=y.longitude,i=t.location.latitude,r=t.location.longitude,a=Math.PI/180,o=(i*=a)-(e*=a),c=(r*=a)-(n*=a),s=Math.sin(o/2)*Math.sin(o/2)+Math.sin(c/2)*Math.sin(c/2)*Math.cos(e)*Math.cos(i),2*Math.asin(Math.sqrt(s))*6372.8);d.textContent=Math.round(1e3*f)+" m"}p()},update_mesh:function(n){Object.keys(v).forEach(function(t){var e=v[t];e.td.textContent=n[t]+e.suffix}),p()},update_wifi:function(t){s.textContent=t.signal,u.textContent=Math.round(t.inactive/1e3)+" s",a.classList.toggle("inactive",200e[0]?-1:t[1]e[1]?1:0});var e=t[0][2];return e&&!/^fe80:/i.test(e)?e:void 0}}return t.wireless&&((u=a.insertCell()).textContent="-",(d=a.insertCell()).textContent="-",(s=a.insertCell()).textContent="-",f=E(n),t.signalgraph.addSignal(f)),a.onmouseenter=function(){a.classList.add("highlight"),f&&(f.highlight=!0)},a.onmouseleave=function(){a.classList.remove("highlight"),f&&(f.highlight=!1)},p(),{get_hostname:function(){return h.textContent},update_nodeinfo:function(t){var e,n,r,i,a,o,c,u,s=y(t.network.addresses);if(s){if("span"===h.nodeName.toLowerCase()){var f=h;h=document.createElement("a"),f.parentNode.replaceChild(h,f)}h.href="http://["+s+"]/"}if(h.textContent=t.hostname,C&&t.location){var l=(e=C.latitude,n=C.longitude,r=t.location.latitude,i=t.location.longitude,a=Math.PI/180,o=(r*=a)-(e*=a),c=(i*=a)-(n*=a),u=Math.sin(o/2)*Math.sin(o/2)+Math.sin(c/2)*Math.sin(c/2)*Math.cos(e)*Math.cos(r),2*Math.asin(Math.sqrt(u))*6372.8);d.textContent=Math.round(1e3*l)+" m"}p()},update_mesh:function(n){Object.keys(v).forEach(function(t){var e=v[t];e.td.textContent=n[t]+e.suffix}),p()},update_wifi:function(t){u.textContent=t.signal,s.textContent=Math.round(t.inactive/1e3)+" s",a.classList.toggle("inactive",200 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "template_lmo.h" + +#include +#include +#include +#include +#include + + +__attribute__((noreturn)) +static void die(const char *msg) +{ + fprintf(stderr, "Error: %s\n", msg); + exit(1); +} + +__attribute__((noreturn)) +static void usage(const char *name) +{ + fprintf(stderr, "Usage: %s input.po output.lmo\n", name); + exit(1); +} + +static void print(const void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + if( fwrite(ptr, size, nmemb, stream) == 0 ) + die("Failed to write stdout"); +} + +static ssize_t extract_string(const char *src, char *dest, size_t len) +{ + size_t pos = 0; + int esc = 0; + int off = -1; + + for( pos = 0; (pos < strlen(src)) && (pos < len); pos++ ) + { + if( (off == -1) && (src[pos] == '"') ) + { + off = pos + 1; + } + else if( off >= 0 ) + { + if( esc == 1 ) + { + switch (src[pos]) + { + case '"': + case '\\': + off++; + break; + } + dest[pos-off] = src[pos]; + esc = 0; + } + else if( src[pos] == '\\' ) + { + dest[pos-off] = src[pos]; + esc = 1; + } + else if( src[pos] != '"' ) + { + dest[pos-off] = src[pos]; + } + else + { + dest[pos-off] = '\0'; + break; + } + } + } + + return (off > -1) ? (ssize_t) strlen(dest) : -1; +} + +static int cmp_index(const void *a, const void *b) +{ + uint32_t x = ((const lmo_entry_t *)a)->key_id; + uint32_t y = ((const lmo_entry_t *)b)->key_id; + + if (x < y) + return -1; + else if (x > y) + return 1; + + return 0; +} + +static void print_uint32(uint32_t x, FILE *out) +{ + uint32_t y = htonl(x); + print(&y, sizeof(uint32_t), 1, out); +} + +static void print_index(void *array, int n, FILE *out) +{ + lmo_entry_t *e; + + qsort(array, n, sizeof(*e), cmp_index); + + for (e = array; n > 0; n--, e++) + { + print_uint32(e->key_id, out); + print_uint32(e->val_id, out); + print_uint32(e->offset, out); + print_uint32(e->length, out); + } +} + +int main(int argc, char *argv[]) +{ + char line[4096]; + char key[4096]; + char val[4096]; + char tmp[4096]; + int state = 0; + int offset = 0; + int length = 0; + int n_entries = 0; + void *array = NULL; + lmo_entry_t *entry = NULL; + uint32_t key_id, val_id; + + FILE *in; + FILE *out; + + if( (argc != 3) || ((in = fopen(argv[1], "r")) == NULL) || ((out = fopen(argv[2], "w")) == NULL) ) + usage(argv[0]); + + memset(line, 0, sizeof(key)); + memset(key, 0, sizeof(val)); + memset(val, 0, sizeof(val)); + + while( (NULL != fgets(line, sizeof(line), in)) || (state >= 2 && feof(in)) ) + { + if( state == 0 && strstr(line, "msgid \"") == line ) + { + switch(extract_string(line, key, sizeof(key))) + { + case -1: + die("Syntax error in msgid"); + case 0: + state = 1; + break; + default: + state = 2; + } + } + else if( state == 1 || state == 2 ) + { + if( strstr(line, "msgstr \"") == line || state == 2 ) + { + switch(extract_string(line, val, sizeof(val))) + { + case -1: + state = 4; + break; + default: + state = 3; + } + } + else + { + switch(extract_string(line, tmp, sizeof(tmp))) + { + case -1: + state = 2; + break; + default: + strcat(key, tmp); + } + } + } + else if( state == 3 ) + { + switch(extract_string(line, tmp, sizeof(tmp))) + { + case -1: + state = 4; + break; + default: + strcat(val, tmp); + } + } + + if( state == 4 ) + { + if( strlen(key) > 0 && strlen(val) > 0 ) + { + key_id = sfh_hash(key, strlen(key)); + val_id = sfh_hash(val, strlen(val)); + + if( key_id != val_id ) + { + n_entries++; + array = realloc(array, n_entries * sizeof(lmo_entry_t)); + entry = (lmo_entry_t *)array + n_entries - 1; + + if (!array) + die("Out of memory"); + + entry->key_id = key_id; + entry->val_id = val_id; + entry->offset = offset; + entry->length = strlen(val); + + length = strlen(val) + ((4 - (strlen(val) % 4)) % 4); + + print(val, length, 1, out); + offset += length; + } + } + + state = 0; + memset(key, 0, sizeof(key)); + memset(val, 0, sizeof(val)); + } + + memset(line, 0, sizeof(line)); + } + + print_index(array, n_entries, out); + + if( offset > 0 ) + { + print_uint32(offset, out); + fsync(fileno(out)); + fclose(out); + } + else + { + fclose(out); + unlink(argv[2]); + } + + fclose(in); + return(0); +} diff --git a/package/gluon-web/src/template_lmo.c b/package/gluon-web/src/template_lmo.c index 0a86bbc9..062497b3 100644 --- a/package/gluon-web/src/template_lmo.c +++ b/package/gluon-web/src/template_lmo.c @@ -25,20 +25,11 @@ #include #include #include -#include #include #include #include -struct lmo_entry { - uint32_t key_id; - uint32_t val_id; - uint32_t offset; - uint32_t length; -} __attribute__((packed)); - - static inline uint16_t get_le16(const void *data) { const uint8_t *d = data; return (((uint16_t)d[1]) << 8) | d[0]; @@ -56,7 +47,7 @@ static inline uint32_t get_be32(const void *data) { * Hash function from http://www.azillionmonkeys.com/qed/hash.html * Copyright (C) 2004-2008 by Paul Hsieh */ -static uint32_t sfh_hash(const void *input, size_t len) +uint32_t sfh_hash(const void *input, size_t len) { const uint8_t *data = input; uint32_t hash = len, tmp; diff --git a/package/gluon-web/src/template_lmo.h b/package/gluon-web/src/template_lmo.h index 4af6cac1..f381c7c1 100644 --- a/package/gluon-web/src/template_lmo.h +++ b/package/gluon-web/src/template_lmo.h @@ -22,8 +22,15 @@ #include #include +#include +struct lmo_entry { + uint32_t key_id; + uint32_t val_id; + uint32_t offset; + uint32_t length; +} __attribute__((packed)); typedef struct lmo_entry lmo_entry_t; @@ -37,6 +44,8 @@ struct lmo_catalog { typedef struct lmo_catalog lmo_catalog_t; +uint32_t sfh_hash(const void *input, size_t len); + bool lmo_load(lmo_catalog_t *cat, const char *file); void lmo_unload(lmo_catalog_t *cat); bool lmo_translate(const lmo_catalog_t *cat, const char *key, size_t keylen, const char **out, size_t *outlen); diff --git a/package/gluon.mk b/package/gluon.mk index 90aeabc9..7246a318 100644 --- a/package/gluon.mk +++ b/package/gluon.mk @@ -1,8 +1,7 @@ GLUON_MK := $(abspath $(lastword $(MAKEFILE_LIST))) PKG_FILE_DEPENDS += $(GLUON_MK) -# Dependencies for LuaSrcDiet -PKG_BUILD_DEPENDS += luci-base/host +PKG_BUILD_DEPENDS += luasrcdiet/host ifneq ($(wildcard ./src/respondd.c),) PKG_BUILD_DEPENDS += respondd @@ -31,6 +30,7 @@ GLUON_I18N_CONFIG := $(foreach lang,$(GLUON_SUPPORTED_LANGS),CONFIG_GLUON_WEB_LA GLUON_ENABLED_LANGS := en $(foreach lang,$(GLUON_SUPPORTED_LANGS),$(if $(CONFIG_GLUON_WEB_LANG_$(lang)),$(lang))) ifneq ($(wildcard ./i18n/.),) + PKG_BUILD_DEPENDS += gluon-web/host PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) endif @@ -40,7 +40,7 @@ define GluonBuildI18N for lang in $$(GLUON_ENABLED_LANGS); do \ if [ -e $(1)/$$$$lang.po ]; then \ rm -f $$(PKG_BUILD_DIR)/i18n/$$$$lang.lmo; \ - po2lmo $(1)/$$$$lang.po $$(PKG_BUILD_DIR)/i18n/$$$$lang.lmo; \ + gluon-po2lmo $(1)/$$$$lang.po $$(PKG_BUILD_DIR)/i18n/$$$$lang.lmo; \ fi; \ done endef diff --git a/patches/openwrt/0001-procd-add-support-for-alternative-rc.d-directories.patch b/patches/openwrt/0001-procd-add-support-for-alternative-rc.d-directories.patch index db29794d..be6f38e8 100644 --- a/patches/openwrt/0001-procd-add-support-for-alternative-rc.d-directories.patch +++ b/patches/openwrt/0001-procd-add-support-for-alternative-rc.d-directories.patch @@ -4,10 +4,10 @@ Subject: procd: add support for alternative rc.d directories diff --git a/package/system/procd/patches/0001-Add-support-for-alternative-rc.d-directories.patch b/package/system/procd/patches/0001-Add-support-for-alternative-rc.d-directories.patch new file mode 100644 -index 0000000000000000000000000000000000000000..bc2434200364b46f1db4c2eec22c4e8b973844d5 +index 0000000000000000000000000000000000000000..16d3179f05c64b7178f883745294c64a27127775 --- /dev/null +++ b/package/system/procd/patches/0001-Add-support-for-alternative-rc.d-directories.patch -@@ -0,0 +1,97 @@ +@@ -0,0 +1,80 @@ +From 03a2bc70e4260ec9f669391c47b9a7a9ecd0b75d Mon Sep 17 00:00:00 2001 +Message-Id: <03a2bc70e4260ec9f669391c47b9a7a9ecd0b75d.1407329621.git.mschiffer@universe-factory.net> +From: Matthias Schiffer @@ -19,21 +19,10 @@ index 0000000000000000000000000000000000000000..bc2434200364b46f1db4c2eec22c4e8b + rcS.c | 2 +- + 2 files changed, 39 insertions(+), 1 deletion(-) + -+diff --git a/initd/preinit.c b/initd/preinit.c -+index fb94527..8b832a7 100644 +--- a/initd/preinit.c ++++ b/initd/preinit.c -+@@ -12,6 +12,8 @@ -+ * GNU General Public License for more details. -+ */ -+ -++#define _GNU_SOURCE -++ -+ #include -+ #include -+ #include -+@@ -46,6 +48,35 @@ check_dbglvl(void) -+ debug = lvl; ++@@ -87,12 +87,42 @@ fail: ++ free(command); + } + ++static char* @@ -68,15 +57,14 @@ index 0000000000000000000000000000000000000000..bc2434200364b46f1db4c2eec22c4e8b + static void + spawn_procd(struct uloop_process *proc, int ret) + { -+@@ -53,6 +84,7 @@ spawn_procd(struct uloop_process *proc, int ret) ++ char *wdt_fd = watchdog_fd(); + char *argv[] = { "/sbin/procd", NULL}; -+ struct stat s; + char dbg[2]; ++ char *rc_d_path; + + if (plugd_proc.pid > 0) + kill(plugd_proc.pid, SIGKILL); -+@@ -72,6 +104,12 @@ spawn_procd(struct uloop_process *proc, int ret) ++@@ -112,6 +142,12 @@ spawn_procd(struct uloop_process *proc, + setenv("DBGLVL", dbg, 1); + } + @@ -89,11 +77,9 @@ index 0000000000000000000000000000000000000000..bc2434200364b46f1db4c2eec22c4e8b + execvp(argv[0], argv); + } + -+diff --git a/rcS.c b/rcS.c -+index 0e1b0ba..1b00831 100644 +--- a/rcS.c ++++ b/rcS.c -+@@ -150,7 +150,7 @@ int rcS(char *pattern, char *param, void (*q_empty)(struct runqueue *)) ++@@ -184,7 +184,7 @@ int rcS(char *pattern, char *param, void + q.empty_cb = q_empty; + q.max_running_tasks = 1; + @@ -102,6 +88,3 @@ index 0000000000000000000000000000000000000000..bc2434200364b46f1db4c2eec22c4e8b + } + + int rc(const char *file, char *param) -+-- -+2.0.4 -+ diff --git a/patches/openwrt/0003-libjson-c-Add-support-for-custom-format-strings-for-doubles.patch b/patches/openwrt/0003-libjson-c-Add-support-for-custom-format-strings-for-doubles.patch index 662d8960..a5960219 100644 --- a/patches/openwrt/0003-libjson-c-Add-support-for-custom-format-strings-for-doubles.patch +++ b/patches/openwrt/0003-libjson-c-Add-support-for-custom-format-strings-for-doubles.patch @@ -4,10 +4,10 @@ Subject: libjson-c: Add support for custom format strings for doubles diff --git a/package/libs/libjson-c/patches/002-custom-format-string.patch b/package/libs/libjson-c/patches/002-custom-format-string.patch new file mode 100644 -index 0000000000000000000000000000000000000000..2f454c560ff78c1edd4654b9651f0e6299bd5e6f +index 0000000000000000000000000000000000000000..b67433a7baf37654a17fa5036c4266b33bdda9f2 --- /dev/null +++ b/package/libs/libjson-c/patches/002-custom-format-string.patch -@@ -0,0 +1,98 @@ +@@ -0,0 +1,91 @@ +From 21dc5dc92bd56f5f4dc2c90b9ea6bf1e1407714e Mon Sep 17 00:00:00 2001 +From: Jan-Philipp Litza +Date: Fri, 6 May 2016 16:12:44 +0200 @@ -20,11 +20,9 @@ index 0000000000000000000000000000000000000000..2f454c560ff78c1edd4654b9651f0e62 + json_object.h | 28 ++++++++++++++++++++++++++++ + 2 files changed, 34 insertions(+), 6 deletions(-) + -+diff --git a/json_object.c b/json_object.c -+index 7d60884..46701e7 100644 +--- a/json_object.c ++++ b/json_object.c -+@@ -55,7 +55,6 @@ static struct json_object* json_object_new(enum json_type o_type); ++@@ -55,7 +55,6 @@ static struct json_object* json_object_n + static json_object_to_json_string_fn json_object_object_to_json_string; + static json_object_to_json_string_fn json_object_boolean_to_json_string; + static json_object_to_json_string_fn json_object_int_to_json_string; @@ -32,7 +30,7 @@ index 0000000000000000000000000000000000000000..2f454c560ff78c1edd4654b9651f0e62 + static json_object_to_json_string_fn json_object_string_to_json_string; + static json_object_to_json_string_fn json_object_array_to_json_string; + -+@@ -644,10 +643,10 @@ int64_t json_object_get_int64(const struct json_object *jso) ++@@ -560,10 +559,10 @@ int64_t json_object_get_int64(struct jso + + /* json_object_double */ + @@ -47,7 +45,7 @@ index 0000000000000000000000000000000000000000..2f454c560ff78c1edd4654b9651f0e62 + { + char buf[128], *p, *q; + int size; -+@@ -663,7 +662,8 @@ static int json_object_double_to_json_string(struct json_object* jso, ++@@ -579,7 +578,8 @@ static int json_object_double_to_json_st + else + size = snprintf(buf, sizeof(buf), "-Infinity"); + else @@ -57,11 +55,9 @@ index 0000000000000000000000000000000000000000..2f454c560ff78c1edd4654b9651f0e62 + + p = strchr(buf, ','); + if (p) { -+diff --git a/json_object.h b/json_object.h -+index 2bce454..a89de44 100644 +--- a/json_object.h ++++ b/json_object.h -+@@ -614,6 +614,9 @@ extern int64_t json_object_get_int64(const struct json_object *obj); ++@@ -515,6 +515,9 @@ extern int64_t json_object_get_int64(str + /* double type methods */ + + /** Create a new empty json_object of type json_type_double @@ -71,7 +67,7 @@ index 0000000000000000000000000000000000000000..2f454c560ff78c1edd4654b9651f0e62 + * @param d the double + * @returns a json_object of type json_type_double + */ -+@@ -642,6 +645,31 @@ extern struct json_object* json_object_new_double(double d); ++@@ -543,6 +546,31 @@ extern struct json_object* json_object_n + */ + extern struct json_object* json_object_new_double_s(double d, const char *ds); + @@ -103,6 +99,3 @@ index 0000000000000000000000000000000000000000..2f454c560ff78c1edd4654b9651f0e62 + /** Get the double floating point value of a json_object + * + * The type is coerced to a double if the passed object is not a double. -+-- -+2.7.4 -+ diff --git a/patches/openwrt/0005-kernel-ebtables-add-support-for-ICMP-IGMP-type-matches.patch b/patches/openwrt/0005-kernel-ebtables-add-support-for-ICMP-IGMP-type-matches.patch index b21691ac..37698460 100644 --- a/patches/openwrt/0005-kernel-ebtables-add-support-for-ICMP-IGMP-type-matches.patch +++ b/patches/openwrt/0005-kernel-ebtables-add-support-for-ICMP-IGMP-type-matches.patch @@ -6,10 +6,10 @@ Signed-off-by: Matthias Schiffer diff --git a/target/linux/generic/backport-4.14/096-0001-ebtables-add-support-for-matching-ICMP-type-and-code.patch b/target/linux/generic/backport-4.14/096-0001-ebtables-add-support-for-matching-ICMP-type-and-code.patch new file mode 100644 -index 0000000000000000000000000000000000000000..9e4d90fb3b8e2c91e4adf0e0efdb3f4575b5027d +index 0000000000000000000000000000000000000000..fe9c479338a7b597be649c761c70a63085b51c5f --- /dev/null +++ b/target/linux/generic/backport-4.14/096-0001-ebtables-add-support-for-matching-ICMP-type-and-code.patch -@@ -0,0 +1,141 @@ +@@ -0,0 +1,134 @@ +From: Matthias Schiffer +Date: Sat, 3 Mar 2018 11:55:21 +0100 +Subject: [PATCH 1/2] ebtables: add support for matching ICMP type and code @@ -23,8 +23,6 @@ index 0000000000000000000000000000000000000000..9e4d90fb3b8e2c91e4adf0e0efdb3f45 + net/bridge/netfilter/ebt_ip.c | 43 +++++++++++++++++++++------- + 2 files changed, 43 insertions(+), 13 deletions(-) + -+diff --git a/include/uapi/linux/netfilter_bridge/ebt_ip.h b/include/uapi/linux/netfilter_bridge/ebt_ip.h -+index 8e462fb1983f..4ed7fbb0a482 100644 +--- a/include/uapi/linux/netfilter_bridge/ebt_ip.h ++++ b/include/uapi/linux/netfilter_bridge/ebt_ip.h +@@ -24,8 +24,9 @@ @@ -55,8 +53,6 @@ index 0000000000000000000000000000000000000000..9e4d90fb3b8e2c91e4adf0e0efdb3f45 + }; + + #endif -+diff --git a/net/bridge/netfilter/ebt_ip.c b/net/bridge/netfilter/ebt_ip.c -+index 2b46c50abce0..8cb8f8395768 100644 +--- a/net/bridge/netfilter/ebt_ip.c ++++ b/net/bridge/netfilter/ebt_ip.c +@@ -19,9 +19,15 @@ @@ -78,7 +74,7 @@ index 0000000000000000000000000000000000000000..9e4d90fb3b8e2c91e4adf0e0efdb3f45 + }; + + static bool -+@@ -30,8 +36,8 @@ ebt_ip_mt(const struct sk_buff *skb, struct xt_action_param *par) ++@@ -30,8 +36,8 @@ ebt_ip_mt(const struct sk_buff *skb, str + const struct ebt_ip_info *info = par->matchinfo; + const struct iphdr *ih; + struct iphdr _iph; @@ -89,7 +85,7 @@ index 0000000000000000000000000000000000000000..9e4d90fb3b8e2c91e4adf0e0efdb3f45 + + ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph); + if (ih == NULL) -+@@ -50,29 +56,38 @@ ebt_ip_mt(const struct sk_buff *skb, struct xt_action_param *par) ++@@ -50,29 +56,38 @@ ebt_ip_mt(const struct sk_buff *skb, str + if (info->bitmask & EBT_IP_PROTO) { + if (NF_INVF(info, EBT_IP_PROTO, info->protocol != ih->protocol)) + return false; @@ -133,7 +129,7 @@ index 0000000000000000000000000000000000000000..9e4d90fb3b8e2c91e4adf0e0efdb3f45 + } + return true; + } -+@@ -101,6 +116,14 @@ static int ebt_ip_mt_check(const struct xt_mtchk_param *par) ++@@ -101,6 +116,14 @@ static int ebt_ip_mt_check(const struct + return -EINVAL; + if (info->bitmask & EBT_IP_SPORT && info->sport[0] > info->sport[1]) + return -EINVAL; @@ -148,15 +144,12 @@ index 0000000000000000000000000000000000000000..9e4d90fb3b8e2c91e4adf0e0efdb3f45 + return 0; + } + -+-- -+2.16.2 -+ diff --git a/target/linux/generic/backport-4.14/096-0002-ebtables-add-support-for-matching-IGMP-type.patch b/target/linux/generic/backport-4.14/096-0002-ebtables-add-support-for-matching-IGMP-type.patch new file mode 100644 -index 0000000000000000000000000000000000000000..35b93adc802c2850cd6ee218c3d7d6f6c53bba29 +index 0000000000000000000000000000000000000000..4c8144834d87c58ff90363cdc2f2933194e54fdc --- /dev/null +++ b/target/linux/generic/backport-4.14/096-0002-ebtables-add-support-for-matching-IGMP-type.patch -@@ -0,0 +1,95 @@ +@@ -0,0 +1,88 @@ +From: Matthias Schiffer +Date: Sat, 3 Mar 2018 12:02:21 +0100 +Subject: [PATCH 2/2] ebtables: add support for matching IGMP type @@ -171,8 +164,6 @@ index 0000000000000000000000000000000000000000..35b93adc802c2850cd6ee218c3d7d6f6 + net/bridge/netfilter/ebt_ip.c | 19 +++++++++++++++++-- + 2 files changed, 20 insertions(+), 3 deletions(-) + -+diff --git a/include/uapi/linux/netfilter_bridge/ebt_ip.h b/include/uapi/linux/netfilter_bridge/ebt_ip.h -+index 4ed7fbb0a482..46d6261370b0 100644 +--- a/include/uapi/linux/netfilter_bridge/ebt_ip.h ++++ b/include/uapi/linux/netfilter_bridge/ebt_ip.h +@@ -25,8 +25,9 @@ @@ -194,8 +185,6 @@ index 0000000000000000000000000000000000000000..35b93adc802c2850cd6ee218c3d7d6f6 + }; + union { + __u16 dport[2]; -+diff --git a/net/bridge/netfilter/ebt_ip.c b/net/bridge/netfilter/ebt_ip.c -+index 8cb8f8395768..ffaa8ce2e724 100644 +--- a/net/bridge/netfilter/ebt_ip.c ++++ b/net/bridge/netfilter/ebt_ip.c +@@ -28,6 +28,9 @@ union pkthdr { @@ -208,7 +197,7 @@ index 0000000000000000000000000000000000000000..35b93adc802c2850cd6ee218c3d7d6f6 + }; + + static bool -+@@ -57,12 +60,12 @@ ebt_ip_mt(const struct sk_buff *skb, struct xt_action_param *par) ++@@ -57,12 +60,12 @@ ebt_ip_mt(const struct sk_buff *skb, str + if (NF_INVF(info, EBT_IP_PROTO, info->protocol != ih->protocol)) + return false; + if (!(info->bitmask & (EBT_IP_DPORT | EBT_IP_SPORT | @@ -223,7 +212,7 @@ index 0000000000000000000000000000000000000000..35b93adc802c2850cd6ee218c3d7d6f6 + pptr = skb_header_pointer(skb, ih->ihl*4, + sizeof(_pkthdr), &_pkthdr); + if (pptr == NULL) -+@@ -88,6 +91,11 @@ ebt_ip_mt(const struct sk_buff *skb, struct xt_action_param *par) ++@@ -88,6 +91,11 @@ ebt_ip_mt(const struct sk_buff *skb, str + pptr->icmphdr.code < info->icmp_code[0] || + pptr->icmphdr.code > info->icmp_code[1])) + return false; @@ -235,7 +224,7 @@ index 0000000000000000000000000000000000000000..35b93adc802c2850cd6ee218c3d7d6f6 + } + return true; + } -+@@ -124,6 +132,13 @@ static int ebt_ip_mt_check(const struct xt_mtchk_param *par) ++@@ -124,6 +132,13 @@ static int ebt_ip_mt_check(const struct + info->icmp_code[0] > info->icmp_code[1]) + return -EINVAL; + } @@ -249,254 +238,3 @@ index 0000000000000000000000000000000000000000..35b93adc802c2850cd6ee218c3d7d6f6 + return 0; + } + -+-- -+2.16.2 -+ -diff --git a/target/linux/generic/backport-4.9/096-0001-ebtables-add-support-for-matching-ICMP-type-and-code.patch b/target/linux/generic/backport-4.9/096-0001-ebtables-add-support-for-matching-ICMP-type-and-code.patch -new file mode 100644 -index 0000000000000000000000000000000000000000..db82fd6b69b3c4e279f39db7ca4b415498457e75 ---- /dev/null -+++ b/target/linux/generic/backport-4.9/096-0001-ebtables-add-support-for-matching-ICMP-type-and-code.patch -@@ -0,0 +1,141 @@ -+From: Matthias Schiffer -+Date: Sat, 3 Mar 2018 11:55:21 +0100 -+Subject: [PATCH 1/2] ebtables: add support for matching ICMP type and code -+ -+We already have ICMPv6 type/code matches. This adds support for IPv4 ICMP -+matches in the same way. -+ -+Signed-off-by: Matthias Schiffer -+--- -+ include/uapi/linux/netfilter_bridge/ebt_ip.h | 13 +++++++-- -+ net/bridge/netfilter/ebt_ip.c | 43 +++++++++++++++++++++------- -+ 2 files changed, 43 insertions(+), 13 deletions(-) -+ -+diff --git a/include/uapi/linux/netfilter_bridge/ebt_ip.h b/include/uapi/linux/netfilter_bridge/ebt_ip.h -+index c4bbc41b0ea4..63a2860ae1e3 100644 -+--- a/include/uapi/linux/netfilter_bridge/ebt_ip.h -++++ b/include/uapi/linux/netfilter_bridge/ebt_ip.h -+@@ -23,8 +23,9 @@ -+ #define EBT_IP_PROTO 0x08 -+ #define EBT_IP_SPORT 0x10 -+ #define EBT_IP_DPORT 0x20 -++#define EBT_IP_ICMP 0x40 -+ #define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\ -+- EBT_IP_SPORT | EBT_IP_DPORT ) -++ EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_ICMP) -+ #define EBT_IP_MATCH "ip" -+ -+ /* the same values are used for the invflags */ -+@@ -37,8 +38,14 @@ struct ebt_ip_info { -+ __u8 protocol; -+ __u8 bitmask; -+ __u8 invflags; -+- __u16 sport[2]; -+- __u16 dport[2]; -++ union { -++ __u16 sport[2]; -++ __u8 icmp_type[2]; -++ }; -++ union { -++ __u16 dport[2]; -++ __u8 icmp_code[2]; -++ }; -+ }; -+ -+ #endif -+diff --git a/net/bridge/netfilter/ebt_ip.c b/net/bridge/netfilter/ebt_ip.c -+index d06968bdf5ec..e4fc77072b27 100644 -+--- a/net/bridge/netfilter/ebt_ip.c -++++ b/net/bridge/netfilter/ebt_ip.c -+@@ -19,9 +19,15 @@ -+ #include -+ #include -+ -+-struct tcpudphdr { -+- __be16 src; -+- __be16 dst; -++union pkthdr { -++ struct { -++ __be16 src; -++ __be16 dst; -++ } tcpudphdr; -++ struct { -++ u8 type; -++ u8 code; -++ } icmphdr; -+ }; -+ -+ static bool -+@@ -30,8 +36,8 @@ ebt_ip_mt(const struct sk_buff *skb, struct xt_action_param *par) -+ const struct ebt_ip_info *info = par->matchinfo; -+ const struct iphdr *ih; -+ struct iphdr _iph; -+- const struct tcpudphdr *pptr; -+- struct tcpudphdr _ports; -++ const union pkthdr *pptr; -++ union pkthdr _pkthdr; -+ -+ ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph); -+ if (ih == NULL) -+@@ -50,29 +56,38 @@ ebt_ip_mt(const struct sk_buff *skb, struct xt_action_param *par) -+ if (info->bitmask & EBT_IP_PROTO) { -+ if (NF_INVF(info, EBT_IP_PROTO, info->protocol != ih->protocol)) -+ return false; -+- if (!(info->bitmask & EBT_IP_DPORT) && -+- !(info->bitmask & EBT_IP_SPORT)) -++ if (!(info->bitmask & (EBT_IP_DPORT | EBT_IP_SPORT | -++ EBT_IP_ICMP))) -+ return true; -+ if (ntohs(ih->frag_off) & IP_OFFSET) -+ return false; -++ -++ /* min icmp headersize is 4, so sizeof(_pkthdr) is ok. */ -+ pptr = skb_header_pointer(skb, ih->ihl*4, -+- sizeof(_ports), &_ports); -++ sizeof(_pkthdr), &_pkthdr); -+ if (pptr == NULL) -+ return false; -+ if (info->bitmask & EBT_IP_DPORT) { -+- u32 dst = ntohs(pptr->dst); -++ u32 dst = ntohs(pptr->tcpudphdr.dst); -+ if (NF_INVF(info, EBT_IP_DPORT, -+ dst < info->dport[0] || -+ dst > info->dport[1])) -+ return false; -+ } -+ if (info->bitmask & EBT_IP_SPORT) { -+- u32 src = ntohs(pptr->src); -++ u32 src = ntohs(pptr->tcpudphdr.src); -+ if (NF_INVF(info, EBT_IP_SPORT, -+ src < info->sport[0] || -+ src > info->sport[1])) -+ return false; -+ } -++ if ((info->bitmask & EBT_IP_ICMP) && -++ NF_INVF(info, EBT_IP_ICMP, -++ pptr->icmphdr.type < info->icmp_type[0] || -++ pptr->icmphdr.type > info->icmp_type[1] || -++ pptr->icmphdr.code < info->icmp_code[0] || -++ pptr->icmphdr.code > info->icmp_code[1])) -++ return false; -+ } -+ return true; -+ } -+@@ -101,6 +116,14 @@ static int ebt_ip_mt_check(const struct xt_mtchk_param *par) -+ return -EINVAL; -+ if (info->bitmask & EBT_IP_SPORT && info->sport[0] > info->sport[1]) -+ return -EINVAL; -++ if (info->bitmask & EBT_IP_ICMP) { -++ if ((info->invflags & EBT_IP_PROTO) || -++ info->protocol != IPPROTO_ICMP) -++ return -EINVAL; -++ if (info->icmp_type[0] > info->icmp_type[1] || -++ info->icmp_code[0] > info->icmp_code[1]) -++ return -EINVAL; -++ } -+ return 0; -+ } -+ -+-- -+2.16.2 -+ -diff --git a/target/linux/generic/backport-4.9/096-0002-ebtables-add-support-for-matching-IGMP-type.patch b/target/linux/generic/backport-4.9/096-0002-ebtables-add-support-for-matching-IGMP-type.patch -new file mode 100644 -index 0000000000000000000000000000000000000000..5750b612fc0f322e0a257f3229b5b698328b428b ---- /dev/null -+++ b/target/linux/generic/backport-4.9/096-0002-ebtables-add-support-for-matching-IGMP-type.patch -@@ -0,0 +1,95 @@ -+From: Matthias Schiffer -+Date: Sat, 3 Mar 2018 12:02:21 +0100 -+Subject: [PATCH 2/2] ebtables: add support for matching IGMP type -+ -+We already have ICMPv6 type/code matches (which can be used to distinguish -+different types of MLD packets). Add support for IPv4 IGMP matches in the -+same way. -+ -+Signed-off-by: Matthias Schiffer -+--- -+ include/uapi/linux/netfilter_bridge/ebt_ip.h | 4 +++- -+ net/bridge/netfilter/ebt_ip.c | 19 +++++++++++++++++-- -+ 2 files changed, 20 insertions(+), 3 deletions(-) -+ -+diff --git a/include/uapi/linux/netfilter_bridge/ebt_ip.h b/include/uapi/linux/netfilter_bridge/ebt_ip.h -+index 63a2860ae1e3..ae5d4d108418 100644 -+--- a/include/uapi/linux/netfilter_bridge/ebt_ip.h -++++ b/include/uapi/linux/netfilter_bridge/ebt_ip.h -+@@ -24,8 +24,9 @@ -+ #define EBT_IP_SPORT 0x10 -+ #define EBT_IP_DPORT 0x20 -+ #define EBT_IP_ICMP 0x40 -++#define EBT_IP_IGMP 0x80 -+ #define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\ -+- EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_ICMP) -++ EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_ICMP | EBT_IP_IGMP) -+ #define EBT_IP_MATCH "ip" -+ -+ /* the same values are used for the invflags */ -+@@ -41,6 +42,7 @@ struct ebt_ip_info { -+ union { -+ __u16 sport[2]; -+ __u8 icmp_type[2]; -++ __u8 igmp_type[2]; -+ }; -+ union { -+ __u16 dport[2]; -+diff --git a/net/bridge/netfilter/ebt_ip.c b/net/bridge/netfilter/ebt_ip.c -+index e4fc77072b27..57fbb13cb8e0 100644 -+--- a/net/bridge/netfilter/ebt_ip.c -++++ b/net/bridge/netfilter/ebt_ip.c -+@@ -28,6 +28,9 @@ union pkthdr { -+ u8 type; -+ u8 code; -+ } icmphdr; -++ struct { -++ u8 type; -++ } igmphdr; -+ }; -+ -+ static bool -+@@ -57,12 +60,12 @@ ebt_ip_mt(const struct sk_buff *skb, struct xt_action_param *par) -+ if (NF_INVF(info, EBT_IP_PROTO, info->protocol != ih->protocol)) -+ return false; -+ if (!(info->bitmask & (EBT_IP_DPORT | EBT_IP_SPORT | -+- EBT_IP_ICMP))) -++ EBT_IP_ICMP | EBT_IP_IGMP))) -+ return true; -+ if (ntohs(ih->frag_off) & IP_OFFSET) -+ return false; -+ -+- /* min icmp headersize is 4, so sizeof(_pkthdr) is ok. */ -++ /* min icmp/igmp headersize is 4, so sizeof(_pkthdr) is ok. */ -+ pptr = skb_header_pointer(skb, ih->ihl*4, -+ sizeof(_pkthdr), &_pkthdr); -+ if (pptr == NULL) -+@@ -88,6 +91,11 @@ ebt_ip_mt(const struct sk_buff *skb, struct xt_action_param *par) -+ pptr->icmphdr.code < info->icmp_code[0] || -+ pptr->icmphdr.code > info->icmp_code[1])) -+ return false; -++ if ((info->bitmask & EBT_IP_IGMP) && -++ NF_INVF(info, EBT_IP_IGMP, -++ pptr->igmphdr.type < info->igmp_type[0] || -++ pptr->igmphdr.type > info->igmp_type[1])) -++ return false; -+ } -+ return true; -+ } -+@@ -124,6 +132,13 @@ static int ebt_ip_mt_check(const struct xt_mtchk_param *par) -+ info->icmp_code[0] > info->icmp_code[1]) -+ return -EINVAL; -+ } -++ if (info->bitmask & EBT_IP_IGMP) { -++ if ((info->invflags & EBT_IP_PROTO) || -++ info->protocol != IPPROTO_IGMP) -++ return -EINVAL; -++ if (info->igmp_type[0] > info->igmp_type[1]) -++ return -EINVAL; -++ } -+ return 0; -+ } -+ -+-- -+2.16.2 -+ diff --git a/patches/openwrt/0006-build-set-TARGET_ROOTFS_PARTSIZE-to-make-combined-image-fit-in-128MB.patch b/patches/openwrt/0006-build-set-TARGET_ROOTFS_PARTSIZE-to-make-combined-image-fit-in-128MB.patch new file mode 100644 index 00000000..773b2800 --- /dev/null +++ b/patches/openwrt/0006-build-set-TARGET_ROOTFS_PARTSIZE-to-make-combined-image-fit-in-128MB.patch @@ -0,0 +1,27 @@ +From: Matthias Schiffer +Date: Sat, 21 Sep 2019 13:21:36 +0200 +Subject: build: set TARGET_ROOTFS_PARTSIZE to make combined image fit in 128MB + +Change TARGET_ROOTFS_PARTSIZE from 128 to 104 MiB, so the whole image +(bootloader + boot + root) will fit on a 128MB CF card by default. + +With these settings, the generated images (tested on x86-generic and +x86-64) have 126,353,408 bytes; the smallest CF card marketed as "128MB" +that I found a datasheet for (a Transcend TS128MCF80) has 126,959,616 +bytes. + +Signed-off-by: Matthias Schiffer + +diff --git a/config/Config-images.in b/config/Config-images.in +index 8548c7cd24742daad4fb1c64e58bad82590795c2..dc7a9cbd54ffbe3c78a7fdbd124f389c102ef6c1 100644 +--- a/config/Config-images.in ++++ b/config/Config-images.in +@@ -274,7 +274,7 @@ menu "Target Images" + config TARGET_ROOTFS_PARTSIZE + int "Root filesystem partition size (in MB)" + depends on GRUB_IMAGES || USES_ROOTFS_PART || TARGET_ROOTFS_EXT4FS || TARGET_omap || TARGET_rb532 || TARGET_sunxi || TARGET_uml +- default 256 ++ default 104 + help + Select the root filesystem partition size. + diff --git a/patches/openwrt/0006-ipq-wifi-add-AVM-FRITZ-Repeater-1200-bdf.patch b/patches/openwrt/0006-ipq-wifi-add-AVM-FRITZ-Repeater-1200-bdf.patch deleted file mode 100644 index 6b4e48b6..00000000 --- a/patches/openwrt/0006-ipq-wifi-add-AVM-FRITZ-Repeater-1200-bdf.patch +++ /dev/null @@ -1,87 +0,0 @@ -From: David Bauer -Date: Sat, 21 Sep 2019 18:59:28 +0200 -Subject: ipq-wifi: add AVM FRITZ!Repeater 1200 bdf - -Signed-off-by: David Bauer - -diff --git a/package/firmware/ipq-wifi/Makefile b/package/firmware/ipq-wifi/Makefile -index 922064b7f78b80670cdb1ec7e9f86ede224cb7fb..eb7c2df1aa36ded7774a772c8a7e02b2acb81b40 100644 ---- a/package/firmware/ipq-wifi/Makefile -+++ b/package/firmware/ipq-wifi/Makefile -@@ -27,6 +27,7 @@ ALLWIFIBOARDS:= \ - alfa-network_ap120c-ac \ - asus_map-ac2200 \ - avm_fritzbox-7530 \ -+ avm_fritzrepeater-1200 \ - avm_fritzrepeater-3000 \ - engenius_eap1300 \ - engenius_ens620ext \ -@@ -98,6 +99,7 @@ endef - $(eval $(call generate-ipq-wifi-package,alfa-network_ap120c-ac,ALFA Network AP120C-AC)) - $(eval $(call generate-ipq-wifi-package,asus_map-ac2200,ASUS MAP-AC2200)) - $(eval $(call generate-ipq-wifi-package,avm_fritzbox-7530,AVM FRITZ!Box 7530)) -+$(eval $(call generate-ipq-wifi-package,avm_fritzrepeater-1200,AVM FRITZRepeater 1200)) - $(eval $(call generate-ipq-wifi-package,avm_fritzrepeater-3000,AVM FRITZ!Repeater 3000)) - $(eval $(call generate-ipq-wifi-package,engenius_eap1300,EnGenius EAP1300)) - $(eval $(call generate-ipq-wifi-package,engenius_ens620ext,EnGenius ENS620EXT)) -diff --git a/package/firmware/ipq-wifi/board-avm_fritzrepeater-1200.qca4019 b/package/firmware/ipq-wifi/board-avm_fritzrepeater-1200.qca4019 -new file mode 100644 -index 0000000000000000000000000000000000000000..d78a49d4dbf3fc22c40a83d052fc7c55542ff8e3 -GIT binary patch -literal 24332 -zcmeHPTTl~O8a_d8Dk`0XTL?`^xFjwK5Lk^61wv#JXn|o7A-XOgCAEojsjSAdzHD5LPbzhtuaj -zf1m&S|M|L;bocql=Nak3^a4dfe6~=Qo1QNRH8nK=N_`x$1wal<*^#>KrIlr|Wi@Ky -zfl9Sjs4m|gZ*G;rhrZ_&fp;V_X{i1$*df_f%X1=mOm0zK)D6Oy12@}Ne@iaIN -z2ad^!oA9U6z?$Rqq(Wl+&4a)LlmM{K$De2dxaB6o+84eYi9nD@3AEI@MvulP*S_ -z?YC}bNDd%hGX{&oq}y5?$9?ExTw)|*X10X^+eBeo3as3c_3Jlobj!g(XRZU=r!Z+d -z#);F$BK8@)8kuNs*Qk}M)K?SzZO!GXY~{8`qy4Abb?VQRTON%;txlb<{OwyPx9y -z+I&DIhuyCCw?o%#3IEYV|Al6)Dqj+Bafq?c?*px7C?DuzzngNf$HQ@JC7|SZX3NX^ -zWU%VXEKU5Lz|`?8b!}VAqjs~hAC4aG%{o;sd7y&^cp<&_HPyE@M_>7$utCw93 -zFNgr3(L6jnXvB8S8ZR#|Z;SYhbT*YJo}I|!Gb1B;@GpuR5y9g|aJhw^zQA&YVmBJq -zSX2Z$I~y7b3b0HGSij!en+zopMDe)XaM)n_{O9evcL7i%ZG17RnN_Fn`n^2}Wh8OeA|Q -zL$c5;Q5KelrXdPcjEY6#=VBxoO%^3%@n}3EL1&UM4mnn5a*|4CvZB;E$Hx^&7%1a4 -z0|`Y#MWI**n(;aV$wsq9*;pc)_&O0uK~qF27SI>>H)+!4YV-+7lYU(Qm0asTD -zT!#dFE2G -zML^+%L;QlE0&60_rDR*`r|U%@1f(SaV4x$kKq#G-`l6-g`yxOJq@HO20e^oiXaOJr -z@DRwOg2WpxX_)L$WK|wl{<2+j$EC? -z@(POfm6TT+IxqHI9vmJSzcqR9;a`6E@rC<4Y}WDIyK-GNy@7ch6r;CUS3=EepqQ-9 -zx(aGu|HQ;?))i3qL3HY|^3h#3r@_if)Ri^koWlJFJG!r2$L~)4&6&QkP??<#^Bogm -zqihiyV*>d*If9{>2*czc>0J^cMWrGsmb75^*RxUG(E`PR2ujZsXCgWDE#fW64!Ww3 -zc+DNd`aNf@m&+}VyWIN(m$~;?H;o2~_f4Hrow9cAVsh`(n1jrh4*$==4i=}4v9U3y`{wR|$J$2b?swI)DwlMr -zNxO1-EJ2i9Nt^0JAwVHOA+TH#C@E1DlH7Yb-G2i)3pcs&kN!Th=|Po6{vHxaeErjcm)iC-je` -z-bZ0Y!~^e#FKliv?9>l^cub!$RpXd3!N8twGgaZ)MzJAm>aMX{f4DeP5;b)jA2#SU -z#S%90|6-SWV)$UX%hZgkjA;hp^d*xX-)oc^;_yl1phi=iBZ-~*v+;tyrdTH75Dv!P -zm>4kKXF7==GUge!PY;;R;MK<6dLjO;pJ>Zr!R826n!RL7#y%n?qp2OQ(#wk@r-w}Eah+keW(WSAp;yzO -zQ1C;i?inwcQwk?iy3)so5qeBt;Rp0P6fEf4hO6~5MJWC!4i9T5oGTm!x#mn_lMF>o!SAV29TOu&s#rq68O|Bx6j39t1oi{b% -zMS8Ju;WY@=^|cV?^LFssZj^ZVh7bKCX2LqWxV -z?P^k`3Znypz3yB(R+S|a$At!;A1v%hILgs%%6WRT`a)VuR87eKXMO6ttufI-06ZEv -zTCK)7*Ul7_pNo_2e*?sCpKeq(UOsy%V2iBkxy00chvmpFWE#Q`3JZCZt-NhKBYqoN|= -zAN&;#4lg2t8&T-BWPXWbE-&6nz4u+Pb^Ez7tknCp3l_rx{FI48V15X=O8i*pe)G$A -z#duNNd&rAlMBe^V;@LaOWvQRYBal;1a^Mj&kDlPzuWJ>w$RSsL^EPfeS;7x*-exXW -z{XG-RTzY~}@6)ml7NYjzn7Q`^-`-2`PcsLfhoXC`4QZBPsoig>KXZAF}U%I -zjjc1zz199HdG|zYihDo1G&c{8;@-~#G|FXZBjC!Ku`|BCt$k_Fa{k#--227;*8KJH -F{|7QKi|GIW - -literal 0 -HcmV?d00001 - diff --git a/patches/openwrt/0007-ipq-wifi-add-BDF-for-Aruba-AP-303.patch b/patches/openwrt/0007-ipq-wifi-add-BDF-for-Aruba-AP-303.patch new file mode 100644 index 00000000..bfc386a2 --- /dev/null +++ b/patches/openwrt/0007-ipq-wifi-add-BDF-for-Aruba-AP-303.patch @@ -0,0 +1,92 @@ +From: David Bauer +Date: Sun, 15 Dec 2019 23:02:54 +0100 +Subject: ipq-wifi: add BDF for Aruba AP-303 + +The BDF originates from the vendor-firmware. + +Signed-off-by: David Bauer +(cherry picked from commit 4113d8a2554adf5ecee55cc07956eafad378eaff) + +diff --git a/package/firmware/ipq-wifi/Makefile b/package/firmware/ipq-wifi/Makefile +index eb7c2df1aa36ded7774a772c8a7e02b2acb81b40..cc0505b97c6a04bafd88972cf6ce7890a637c33b 100644 +--- a/package/firmware/ipq-wifi/Makefile ++++ b/package/firmware/ipq-wifi/Makefile +@@ -25,6 +25,7 @@ endef + + ALLWIFIBOARDS:= \ + alfa-network_ap120c-ac \ ++ aruba_ap-303 \ + asus_map-ac2200 \ + avm_fritzbox-7530 \ + avm_fritzrepeater-1200 \ +@@ -97,6 +98,7 @@ endef + # Add $(eval $(call generate-ipq-wifi-package,,)) + + $(eval $(call generate-ipq-wifi-package,alfa-network_ap120c-ac,ALFA Network AP120C-AC)) ++$(eval $(call generate-ipq-wifi-package,aruba_ap-303,Aruba AP-303)) + $(eval $(call generate-ipq-wifi-package,asus_map-ac2200,ASUS MAP-AC2200)) + $(eval $(call generate-ipq-wifi-package,avm_fritzbox-7530,AVM FRITZ!Box 7530)) + $(eval $(call generate-ipq-wifi-package,avm_fritzrepeater-1200,AVM FRITZRepeater 1200)) +diff --git a/package/firmware/ipq-wifi/board-aruba_ap-303.qca4019 b/package/firmware/ipq-wifi/board-aruba_ap-303.qca4019 +new file mode 100644 +index 0000000000000000000000000000000000000000..4848115cfbe3a4a0ed6b17cac929731ecbd7968c +GIT binary patch +literal 24316 +zcmeHPdr(tX8b1l)p-UHTNDu)pAp}Se0tBi-!W$`%6c7~&un1I6BFeZwJ$y}AjvN}B`Pfz$mMbX<(NN~1F#FGd_`$kUSYm( +zzFg|}UZJ$ePkJaU0I%hr$SXO7RRsaQWqBpiyyGXsqDmC`d45r;enA02aybRIXTiQ$ +z{(Fv6D8Qnc9-NN#>(d1&AQynm*7jHxFaWR*!ZjM6>t{S38|w;yprD{vFJ4eY3@h-< +z-!4WF$pUt;M0u#+u2DM@cmo9V_`vZ+ET^9yjw-&*$wzjskw6xF>07kKy8YxWZr<)vMT{juo&5WBJl$pvJ +zSBe@2uw^qXb0;%4&|Y78I5R0hICi_exl*3FFCluYul;;oiF8lGjWOy2|{_1bA?;y|Gf7nVJwj){D78n-DgruPe_KCxqe+o_PC!v0LpI;0W&~ +zgp7R#8_4hmJ+PC)%p@TfcGpx{l$j&E$%$G#3{F}KdUX|Jgd|puct0g5t8qXU6jp>E=A|Pc_n}{`jGyHYexpa) +z8eg})+@@SU~bv!vW@t_*D0~j*k2Ra54<44 +zGAfly!Ey@=__b^`E!H<{G6I~Qyq_vSIUEo8>&bR^_h7rT+37SJ;+lkrg)CPdfsBl_ +zWH#Fk4)pWSFMfRe8oL4#@;p7Xw*UV4*B^9knBz8EYbuTQKj>!%PuOhxmoH!ZTkE^h +zQ5Oxs>k&9eQFX%rmay^oy5hs-a5%Vu>&0fVaLp_>UjzM_W;28hf+9#18ifR+fk=_! +zRP~t;8=70^D?l_Y4@^?%D4kD#N=KYgXTG!89<@iD&}cN8AN@2MNkkL*iQ-5!5{X9z +zsDLkcDnNFjyZF1r0cZdsL}!9fUpK7I#3T~UL`ACe&W|yWIG_$w4u}it!gmqJpfOW1 +zND`XFPZ9^AK~q6UC>qKS6>Cp|ZjKM7g?`0zZ0#0(s21q!}Wsktx^q!Hyz)q)K=GO +zoF7djK!C#!ycz%kffr-~xxvJNR46t~SlLJq1Z=jeD_c)mpnblT&CYJ-0FjUaUY!7- +z#TubR1_QvgL4XK|Xt`DhpfahOvtem(k8e884~Vp^8wB1A+A^rrLvRNI?k-blHXlQ| +z28Ed52$bd6#2N6zwQKmBg-UNPPtI?dv^#g&y*lmgoH%t~Mt1I@LRDi+Ye!f2&4Iz; +zkI`9mEA&tbcUZ +z%raPCff}=CoSdFh&~W)`kLJ$!*9+*BuD^e+C^f1J|FyU;r!;;^^oI +zutbQ7^|zo9O_y4-fz<*{BN<(cKQSIMS&pfWHI9R`Q7+)GZ~m87zSOtRt#@=xPIh$J +z+RmlJ%=Iy)wjsB2$w?ctL{=e6#)NGiAEXw5z3>BC;Y0;D{!GEsIar?io&qX3RM0m- +z1^qu!!LtzyFeRb^yHOg52(ttT)56l)JRy+1kO+_nY&ZmFIrD}%_y76l-@pIvyT3qG +z!a_rK!Uv_0b8llsqdtHB4`|cp+)q8%a_-ajrKM^)`>$U7G-ZAsz9G)NzdxUkC2X$& +zduqM~`z#Q)p7ZVawgPK2|7z4Vsn5hz4U5-aIh*Kyy`9 +z2K#+`d{Fa=s!Ar2h&1D>cG=1J-CQSpgrl-7ZAjx2Fr>-5ns)VRm0Y%a{Fdgrx(+r@ +z*4$UM$;#s6xh~@)>W}b{+^~=yKH~BKoNA}$qFSNKg(0ccXH~^YiRPBNQznm(68cZx +z*IZXs$_@yfwGDV)*c_VFr&I;XWO(qZszR13@rQx5DHW0=A#d`I=8CFBmJ-jw8hkOq +zgDBk|Z&R15a+I-?Bk*9UGFz4i!@LHuj1;2qXotF778Ab}Z}1q-!4z4Am-=K##+*PB +zB@(3t5LgdOV}YrW<_(KL>(KEV5iNeTE@js=e`t@r=v}q-_{qz0XL!ZV`L=NnyANLo +zQ+gcPBDpqn@zBNZRxW7|) +z$*qbmtL@F{5S&95^!$;V#g`*L;FZw#KkAbCs3#V=uB4NN#U`sakZFU2HEI?ks7Dsq&ROrak#AvEH|GYk~cN +z-oYbXaZQ|4jDps_<5wfH44oN*XPh1H-<59xMxzd~07FF+FO3!KO +zkzNs<^C)%5zR+;s{a_h8iyk@DSK5($fm`l$c*8Cna^fTc>i~h}zJUY22WwUg;4xU6 +zE40Voz~Sl1fxqzW8!QiZceZ;vST%3pn9qkNDEBsI+pnKL20^*sWVSI3z)zY;1PmfD +zk8=M~&&^oEhq?Xq!q{llMLGBQ>t)~ra4xR!eZAQ1X^ph;*FG+*f4xJlJ!C>*eEV+r +z#z~GXOppZ=2|4(iyLmNON}QN2ao#+YHqDy{lvv2w_X*(?ul{+G5$Yp=apGx^6Q9v~ +z^YKb>;`PTfcYPtQJz@VX`S#e@Bso3?a_*Ok9NBKwB4Es(@j^U%UHht?;4%Xv +NIrrxNmNc!u{{!hMI2Hf^ + +literal 0 +HcmV?d00001 + diff --git a/patches/openwrt/0007-ipq40xx-add-support-for-AVM-FRITZ-Repeater-1200.patch b/patches/openwrt/0007-ipq40xx-add-support-for-AVM-FRITZ-Repeater-1200.patch deleted file mode 100644 index c080a09a..00000000 --- a/patches/openwrt/0007-ipq40xx-add-support-for-AVM-FRITZ-Repeater-1200.patch +++ /dev/null @@ -1,374 +0,0 @@ -From: David Bauer -Date: Tue, 10 Sep 2019 21:07:23 +0200 -Subject: ipq40xx: add support for AVM FRITZ!Repeater 1200 - -Signed-off-by: David Bauer - -diff --git a/target/linux/ipq40xx/base-files/etc/board.d/02_network b/target/linux/ipq40xx/base-files/etc/board.d/02_network -index 6a7b09cc603a245e98c37305c1f25c2cc11694ae..01825b8bac46eec6325de00396d96307c946f975 100755 ---- a/target/linux/ipq40xx/base-files/etc/board.d/02_network -+++ b/target/linux/ipq40xx/base-files/etc/board.d/02_network -@@ -39,10 +39,7 @@ ipq40xx_setup_interfaces() - ucidef_add_switch "switch0" \ - "0u@eth0" "1:lan" "2:lan" "3:lan" "4:lan" - ;; -- avm,fritzrepeater-3000|\ -- compex,wpj428) -- ucidef_set_interface_lan "eth0 eth1" -- ;; -+ avm,fritzrepeater-1200|\ - engenius,eap1300|\ - meraki,mr33|\ - netgear,ex6100v2|\ -@@ -50,6 +47,10 @@ ipq40xx_setup_interfaces() - zyxel,wre6606) - ucidef_set_interface_lan "eth0" - ;; -+ avm,fritzrepeater-3000|\ -+ compex,wpj428) -+ ucidef_set_interface_lan "eth0 eth1" -+ ;; - glinet,gl-b1300) - ucidef_set_interfaces_lan_wan "eth0" "eth1" - ucidef_add_switch "switch0" \ -diff --git a/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata b/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata -index 5f7e5f4923f19ecd78a981be55230cfcd3779146..b0035ce8a394b6e87d7d89b9f55a6ec7c66e448e 100644 ---- a/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata -+++ b/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata -@@ -148,6 +148,7 @@ case "$FIRMWARE" in - /usr/bin/fritz_cal_extract -i 1 -s 0x400 -e 0x207 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader_config") - ;; - avm,fritzbox-7530 |\ -+ avm,fritzrepeater-1200 |\ - avm,fritzrepeater-3000) - /usr/bin/fritz_cal_extract -i 1 -s 0x3C000 -e 0x207 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader0") || \ - /usr/bin/fritz_cal_extract -i 1 -s 0x3C800 -e 0x207 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader0") || \ -@@ -209,6 +210,7 @@ case "$FIRMWARE" in - /usr/bin/fritz_cal_extract -i 1 -s 0x400 -e 0x208 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader_config") - ;; - avm,fritzbox-7530 |\ -+ avm,fritzrepeater-1200 |\ - avm,fritzrepeater-3000) - /usr/bin/fritz_cal_extract -i 1 -s 0x3C800 -e 0x208 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader0") || \ - /usr/bin/fritz_cal_extract -i 1 -s 0x3D000 -e 0x208 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader0") || \ -diff --git a/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh b/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh -index 2abafabbd0589c07bcd2ceee766d3d7675ba9716..a7b7da1bf378f7cc19e960c497bc52efb3bae4fb 100644 ---- a/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh -+++ b/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh -@@ -49,6 +49,7 @@ platform_do_upgrade() { - 8dev,jalapeno |\ - alfa-network,ap120c-ac |\ - avm,fritzbox-7530 |\ -+ avm,fritzrepeater-1200 |\ - avm,fritzrepeater-3000 |\ - qxwlan,e2600ac-c2) - nand_do_upgrade "$1" -diff --git a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4019-fritzrepeater-1200.dts b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4019-fritzrepeater-1200.dts -new file mode 100644 -index 0000000000000000000000000000000000000000..4d02f8a8384f386c92c70ef24b677ee95058a1bf ---- /dev/null -+++ b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4019-fritzrepeater-1200.dts -@@ -0,0 +1,262 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT -+ -+#include "qcom-ipq4019.dtsi" -+#include -+#include -+#include -+ -+/ { -+ model = "AVM FRITZ!Repeater 1200"; -+ compatible = "avm,fritzrepeater-1200"; -+ -+ aliases { -+ led-boot = &power_green; -+ led-failsafe = &power_red; -+ led-running = &power_green; -+ led-upgrade = &power_red; -+ }; -+ -+ soc { -+ mdio@90000 { -+ status = "okay"; -+ pinctrl-0 = <&mdio_pins>; -+ pinctrl-names = "default"; -+ }; -+ -+ tcsr@1949000 { -+ compatible = "qcom,tcsr"; -+ reg = <0x1949000 0x100>; -+ qcom,wifi_glb_cfg = ; -+ }; -+ -+ ess_tcsr@1953000 { -+ compatible = "qcom,tcsr"; -+ reg = <0x1953000 0x1000>; -+ qcom,ess-interface-select = ; -+ }; -+ -+ tcsr@1957000 { -+ compatible = "qcom,tcsr"; -+ reg = <0x1957000 0x100>; -+ qcom,wifi_noc_memtype_m0_m2 = ; -+ }; -+ -+ crypto@8e3a000 { -+ status = "okay"; -+ }; -+ -+ watchdog@b017000 { -+ status = "okay"; -+ }; -+ -+ ess-switch@c000000 { -+ switch_mac_mode = <0x3>; /* mac mode for RGMII RMII */ -+ switch_lan_bmp = <0x0>; /* lan port bitmap */ -+ switch_wan_bmp = <0x10>; /* wan port bitmap */ -+ }; -+ -+ edma@c080000 { -+ status = "okay"; -+ phy-mode = "rgmii-rxid"; -+ qcom,num_gmac = <1>; -+ qcom,single-phy; -+ }; -+ }; -+ -+ key { -+ compatible = "gpio-keys"; -+ -+ wps { -+ label = "WPS button"; -+ gpios = <&tlmm 10 GPIO_ACTIVE_LOW>; -+ linux,code = ; -+ }; -+ }; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ power_red: power_red { -+ label = "fritzwlan-1200:red:power"; -+ gpios = <&tlmm 50 GPIO_ACTIVE_LOW>; -+ }; -+ -+ power_green: power_green { -+ label = "fritzwlan-1200:green:power"; -+ gpios = <&tlmm 45 GPIO_ACTIVE_HIGH>; -+ }; -+ -+ power_yellow { -+ label = "fritzwlan-1200:yellow:power"; -+ gpios = <&tlmm 49 GPIO_ACTIVE_LOW>; -+ }; -+ }; -+}; -+ -+&tlmm { -+ serial_0_pins: serial_pinmux { -+ mux { -+ pins = "gpio16", "gpio17"; -+ function = "blsp_uart0"; -+ bias-disable; -+ }; -+ }; -+ -+ nand_pins: nand_pins { -+ pullups { -+ pins = "gpio53", "gpio58", "gpio59"; -+ function = "qpic"; -+ bias-pull-up; -+ }; -+ -+ pulldowns { -+ pins = "gpio54", "gpio55", "gpio56", -+ "gpio57", "gpio60", "gpio61", -+ "gpio62", "gpio63", "gpio64", -+ "gpio65", "gpio66", "gpio67", -+ "gpio68", "gpio69"; -+ function = "qpic"; -+ bias-pull-down; -+ }; -+ }; -+ -+ mdio_pins: mdio_pinmux { -+ mux_1 { -+ pins = "gpio6"; -+ function = "mdio"; -+ bias-pull-up; -+ }; -+ mux_2 { -+ pins = "gpio7"; -+ function = "mdc"; -+ bias-pull-up; -+ }; -+ }; -+ -+ phy-reset { -+ line-name = "PHY-reset"; -+ gpios = <19 GPIO_ACTIVE_HIGH>; -+ gpio-hog; -+ output-high; -+ }; -+ -+ phy-reset-2 { -+ line-name = "PHY-reset-2"; -+ gpios = <47 GPIO_ACTIVE_HIGH>; -+ gpio-hog; -+ output-high; -+ }; -+}; -+ -+&nand { -+ pinctrl-0 = <&nand_pins>; -+ pinctrl-names = "default"; -+ status = "okay"; -+ -+ nand@0 { -+ partitions { -+ compatible = "fixed-partitions"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ partition@0 { -+ label = "SBL1"; -+ reg = <0x000000 0x80000>; -+ read-only; -+ }; -+ -+ partition@80000 { -+ label = "MIBIB"; -+ reg = <0x080000 0x80000>; -+ read-only; -+ }; -+ -+ partition@100000 { -+ label = "QSEE"; -+ reg = <0x100000 0x80000>; -+ read-only; -+ }; -+ -+ partition@180000 { -+ label = "CDT"; -+ reg = <0x180000 0x40000>; -+ read-only; -+ }; -+ -+ partition@1c0000 { -+ label = "QSEE_B"; -+ reg = <0x1c0000 0x80000>; -+ read-only; -+ }; -+ -+ partition@240000 { -+ label = "urlader0"; -+ reg = <0x240000 0x40000>; -+ read-only; -+ }; -+ -+ partition@280000 { -+ label = "urlader1"; -+ reg = <0x280000 0x40000>; -+ read-only; -+ }; -+ -+ partition@2c0000 { -+ label = "nand-tffs"; -+ reg = <0x2c0000 0x840000>; -+ read-only; -+ }; -+ -+ partition@b00000 { -+ /* 'kernel1' in AVM firmware */ -+ label = "uboot0"; -+ reg = <0xb00000 0x400000>; -+ }; -+ -+ partition@f00000 { -+ /* 'kernel2' in AVM firmware */ -+ label = "uboot1"; -+ reg = <0xf00000 0x400000>; -+ }; -+ -+ partition@1300000 { -+ label = "ubi"; -+ reg = <0x1300000 0x6d00000>; -+ }; -+ }; -+ }; -+}; -+ -+&cryptobam { -+ status = "okay"; -+}; -+ -+&blsp_dma { -+ status = "okay"; -+}; -+ -+&blsp1_uart1 { -+ pinctrl-0 = <&serial_0_pins>; -+ pinctrl-names = "default"; -+ status = "okay"; -+}; -+ -+&qpic_bam { -+ status = "okay"; -+}; -+ -+&wifi0 { -+ status = "okay"; -+ qcom,ath10k-calibration-variant = "AVM-FRITZRepeater-1200"; -+}; -+ -+&wifi1 { -+ status = "okay"; -+ qcom,ath10k-calibration-variant = "AVM-FRITZRepeater-1200"; -+}; -+ -+&gmac0 { -+ qcom,phy_mdio_addr = <0>; -+ qcom,poll_required = <1>; -+ vlan_tag = <0 0x20>; -+}; -diff --git a/target/linux/ipq40xx/image/Makefile b/target/linux/ipq40xx/image/Makefile -index 3a9b58de4f01f17ac9df368729035d630eb32b04..bdbbcbe851e60ee5a445c576a870a87a46c57fee 100644 ---- a/target/linux/ipq40xx/image/Makefile -+++ b/target/linux/ipq40xx/image/Makefile -@@ -138,6 +138,15 @@ define Device/avm_fritzbox-7530 - endef - TARGET_DEVICES += avm_fritzbox-7530 - -+define Device/avm_fritzrepeater-1200 -+ $(call Device/FitImageLzma) -+ DEVICE_DTS := qcom-ipq4019-fritzrepeater-1200 -+ DEVICE_TITLE := AVM Fritz!Repeater 1200 -+ DEVICE_PACKAGES := fritz-caldata fritz-tffs-nand ipq-wifi-avm_fritzrepeater-1200 -+ IMAGES := sysupgrade.bin -+endef -+TARGET_DEVICES += avm_fritzrepeater-1200 -+ - define Device/avm_fritzrepeater-3000 - $(call Device/FitImageLzma) - DEVICE_DTS := qcom-ipq4019-fritzrepeater-3000 -diff --git a/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch b/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch -index bb539155e98b75df5dd88e39f6405af5a82e0320..f7efd415f1f1c000867793b3b133e44b3e50b0fd 100644 ---- a/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch -+++ b/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch -@@ -10,7 +10,7 @@ Signed-off-by: John Crispin - - --- a/arch/arm/boot/dts/Makefile - +++ b/arch/arm/boot/dts/Makefile --@@ -697,7 +697,30 @@ dtb-$(CONFIG_ARCH_QCOM) += \ -+@@ -697,7 +697,31 @@ dtb-$(CONFIG_ARCH_QCOM) += \ - qcom-apq8074-dragonboard.dtb \ - qcom-apq8084-ifc6540.dtb \ - qcom-apq8084-mtp.dtb \ -@@ -30,6 +30,7 @@ Signed-off-by: John Crispin - + qcom-ipq4019-a62.dtb \ - + qcom-ipq4019-ap.dk04.1-c1.dtb \ - + qcom-ipq4019-fritzbox-7530.dtb \ -++ qcom-ipq4019-fritzrepeater-1200.dtb \ - + qcom-ipq4019-fritzrepeater-3000.dtb \ - + qcom-ipq4019-linksys_ea8300.dtb \ - + qcom-ipq4019-map-ac2200.dtb \ diff --git a/patches/openwrt/0008-ipq40xx-add-support-for-Aruba-AP-303.patch b/patches/openwrt/0008-ipq40xx-add-support-for-Aruba-AP-303.patch new file mode 100644 index 00000000..8b5fc9dd --- /dev/null +++ b/patches/openwrt/0008-ipq40xx-add-support-for-Aruba-AP-303.patch @@ -0,0 +1,646 @@ +From: David Bauer +Date: Wed, 23 Oct 2019 22:25:14 +0200 +Subject: ipq40xx: add support for Aruba AP-303 + +Hardware +-------- + +SoC: Qualcomm IPQ4029 +RAM: 512M DDR3 +FLASH: - 128MB NAND (Macronix MX30LF1G18AC) + - 4MB SPI-NOR (Macronix MX25R3235F) +TPM: Atmel AT97SC3203 +BLE: Texas Instruments CC2540T + attached to ttyMSM0 +ETH: Atheros AR8035 +LED: WiFi (amber / green) + System (red / green) +BTN: Reset + +To connect to the serial console, you can solder to the labled pads next +to the USB port or use your Aruba supplied UARt adapter. + +Do NOT plug a standard USB cable into the Console labled USB-port! +Aruba/HPE simply put UART on the micro-USB pins. You can solder yourself +an adapter cable: + +VCC - NC + D+ - TX + D- - RX +GND - GND + +The console setting in bootloader and OS is 9600 8N1. Voltage level is +3.3V. + +To enable a full list of commands in the U-Boot "help" command, execute +the literal "diag" command. + +Installation +------------ + +1. Get the OpenWrt initramfs image. Rename it to ipq40xx.ari and put it + into the TFTP server root directory. Configure the TFTP server to + be reachable at 192.168.1.75/24. Connect the machine running the TFTP + server to the ethernet port of the access point. + +2. Connect to the serial console. Interrupt autobooting by pressing + Enter when prompted. + +3. Configure the bootargs and bootcmd for OpenWrt. + $ setenv bootargs_openwrt "setenv bootargs console=ttyMSM1,9600n8" + $ setenv nandboot_openwrt "run bootargs_openwrt; ubi part aos1; + ubi read 0x85000000 kernel; bootm 0x85000000" + $ setenv ramboot_openwrt "run bootargs_openwrt; + setenv ipaddr 192.168.1.105; setenv serverip 192.168.1.75; + netget; set fdt_high 0x87000000; bootm" + $ setenv bootcmd "run nandboot_openwrt" + $ saveenv + +4. Load OpenWrt into RAM: + $ run ramboot_openwrt + +5. After OpenWrt booted, transfer the OpenWrt sysupgrade image to the + /tmp folder on the device. + +6. Flash OpenWrt: + $ ubidetach -p /dev/mtd1 + $ ubiformat /dev/mtd1 + $ sysupgrade -n /tmp/openwrt-sysupgrade.bin + +To go back to the stock firmware, simply reset the bootcmd in the +bootloader to the original value: + + $ setenv bootcmd "boot" + $ saveenv + +Signed-off-by: David Bauer +(cherry picked from commit 102c8c55f217606cdbdc9a449667e034676b3e75) + +diff --git a/target/linux/ipq40xx/base-files/etc/board.d/02_network b/target/linux/ipq40xx/base-files/etc/board.d/02_network +index 01825b8bac46eec6325de00396d96307c946f975..49dd570242533068adf2c9df89e78560ba5f70eb 100755 +--- a/target/linux/ipq40xx/base-files/etc/board.d/02_network ++++ b/target/linux/ipq40xx/base-files/etc/board.d/02_network +@@ -39,6 +39,7 @@ ipq40xx_setup_interfaces() + ucidef_add_switch "switch0" \ + "0u@eth0" "1:lan" "2:lan" "3:lan" "4:lan" + ;; ++ aruba,ap-303|\ + avm,fritzrepeater-1200|\ + engenius,eap1300|\ + meraki,mr33|\ +diff --git a/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata b/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata +index b0035ce8a394b6e87d7d89b9f55a6ec7c66e448e..15a2f2c09f8a92cc0accfbf9a977dbeb3355570d 100644 +--- a/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata ++++ b/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata +@@ -137,6 +137,10 @@ case "$FIRMWARE" in + qcom,ap-dk01.1-c1) + ath10kcal_extract "ART" 4096 12064 + ;; ++ aruba,ap-303) ++ ath10kcal_extract "ART" 4096 12064 ++ ath10kcal_patch_mac_crc $(mtd_get_mac_binary mfginfo 29) ++ ;; + asus,map-ac2200) + ath10kcal_ubi_extract "Factory" 4096 12064 + ;; +@@ -199,6 +203,10 @@ case "$FIRMWARE" in + qcom,ap-dk01.1-c1) + ath10kcal_extract "ART" 20480 12064 + ;; ++ aruba,ap-303) ++ ath10kcal_extract "ART" 20480 12064 ++ ath10kcal_patch_mac_crc $(macaddr_add $(mtd_get_mac_binary mfginfo 29) +1) ++ ;; + asus,map-ac2200) + ath10kcal_ubi_extract "Factory" 20480 12064 + ;; +diff --git a/target/linux/ipq40xx/base-files/etc/inittab b/target/linux/ipq40xx/base-files/etc/inittab +index 809bba5e5ff49869429c91cf791cea73ab67d14e..3181021a0592720657b815c3eac803a57f4ea438 100644 +--- a/target/linux/ipq40xx/base-files/etc/inittab ++++ b/target/linux/ipq40xx/base-files/etc/inittab +@@ -2,3 +2,4 @@ + ::sysinit:/etc/init.d/rcS S boot + ::shutdown:/etc/init.d/rcS K shutdown + ttyMSM0::askfirst:/usr/libexec/login.sh ++ttyMSM1::askfirst:/usr/libexec/login.sh +diff --git a/target/linux/ipq40xx/base-files/lib/preinit/06_set_preinit_iface_ipq40xx.sh b/target/linux/ipq40xx/base-files/lib/preinit/06_set_preinit_iface_ipq40xx.sh +index be4b6322cb6a91f489dfec237ac6b79ce079e0eb..a0dec1042a3dd7416ece3307666c8ecf9d15d277 100644 +--- a/target/linux/ipq40xx/base-files/lib/preinit/06_set_preinit_iface_ipq40xx.sh ++++ b/target/linux/ipq40xx/base-files/lib/preinit/06_set_preinit_iface_ipq40xx.sh +@@ -4,6 +4,7 @@ set_preinit_iface() { + . /lib/functions.sh + + case $(board_name) in ++ aruba,ap-303| \ + asus,rt-ac58u| \ + avm,fritzbox-4040| \ + glinet,gl-b1300| \ +diff --git a/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh b/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh +index a7b7da1bf378f7cc19e960c497bc52efb3bae4fb..7253139497a8a8b9fab49cef3fce5eabe98d8002 100644 +--- a/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh ++++ b/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh +@@ -48,6 +48,7 @@ platform_do_upgrade() { + case "$(board_name)" in + 8dev,jalapeno |\ + alfa-network,ap120c-ac |\ ++ aruba,ap-303 |\ + avm,fritzbox-7530 |\ + avm,fritzrepeater-1200 |\ + avm,fritzrepeater-3000 |\ +diff --git a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4029-ap-303.dts b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4029-ap-303.dts +new file mode 100644 +index 0000000000000000000000000000000000000000..7929494d027aca5c696910232a36d484f5ce6562 +--- /dev/null ++++ b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4029-ap-303.dts +@@ -0,0 +1,418 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++ ++#include "qcom-ipq4019.dtsi" ++#include ++#include ++#include ++ ++/ { ++ model = "Aruba AP-303"; ++ compatible = "aruba,ap-303"; ++ ++ aliases { ++ led-boot = &led_system_green; ++ led-failsafe = &led_system_red; ++ led-running = &led_system_green; ++ led-upgrade = &led_system_red; ++ }; ++ ++ memory { ++ device_type = "memory"; ++ reg = <0x80000000 0x10000000>; ++ }; ++ ++ soc { ++ mdio@90000 { ++ status = "okay"; ++ pinctrl-0 = <&mdio_pins>; ++ pinctrl-names = "default"; ++ ++ /delete-node/ ethernet-phy@0; ++ /delete-node/ ethernet-phy@2; ++ /delete-node/ ethernet-phy@3; ++ /delete-node/ ethernet-phy@4; ++ ++ ethernet-phy@5 { ++ reg = <0x5>; ++ }; ++ }; ++ ++ counter@4a1000 { ++ compatible = "qcom,qca-gcnt"; ++ reg = <0x4a1000 0x4>; ++ }; ++ ++ ess_tcsr@1953000 { ++ compatible = "qcom,tcsr"; ++ reg = <0x1953000 0x1000>; ++ qcom,ess-interface-select = ; ++ }; ++ ++ tcsr@1949000 { ++ compatible = "qcom,tcsr"; ++ reg = <0x1949000 0x100>; ++ qcom,wifi_glb_cfg = ; ++ }; ++ ++ tcsr@1957000 { ++ compatible = "qcom,tcsr"; ++ reg = <0x1957000 0x100>; ++ qcom,wifi_noc_memtype_m0_m2 = ; ++ }; ++ ++ blsp1_uart2: serial@78b0000 { ++ }; ++ ++ crypto@8e3a000 { ++ status = "okay"; ++ }; ++ ++ watchdog@b017000 { ++ status = "okay"; ++ }; ++ ++ ess-switch@c000000 { ++ switch_mac_mode = <0x3>; /* mac mode for RGMII RMII */ ++ switch_lan_bmp = <0x0>; /* lan port bitmap */ ++ switch_wan_bmp = <0x10>; /* wan port bitmap */ ++ }; ++ ++ edma@c080000 { ++ qcom,single-phy; ++ qcom,num_gmac = <1>; ++ phy-mode = "rgmii-id"; ++ status = "okay"; ++ }; ++ ++ i2c_0: i2c@78b7000 { ++ pinctrl-0 = <&i2c_0_pins>; ++ pinctrl-names = "default"; ++ status = "ok"; ++ ++ tpm@29 { ++ /* No Driver */ ++ compatible = "atmel,at97sc3203"; ++ reg = <0x29>; ++ read-only; ++ }; ++ }; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ wifi_green { ++ label = "ap-303:green:wifi"; ++ gpios = <&tlmm 39 GPIO_ACTIVE_HIGH>; ++ linux,default-trigger = "phy0tpt"; ++ }; ++ ++ wifi_amber { ++ label = "ap-303:amber:wifi"; ++ gpios = <&tlmm 40 GPIO_ACTIVE_HIGH>; ++ linux,default-trigger = "phy1tpt"; ++ }; ++ ++ led_system_red: system_red { ++ label = "ap-303:red:system"; ++ gpios = <&tlmm 46 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ led_system_green: system_green { ++ label = "ap-303:green:system"; ++ gpios = <&tlmm 47 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ ++ keys { ++ compatible = "gpio-keys"; ++ ++ reset { ++ label = "Reset button"; ++ gpios = <&tlmm 50 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ }; ++}; ++ ++&blsp_dma { ++ status = "okay"; ++}; ++ ++&blsp1_uart1 { ++ /* Texas Instruments CC2540T BLE radio */ ++ pinctrl-0 = <&serial_0_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&blsp1_uart2 { ++ pinctrl-0 = <&serial_1_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&cryptobam { ++ status = "okay"; ++}; ++ ++&gmac0 { ++ qcom,phy_mdio_addr = <5>; ++ qcom,poll_required = <1>; ++ vlan_tag = <0 0x20>; ++}; ++ ++&qpic_bam { ++ status = "okay"; ++}; ++ ++&tlmm { ++ /* ++ * In addition to the Pins listed below, ++ * the following GPIOs have "features": ++ * 54 - out - active low to force HW reset ++ * 41 - out - active low to reset TPM ++ * 43 - out - active low to reset BLE radio ++ * 19 - in - active high when DC powered ++ */ ++ mdio_pins: mdio_pinmux { ++ mux_1 { ++ pins = "gpio6"; ++ function = "mdio"; ++ bias-pull-up; ++ }; ++ mux_2 { ++ pins = "gpio7"; ++ function = "mdc"; ++ bias-pull-up; ++ }; ++ }; ++ ++ nand_pins: nand_pins { ++ pullups { ++ pins = "gpio53", "gpio58", "gpio59"; ++ function = "qpic"; ++ bias-pull-up; ++ }; ++ ++ pulldowns { ++ pins = "gpio54", "gpio55", "gpio56", ++ "gpio57", "gpio60", "gpio61", ++ "gpio62", "gpio63", "gpio64", ++ "gpio65", "gpio66", "gpio67", ++ "gpio68", "gpio69"; ++ function = "qpic"; ++ bias-pull-down; ++ }; ++ }; ++ ++ spi_0_pins: spi_0_pinmux { ++ pin { ++ function = "blsp_spi0"; ++ pins = "gpio13", "gpio14", "gpio15"; ++ drive-strength = <12>; ++ bias-disable; ++ }; ++ pin_cs { ++ function = "gpio"; ++ pins = "gpio12"; ++ drive-strength = <2>; ++ bias-disable; ++ output-high; ++ }; ++ }; ++ i2c_0_pins: i2c_0_pinmux { ++ mux { ++ pins = "gpio10", "gpio11"; ++ function = "blsp_i2c0"; ++ drive-strength = <4>; ++ bias-disable; ++ }; ++ }; ++ ++ serial_0_pins: serial_0_pinmux { ++ mux { ++ pins = "gpio16", "gpio17"; ++ function = "blsp_uart0"; ++ bias-disable; ++ }; ++ }; ++ ++ serial_1_pins: serial_1_pinmux { ++ mux { ++ pins = "gpio8", "gpio9"; ++ function = "blsp_uart1"; ++ bias-disable; ++ }; ++ }; ++ ++ phy-reset { ++ line-name = "PHY-reset"; ++ gpios = <42 GPIO_ACTIVE_HIGH>; ++ gpio-hog; ++ output-high; ++ }; ++}; ++ ++&nand { ++ pinctrl-0 = <&nand_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ nand@0 { ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ /* 'aos0' in Aruba firmware */ ++ label = "aos0"; ++ reg = <0x0 0x2000000>; ++ read-only; ++ }; ++ ++ partition@2000000 { ++ /* 'aos1' in AVM firmware */ ++ label = "ubi"; ++ reg = <0x2000000 0x2000000>; ++ }; ++ ++ partition@4000000 { ++ label = "aruba-ubifs"; ++ reg = <0x4000000 0x4000000>; ++ read-only; ++ }; ++ }; ++ }; ++}; ++ ++&blsp1_spi1 { ++ pinctrl-0 = <&spi_0_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ cs-gpios = <&tlmm 12 GPIO_ACTIVE_HIGH>; ++ ++ flash@0 { ++ compatible = "jedec,spi-nor"; ++ reg = <0>; ++ spi-max-frequency = <24000000>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ /* ++ * There is no partition map for the NOR flash ++ * in the stock firmware. ++ * ++ * All partitions here are based on offsets ++ * found in the U-Boot GPL code and information ++ * from smem. ++ */ ++ ++ partition@0 { ++ label = "sbl1"; ++ reg = <0x0 0x40000>; ++ read-only; ++ }; ++ ++ partition@40000 { ++ label = "mibib"; ++ reg = <0x40000 0x20000>; ++ read-only; ++ }; ++ ++ partition@60000 { ++ label = "qsee"; ++ reg = <0x60000 0x60000>; ++ read-only; ++ }; ++ ++ partition@c0000 { ++ label = "cdt"; ++ reg = <0xc0000 0x10000>; ++ read-only; ++ }; ++ ++ partition@d0000 { ++ label = "ddrparams"; ++ reg = <0xd0000 0x10000>; ++ read-only; ++ }; ++ ++ partition@e0000 { ++ label = "ART"; ++ reg = <0xe0000 0x10000>; ++ read-only; ++ }; ++ ++ partition@f0000 { ++ label = "appsbl"; ++ reg = <0xf0000 0xf0000>; ++ read-only; ++ }; ++ ++ partition@1e0000 { ++ label = "mfginfo"; ++ reg = <0x1e0000 0x10000>; ++ read-only; ++ }; ++ ++ partition@1f0000 { ++ label = "apcd"; ++ reg = <0x1f0000 0x10000>; ++ read-only; ++ }; ++ ++ partition@200000 { ++ label = "osss"; ++ reg = <0x200000 0x180000>; ++ read-only; ++ }; ++ ++ partition@380000 { ++ /* This is empty */ ++ label = "appsblenv"; ++ reg = <0x380000 0x10000>; ++ read-only; ++ }; ++ ++ partition@390000 { ++ label = "pds"; ++ reg = <0x390000 0x10000>; ++ read-only; ++ }; ++ ++ partition@3a0000 { ++ label = "fcache"; ++ reg = <0x3a0000 0x10000>; ++ read-only; ++ }; ++ ++ partition@3b0000 { ++ /* Called osss1 in smem */ ++ label = "u-boot-env-bak"; ++ reg = <0x3b0000 0x10000>; ++ read-only; ++ }; ++ ++ partition@3f0000 { ++ label = "u-boot-env"; ++ reg = <0x3f0000 0x10000>; ++ read-only; ++ }; ++ }; ++ }; ++}; ++ ++&wifi0 { ++ status = "okay"; ++ qcom,ath10k-calibration-variant = "Aruba-AP-303"; ++}; ++ ++&wifi1 { ++ status = "okay"; ++ qcom,ath10k-calibration-variant = "Aruba-AP-303"; ++}; +diff --git a/target/linux/ipq40xx/image/Makefile b/target/linux/ipq40xx/image/Makefile +index 98c81726d9c12bd466df2150c3e98a76cfb46f78..68dcbc59a42f6d8360b87c7b4e74cd34f697b465 100644 +--- a/target/linux/ipq40xx/image/Makefile ++++ b/target/linux/ipq40xx/image/Makefile +@@ -85,6 +85,15 @@ define Device/alfa-network_ap120c-ac + endef + TARGET_DEVICES += alfa-network_ap120c-ac + ++define Device/aruba_ap-303 ++ $(call Device/FitImageLzma) ++ DEVICE_TITLE := Aruba AP-303 ++ DEVICE_DTS := qcom-ipq4029-ap-303 ++ DEVICE_PACKAGES := ipq-wifi-aruba_ap-303 ++ IMAGES := sysupgrade.bin ++endef ++TARGET_DEVICES += aruba_ap-303 ++ + define Device/asus_map-ac2200 + $(call Device/FitImageLzma) + DEVICE_DTS := qcom-ipq4019-map-ac2200 +diff --git a/target/linux/ipq40xx/patches-4.14/304-mtd-spi-nor-Add-support-for-mx25r3235f.patch b/target/linux/ipq40xx/patches-4.14/304-mtd-spi-nor-Add-support-for-mx25r3235f.patch +new file mode 100644 +index 0000000000000000000000000000000000000000..d95923a1610d4764538e79bb783702903edcdcad +--- /dev/null ++++ b/target/linux/ipq40xx/patches-4.14/304-mtd-spi-nor-Add-support-for-mx25r3235f.patch +@@ -0,0 +1,26 @@ ++From 158acdbf0336f601971637f988b57a6a67a0869b Mon Sep 17 00:00:00 2001 ++From: David Bauer ++Date: Sun, 15 Dec 2019 13:10:50 +0100 ++Subject: [PATCH] mtd: spi-nor: Add support for mx25r3235f ++ ++Add MTD support for the Macronix MX25R3235F SPI NOR chip from Macronix. ++The chip has 4MB of total capacity, divided into a total of 64 sectors, ++each 64KB sized. The chip also supports 4KB large sectors. ++Additionally, it supports dual and quad read modes. ++ ++Signed-off-by: David Bauer ++--- ++ drivers/mtd/spi-nor/spi-nor.c | 2 ++ ++ 1 file changed, 2 insertions(+) ++ ++--- a/drivers/mtd/spi-nor/spi-nor.c +++++ b/drivers/mtd/spi-nor/spi-nor.c ++@@ -1024,6 +1024,8 @@ static const struct flash_info spi_nor_i ++ { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, SECT_4K) }, ++ { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) }, ++ { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) }, +++ { "mx25r3235f", INFO(0xc22816, 0, 64 * 1024, 64, +++ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, ++ { "mx25u3235f", INFO(0xc22536, 0, 64 * 1024, 64, 0) }, ++ { "mx25u2033e", INFO(0xc22532, 0, 64 * 1024, 4, SECT_4K) }, ++ { "mx25u4035", INFO(0xc22533, 0, 64 * 1024, 8, SECT_4K) }, +diff --git a/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch b/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch +index f7efd415f1f1c000867793b3b133e44b3e50b0fd..fc8a88336491c2ac7c2a93fafb1f2b6fd38695be 100644 +--- a/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch ++++ b/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch +@@ -10,7 +10,7 @@ Signed-off-by: John Crispin + + --- a/arch/arm/boot/dts/Makefile + +++ b/arch/arm/boot/dts/Makefile +-@@ -697,7 +697,31 @@ dtb-$(CONFIG_ARCH_QCOM) += \ ++@@ -697,7 +697,32 @@ dtb-$(CONFIG_ARCH_QCOM) += \ + qcom-apq8074-dragonboard.dtb \ + qcom-apq8084-ifc6540.dtb \ + qcom-apq8084-mtp.dtb \ +@@ -37,6 +37,7 @@ Signed-off-by: John Crispin + + qcom-ipq4019-qxwlan-e2600ac-c1.dtb \ + + qcom-ipq4019-qxwlan-e2600ac-c2.dtb \ + + qcom-ipq4028-wpj428.dtb \ +++ qcom-ipq4029-ap-303.dtb \ + + qcom-ipq4029-gl-b1300.dtb \ + + qcom-ipq4029-mr33.dtb \ + qcom-ipq8064-ap148.dtb \ diff --git a/scripts/features.sh b/scripts/features.sh index 2d35fdee..1d7184ee 100755 --- a/scripts/features.sh +++ b/scripts/features.sh @@ -31,14 +31,14 @@ sanitize() { echo -n "$v" } -vars= +vars=() for feature in $1; do - if [ "$(type -t gluon_feature_nodefault_${feature})" != 'function' ]; then + if [ "$(type -t "gluon_feature_nodefault_${feature}")" != 'function' ]; then echo "gluon-${feature}" fi - vars="$vars $(sanitize "$feature")=1" + vars+=("$(sanitize "$feature")=1") done @@ -46,18 +46,19 @@ nodefault() { : } +# shellcheck disable=SC2086 packages() { local cond="$(sanitize "$1")" shift # We only allow variable names, parentheses and the operators: & | ! - if [ "$(expr match "$cond" '.*[^A-Za-z0-9_()&|! ].*')" -gt 0 ]; then + if grep -q '[^A-Za-z0-9_()&|! ]' <<< "$cond"; then exit 1 fi # Let will return false when the result of the passed expression is 0, # so we always add 1. This way false is only returned for syntax errors. - local ret="$(env -i $vars bash --norc -ec "let _result_='1+($cond)'; echo -n \"\$_result_\"" 2>/dev/null)" + local ret="$(env -i "${vars[@]}" bash --norc -ec "let _result_='1+($cond)'; echo -n \"\$_result_\"" 2>/dev/null)" case "$ret" in 2) for pkg in "$@"; do diff --git a/scripts/filesize.sh b/scripts/filesize.sh index 1a6ea4dd..7068eb54 100755 --- a/scripts/filesize.sh +++ b/scripts/filesize.sh @@ -1,7 +1,7 @@ #!/bin/sh check_command() { - which "$1" >/dev/null 2>&1 + command -v "$1" >/dev/null } if check_command gnustat; then diff --git a/scripts/lint-lua.sh b/scripts/lint-lua.sh new file mode 100755 index 00000000..e958e3f1 --- /dev/null +++ b/scripts/lint-lua.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +set -e + +luacheck package scripts targets diff --git a/scripts/lint-sh.sh b/scripts/lint-sh.sh new file mode 100755 index 00000000..71ce5463 --- /dev/null +++ b/scripts/lint-sh.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +set -e + +is_scriptfile() { + echo "$1" | grep -qE '.*\.sh$' || head -n1 "$1" | grep -qE '^#.*(sh|bash)$' +} + +find contrib -type f | while read -r file; do + is_scriptfile "$file" || continue + + echo "Checking $file" + shellcheck -f gcc "$file" +done + +find package -type f | while read -r file; do + is_scriptfile "$file" || continue + + echo "Checking $file" + shellcheck -f gcc -x -s sh -e SC2039,SC1091,SC2155,SC2034 "$file" +done + +find scripts -type f | while read -r file; do + is_scriptfile "$file" || continue + + echo "Checking $file" + shellcheck -f gcc -x -e SC2154,SC1090,SC2181,SC2155,SC2148,SC2034,SC2148 "$file" +done diff --git a/scripts/modules.sh b/scripts/modules.sh index 4df7e580..78b819c3 100644 --- a/scripts/modules.sh +++ b/scripts/modules.sh @@ -1,6 +1,7 @@ . ./modules [ ! -f "$GLUON_SITEDIR"/modules ] || . "$GLUON_SITEDIR"/modules +# shellcheck disable=SC2086 FEEDS="$(echo $GLUON_FEEDS $GLUON_SITE_FEEDS | tr ' ' '\n')" GLUON_MODULES=openwrt diff --git a/scripts/patch.sh b/scripts/patch.sh index 082ca1fc..9269ffb5 100755 --- a/scripts/patch.sh +++ b/scripts/patch.sh @@ -3,7 +3,7 @@ set -e shopt -s nullglob -[ "$GLUON_TMPDIR" -a "$GLUON_PATCHESDIR" ] || exit 1 +[ "$GLUON_TMPDIR" ] && [ "$GLUON_PATCHESDIR" ] || exit 1 . scripts/modules.sh diff --git a/scripts/sha256sum.sh b/scripts/sha256sum.sh index e4f6f3e5..99d97acd 100755 --- a/scripts/sha256sum.sh +++ b/scripts/sha256sum.sh @@ -1,7 +1,7 @@ #!/bin/sh check_command() { - which "$1" >/dev/null 2>&1 + command -v "$1" >/dev/null 2>&1 } if check_command sha256sum; then diff --git a/scripts/sha512sum.sh b/scripts/sha512sum.sh index d9fd544d..cb4b07e4 100755 --- a/scripts/sha512sum.sh +++ b/scripts/sha512sum.sh @@ -1,7 +1,7 @@ #!/bin/sh check_command() { - which "$1" >/dev/null 2>&1 + command -v "$1" >/dev/null 2>&1 } if check_command sha512sum; then diff --git a/scripts/update-patches.sh b/scripts/update-patches.sh index 933d20ac..94f103fa 100755 --- a/scripts/update-patches.sh +++ b/scripts/update-patches.sh @@ -13,13 +13,13 @@ GLUONDIR="$(pwd)" for module in $GLUON_MODULES; do echo "--- Updating patches for module '$module' ---" - rm -rf "${GLUON_PATCHESDIR}/$module" + rm -rf "${GLUON_PATCHESDIR:?}/$module" cd "$GLUONDIR"/"$module" n=0 for commit in $(git rev-list --reverse --no-merges base..patched); do - let n=n+1 + (( ++n )) mkdir -p "${GLUON_PATCHESDIR}/$module" git -c core.abbrev=40 show --pretty=format:'From: %an <%ae>%nDate: %aD%nSubject: %B' --no-renames --binary "$commit" > "${GLUON_PATCHESDIR}/$module/$(printf '%04u' $n)-$(git show -s --pretty=format:%f "$commit").patch" done diff --git a/scripts/update.sh b/scripts/update.sh index afea8e71..0d33a8cc 100755 --- a/scripts/update.sh +++ b/scripts/update.sh @@ -10,9 +10,9 @@ GLUONDIR="$(pwd)" for module in $GLUON_MODULES; do echo "--- Updating module '$module' ---" var=$(echo "$module" | tr '[:lower:]/' '[:upper:]_') - eval repo=\${${var}_REPO} - eval branch=\${${var}_BRANCH} - eval commit=\${${var}_COMMIT} + eval 'repo=${'"${var}"'_REPO}' + eval 'branch=${'"${var}"'_BRANCH}' + eval 'commit=${'"${var}"'_COMMIT}' mkdir -p "$GLUONDIR/$module" cd "$GLUONDIR/$module" diff --git a/targets/ar71xx-generic b/targets/ar71xx-generic index 69892177..497a00e5 100644 --- a/targets/ar71xx-generic +++ b/targets/ar71xx-generic @@ -4,18 +4,21 @@ config 'CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=64' local ATH10K_PACKAGES = { 'kmod-ath10k', '-kmod-ath10k-ct', + '-kmod-ath10k-ct-smallbuffers', 'ath10k-firmware-qca988x', '-ath10k-firmware-qca988x-ct', } local ATH10K_PACKAGES_QCA9887 = { 'kmod-ath10k', '-kmod-ath10k-ct', + '-kmod-ath10k-ct-smallbuffers', 'ath10k-firmware-qca9887', '-ath10k-firmware-qca9887-ct', } local ATH10K_PACKAGES_QCA9888 = { 'kmod-ath10k', '-kmod-ath10k-ct', + '-kmod-ath10k-ct-smallbuffers', 'ath10k-firmware-qca9888', '-ath10k-firmware-qca9888-ct', } @@ -99,7 +102,7 @@ device('d-link-dir-825-rev-b1', 'dir-825-b1', { }) --- GL Innovations +-- GL.iNet device('gl-inet-6408a-v1', 'gl-inet-6408A-v1') @@ -154,6 +157,7 @@ device('netgear-wndr3700v2', 'wndr3700v2', { }) device('netgear-wndr3800', 'wndr3800', { + aliases = {'netgear-wndr3800chmychart'}, factory_ext = '.img', }) diff --git a/targets/ath79-generic b/targets/ath79-generic index 22470632..7caf6578 100644 --- a/targets/ath79-generic +++ b/targets/ath79-generic @@ -1,10 +1,63 @@ +local ATH10K_PACKAGES_QCA9880 = { + 'kmod-ath10k', + '-kmod-ath10k-ct', + '-kmod-ath10k-ct-smallbuffers', + 'ath10k-firmware-qca988x', + '-ath10k-firmware-qca988x-ct', +} + local ATH10K_PACKAGES_QCA9888 = { 'kmod-ath10k', '-kmod-ath10k-ct', + '-kmod-ath10k-ct-smallbuffers', 'ath10k-firmware-qca9888', '-ath10k-firmware-qca9888-ct', } +-- devolo + +device('devolo-wifi-pro-1200e', 'devolo_dvl1200e', { + packages = ATH10K_PACKAGES_QCA9880, + factory = false, +}) + +device('devolo-wifi-pro-1200i', 'devolo_dvl1200i', { + packages = ATH10K_PACKAGES_QCA9880, + factory = false, +}) + +device('devolo-wifi-pro-1750c', 'devolo_dvl1750c', { + packages = ATH10K_PACKAGES_QCA9880, + factory = false, +}) + +device('devolo-wifi-pro-1750e', 'devolo_dvl1750e', { + packages = ATH10K_PACKAGES_QCA9880, + factory = false, +}) + +device('devolo-wifi-pro-1750i', 'devolo_dvl1750i', { + packages = ATH10K_PACKAGES_QCA9880, + factory = false, +}) + +device('devolo-wifi-pro-1750x', 'devolo_dvl1750x', { + packages = ATH10K_PACKAGES_QCA9880, + factory = false, +}) + +-- GL.iNet + +device('gl.inet-gl-ar300m-lite', 'glinet_gl-ar300m-lite', { + factory = false, +}) + +-- OCEDO + +device('ocedo-raccoon', 'ocedo_raccoon', { + factory = false, +}) + -- TP-Link device('tp-link-archer-c6-v2', 'tplink_archer-c6-v2', { diff --git a/targets/brcm2708-bcm2708 b/targets/brcm2708-bcm2708 index 15ebd193..4d4068ab 100644 --- a/targets/brcm2708-bcm2708 +++ b/targets/brcm2708-bcm2708 @@ -1,7 +1,11 @@ include 'brcm2708.inc' -device('raspberry-pi', 'rpi', { +device('raspberrypi-model-b', 'rpi', { manifest_aliases = { + 'raspberrypi-model-b-plus', + 'raspberrypi-model-b-rev2', + + -- from Gluon 2019.1 and older 'raspberry-pi-model-b-rev-2', 'raspberry-pi-model-b-plus-rev-1.2', }, diff --git a/targets/brcm2708-bcm2709 b/targets/brcm2708-bcm2709 index e0fbf0cd..e5af9c89 100644 --- a/targets/brcm2708-bcm2709 +++ b/targets/brcm2708-bcm2709 @@ -1,7 +1,8 @@ include 'brcm2708.inc' -device('raspberry-pi-2', 'rpi-2', { +device('raspberrypi-2-model-b', 'rpi-2', { manifest_aliases = { + -- from Gluon 2019.1 and older 'raspberry-pi-2-model-b-rev-1.1', }, }) diff --git a/targets/brcm2708-bcm2710 b/targets/brcm2708-bcm2710 index c0133f52..1cf9ef36 100644 --- a/targets/brcm2708-bcm2710 +++ b/targets/brcm2708-bcm2710 @@ -1,3 +1,10 @@ include 'brcm2708.inc' -device('raspberry-pi-3', 'rpi-3') +device('raspberrypi-3-model-b', 'rpi-3', { + manifest_aliases = { + 'raspberrypi-3-model-b-plus', + + -- from Gluon 2019.1 and older + 'raspberry-pi-3-model-b-rev-1.2', + }, +}) diff --git a/targets/generic b/targets/generic index 0153386d..65982ef4 100644 --- a/targets/generic +++ b/targets/generic @@ -56,6 +56,8 @@ if envtrue.GLUON_DEBUG then config 'CONFIG_NO_STRIP=y' config '# CONFIG_USE_STRIP is not set' config '# CONFIG_USE_SSTRIP is not set' + + try_config 'CONFIG_TARGET_ROOTFS_PARTSIZE=500' end diff --git a/targets/ipq40xx-generic b/targets/ipq40xx-generic index f06e15f2..8df11ea2 100644 --- a/targets/ipq40xx-generic +++ b/targets/ipq40xx-generic @@ -1,12 +1,14 @@ local ATH10K_PACKAGES_IPQ40XX = { 'kmod-ath10k', '-kmod-ath10k-ct', + '-kmod-ath10k-ct-smallbuffers', 'ath10k-firmware-qca4019', '-ath10k-firmware-qca4019-ct', } local ATH10K_PACKAGES_IPQ40XX_QCA9888 = { 'kmod-ath10k', '-kmod-ath10k-ct', + '-kmod-ath10k-ct-smallbuffers', 'ath10k-firmware-qca4019', '-ath10k-firmware-qca4019-ct', 'ath10k-firmware-qca9888', @@ -19,6 +21,14 @@ defaults { } +-- Aruba + +device('aruba-ap-303', 'aruba_ap-303', { + factory = false, + aliases = {'aruba-instant-on-ap11'}, +}) + + -- AVM device('avm-fritz-box-4040', 'avm_fritzbox-4040', { diff --git a/targets/lantiq-xrx200 b/targets/lantiq-xrx200 index 35d83bd1..d797f59f 100644 --- a/targets/lantiq-xrx200 +++ b/targets/lantiq-xrx200 @@ -1,15 +1,24 @@ +device('avm-fritz-box-7360-sl', 'avm_fritz7360sl', { + factory = false, + aliases = {'avm-fritz-box-7360-v1', 'avm-fritz-box-7360-v2'}, +}) + +device('avm-fritz-box-7362-sl', 'avm_fritz7362sl', { + factory = false, +}) + device('avm-fritz-box-7412', 'avm_fritz7412', { factory = false, }) -- TP-Link - -- CAVEAT: These devices don't have a dedicated WAN port. + -- CAVEAT: These devices don't have a dedicated WAN port. -- All ethernet ports on the device are bridged and -- used as WAN ports. Clients connected to these -- ports will be connected to your private network. -device('tp-link-td-w8970', 'tplink_tdw8970') +device('tp-link-td-w8970', 'tplink_tdw8970') device('tp-link-td-w8980', 'tplink_tdw8980', { aliases = {'tp-link-td-w9980'}, diff --git a/targets/lantiq-xway b/targets/lantiq-xway index e3d5da98..bc556d7a 100644 --- a/targets/lantiq-xway +++ b/targets/lantiq-xway @@ -1,3 +1,8 @@ device('avm-fritz-box-7312', 'avm_fritz7312', { factory = false, }) + +device('avm-fritz-box-7320', 'avm_fritz7320', { + factory = false, + aliases = {'avm-fritz-box-7330', 'avm-fritz-box-7330-sl'}, +}) diff --git a/targets/mpc85xx-p1020 b/targets/mpc85xx-p1020 index c6fb7d16..ee120111 100644 --- a/targets/mpc85xx-p1020 +++ b/targets/mpc85xx-p1020 @@ -4,6 +4,14 @@ device('aerohive-hiveap-330', 'hiveap-330', { factory = false, }) + +-- Enterasys + +device('enterasys-ws-ap3710i', 'ws-ap3710i', { + factory = false, +}) + + -- OCEDO device('ocedo-panda', 'panda', { diff --git a/targets/ramips-mt7620 b/targets/ramips-mt7620 index 8aa005f1..9dd6a2d9 100644 --- a/targets/ramips-mt7620 +++ b/targets/ramips-mt7620 @@ -6,7 +6,7 @@ device('asus-rt-ac51u', 'rt-ac51u', { }) --- GL Innovations +-- GL.iNet device('gl-mt300a', 'gl-mt300a', { factory = false, @@ -31,10 +31,28 @@ device('nexx-wt3020-8m', 'wt3020-8M', { }, }) +-- TP-Link + +local tplink_region_suffix = '' +if (env.GLUON_REGION or '') ~= '' then + tplink_region_suffix = '-' .. env.GLUON_REGION +end + +device('tp-link-archer-c2-v1', 'tplink_c2-v1', { + factory = false, +}) + +device('tp-link-archer-c20-v1', 'tplink_c20-v1') + +device('tp-link-archer-c20i', 'ArcherC20i') + +device('tp-link-archer-c50', 'ArcherC50v1', { + factory = '-squashfs-factory' .. tplink_region_suffix, +}) + -- Xiaomi device('xiaomi-miwifi-mini', 'miwifi-mini', { factory = false, - broken = true, -- 2.4GHz WiFi is unstable }) diff --git a/targets/ramips-mt7621 b/targets/ramips-mt7621 index 196022b0..9b3ddf86 100644 --- a/targets/ramips-mt7621 +++ b/targets/ramips-mt7621 @@ -12,6 +12,10 @@ device('d-link-dir-860l-b1', 'dir-860l-b1') -- Netgear +device('netgear-ex6150', 'netgear_ex6150', { + factory_ext = '.chk', +}) + device('netgear-r6220', 'r6220', { factory_ext = '.img', }) diff --git a/targets/ramips-mt76x8 b/targets/ramips-mt76x8 index 4c2f8fed..c1e0354f 100644 --- a/targets/ramips-mt76x8 +++ b/targets/ramips-mt76x8 @@ -29,6 +29,13 @@ device('tp-link-archer-c50-v4', 'tplink_c50-v4', { factory = false, }) +device('tp-link-tl-mr3020-v3', 'tplink_tl-mr3020-v3', { + factory = false, + extra_images = { + {'-squashfs-tftp-recovery', '-bootloader', '.bin'}, + }, +}) + device('tp-link-tl-mr3420-v5', 'tplink_tl-mr3420-v5', { factory = false, extra_images = { @@ -36,6 +43,13 @@ device('tp-link-tl-mr3420-v5', 'tplink_tl-mr3420-v5', { }, }) +device('tp-link-tl-wa801nd-v5', 'tplink_tl-wa801nd-v5', { + factory = false, + extra_images = { + {'-squashfs-tftp-recovery', '-bootloader', '.bin'}, + }, +}) + device('tp-link-tl-wr841n-v13', 'tl-wr841n-v13', { factory = false, extra_images = { @@ -43,6 +57,12 @@ device('tp-link-tl-wr841n-v13', 'tl-wr841n-v13', { }, }) +device('tp-link-tl-wr902ac-v3', 'tplink_tl-wr902ac-v3', { + factory = false, + extra_images = { + {'-squashfs-tftp-recovery', '-bootloader', '.bin'}, + }, +}) -- VoCore 2