(and removed trailing whitespace)
This commit is contained in:
David Lutz 2020-03-02 21:44:52 +01:00
commit 90ba3608ec
90 changed files with 3254 additions and 2196 deletions

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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
*/

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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 <<EOHELP
Usage: $0 <secret> <manifest>

View File

@ -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 <<EOHELP
Usage: $0 <public> <signed manifest>
@ -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

View File

@ -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

View File

@ -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.

View File

@ -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
~~~~~~~~~~~~~~

View File

@ -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

View File

@ -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
---------------

View File

@ -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 <https://github.com/freifunk-gluon/gluon/issues/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 <https://github.com/freifunk-gluon/gluon/pull/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 <https://github.com/freifunk-gluon/gluon/issues/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 <https://github.com/freifunk-gluon/gluon/issues/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 <https://github.com/freifunk-gluon/gluon/issues/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 <https://github.com/freifunk-gluon/gluon/issues/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.

View File

@ -0,0 +1,62 @@
Gluon 2019.1.1
##############
Bugfixes
********
* Fixes device alias for Ubiquiti UniFi AC LR. (`#1834 <https://github.com/freifunk-gluon/gluon/issues/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 <https://github.com/freifunk-gluon/gluon/pull/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 <https://github.com/freifunk-gluon/gluon/issues/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 <https://github.com/freifunk-gluon/gluon/issues/1768>`_)
* The integration of the BATMAN_V routing algorithm is incomplete.
- | Mesh neighbors don't appear on the status page. (`#1726 <https://github.com/freifunk-gluon/gluon/issues/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 <https://github.com/freifunk-gluon/gluon/issues/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 <https://github.com/freifunk-gluon/gluon/issues/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 <https://github.com/freifunk-gluon/gluon/issues/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 <https://github.com/freifunk-gluon/gluon/issues/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 <https://github.com/freifunk-gluon/gluon/issues/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.

View File

@ -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 <https://github.com/freifunk-gluon/gluon/issues/1768>`_)
* The integration of the BATMAN_V routing algorithm is incomplete.
- | Mesh neighbors don't appear on the status page. (`#1726 <https://github.com/freifunk-gluon/gluon/issues/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 <https://github.com/freifunk-gluon/gluon/issues/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 <https://github.com/freifunk-gluon/gluon/issues/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 <https://github.com/freifunk-gluon/gluon/issues/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 <https://github.com/freifunk-gluon/gluon/issues/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 <https://github.com/freifunk-gluon/gluon/issues/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.

View File

@ -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

191
docs/releases/v2020.1.rst Normal file
View File

@ -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.

View File

@ -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.

View File

@ -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.
::

View File

@ -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.
commit which added support in OpenWrt.
.. [#lan_as_wan]
All LAN ports on this device are used as WAN.

14
modules
View File

@ -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

View File

@ -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"

View File

@ -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')

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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 $@ $^

View File

@ -26,17 +26,15 @@
#include <respondd.h>
#include <iwinfo.h>
#include <json-c/json.h>
#include <libgluonutil.h>
#include <uci.h>
#include <alloca.h>
#include <glob.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
@ -49,33 +47,18 @@
#include <sys/un.h>
#include <ifaddrs.h>
#include <linux/ethtool.h>
#include <linux/if_addr.h>
#include <linux/sockios.h>
#include <netdb.h>
#include "errno.h"
#include <errno.h>
#include <libbabelhelper/babelhelper.h>
#include <libubox/blobmsg_json.h>
#include "libubus.h"
#define _STRINGIFY(s) #s
#define STRINGIFY(s) _STRINGIFY(s)
#include <stdlib.h>
#define MAX_INACTIVITY 60000
#include <libubus.h>
#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;
}

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -0,0 +1,30 @@
/*
Copyright (c) 2016-2019, Matthias Schiffer <mschiffer@universe-factory.net>
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);

View File

@ -0,0 +1,176 @@
/*
Copyright (c) 2016-2019, Matthias Schiffer <mschiffer@universe-factory.net>
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 <batadv-genl.h>
#include <libgluonutil.h>
#include <json-c/json.h>
#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <net/if.h>
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;
}

View File

@ -0,0 +1,219 @@
/*
Copyright (c) 2016-2019, Matthias Schiffer <mschiffer@universe-factory.net>
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 <libgluonutil.h>
#include <json-c/json.h>
#include <netlink/netlink.h>
#include <netlink/msg.h>
#include <glob.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <linux/if_addr.h>
#include <linux/rtnetlink.h>
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;
}

View File

@ -0,0 +1,322 @@
/*
Copyright (c) 2016-2019, Matthias Schiffer <mschiffer@universe-factory.net>
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 <batadv-genl.h>
#include <json-c/json.h>
#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>
#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;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (c) 2016, Matthias Schiffer <mschiffer@universe-factory.net>
Copyright (c) 2016-2019, Matthias Schiffer <mschiffer@universe-factory.net>
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 <respondd.h>
#include <ifaddrs.h>
#include <iwinfo.h>
#include <json-c/json.h>
#include <libgluonutil.h>
#include <uci.h>
#include <alloca.h>
#include <glob.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/ethtool.h>
#include <linux/if_addr.h>
#include <linux/rtnetlink.h>
#include <linux/sockios.h>
#include <batadv-genl.h>
#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},

View File

@ -37,8 +37,8 @@
void usage() {
puts("Usage: gluon-neighbour-info [-h] [-s] [-l] [-c <count>] [-t <sec>] -d <dest> -p <port> -i <if0> -r <request>");
puts(" -p <int> UDP port");
puts(" -d <ip6> destination address (unicast ip6 or multicast group, e.g. ff02:0:0:0:0:0:2:1001)");
puts(" -p <int> UDP port (default: 1001)");
puts(" -d <ip6> destination address (unicast ip6 or multicast group, e.g. ff02:0:0:0:0:0:2:1001, default: ::1)");
puts(" -i <string> interface, e.g. eth0 ");
puts(" -r <string> request, e.g. nodeinfo");
puts(" -t <sec> 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;

View File

@ -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

View File

@ -0,0 +1,32 @@
/*
Copyright (c) 2016-2019, Matthias Schiffer <mschiffer@universe-factory.net>
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);

View File

@ -0,0 +1,130 @@
/*
Copyright (c) 2016-2019, Matthias Schiffer <mschiffer@universe-factory.net>
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 <libgluonutil.h>
#include <iwinfo.h>
#include <json-c/json.h>
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;
}

View File

@ -0,0 +1,132 @@
/*
Copyright (c) 2016-2019, Matthias Schiffer <mschiffer@universe-factory.net>
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 <libgluonutil.h>
#include <libplatforminfo.h>
#include <json-c/json.h>
#include <uci.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
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;
}

View File

@ -0,0 +1,309 @@
/*
Copyright (c) 2016-2019, Matthias Schiffer <mschiffer@universe-factory.net>
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 <libgluonutil.h>
#include <iwinfo.h>
#include <json-c/json.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/vfs.h>
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;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (c) 2016, Matthias Schiffer <mschiffer@universe-factory.net>
Copyright (c) 2016-2019, Matthias Schiffer <mschiffer@universe-factory.net>
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 <respondd.h>
#include <json-c/json.h>
#include <libgluonutil.h>
#include <libplatforminfo.h>
#include <uci.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <inttypes.h>
#include <sys/vfs.h>
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},

View File

@ -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
;;

View File

@ -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
}

View File

@ -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)

View File

@ -135,7 +135,7 @@
<tr><th><%:Load average%></th><td><%= statistics('loadavg', 'decimal') %></td></tr>
<tr><th><%:RAM%></th><td><%= statistics('memory', 'memory') %></td></tr>
<tr><th><%:Filesystem%></th><td><%= statistics('rootfs_usage', 'percent') %></td></tr>
<tr><th><%:Gateway%></th><td><%= statistics('gateway') %></td></tr>
<tr><th><%:Gateway%></th><td><%= statistics('gateway') %><br /><%= statistics('gateway_nexthop', 'neighbour') %></td></tr>
<tr><th><%:Clients%></th><td><%= statistics('clients/total') %></td></tr>
</table>

File diff suppressed because one or more lines are too long

View File

@ -55,6 +55,9 @@ msgstr "Weitergeleitet"
msgid "Gateway"
msgstr "Gateway"
msgid "Gateway Nexthop"
msgstr "Gateway Nexthop"
msgid "IP address"
msgstr "IP-Adresse"

View File

@ -46,6 +46,9 @@ msgstr ""
msgid "Gateway"
msgstr ""
msgid "Gateway Nexthop"
msgstr ""
msgid "IP address"
msgstr ""

View File

@ -112,6 +112,20 @@
'bytes': function(bytes) {
return prettyBytes(bytes);
},
'neighbour': function(addr) {
if (!addr)
return '';
for (var i in interfaces) {
var iface = interfaces[i];
var neigh = iface.lookup_neigh(addr);
if (!neigh)
continue;
return 'via ' + neigh.get_hostname() + ' (' + i + ')';
}
return 'via ' + addr + ' (unknown iface)';
}
}
@ -582,6 +596,9 @@
}
return {
'get_hostname': function() {
return hostname.textContent;
},
'update_nodeinfo': function(nodeinfo) {
var addr = choose_address(nodeinfo.network.addresses);
if (addr) {
@ -711,6 +728,9 @@
}
}
function lookup_neigh(addr) {
return neighs[addr];
}
function get_neigh(addr) {
var neigh = neighs[addr];
@ -738,6 +758,7 @@
return {
'get_neigh': get_neigh,
'lookup_neigh': lookup_neigh
};
}

View File

@ -6,6 +6,7 @@ PKG_VERSION:=1
PKG_INSTALL:=1
include ../gluon.mk
include $(INCLUDE_DIR)/host-build.mk
define Package/gluon-web
TITLE:=Minimal Lua web framework derived from LuCI
@ -24,4 +25,18 @@ define Package/gluon-web/config
$(foreach lang,$(GLUON_SUPPORTED_LANGS),$(call lang-config,$(lang)))
endef
define Host/Prepare
$(CP) ./src/* $(HOST_BUILD_DIR)
endef
define Host/Compile
$(call Host/Compile/Default,gluon-po2lmo)
endef
define Host/Install
$(INSTALL_DIR) $(1)/bin
$(INSTALL_BIN) $(HOST_BUILD_DIR)/gluon-po2lmo $(1)/bin/
endef
$(eval $(call BuildPackageGluon,gluon-web))
$(eval $(call HostBuild))

View File

@ -9,6 +9,8 @@ clean:
parser.so: template_parser.o template_utils.o template_lmo.o template_lualib.o
$(CC) $(LDFLAGS) -shared -o $@ $^
gluon-po2lmo: gluon-po2lmo.o template_lmo.o
compile: parser.so
install: compile

View File

@ -0,0 +1,256 @@
/*
* lmo - Lua Machine Objects - PO to LMO conversion tool
*
* Copyright (C) 2009-2012 Jo-Philipp Wich <jow@openwrt.org>
*
* 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 <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
__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);
}

View File

@ -25,20 +25,11 @@
#include <arpa/inet.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
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;

View File

@ -22,8 +22,15 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
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);

View File

@ -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

View File

@ -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 <mschiffer@universe-factory.net>
@ -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 <sys/stat.h>
+ #include <sys/types.h>
+ #include <sys/mount.h>
+@@ -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
+

View File

@ -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 <janphilipp@litza.de>
+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
+

View File

@ -6,10 +6,10 @@ Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
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 <mschiffer@universe-factory.net>
+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 <mschiffer@universe-factory.net>
+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 <mschiffer@universe-factory.net>
+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 <mschiffer@universe-factory.net>
+---
+ 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 <linux/netfilter_bridge/ebtables.h>
+ #include <linux/netfilter_bridge/ebt_ip.h>
+
+-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 <mschiffer@universe-factory.net>
+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 <mschiffer@universe-factory.net>
+---
+ 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
+

View File

@ -0,0 +1,27 @@
From: Matthias Schiffer <mschiffer@universe-factory.net>
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 <mschiffer@universe-factory.net>
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.

View File

@ -1,87 +0,0 @@
From: David Bauer <mail@david-bauer.net>
Date: Sat, 21 Sep 2019 18:59:28 +0200
Subject: ipq-wifi: add AVM FRITZ!Repeater 1200 bdf
Signed-off-by: David Bauer <mail@david-bauer.net>
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-XOgC<!pcfLx4IQVuF&
zL`Ib1VgxBv<kIUZ<?4*e?CQAAmZsc&nKxhdZ62h`+S>AEojsjSAdzHD5LPbzhtuaj
zf1m&S|M|L;bocql=Nak3^a4dfe6~=Qo1QNRH8nK=N_`x$1wal<*^#>KrIlr|Wi@Ky
zfl9Sjs4m|gZ*G;<mg>rhrZ_&fp;V_X{i1$*df_f%X1=mOm0zK)D6Oy12@}Ne@iaIN
z2ad^!oA9U6z?$Rqq(Wl+&4a)LlmM{K$De2dxaB6o+84eYi9nD@3<W@9V&cEwya7_C
zH+cK6^QqRdhUv)b!!{0}J$=7dCm9L+0_FXE&fA-2cKO5E5HG6`Ia>AEI@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<{OwyPx9<vK
z!0XY8lkHXNU8=NKWBsR^D^-|M`sgOnO{G*ypu^erMrcbR9bz_v*TWOXnu}D)%2?>y
z+I&DIhuyCCw?o%#3IEYV|Al6)Dqj+Bafq?c?*px7C?DuzzngNf$HQ@JC7|SZX3NX^
zWU%VXEKU5Lz|`?8b!}VAqjs~hAC4aG%{<N51()=W?d{!mnp4Lpy?<GKEW3)gD=_W;
zQ0=LdN<ncb_Vi}+H@T-pbzuj-9c%2}bynEOKKSH{_E=^GSIJ0zJY3tFRU5rKP=4dO
zx<}Feo5s+}`x6ZVamT~8jFRPr5|ynL0WY7m>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%ZG<t*&&R{l^S|b<G~mde
z9A)vg+HrV20*BWg?-(Zv5s7b+=tx4ioUp*?NG_LyvRT1Uo4*Zu@_0OAAULXJypORt
zLIpt)Bppph63_%hd*tZx)-xSlJ#!Txwa5dv6go;5(Vx>17RnN_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~qF27<mwEx8_hJ^ozbF&Ry*p<G5{!`be4m
zW^t@JdcVxqwi2#MsX4fE^eL1ml$;<yof=Mnu`{nql<W|o8WaK)0u%xi0u%xi0;?E-
zAaM{9PXA2&8InuiD&C5u(tWK0^2;s^-F|Glwch%>SI>>H)+!4YV-+7lYU(Qm0asTD
zT<y2aaKZLf8YW)=0P7~h;N*+<YxtxZKBGq2Axs{RLq7b5+S0Lcp_uavHY>!#dFE2G
zML^+%L;QlE0&60_rDR*`r|U%@1f(SaV4x$kKq#G-`l6-g`yxOJq@HO20e^oiXaOJr
z@DRwOg2Wpx<nvgI6xwB8f|oKM!9QRjYIE`TM1W6=7iR?SfA#Wb@Y7E}n`=TR3MDHS
zfnRR<F+DuW;R*x*G!IYTZ=hU-Vx93lC?8|Pir|Oq;N*|a>X_)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~_f4H<CU}5_dmrFKA_Olhc?9<!08dZSV!!46
zZZ7v8au8CjWxm{d80CBWNB}G}_nyd+h=JM#a?F9B<<#4Cp3|7^=K}ZM&f9TZcewX}
z!C*KnY&IJZ#m~>row9cAVsh`(n1jrh4*$==4i=}4v9U3y`{wR|$J$2b?swI)DwlMr
zNxO1-EJ2i9Nt^0JAwVHOA+TH#C@E1DlH7Yb-G2i)3pcs<C8Ym`4IXbu|APmuW3pKA
znrgv?;@(^C%pO?p(0)y!xc4*YxI%%qLi&I2>&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;p<AO<$R%Rv(50`oI$Y_E5dhfj9IiFwYqm^Z
zGj-ujh9Zp=pEC4o>J>Zr!R826n!RL7#y%n?qp2OQ(#wk@r-w}Eah+keW(WSAp;yzO
zQ1C;i?inwcQwk?iy3)so5qeBt;Rp0P6fEf4hO6~5MJWC!<AA0{kuHfdeTNSjnl*bQ
zEW%-+PY?~JyG<>4i9T5oGTm!x#mn_lMF>o!SAV29TOu&s#rq68O|Bx6j39t1oi{b%
zMS8J<IsLWiD6WDUV!DrCg;=IZ&{ub+E*l#)8Hx}x0-S?8vIH;nsgztffD}p;N=^`1
z38#jWsZr)ti@@D8$9}&vLC6mAzSdT~Z>u;WY@=^|cV?^LFssZj^ZVh7bKCX2LqWxV
z?P^k`3Znypz3yB(R+S|a$At!;A1v%hILgs%%6WRT`a)VuR87eKXMO6ttufI-06ZEv
zTCK<s3B$tfjU4VyJ0Z}~cRwCgccr%Qs)P4G8K^6fZHZzB`#rc;eMq4|x&918f6mE-
z`hYzfcHX~Pb|LvVrz&9YLu2*6Jb7#+;yF3gpxde7@&j1yy}7578iI@c6nDn{a7l6^
zye44(WKaD8<&Ib$!+X@&P^ZMil7P_30bNJNvDlix{AYj6Ivd*@a?pRzt?r|mT)BWt
z_a5%8{UWbGm=wyr(W`FTab)u$M)viQ+P;)lo{qWy#(8a-JcY+*GyA?Suh^LtD-K|t
z>)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`PcsLf<l(<u>hoXC`4QZBPsoig>KXZAF}U%I
zjjc1zz199HdG|zYihDo1G&c{8;@-~#G|FXZBjC!Ku`|BCt$k_Fa{k#--227;*8KJH
F{|7QKi|GIW
literal 0
HcmV?d00001

View File

@ -0,0 +1,92 @@
From: David Bauer <mail@david-bauer.net>
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 <mail@david-bauer.net>
(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,<devicename>,<display name>))
$(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~&un1I<M58<m4?`F1_@EFG
zfm#qEXc?48Q$)t%1F%?IJEP40v48CBA8luLw|}fVw5!gvGrOyM?hO}02ql3q<#9ha
z=X~e8-#O<yzk5jTz30c>6BFeZwJ$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@cmo9<o32e4-TK}{-42{)MS-YT8nB=KA&y`%68dZzvGj;%
zJAvBfnQ>V_`vZ+ET^9yjw-&*$wzjskw6xF>07kKy8YxWZr<)vMT{juo&5WBJl$pvJ
zSBe@2uw^qXb0;%4&|Y78I5R0hICi_exl*3FFCluYul;;oiF8lGj<J5Il}ghR-u?y3
z<F9$%VC>WOy2|{_1bA?;y|Gf7nVJwj){D78n-DgruPe_KCxqe+o_PC!v0LpI;0W&~
zgp7R#8_4hmJ+PC)%p@TfcGpx{l$j<Bm~P-bH@-z`l~5LOnR}RQFc%NQwe^6K;hC*1
zYj=HKdB|b!bl0Sb=920-IsYItdbF>&E$%$G#3{F}KdUX|Jgd|puct0g5t8q<cU!`P
z#^Y7HrM_9r@UMC+KTbK%FWvUuz5epHckBJiT?>XU6jp>E=A|Pc_n}{`jGyHYexpa)
z8eg})+@<jDr)8b~)ow)&xoZn0GFk!wOY2R)d&>@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(s2<Qwp34-SuNH%<p}&`<+SbE0
zDLDsY&OV6}iP8cHkV|6$VCI-NBuaA-AS)ySBmyJ?BmyJ?Bmx^4fh~e9h#UPK!8=F_
zeWze25<#~i1f=CRT_1X+n-jPGrj_%@*hGlg#@N88kes@S2)vvpCU&q=?$dOIMY}iF
zZ_$ocmxDOFP&NDv09aP2x`v<WmwZ28Utjp7n}x1U4F>1q!}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;
zk<l+6fAh@r13LS7rd_$N8E=5^gNo_3#7-!_2P%%PC3Zpa{ZFx=me>I`9mEA&tbcUZ
z%raPCff}=CoSdFh&~W)`kLJ$!*9+<E3zgZ~FkUkdSJaj7DrSJ#*RhBg74ya7SP=X=
z7!jc&zDOKww)^YZQBBbt1&#<xj}ycp$@Cq99Y{Dm^9uGezYpSjjwsj4Esm+2`@lsx
z_pP233MAZDG~x_!W*4x)IQLBJ8XOwPV6wwG_mF@_V5M8~BrC?bzpXnCrvEDEUf+49
zzBuO|MP{6#qUF9@TUl7rX4vll48Jjsia$KVkvGV>*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$&
zduq<ccO90m`EJJ_!n5Hnfmt*|3ykF4Yws{0%-(2jK-HM%C%SBVt&T&cMQg=#Z0+ju
z?J<3slzUHc2KJzP^x51yjM<u@zZYHGw?pGC>M~`z#Q)p7<L&AyWsXERen)*-SuBYY
zdX5iix>ZV<MCgkBpV)(k-dq41G^-WL{SyA<pyrb5ge*-W)C{Y;WHL#z(0BZEb(2yq
zi59Z32BQ<+-T-%#DbtndllL?oDuryXWT)ny>awgPK2|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@<w#Cf31sRXs|$?cxn3|T~1u=N^b}}#gf@2f7N@eDYC{>zBNZRxW7|)
z$*qbmtL@F{5S&95^!$;V#g`*L;FZw#KkAb<N7Q&6bIPge-+$Gw*17EWd3}TBpF}or
ztF{!X+LO-)o@5?)YxmvW{H9&itfS1VFYhY*Qrf*wJIXb;6xT!R*k$yCb!{o<g3FvF
zw(+<74}K*4z)jA~>Cs3#V=uB4NN#U`sakZFU2HEI?ks7Dsq&ROrak#AvEH|GYk~cN
z-oYbXaZQ|4jDps_<5wf<yeb%ZH`=7N;R>H44oN*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@B<CLA>so3?a_*Ok9NBKwB4Es(@j^U%UHht?;4%Xv
NIrrxNmNc!u{{!hMI2Hf^
literal 0
HcmV?d00001

View File

@ -1,374 +0,0 @@
From: David Bauer <mail@david-bauer.net>
Date: Tue, 10 Sep 2019 21:07:23 +0200
Subject: ipq40xx: add support for AVM FRITZ!Repeater 1200
Signed-off-by: David Bauer <mail@david-bauer.net>
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 <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/soc/qcom,tcsr.h>
+
+/ {
+ 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 = <TCSR_WIFI_GLB_CFG>;
+ };
+
+ ess_tcsr@1953000 {
+ compatible = "qcom,tcsr";
+ reg = <0x1953000 0x1000>;
+ qcom,ess-interface-select = <TCSR_ESS_PSGMII_RGMII5>;
+ };
+
+ tcsr@1957000 {
+ compatible = "qcom,tcsr";
+ reg = <0x1957000 0x100>;
+ qcom,wifi_noc_memtype_m0_m2 = <TCSR_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 = <KEY_WPS_BUTTON>;
+ };
+ };
+
+ 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 <john@phrozen.org>
--- 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 <john@phrozen.org>
+ 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 \

View File

@ -0,0 +1,646 @@
From: David Bauer <mail@david-bauer.net>
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 <mail@david-bauer.net>
(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 <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/soc/qcom,tcsr.h>
+
+/ {
+ 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_ESS_PSGMII_RGMII5>;
+ };
+
+ tcsr@1949000 {
+ compatible = "qcom,tcsr";
+ reg = <0x1949000 0x100>;
+ qcom,wifi_glb_cfg = <TCSR_WIFI_GLB_CFG>;
+ };
+
+ tcsr@1957000 {
+ compatible = "qcom,tcsr";
+ reg = <0x1957000 0x100>;
+ qcom,wifi_noc_memtype_m0_m2 = <TCSR_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 = <KEY_RESTART>;
+ };
+ };
+};
+
+&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 <mail@david-bauer.net>
+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 <mail@david-bauer.net>
+---
+ 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 <john@phrozen.org>
--- 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 <john@phrozen.org>
+ 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 \

View File

@ -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

View File

@ -1,7 +1,7 @@
#!/bin/sh
check_command() {
which "$1" >/dev/null 2>&1
command -v "$1" >/dev/null
}
if check_command gnustat; then

5
scripts/lint-lua.sh Executable file
View File

@ -0,0 +1,5 @@
#!/bin/sh
set -e
luacheck package scripts targets

28
scripts/lint-sh.sh Executable file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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',
})

View File

@ -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', {

View File

@ -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',
},

View File

@ -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',
},
})

View File

@ -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',
},
})

View File

@ -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

View File

@ -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', {

View File

@ -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'},

View File

@ -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'},
})

View File

@ -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', {

View File

@ -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
})

View File

@ -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',
})

View File

@ -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