Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Christian Obersteiner 2016-02-22 19:17:52 +01:00
commit a43d6bfc6e
182 changed files with 17467 additions and 7247 deletions

View File

@ -1,5 +1,5 @@
The code of Project Gluon may be distributed under the following terms, unless The code of Project Gluon may be distributed under the following terms, unless
noted otherwise in indiviual files or subtrees. noted otherwise in individual files or subtrees.
Copyright (c) 2013, Project Gluon Copyright (c) 2013, Project Gluon
All rights reserved. All rights reserved.
@ -25,7 +25,7 @@ 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. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
OpenWRT is licensed under the terms of the GNU General Public License Version 2, OpenWrt is licensed under the terms of the GNU General Public License Version 2,
which can be found under openwrt/LICENSE after the openwrt submodule has been which can be found under openwrt/LICENSE after the openwrt submodule has been
obtained. This applies to the following submodules: obtained. This applies to the following submodules:
* openwrt * openwrt

View File

@ -177,6 +177,9 @@ GLUON_$(1)_MODEL_$(2)_ALIASES += $(3)
endef endef
export SHA512SUM := $(GLUONDIR)/scripts/sha512sum.sh
prereq: FORCE prereq: FORCE
+$(NO_TRACE_MAKE) prereq +$(NO_TRACE_MAKE) prereq
@ -209,7 +212,12 @@ gluon-tools: FORCE
+$(GLUONMAKE_EARLY) package/lua/host/install package/usign/host/install +$(GLUONMAKE_EARLY) package/lua/host/install package/usign/host/install
early_prepared_stamp := $(GLUON_BUILDDIR)/prepared
early_prepared_stamp := $(GLUON_BUILDDIR)/prepared_$(shell \
( \
$(SHA512SUM) $(GLUONDIR)/modules; \
[ ! -r $(GLUON_SITEDIR)/modules ] || $(SHA512SUM) $(GLUON_SITEDIR)/modules \
) | $(SHA512SUM) )
prepare-early: FORCE prepare-early: FORCE
for dir in build_dir dl staging_dir; do \ for dir in build_dir dl staging_dir; do \
@ -223,11 +231,12 @@ prepare-early: FORCE
touch $(early_prepared_stamp) touch $(early_prepared_stamp)
$(early_prepared_stamp): $(early_prepared_stamp):
rm -f $(GLUON_BUILDDIR)/prepared_*
+$(GLUONMAKE_EARLY) prepare-early +$(GLUONMAKE_EARLY) prepare-early
$(GLUON_OPKG_KEY): $(early_prepared_stamp) FORCE $(GLUON_OPKG_KEY): $(early_prepared_stamp) FORCE
[ -s $(GLUON_OPKG_KEY) -a -s $(GLUON_OPKG_KEY).pub ] || \ [ -s $(GLUON_OPKG_KEY) -a -s $(GLUON_OPKG_KEY).pub ] || \
mkdir -p $$(dirname $(GLUON_OPKG_KEY)) && $(STAGING_DIR_HOST)/bin/usign -G -s $(GLUON_OPKG_KEY) -p $(GLUON_OPKG_KEY).pub -c "Gluon opkg key" ( mkdir -p $$(dirname $(GLUON_OPKG_KEY)) && $(STAGING_DIR_HOST)/bin/usign -G -s $(GLUON_OPKG_KEY) -p $(GLUON_OPKG_KEY).pub -c "Gluon opkg key" )
$(GLUON_OPKG_KEY).pub: $(GLUON_OPKG_KEY) $(GLUON_OPKG_KEY).pub: $(GLUON_OPKG_KEY)
@ -253,8 +262,9 @@ MODULE_PREFIX = gluon-$(GLUON_SITE_CODE)-$(PREPARED_RELEASE)
include $(INCLUDE_DIR)/target.mk include $(INCLUDE_DIR)/target.mk
build-key: FORCE build-key: FORCE
ln -sf $(GLUON_OPKG_KEY) $(BUILD_KEY) rm -f $(BUILD_KEY) $(BUILD_KEY).pub
ln -sf $(GLUON_OPKG_KEY).pub $(BUILD_KEY).pub cp $(GLUON_OPKG_KEY) $(BUILD_KEY)
cp $(GLUON_OPKG_KEY).pub $(BUILD_KEY).pub
config: FORCE config: FORCE
+$(NO_TRACE_MAKE) scripts/config/conf OPENWRT_BUILD= QUIET=0 +$(NO_TRACE_MAKE) scripts/config/conf OPENWRT_BUILD= QUIET=0
@ -304,9 +314,6 @@ clean: FORCE
rm -f $(gluon_prepared_stamp) rm -f $(gluon_prepared_stamp)
export SHA512SUM := $(GLUONDIR)/scripts/sha512sum.sh
download: FORCE download: FORCE
+$(SUBMAKE) tools/download +$(SUBMAKE) tools/download
+$(SUBMAKE) toolchain/download +$(SUBMAKE) toolchain/download
@ -331,7 +338,7 @@ prepare-image: FORCE
+$(SUBMAKE) -C $(TOPDIR)/target/linux/$(BOARD)/image image_prepare KDIR="$(BOARD_KDIR)" +$(SUBMAKE) -C $(TOPDIR)/target/linux/$(BOARD)/image image_prepare KDIR="$(BOARD_KDIR)"
prepare: FORCE prepare: FORCE
@$(STAGING_DIR_HOST)/bin/lua $(GLUONDIR)/package/gluon-core/files/usr/lib/lua/gluon/site_config.lua \ @$(STAGING_DIR_HOST)/bin/lua $(GLUONDIR)/scripts/site_config.lua \
|| (echo 'Your site configuration did not pass validation.'; false) || (echo 'Your site configuration did not pass validation.'; false)
mkdir -p $(GLUON_IMAGEDIR) $(BOARD_BUILDDIR) mkdir -p $(GLUON_IMAGEDIR) $(BOARD_BUILDDIR)

View File

@ -1,5 +1,5 @@
Documentation (incomplete at this time, contribute if you can!) may be found at Documentation (incomplete at this time, contribute if you can!) may be found at
http://gluon.readthedocs.org/ http://gluon.readthedocs.org/.
If you're new to Gluon and ready to get your feet wet, have a look at the If you're new to Gluon and ready to get your feet wet, have a look at the
[Getting Started Guide](http://gluon.readthedocs.org/en/latest/user/getting_started.html). [Getting Started Guide](http://gluon.readthedocs.org/en/latest/user/getting_started.html).
@ -8,15 +8,15 @@ If you're new to Gluon and ready to get your feet wet, have a look at the
## Issues & Feature requests ## Issues & Feature requests
Before opening an issue make sure to read check whether any existing issues Before opening an issue, make sure to check whether any existing issues
(open or closed) match. If you're suggesting a new feature, drop by on IRC or (open or closed) match. If you're suggesting a new feature, drop by on IRC or
our mailinglist to discuss it first. our mailinglist to discuss it first.
## Use a release! ## Use a release!
Please refrain from using the master branch for anything else but development purposes! Please refrain from using the `master` branch for anything else but development purposes!
Use the most recent release instead. You can list all relaseses by running `git branch -a` Use the most recent release instead. You can list all relaseses by running `git branch -a`
and switch to one by running `git checkout v2015.1 && make update`. and switch to one by running `git checkout v2016.1 && make update`.
If you're using the autoupdater, do not autoupdate nodes with anything but releases. 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. If you upgrade using random master commits the nodes *will break* eventually.

View File

@ -1,6 +1,8 @@
#!/bin/sh #!/bin/sh
if [ $# -eq 0 -o "-h" = "$1" -o "-help" = "$1" -o "--help" = "$1" ]; then set -e
if [ $# -ne 2 -o "-h" = "$1" -o "--help" = "$1" -o ! -r "$1" -o ! -r "$2" ]; then
cat <<EOHELP cat <<EOHELP
Usage: $0 <secret> <manifest> Usage: $0 <secret> <manifest>
@ -25,16 +27,18 @@ manifest="$2"
upper="$(mktemp)" upper="$(mktemp)"
lower="$(mktemp)" lower="$(mktemp)"
awk "BEGIN { sep=0 } trap 'rm -f "$upper" "$lower"' EXIT
/^---\$/ { sep=1; next }
{ if(sep==0) print > \"$upper\"; awk 'BEGIN { sep=0 }
else print > \"$lower\"}" \ /^---$/ { sep=1; next }
{ if(sep==0) print > "'"$upper"'";
else print > "'"$lower"'"}' \
"$manifest" "$manifest"
ecdsasign "$upper" < "$SECRET" >> "$lower" ecdsasign "$upper" < "$SECRET" >> "$lower"
cat "$upper" > "$manifest" (
echo --- >> "$manifest" cat "$upper"
cat "$lower" >> "$manifest" echo ---
cat "$lower"
rm -f "$upper" "$lower" ) > "$manifest"

View File

@ -54,9 +54,9 @@ copyright = '2015, Project Gluon'
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '2015.1+' version = '2016.1+'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '2015.1+' release = '2016.1+'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

View File

@ -15,8 +15,8 @@ ecdsautils) can by found in the `contrib` directory. When creating the manifest,
be set on the command line, or it can be taken from the ``site.mk``. be set on the command line, or it can be taken from the ``site.mk``.
The priority defines the maximum number of days that may pass between releasing an update and installation The priority defines the maximum number of days that may pass between releasing an update and installation
of the images. The update probability with start at 0 after the release time mentioned in the manifest of the images. The update probability will start at 0 after the release time mentioned in the manifest
and then slowly rise to 1 after the number of days given by the priority has passed. and then slowly rise to 1 up to the point when the number of days given by the priority has passed.
The priority may be an integer or a decimal fraction. The priority may be an integer or a decimal fraction.
@ -59,7 +59,7 @@ The server must be available via IPv6.
Command Line Command Line
------------ ------------
These commands can be used on a node. These commands can be used on a node:
:: ::

View File

@ -1,5 +1,5 @@
Announcing Node Information Node monitoring
=========================== ===============
Gluon is capable of announcing information about each node to the mesh Gluon is capable of announcing information about each node to the mesh
and to neighbouring nodes. This allows nodes to learn each others hostname, and to neighbouring nodes. This allows nodes to learn each others hostname,
@ -8,7 +8,7 @@ IP addresses, location, software versions and various other information.
Format of collected data Format of collected data
------------------------ ------------------------
Information to be announced is currently split into two categories: Information to be announced is currently split into three categories:
nodeinfo nodeinfo
In this category (mostly) static information is collected. If In this category (mostly) static information is collected. If
@ -19,15 +19,19 @@ Information to be announced is currently split into two categories:
This category holds fast changing data, like traffic counters, uptime, This category holds fast changing data, like traffic counters, uptime,
system load or the selected gateway. system load or the selected gateway.
Both categories will have a ``node_id`` key by default. It should be used to neighbours
match data from *statistics* to *nodeinfo*. `neighbours` contains information about all neighbouring nodes of all
interfaces. This data can be used to determine the network topology.
All categories will have a ``node_id`` key. It should be used to
relate data of different catagories.
Accessing Node Information Accessing Node Information
-------------------------- --------------------------
There are two packages responsible for distribution of the information. For There are two packages responsible for distribution of the information. For
one, information is distributed across the mesh using alfred_. Information one, information is distributed across the mesh using alfred_. Information
between neighbouring nodes is exchanged using `gluon-announced`. between neighbouring nodes is exchanged using `gluon-respondd`.
.. _alfred: http://www.open-mesh.org/projects/alfred .. _alfred: http://www.open-mesh.org/projects/alfred
@ -43,8 +47,13 @@ installed. Please note that at least one alfred daemon is required to run as
.. _alfred-json: https://github.com/tcatm/alfred-json .. _alfred-json: https://github.com/tcatm/alfred-json
`nodeinfo` is distributed as alfred datatype `158`, while `statistics` uses The following datatypes are used:
`159`. Both are compressed using GZip (alfred-json can handle the decompression).
* `nodeinfo`: 158
* `statistics`: 159
* `neighbours`: 160
All data is compressed using GZip (alfred-json can handle the decompression).
In order to retrieve statistics data you could run: In order to retrieve statistics data you could run:
@ -90,18 +99,26 @@ You can find more information about alfred in its README_.
.. _README: http://www.open-mesh.org/projects/alfred/repository/revisions/master/entry/README .. _README: http://www.open-mesh.org/projects/alfred/repository/revisions/master/entry/README
gluon-announced gluon-respondd
~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~
`gluon-announced` allows querying neighbouring nodes for their `nodeinfo`. `gluon-respondd` allows querying neighbouring nodes for their information.
It is a daemon listening on the multicast address ``ff02::2:1001`` on It is a daemon listening on the multicast address ``ff02::2:1001`` on
UDP port 1001 on the bare mesh interfaces. UDP port 1001 on both the bare mesh interfaces and `br-client`. Unicast
requests are supported as well.
The supported requests are:
* ``nodeinfo``, ``statistics``, ``neighbours``: Returns the data of single category uncompressed.
* ``GET nodeinfo``, ...: Returns the data of one or multiple categories (separated by spaces)
compressed using the `deflate` algorithm (without a gzip header). The data may
be decompressed using zlib and many zlib bindings using -15 as the window size parameter.
gluon-neighbour-info gluon-neighbour-info
~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
A programm called `gluon-neighbour-info` has been developed to retrieve The programm `gluon-neighbour-info` can be used to retrieve
information from neighbours. information from other nodes.
:: ::
@ -109,55 +126,13 @@ information from neighbours.
-p 1001 -d ff02:0:0:0:0:0:2:1001 \ -p 1001 -d ff02:0:0:0:0:0:2:1001 \
-r nodeinfo -r nodeinfo
On optional timeout may be specified, e.g. `-t 5` (default: 3 seconds). An optional timeout may be specified, e.g. `-t 5` (default: 3 seconds). See
the usage information printed by ``gluon-neighbour-info -h`` for more information
about the supported arguments.
Adding a fact Adding a data provider
------------- ----------------------
To add a fact just add a file to either ``/lib/gluon/announce/nodeinfo.d/`` or To add a provider, you need to install a shared object into ``/lib/gluon/respondd``.
``/lib/gluon/announce/statistics.d/``. For more information, refer to the `respondd README <https://github.com/freifunk-gluon/packages/blob/master/net/respondd/README.md>`_
and have a look the existing providers.
The file must contain a lua script and its name will become the key for the
resulting JSON object. A simple script adding a ``hostname`` field might look
like this:
::
return uci:get_first('system', 'system', 'hostname')
The directory structure will be converted to a JSON object, i.e. you may
create subdirectories. So, if the directories look like this
::
.
├── hardware
│   └── model
├── hostname
├── network
│   └── mac
├── node_id
└── software
└── firmware
the resulting JSON would become:
::
# /lib/gluon/announce/announce.lua nodeinfo
{
"hardware" : {
"model" : "TP-Link TL-MR3420 v1"
},
"hostname" : "mr3420-test",
"network" : {
"mac" : "90:f6:52:82:06:02"
},
"node_id" : "90f652820602",
"software" : {
"firmware" : {
"base" : "gluon-v2014.2-32-ge831099",
"release" : "0.4.1+0-exp20140720"
}
}
}

View File

@ -60,6 +60,6 @@ It may be disabled by running::
done done
uci commit uci commit
Please note that this configuration has changed in Gluon v2015.2. Using Please note that this configuration has changed in Gluon v2016.1. Using
the old commands on v2015.2 will break the corresponding Export Mode the old commands on v2016.1 will break the corresponding Expert Mode
settings. settings.

View File

@ -0,0 +1,26 @@
WLAN configuration
==================
Gluon allows to configure 2.4GHz and 5GHz radios independently. The configuration
may include any or all of the three networks "client" (AP mode), "mesh" (802.11s
mode) and "ibss" (adhoc mode), which can be used simultaneously (using "mesh" and
"ibss" at same time should be avoided though as weaker hardware usually can't handle the additional
load). See :doc:`../user/site` for details on the configuration.
Upgrade behaviour
-----------------
For each of these networks, the site configuration may define a `disabled` flag (by
default, all configured networks are enabled). This flag is merely a default setting,
on upgrades the existing setting is always retained (as this setting may have been changed
by the user). This means that is is not possible to enable or disable an existing network
configurations during upgrades.
For the "mesh" and "ibss" networks, the default setting only has an effect if none
of the two has existed before. If a new configuration has been added for "mesh" or "ibss",
while the other of the two has already existed before, the enabled/disabled state of the
existing configuration will also be set for the new configuration.
This allows upgrades to change from IBSS to 11s and vice-versa while retaining the
"wireless meshing is enabled/disabled" property configured by the user regardless
of the used mode.

View File

@ -24,9 +24,10 @@ Features
features/configmode features/configmode
features/autoupdater features/autoupdater
features/wlan-configuration
features/private-wlan features/private-wlan
features/wired-mesh features/wired-mesh
features/announce features/monitoring
features/authorized-keys features/authorized-keys
features/roles features/roles
@ -50,6 +51,8 @@ Packages
:maxdepth: 1 :maxdepth: 1
package/gluon-client-bridge package/gluon-client-bridge
package/gluon-ebtables-filter-multicast
package/gluon-ebtables-filter-ra-dhcp
Releases Releases
-------- --------
@ -57,7 +60,7 @@ Releases
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
releases/v2015.2 releases/v2016.1
releases/v2015.1.2 releases/v2015.1.2
releases/v2015.1.1 releases/v2015.1.1
releases/v2015.1 releases/v2015.1
@ -79,12 +82,14 @@ ar71xx-generic
* Buffalo * Buffalo
- WZR-HP-AG300H / WZR-600DHP - WZR-HP-AG300H / WZR-600DHP
- WZR-HP-G300NH
- WZR-HP-G450H - WZR-HP-G450H
* D-Link * D-Link
- DIR-825 (B1) - DIR-505 (A1)
- DIR-615 (C1) - DIR-615 (C1)
- DIR-825 (B1)
* GL-Inet * GL-Inet
@ -103,10 +108,10 @@ ar71xx-generic
* TP-Link * TP-Link
- CPE210 (v1) - CPE210 (v1.0, v1.1)
- CPE220 (v1) - CPE220 (v1.0, v1.1)
- CPE510 (v1) - CPE510 (v1.0, v1.1)
- CPE520 (v1) - CPE520 (v1.0, v1.1)
- TL-MR3020 (v1) - TL-MR3020 (v1)
- TL-MR3040 (v1, v2) - TL-MR3040 (v1, v2)
- TL-MR3220 (v1, v2) - TL-MR3220 (v1, v2)
@ -117,32 +122,43 @@ ar71xx-generic
- TL-WA830RE (v1, v2) - TL-WA830RE (v1, v2)
- TL-WA850RE (v1) - TL-WA850RE (v1)
- TL-WA860RE (v1) - TL-WA860RE (v1)
- TL-WA901N/ND (v2, v3) - TL-WA901N/ND (v1, v2, v3)
- TL-WDR3500 (v1) - TL-WDR3500 (v1)
- TL-WDR3600 (v1) - TL-WDR3600 (v1)
- TL-WDR4300 (v1) - TL-WDR4300 (v1)
- TL-WR1043N/ND (v1, v2)
- TL-WR703N (v1) - TL-WR703N (v1)
- TL-WR710N (v1) - TL-WR710N (v1, v2)
- TL-WR740N (v1, v3, v4, v5) - TL-WR740N (v1, v3, v4, v5)
- TL-WR741N/ND (v1, v2, v4, v5) - TL-WR741N/ND (v1, v2, v4, v5)
- TL-WR743N/ND (v1, v2) - TL-WR743N/ND (v1, v2)
- TL-WR801N/ND (v1, v2)
- TL-WR841N/ND (v3, v5, v7, v8, v9, v10) - TL-WR841N/ND (v3, v5, v7, v8, v9, v10)
- TL-WR842N/ND (v1, v2) - TL-WR842N/ND (v1, v2)
- TL-WR941N/ND (v2, v3, v4, v5) - TL-WR843N/ND (v1)
- TL-WR940N (v1, v2, v3)
- TL-WR941ND (v2, v3, v4, v5, v6)
- TL-WR1043N/ND (v1, v2, v3)
- TL-WR2543N/ND (v1) - TL-WR2543N/ND (v1)
* Ubiquiti * Ubiquiti
- Bullet M2 - Air Gateway
- Nanostation M2 - Air Router
- Bullet M
- Nanostation M
- Nanostation M XW - Nanostation M XW
- Loco M XW - Loco M XW
- Picostation M2 - Picostation M
- Rocket M2 - Rocket M
- UniFi AP - UniFi AP
- UniFi AP Pro - UniFi AP Pro
- UniFi AP Outdoor - UniFi AP Outdoor
- UniFi AP Outdoor+
* Western Digital
- My Net N600
- My Net N750
ar71xx-nand ar71xx-nand
^^^^^^^^^^^ ^^^^^^^^^^^
@ -173,6 +189,20 @@ x86-kvm_guest
See also: :doc:`user/x86` See also: :doc:`user/x86`
x86-xen_domu
^^^^^^^^^^^^
* x86-xen
See also: :doc:`user/x86`
x86-64
^^^^^^
* x86-64-generic
* x86-64-virtualbox
* x86-64-vmware
See also: :doc:`user/x86`
License License
------- -------

View File

@ -0,0 +1,30 @@
gluon-ebtables-filter-multicast
===============================
The *gluon-ebtables-filter-multicast* package filters out various kinds of
non-essential multicast traffic, as this traffic often constitutes a
disproportionate burden on the mesh network. Unfortunately, this breaks many useful services
(Avahi, Bonjour chat, ...), but this seems unavoidable, as the current Avahi implementation is
optimized for small local networks and causes too much traffic in large mesh networks.
The multicast packets are filtered between the nodes' client bridge (*br-client*) and mesh
interface (*bat0*) on output.
The following packet types are considered essential and aren't filtered:
* ARP (except requests for/replies from 0.0.0.0)
* DHCP, DHCPv6
* ICMPv6 (except Echo Requests (ping) and Node Information Queries (RFC4620)
* IGMP
In addition, the following packet types are allowed to allow experimentation with
layer 3 routing protocols.
* Babel
* OSPF
* RIPng
The following packet types are also allowed:
* BitTorrent Local Peer Discovery (it seems better to have local peers for BitTorrent than sending everything through the internet)

View File

@ -0,0 +1,13 @@
gluon-ebtables-filter-ra-dhcp
=============================
The *gluon-ebtables-filter-ra-dhcp* package tries to prevent common
misconfigurations (i.e. connecting the client interface of a Gluon
node to a private network) from causing issues for either of the
networks.
The rules are the following:
* DHCP requests, DHCPv6 requests and Router Solicitations may only be sent from clients to the mesh, but aren't forwarded
from the mesh to clients
* DHCP replies, DHCPv6 replies and Router Advertisements from clients aren't forwarded to the mesh

View File

@ -1,145 +0,0 @@
Gluon 2015.2 (in development)
=============================
Added (and removed) hardware support
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
New features
~~~~~~~~~~~~
Bugfixes
~~~~~~~~
Site changes
~~~~~~~~~~~~
* ``site.conf``
- New WLAN configuration
``wifi24`` and ``wifi5`` need to be updated to a new more flexible format.
A configuration using the old format
::
{
channel = 1,
htmode = 'HT20'
ssid = 'entenhausen.freifunk.net',
mesh_ssid = 'xe:xx:xx:xx:xx:xx',
mesh_bssid = 'xe:xx:xx:xx:xx:xx',
mesh_mcast_rate = 12000,
}
would look like this in the new format::
{
channel = 1,
ap = {
ssid = 'entenhausen.freifunk.net',
},
ibss = {
ssid = 'xe:xx:xx:xx:xx:xx',
bssid = 'xe:xx:xx:xx:xx:xx',
mcast_rate = 12000,
},
}
The ``htmode`` option has been dropped, the channel width is now always set to 20MHz
(see https://github.com/freifunk-gluon/gluon/issues/487 for a discussion of this change).
In addition to the old IBSS (Adhoc) based meshing, 802.11s-based meshing can be configured
using the ``mesh`` section. Example::
{
channel = 1,
ap = {
ssid = 'entenhausen.freifunk.net',
},
mesh = {
id = 'mesh.entenhausen.freifunk.net', -- can by any string, human-readable or random
mcast_rate = 12000,
},
}
While using ``ibss`` and ``mesh`` at the same time is possible, is causes high load in
very active meshes, so it is advisable to avoid such configurations.
- Bandwidth limitation defaults
The old section ``simple_tc.mesh_vpn`` has been moved to ``fastd_mesh_vpn.bandwidth_limit`` and the ``ifname``
field isn't used anymore. What looked like this
before
::
simple_tc = {
mesh_vpn = {
ifname = 'mesh-vpn',
enabled = false,
limit_ingress = 3000,
limit_egress = 200,
}
}
needs to be changed to
::
fastd_mesh_vpn = {
-- ...
bandwidth_limit = {
enabled = false,
ingress = 3000,
egress = 200,
},
}
- opkg repository configuration
The opkg configuration has been changed to be more flexible and allow specifying custom repositories.
Example::
opkg = {
openwrt = 'http://opkg.services.ffeh/openwrt/%n/%v/%S/packages',
extra = {
modules = 'http://opkg.services.ffeh/modules/gluon-%GS-%GR/%S',
},
}
The keys of the ``extra`` table (like ``modules`` in this example) can be chosen arbitrarily.
Instead of explicitly specifying the whole URL, using patterns is recommended. The following
patterns are understood:
- ``%n`` is replaced by the OpenWrt version codename (e.g. "chaos_calmer")
- ``%v`` is replaced by the OpenWrt version number (e.g. "15.05")
- ``%S`` is replaced by the target architecture (e.g. "ar71xx/generic")
- ``%GS`` is replaced by the Gluon site code (as specified in ``site.conf``)
- ``%GV`` is replaced by the Gluon version
- ``%GR`` is replaced by the Gluon release (as specified in ``site.mk``)
* ``i18n/``
- The translations of ``gluon-config-mode:pubkey`` now have to show the fastd
public key itself if desired, making the formatting of the key and whether it is shown at
all configurable. To retain the old format, add ``<p>`` to the beginning of
your translations and append::
"</p>"
"<div class=\"the-key\">"
" # <%= hostname %>"
" <br/>"
"<%= pubkey %>"
"</div>"
Internals
~~~~~~~~~
Known Issues
~~~~~~~~~~~~

276
docs/releases/v2016.1.rst Normal file
View File

@ -0,0 +1,276 @@
Gluon 2016.1
============
Added hardware support
~~~~~~~~~~~~~~~~~~~~~~
ar71xx-generic
^^^^^^^^^^^^^^
* Buffalo
- WZR-HP-G300NH
* D-Link
- DIR-505 (A1)
* TP-Link
- CPE210/220/510/520 v1.1
- TL-WA901N/ND v1
- TL-WR710N v2
- TL-WR801N/ND v1, v2
- TL-WR841N/ND v10
- TL-WR843N/ND v1
- TL-WR940N v1, v2, v3
- TL-WR941ND v6
- TL-WR1043N/ND v3
* Ubiquiti
- airGateway
- airRouter
- UniFi AP Outdoor+
* Western Digital
- My Net N600
- My Net N750
x86-xen_domu
^^^^^^^^^^^^
New target containing the necessary drivers for use in Xen.
x86-64
^^^^^^
64bit version of `x86-generic`. The generic image can also be used in KVM with VirtIO.
New features
~~~~~~~~~~~~
Kernel module opkg repository
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
We've not been able to keep ABI compatiblity with the kernel of the official OpenWrt images.
Therefore, Gluon now generates an opkg repository with modules itself.
The repository can be found at `output/modules/` by default, the image output directory has
been moved from `images/` to `output/images/`. See the updated :doc:`../user/getting_started` guide
for information on the handling of the signing keys for this repository.
The `opkg_repo` site.conf option has been replaced to allow specifying this and other additional repositories.
New status page
^^^^^^^^^^^^^^^
The new status page provides a visually pleasing experience, and displays all important information
on a node in a clear manner. It also contains a real-time signal strength graph for all neighbouring
nodes to aid with the alignment of antennas.
802.11s mesh support
^^^^^^^^^^^^^^^^^^^^
Gluon now supports using 802.11s for its mesh links instead of IBSS (Adhoc). This will allow supporting
more WLAN hardware in the future (like Ralink/Mediatek, which don't support AP and IBSS mode simultaneously).
Note that batman-adv is still used on top of 802.11s (and 802.11s forwarding is disabled), the mesh routing protocol
provided by 802.11s is not used.
Multicast filter extension
^^^^^^^^^^^^^^^^^^^^^^^^^^
The `gluon-ebtables-filter-multicast` package has been extended to filter out multicast
ICMP and ICMPv6 Echo Requests (ping) and Node Information Queries (RFC4620). This prevents
pings to multicast addresses like ff02::1 to cause traffic peaks
(as all nodes and clients would answer such a ping).
French translation
^^^^^^^^^^^^^^^^^^
A French translation for the Config Mode/Expert Mode has been added.
Bugfixes
~~~~~~~~
* Update kernel code for the QCA953x
Might improve stability of the TP-Link TL-WR841N/ND v9.
* Fix model detection on some Netgear WNDR3700v2
The broken devices will identify as "NETGEAR ".
This also breaks the autoupdater, making a manual upgrade necessary.
* Ensure that `odhcp6c` doesn't spawn multiple instances of ``dhcpv6.script``
* Fix support for Buffalo WZR-600DHP
A flashable factory image is generated now. The sysupgrade image is still shared
with the WZR-HP-AG300H.
Site changes
~~~~~~~~~~~~
* ``site.conf``
- New WLAN configuration
``wifi24`` and ``wifi5`` need to be updated to a new more flexible format.
A configuration using the old format
::
{
channel = 1,
htmode = 'HT20'
ssid = 'entenhausen.freifunk.net',
mesh_ssid = 'xe:xx:xx:xx:xx:xx',
mesh_bssid = 'xe:xx:xx:xx:xx:xx',
mesh_mcast_rate = 12000,
}
would look like this in the new format::
{
channel = 1,
ap = {
ssid = 'entenhausen.freifunk.net',
},
ibss = {
ssid = 'xe:xx:xx:xx:xx:xx',
bssid = 'xe:xx:xx:xx:xx:xx',
mcast_rate = 12000,
},
}
The ``htmode`` option has been dropped, the channel width is now always set to 20MHz
(see https://github.com/freifunk-gluon/gluon/issues/487 for a discussion of this change).
In addition to the old IBSS (Adhoc) based meshing, 802.11s-based meshing can be configured
using the ``mesh`` section. Example::
{
channel = 1,
ap = {
ssid = 'entenhausen.freifunk.net',
},
mesh = {
id = 'mesh.entenhausen.freifunk.net', -- can by any string, human-readable or random
mcast_rate = 12000,
},
}
While using ``ibss`` and ``mesh`` at the same time is possible, is causes high load in
very active meshes, so it is advisable to avoid such configurations.
- Bandwidth limitation defaults
The old section ``simple_tc.mesh_vpn`` has been moved to ``fastd_mesh_vpn.bandwidth_limit`` and the ``ifname``
field isn't used anymore. What looked like this
before
::
simple_tc = {
mesh_vpn = {
ifname = 'mesh-vpn',
enabled = false,
limit_ingress = 3000,
limit_egress = 200,
}
}
needs to be changed to
::
fastd_mesh_vpn = {
-- ...
bandwidth_limit = {
enabled = false,
ingress = 3000,
egress = 200,
},
}
- opkg repository configuration
The opkg configuration has been changed to be more flexible and allow specifying custom repositories.
Example::
opkg = {
openwrt = 'http://opkg.services.ffeh/openwrt/%n/%v/%S/packages',
extra = {
modules = 'http://opkg.services.ffeh/modules/gluon-%GS-%GR/%S',
},
}
The keys of the ``extra`` table (like ``modules`` in this example) can be chosen arbitrarily.
Instead of explicitly specifying the whole URL, using patterns is recommended. The following
patterns are understood:
- ``%n`` is replaced by the OpenWrt version codename (e.g. "chaos_calmer")
- ``%v`` is replaced by the OpenWrt version number (e.g. "15.05")
- ``%S`` is replaced by the target architecture (e.g. "ar71xx/generic")
- ``%GS`` is replaced by the Gluon site code (as specified in ``site.conf``)
- ``%GV`` is replaced by the Gluon version
- ``%GR`` is replaced by the Gluon release (as specified in ``site.mk``)
* ``site.mk``
- The packages `gluon-announce` and `gluon-announced` were merged into
the package `gluon-respondd`. If you had any of them (probably
`gluon-announced`) in your package list, you have to replace them.
* ``i18n/``
- The translations of ``gluon-config-mode:pubkey`` now have to show the fastd
public key themselves if desired, making the formatting of the key and whether it is shown at
all configurable. To retain the old format, add ``<p>`` to the beginning of
your translations and append::
"</p>"
"<div class=\"the-key\">"
" # <%= hostname %>"
" <br/>"
"<%= pubkey %>"
"</div>"
Internals
~~~~~~~~~
* OpenWrt has been updated to Chaos Calmer
* mac80211 has been backported from OpenWrt trunk r47249 (wireless-testing 2015-07-21)
This allows us to support the TL-WR940N v3/TL-WR941ND v6, which uses a TP9343 (QCA956x) SoC.
* Several packages have been moved from the Gluon repo to the packages repo, removing references to Gluon:
- gluon-cron -> micrond (the crontabs are now read from ``/usr/lib/micron.d`` instead of ``/lib/gluon/cron``)
- gluon-radvd -> uradvd
- gluon-simple-tc -> simple-tc (the config file has been renamed as well)
* Some of the Gluon-specific i18n support code in the build system has been removed, as LuCI now provides
similar facilities
* The C-based `luci-lib-jsonc` library is now used for JSON encoding/decoding instead of the pure Lua `luci-lib-json`
* The site config is now stored as JSON on the node. The Lua interface ``gluon.site_config`` is still available, and a C interface was added as part of the new package `libgluonutil`.
* The `respondd` daemon now uses C modules instead of Lua snippets, which greatly enhances response speed and reduces memory usage. The Gluon integration package has
been renamed from `gluon-announced` to `gluon-respondd`.
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 Expert Mode is recommended.
* batman-adv causes stability issues for both alfred and respondd/announced (`#177 <https://github.com/freifunk-gluon/gluon/issues/177>`_)
* 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 promicious mode is disallowed).
* Inconsistent respondd/announced API (`#522 <https://github.com/freifunk-gluon/gluon/issues/522>`_)
The current API is inconsistent and will be replaced in the next release. The old API will still be supported for a while.

View File

@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"PO-Revision-Date: 2015-03-19 20:28+0100\n" "PO-Revision-Date: 2016-02-04 14:28+0100\n"
"Last-Translator: Matthias Schiffer <mschiffer@universe-factory.net>\n" "Last-Translator: David Lutz <kpanic@hirnduenger.de>\n"
"Language-Team: English\n" "Language-Team: English\n"
"Language: en\n" "Language: en\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@ -12,15 +12,15 @@ msgstr ""
msgid "gluon-config-mode:welcome" msgid "gluon-config-mode:welcome"
msgstr "" msgstr ""
"Welcome the the setup wizard of your new Freifunk Duckburg node. " "Welcome to the setup wizard of your new Freifunk Duckburg node. "
"Please fill out the following form and transmit it." "Please fill out the following form and submit it."
msgid "gluon-config-mode:pubkey" msgid "gluon-config-mode:pubkey"
msgstr "" msgstr ""
"<p>This is your Freifunk node's public key. The node won't be able to " "<p>This is your Freifunk node's public key. The node won't be able to "
"connect to the mesh VPN until the key has been registered on the Freifunk " "connect to the mesh VPN until the key has been registered on the Freifunk "
"Duckburg servers. " "Duckburg servers. "
"To register the key send it together with your node's name (<em><%=hostname%></em>) to " "To register, send the key together with your node's name (<em><%=hostname%></em>) to "
"<a href=\"mailto:keys@entenhausen.freifunk.net\">keys@entenhausen.freifunk.net</a>." "<a href=\"mailto:keys@entenhausen.freifunk.net\">keys@entenhausen.freifunk.net</a>."
"</p>" "</p>"
"<div class=\"the-key\">" "<div class=\"the-key\">"
@ -33,10 +33,10 @@ msgstr ""
msgid "gluon-config-mode:reboot" msgid "gluon-config-mode:reboot"
msgstr "" msgstr ""
"<p>The node is currently rebooting and will try to connect to other " "<p>The node is currently rebooting and will try to connect to other "
"nearby Freifunk nodes after that. " "nearby Freifunk nodes after that. "
"Your can find lots of information on the Freifunk Duckburg community on " "For more information on the Freifunk Duckburg community, have a look at "
"<a href=\"https://entenhausen.freifunk.net/\">our homepage</a>.</p>" "<a href=\"https://entenhausen.freifunk.net/\">our homepage</a>.</p>"
"<p>To get back to this configuration interface, press the reset button for " "<p>To get back to this configuration interface, press the reset button for "
"3 seconds during normal operation. The device will then reboot into config " "3 seconds during normal operation. The device will then reboot into config "
"mode.</p>" "mode.</p>"
"<p>Have fun with your node and exploring the Freifunk network!</p>" "<p>Have fun with your node and exploring of the Freifunk network!</p>"

View File

@ -1,4 +1,4 @@
-- This is an example site configuration for Gluon v2015.1+ -- This is an example site configuration for Gluon v2016.1+
-- --
-- Take a look at the documentation located at -- Take a look at the documentation located at
-- http://gluon.readthedocs.org/ for details. -- http://gluon.readthedocs.org/ for details.

View File

@ -7,7 +7,7 @@
GLUON_SITE_PACKAGES := \ GLUON_SITE_PACKAGES := \
gluon-mesh-batman-adv-15 \ gluon-mesh-batman-adv-15 \
gluon-alfred \ gluon-alfred \
gluon-announced \ gluon-respondd \
gluon-autoupdater \ gluon-autoupdater \
gluon-config-mode-autoupdater \ gluon-config-mode-autoupdater \
gluon-config-mode-contact-info \ gluon-config-mode-contact-info \

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. 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, Take a look at the `list of gluon releases`_ and notice the latest release,
e.g. *v2014.3*. Always get Gluon using git and don't try to download it e.g. *v2016.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. 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 Please keep in mind that there is no "default Gluon" build; a site configuration
@ -42,7 +42,7 @@ Building the images
------------------- -------------------
To build Gluon, first check out the repository. Replace *RELEASE* with the To build Gluon, first check out the repository. Replace *RELEASE* with the
version you'd like to checkout, e.g. *v2015.1*. version you'd like to checkout, e.g. *v2016.1*.
:: ::
@ -90,12 +90,21 @@ In case of errors read the messages carefully and try to fix the stated issues (
``ar71xx-generic`` is the most common target and will generate images for most of the supported hardware. ``ar71xx-generic`` is the most common target and will generate images for most of the supported hardware.
To see a complete list of supported targets, call ``make`` without setting ``GLUON_TARGET``. To see a complete list of supported targets, call ``make`` without setting ``GLUON_TARGET``.
The built images can be found in the directory `output/images`. Of these, the factory You should reserve about 10GB of disk space for each `GLUON_TARGET`.
The built images can be found in the directory `output/images`. Of these, the `factory`
images are to be used when flashing from the original firmware a device came with, images are to be used when flashing from the original firmware a device came with,
and sysupgrade is to upgrade from other versions of Gluon or any other OpenWRT-based and `sysupgrade` is to upgrade from other versions of Gluon or any other OpenWrt-based
system. system.
You should reserve about 10GB of disk space for each `GLUON_TARGET`. **Note:** The images for some models are identical; to save disk space, symlinks are generated instead
of multiple copies of the same image. If your webserver's configuration prohibits following
symlinks, you can use the following command to resolve these links while copying the images::
cp -rL output/images /var/www
Cleaning the build tree
.......................
There are two levels of `make clean`:: There are two levels of `make clean`::

View File

@ -95,14 +95,16 @@ wifi24 : optional
This will only affect new installations. This will only affect new installations.
Upgrades will not changed the disabled state. Upgrades will not changed the disabled state.
``ap`` requires a single parameter, a string, named ``ssid`` which sets the interface's ESSID. ``ap`` requires a single parameter, a string, named ``ssid`` which sets the
interface's ESSID.
``mesh`` requires a single parameter, a string, named ``id`` which sets the mesh id. ``mesh`` requires a single parameter, a string, named ``id`` which sets the mesh id.
``ibss`` requires two parametersr: ``ssid`` (a string) and ``bssid`` (a MAC). ``ibss`` requires two parametersr: ``ssid`` (a string) and ``bssid`` (a MAC).
An optional parameter ``vlan`` (integer) is supported. An optional parameter ``vlan`` (integer) is supported.
Both ``mesh`` and ``ibss`` accept an optional ``mcast_rate`` (kbit/s) parameter for setting the default multicast datarate. Both ``mesh`` and ``ibss`` accept an optional ``mcast_rate`` (kbit/s) parameter for
setting the default multicast datarate.
:: ::
wifi24 = { wifi24 = {
@ -156,10 +158,10 @@ fastd_mesh_vpn
The `enabled` option can be set to true to enable the VPN by default. The `enabled` option can be set to true to enable the VPN by default.
If `configurable` is `false` or unset, the method list will be replaced on updates If `configurable` is set to `false` or unset, the method list will be replaced on updates
with the list in the site configuration. Setting `configurable` to `true` will allow the user to with the list from the site configuration. Setting `configurable` to `true` will allow the user to
add the method ``null`` to the front of the method list or remove ``null`` from it, add the method ``null`` to the beginning of the method list or remove ``null`` from it,
and make this change survive updates. Settings configurable is necessary for the and make this change survive updates. Setting `configurable` is necessary for the
package `gluon-luci-mesh-vpn-fastd`, which adds a UI for this configuration. package `gluon-luci-mesh-vpn-fastd`, which adds a UI for this configuration.
In any case, the ``null`` method should always be the first method in the list In any case, the ``null`` method should always be the first method in the list
@ -169,19 +171,41 @@ fastd_mesh_vpn
fastd_mesh_vpn = { fastd_mesh_vpn = {
methods = {'salsa2012+umac'}, methods = {'salsa2012+umac'},
-- enabled = true, -- enabled = true,
-- configurable = true, -- configurable = true,
mtu = 1280, mtu = 1280,
groups = { groups = {
backbone = { backbone = {
-- Limit number of connected peers from this group
limit = 1, limit = 1,
peers = { peers = {
peer1 = { peer1 = {
key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
remotes = {'ipv4 "vpn1.entenhausen.freifunk.net" port 10000'}, -- Having multiple domains prevents SPOF in freifunk.net
remotes = {
'ipv4 "vpn1.entenhausen.freifunk.net" port 10000',
'ipv4 "vpn1.entenhausener-freifunk.de" port 10000',
},
}, },
} peer2 = {
} key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
-- You can also omit the ipv4 to allow both connection via ipv4 and ipv6
remotes = {'"vpn2.entenhausen.freifunk.net" port 10000'},
},
},
-- Optional: nested peer groups
-- groups = {
-- lowend_backbone = {
-- limit = 1,
-- peers = ...
-- },
-- },
},
-- Optional: additional peer groups, possibly with other limits
-- peertopeer = {
-- limit = 10,
-- peers = { ... },
-- },
}, },
bandwidth_limit = { bandwidth_limit = {
@ -207,14 +231,15 @@ autoupdater : package
:: ::
autoupdater = { autoupdater = {
branch = 'experimental', branch = 'stable',
branches = { branches = {
stable = { stable = {
name = 'stable', name = 'stable',
mirrors = { mirrors = {
'http://[fdca:ffee:babe:1::fec1]/firmware/stable/sysupgrade/', 'http://[fdca:ffee:babe:1::fec1]/firmware/stable/sysupgrade/',
'http://[fdca:ffee:babe:1::fec2]/firmware/stable/sysupgrade/', 'http://autoupdate.entenhausen.freifunk.net/firmware/stable/sysupgrade/',
}, },
-- Number of good signatures required
good_signatures = 2, good_signatures = 2,
pubkeys = { pubkeys = {
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', -- someguy 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', -- someguy
@ -225,9 +250,9 @@ autoupdater : package
} }
roles : optional roles : optional
Optional role definitions. With this nodes will announce their role inside the mesh. Optional role definitions. Nodes will announce their role inside the mesh.
In the backend this adds the facility to distinguish between normal, backbone and This will allow in the backend to distinguish between normal, backbone and
service nodes or even gateways (if they advertise the role, also). It is up to service nodes or even gateways (if they advertise that role). It is up to
the community which roles to define. See the section below as an example. the community which roles to define. See the section below as an example.
``default`` takes the default role which is set initially. This value should be ``default`` takes the default role which is set initially. This value should be
part of ``list``. If you want node owners to change the role via config mode add part of ``list``. If you want node owners to change the role via config mode add
@ -279,7 +304,7 @@ The ``site.mk`` is a Makefile which should define constants
involved in the build process of Gluon. involved in the build process of Gluon.
GLUON_SITE_PACKAGES GLUON_SITE_PACKAGES
Defines a list of packages which should installed in addition Defines a list of packages which should be installed additionally
to the ``gluon-core`` package. to the ``gluon-core`` package.
GLUON_RELEASE GLUON_RELEASE
@ -290,7 +315,7 @@ GLUON_PRIORITY
for more information). for more information).
GLUON_LANGS GLUON_LANGS
List of languages (as two-letter-codes) to include for the web interface. Should always contain List of languages (as two-letter-codes) to be included in the web interface. Should always contain
``en``. ``en``.
.. _site-config-mode-texts: .. _site-config-mode-texts:
@ -362,6 +387,7 @@ site-repos in the wild
This is a non-exhaustive list of site-repos from various communities: This is a non-exhaustive list of site-repos from various communities:
* `site-ffa <https://github.com/tecff/site-ffa>`_ (Altdorf, Landshut & Umgebung)
* `site-ffbs <https://github.com/ffbs/site-ffbs>`_ (Braunschweig) * `site-ffbs <https://github.com/ffbs/site-ffbs>`_ (Braunschweig)
* `site-ffhb <https://github.com/FreifunkBremen/gluon-site-ffhb>`_ (Bremen) * `site-ffhb <https://github.com/FreifunkBremen/gluon-site-ffhb>`_ (Bremen)
* `site-ffda <https://github.com/freifunk-darmstadt/site-ffda>`_ (Darmstadt) * `site-ffda <https://github.com/freifunk-darmstadt/site-ffda>`_ (Darmstadt)
@ -374,7 +400,7 @@ This is a non-exhaustive list of site-repos from various communities:
* `site-ffmyk <https://github.com/FreifunkMYK/site-ffmyk>`_ (Mayen-Koblenz) * `site-ffmyk <https://github.com/FreifunkMYK/site-ffmyk>`_ (Mayen-Koblenz)
* `site-ffm <https://github.com/freifunkMUC/site-ffm>`_ (München) * `site-ffm <https://github.com/freifunkMUC/site-ffm>`_ (München)
* `site-ffms <https://github.com/FreiFunkMuenster/site-ffms>`_ (Münsterland) * `site-ffms <https://github.com/FreiFunkMuenster/site-ffms>`_ (Münsterland)
* `site-ffnw <https://git.freifunk-ol.de/root/siteconf.git>`_ (Nordwest) * `site-ffnw <https://git.nordwest.freifunk.net/ffnw/siteconf/tree/master>`_ (Nordwest)
* `site-ffpb <https://git.c3pb.de/freifunk-pb/site-ffpb>`_ (Paderborn) * `site-ffpb <https://git.c3pb.de/freifunk-pb/site-ffpb>`_ (Paderborn)
* `site-ffka <https://github.com/ffka/site-ffka>`_ (Karlsruhe) * `site-ffka <https://github.com/ffka/site-ffka>`_ (Karlsruhe)
* `site-ffrl <https://github.com/ffrl/sites-ffrl>`_ (Rheinland) * `site-ffrl <https://github.com/ffrl/sites-ffrl>`_ (Rheinland)

View File

@ -2,12 +2,12 @@ x86 support
=========== ===========
Gluon can run on normal x86 systems, for example virtual machines Gluon can run on normal x86 systems, for example virtual machines
and VPN boxes. There is no WLAN support on x86 though. and VPN boxes. By default, there is no WLAN support on x86 though.
Targets Targets
^^^^^^^ ^^^^^^^
There are two targets for x86 images: The following targets for x86 images exist:
`x86-generic` `x86-generic`
Generic x86 support with many different ethernet drivers; should run on Generic x86 support with many different ethernet drivers; should run on
@ -27,3 +27,10 @@ There are two targets for x86 images:
`x86-kvm` `x86-kvm`
The `x86-kvm` image uses VirtIO as its harddisk and network driver. The `x86-kvm` image uses VirtIO as its harddisk and network driver.
`x86-xen_domu`
The `x86-xen_domu` target contains the necessary drivers for use in Xen.
`x86-64`
64bit version of `x86-generic`. Also has VirtIO support, so there's no need for an
`x86-64-kvm` target.

View File

@ -1,5 +1,6 @@
CONFIG_IMAGEOPT=y CONFIG_IMAGEOPT=y
# CONFIG_PER_FEED_REPO is not set # CONFIG_PER_FEED_REPO is not set
# CONFIG_TARGET_ROOTFS_INITRAMFS is not set
CONFIG_DEVEL=y CONFIG_DEVEL=y
CONFIG_ALL_KMODS=y CONFIG_ALL_KMODS=y
@ -17,6 +18,5 @@ CONFIG_BUSYBOX_CONFIG_FEATURE_WGET_TIMEOUT=y
CONFIG_ATH_USER_REGD=y CONFIG_ATH_USER_REGD=y
CONFIG_PACKAGE_ATH_DEBUG=y CONFIG_PACKAGE_ATH_DEBUG=y
CONFIG_ATH10K_CT_COMMUNITY_FW=y
CONFIG_LUCI_SRCDIET=y CONFIG_LUCI_SRCDIET=y

10
modules
View File

@ -1,18 +1,18 @@
GLUON_FEEDS='openwrt gluon routing luci' GLUON_FEEDS='openwrt gluon routing luci'
OPENWRT_REPO=git://git.openwrt.org/15.05/openwrt.git OPENWRT_REPO=git://git.openwrt.org/15.05/openwrt.git
OPENWRT_COMMIT=363508bcabd8e9205f5fffc8ff282439e61d618f OPENWRT_COMMIT=c698aa66043a151ac76d19849be9ee24dfd78b72
PACKAGES_OPENWRT_REPO=git://github.com/openwrt/packages.git PACKAGES_OPENWRT_REPO=git://github.com/openwrt/packages.git
PACKAGES_OPENWRT_COMMIT=f8a70fc188673d0ae8739b0a3095f7f61335fc10 PACKAGES_OPENWRT_COMMIT=9622fe984bba3a4547f48bc507ebaba7637eb2b0
PACKAGES_OPENWRT_BRANCH=for-15.05 PACKAGES_OPENWRT_BRANCH=for-15.05
PACKAGES_GLUON_REPO=git://github.com/freifunk-gluon/packages.git PACKAGES_GLUON_REPO=git://github.com/freifunk-gluon/packages.git
PACKAGES_GLUON_COMMIT=b4f04f51d53b151a45f0618eef6d89d32f52dae7 PACKAGES_GLUON_COMMIT=06f2a62b97a25ddd1b9919d084c626d42cef5489
PACKAGES_ROUTING_REPO=git://github.com/openwrt-routing/packages.git PACKAGES_ROUTING_REPO=git://github.com/openwrt-routing/packages.git
PACKAGES_ROUTING_COMMIT=ae65d4fe027592652376f8dbd3ff2ef37f5a84bc PACKAGES_ROUTING_COMMIT=2a8338559de5c4b077cde7a83f43f4700a17d5cc
PACKAGES_LUCI_REPO=git://github.com/openwrt/luci.git PACKAGES_LUCI_REPO=git://github.com/openwrt/luci.git
PACKAGES_LUCI_COMMIT=8832d534e96d3a934bd02711884371fc78a0d506 PACKAGES_LUCI_COMMIT=cdcdfd2594634804ab09dc8105e46116edce0cd6
PACKAGES_LUCI_BRANCH=for-15.05 PACKAGES_LUCI_BRANCH=for-15.05

View File

@ -11,7 +11,7 @@ include $(INCLUDE_DIR)/package.mk
define Package/gluon-alfred define Package/gluon-alfred
SECTION:=gluon SECTION:=gluon
CATEGORY:=Gluon CATEGORY:=Gluon
DEPENDS:=+gluon-core +gluon-announced +gluon-neighbour-info +micrond +alfred DEPENDS:=+gluon-core +gluon-respondd +gluon-neighbour-info +micrond +alfred
TITLE:=Configure alfred TITLE:=Configure alfred
endef endef

View File

@ -0,0 +1,6 @@
#!/bin/sh
. /lib/gluon/autoupdater/lib.sh
start_enabled alfred

View File

@ -0,0 +1,6 @@
#!/bin/sh
. /lib/gluon/autoupdater/lib.sh
stop alfred

View File

@ -1,32 +0,0 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=gluon-announce
PKG_VERSION:=1
PKG_RELEASE:=1
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)/package.mk
define Package/gluon-announce
SECTION:=gluon
CATEGORY:=Gluon
DEPENDS:=+gluon-core +luci-lib-jsonc +lua-ethtool-stats
TITLE:=Lua scripts announcing various information
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
endef
define Build/Configure
endef
define Build/Compile
endef
define Package/gluon-announce/install
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,gluon-announce))

View File

@ -1 +0,0 @@
return require('gluon.util').node_id()

View File

@ -1 +0,0 @@
return require('platform_info').get_model()

View File

@ -1,14 +0,0 @@
local n = 0
local cpus = util.readline(io.open('/sys/devices/system/cpu/online'))
for entry in cpus:gmatch('([^,]+)') do
local x, y = entry:match('(%d+)-(%d+)')
if x then
n = n + tonumber(y) - tonumber(x) + 1
else
n = n + 1
end
end
return n

View File

@ -1 +0,0 @@
return uci:get_first('system', 'system', 'hostname')

View File

@ -1 +0,0 @@
return require('gluon.sysconfig').primary_mac

View File

@ -1 +0,0 @@
return require('gluon.util').node_id()

View File

@ -1,4 +0,0 @@
return {
base = 'gluon-' .. util.readline(io.open('/lib/gluon/gluon-version')),
release = util.readline(io.open('/lib/gluon/release')),
}

View File

@ -1 +0,0 @@
return require('gluon.site_config').site_code

View File

@ -1 +0,0 @@
return tonumber(util.readline(io.open('/proc/uptime')):match('^[^ ]+ ([^ ]+)'))

View File

@ -1 +0,0 @@
return tonumber(util.readline(io.open('/proc/loadavg')):match('^([^ ]+) '))

View File

@ -1,13 +0,0 @@
local data = io.open('/proc/meminfo'):read('*a')
local fields = {}
for k, v in data:gmatch('([^\n:]+):%s*(%d+) kB') do
fields[k] = tonumber(v)
end
return {
total = fields.MemTotal,
free = fields.MemFree,
buffers = fields.Buffers,
cached = fields.Cached,
}

View File

@ -1 +0,0 @@
return require('gluon.util').node_id()

View File

@ -1,3 +0,0 @@
local running, total = util.readline(io.open('/proc/loadavg')):match('^[^ ]+ [^ ]+ [^ ]+ (%d+)/(%d+)')
return { running = tonumber(running), total = tonumber(total) }

View File

@ -1,4 +0,0 @@
local fs = require "nixio.fs"
local st = fs.statvfs("/")
return 1 - st.bfree / st.blocks

View File

@ -1 +0,0 @@
return tonumber(util.readline(io.open('/proc/uptime')):match('^([^ ]+) '))

View File

@ -1,51 +0,0 @@
#!/usr/bin/lua
module('gluon.announce', package.seeall)
fs = require 'nixio.fs'
uci = require('luci.model.uci').cursor()
util = require 'gluon.util'
local function collect_entry(entry)
if fs.stat(entry, 'type') == 'dir' then
return collect_dir(entry)
else
return loadfile(entry)
end
end
function collect_dir(dir)
local fns = {}
for entry in fs.dir(dir) do
if entry:sub(1, 1) ~= '.' then
collectgarbage()
local fn, err = collect_entry(dir .. '/' .. entry)
if fn then
fns[entry] = fn
else
io.stderr:write(err, '\n')
end
end
end
return function ()
local ret = { [{}] = true }
for k, v in pairs(fns) do
collectgarbage()
local ok, val = pcall(setfenv(v, _M))
if ok then
ret[k] = val
else
io.stderr:write(val, '\n')
end
end
collectgarbage()
return ret
end
end

View File

@ -1,32 +0,0 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=gluon-announced
PKG_VERSION:=2
PKG_RELEASE:=1
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)/package.mk
define Package/gluon-announced
SECTION:=gluon
CATEGORY:=Gluon
TITLE:=Provides node information to the network
DEPENDS:=+gluon-announce +respondd +lua-deflate
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
endef
define Build/Configure
endef
define Build/Compile
endef
define Package/gluon-announced/install
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,gluon-announced))

View File

@ -1,45 +0,0 @@
#!/bin/sh
. /usr/share/libubox/jshn.sh
. /lib/functions/service.sh
DEVLIST=/var/run/gluon-announced.devs
DAEMON=/usr/bin/respondd
ifname_to_dev () {
json_load "$(ubus call network.interface.$1 status)"
json_get_var dev device
echo "$dev"
}
restart_announced () {
SERVICE_USE_PID=1
SERVICE_WRITE_PID=1
SERVICE_DAEMONIZE=1
DEVS=$(cat $DEVLIST | while read dev iface; do echo -n " -i $dev"; done)
service_stop $DAEMON
service_start $DAEMON -g ff02::2:1001 -p 1001 -c 'return require("gluon.announced").handle_request' $DEVS
}
case "$ACTION" in
ifdown)
sed -i "/$INTERFACE/d" $DEVLIST
;;
ifup)
DEVICE="$(ifname_to_dev "$INTERFACE")"
MESH="$(cat "/sys/class/net/$DEVICE/batman_adv/mesh_iface" 2>/dev/null)"
[ "$MESH" = "bat0" -o "$INTERFACE" = "client" ] || exit 0
DEVS=$(cat $DEVLIST; echo $DEVICE $INTERFACE)
echo "$DEVS" | sort -u > $DEVLIST
restart_announced
;;
esac

View File

@ -1,18 +0,0 @@
#!/usr/bin/lua
local uci = require('luci.model.uci').cursor()
-- Allow announced port on WAN to allow resolving neighbours over mesh-on-wan
uci:section('firewall', 'rule', 'wan_announced',
{
name = 'wan_announced',
src = 'wan',
src_ip = 'fe80::/64',
dest_port = '1001',
proto = 'udp',
target = 'ACCEPT',
}
)
uci:save('firewall')
uci:commit('firewall')

View File

@ -1,50 +0,0 @@
local announce = require 'gluon.announce'
local deflate = require 'deflate'
local json = require 'luci.jsonc'
local nixio = require 'nixio'
local fs = require 'nixio.fs'
local memoize = {}
nixio.chdir('/lib/gluon/announce/')
for dir in fs.glob('*.d') do
local name = dir:sub(1, -3)
memoize[name] = announce.collect_dir(dir)
end
local function collect(type)
return memoize[type] and memoize[type]()
end
module('gluon.announced', package.seeall)
function handle_request(query)
collectgarbage()
local m = query:match('^GET ([a-z ]+)$')
local ret
if m then
local data = {}
for q in m:gmatch('([a-z]+)') do
local ok, val = pcall(collect, q)
if ok then
data[q] = val
end
end
if next(data) then
ret = deflate.compress(json.stringify(data))
end
elseif query:match('^[a-z]+$') then
local ok, data = pcall(collect, query)
if ok then
ret = json.stringify(data)
end
end
collectgarbage()
return ret
end

View File

@ -5,29 +5,28 @@ PKG_VERSION:=4
PKG_RELEASE:=$(GLUON_BRANCH) PKG_RELEASE:=$(GLUON_BRANCH)
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
PKG_BUILD_DEPENDS := respondd
include $(GLUONDIR)/include/package.mk include $(GLUONDIR)/include/package.mk
define Package/gluon-autoupdater define Package/gluon-autoupdater
SECTION:=gluon SECTION:=gluon
CATEGORY:=Gluon CATEGORY:=Gluon
DEPENDS:=+gluon-core +micrond +autoupdater DEPENDS:=+gluon-core +libgluonutil +micrond +autoupdater
TITLE:=Automatically update firmware TITLE:=Automatically update firmware
endef endef
define Build/Prepare define Build/Prepare
mkdir -p $(PKG_BUILD_DIR) mkdir -p $(PKG_BUILD_DIR)
endef $(CP) ./src/* $(PKG_BUILD_DIR)/
define Build/Configure
endef
define Build/Compile
endef endef
define Package/gluon-autoupdater/install define Package/gluon-autoupdater/install
$(CP) ./files/* $(1)/ $(CP) ./files/* $(1)/
$(INSTALL_DIR) $(1)/lib/gluon/respondd
$(CP) $(PKG_BUILD_DIR)/respondd.so $(1)/lib/gluon/respondd/autoupdater.so
if [ '$(GLUON_BRANCH)' ]; then \ if [ '$(GLUON_BRANCH)' ]; then \
$(INSTALL_DIR) $(1)/lib/gluon/autoupdater; \ $(INSTALL_DIR) $(1)/lib/gluon/autoupdater; \
echo '$(GLUON_BRANCH)' > $(1)/lib/gluon/autoupdater/default_branch; \ echo '$(GLUON_BRANCH)' > $(1)/lib/gluon/autoupdater/default_branch; \

View File

@ -1,7 +0,0 @@
local autoupdater = uci:get_all('autoupdater', 'settings')
if autoupdater then
return {
branch = autoupdater['branch'],
enabled = uci:get_bool('autoupdater', 'settings', 'enabled'),
}
end

View File

@ -0,0 +1,16 @@
# Library to be sourced by download.d/abort.d scripts
stop() {
if [ -x /etc/init.d/$1 ]; then
echo "Stopping $1..."
/etc/init.d/$1 stop
fi
}
start_enabled() {
if [ -x /etc/init.d/$1 ] && /etc/init.d/$1 enabled; then
echo "Starting $1..."
/etc/init.d/$1 start
fi
}

View File

@ -0,0 +1,9 @@
#!/bin/sh
. /lib/gluon/autoupdater/lib.sh
start_enabled cron
start_enabled haveged
start_enabled micrond
start_enabled sysntpd

View File

@ -0,0 +1,9 @@
#!/bin/sh
. /lib/gluon/autoupdater/lib.sh
stop cron
stop haveged
stop micrond
stop sysntpd

View File

@ -0,0 +1,6 @@
all: respondd.so
CFLAGS += -Wall
respondd.so: respondd.c
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -o $@ $^ $(LDLIBS) -lgluonutil -luci

View File

@ -0,0 +1,79 @@
/*
Copyright (c) 2016, 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.h>
#include <json-c/json.h>
#include <libgluonutil.h>
#include <uci.h>
#include <string.h>
static struct json_object * get_autoupdater(void) {
struct uci_context *ctx = uci_alloc_context();
ctx->flags &= ~UCI_FLAG_STRICT;
struct uci_package *p;
if (uci_load(ctx, "autoupdater", &p))
goto error;
struct uci_section *s = uci_lookup_section(ctx, p, "settings");
if (!s)
goto error;
struct json_object *ret = json_object_new_object();
json_object_object_add(ret, "branch", gluonutil_wrap_string(uci_lookup_option_string(ctx, s, "branch")));
const char *enabled = uci_lookup_option_string(ctx, s, "enabled");
json_object_object_add(ret, "enabled", json_object_new_boolean(enabled && !strcmp(enabled, "1")));
uci_free_context(ctx);
return ret;
error:
uci_free_context(ctx);
return NULL;
}
static struct json_object * respondd_provider_nodeinfo(void) {
struct json_object *ret = json_object_new_object();
struct json_object *software = json_object_new_object();
json_object_object_add(software, "autoupdater", get_autoupdater());
json_object_object_add(ret, "software", software);
return ret;
}
const struct respondd_provider_info respondd_providers[] = {
{"nodeinfo", respondd_provider_nodeinfo},
{}
};

View File

@ -12,7 +12,7 @@ define Package/gluon-core
SECTION:=gluon SECTION:=gluon
CATEGORY:=Gluon CATEGORY:=Gluon
TITLE:=Base files of Gluon TITLE:=Base files of Gluon
DEPENDS:=+gluon-site +lua-platform-info +luci-base +odhcp6c +firewall DEPENDS:=+gluon-site +libgluonutil +lua-platform-info +luci-base +luci-lib-jsonc +odhcp6c +firewall
endef endef

View File

@ -1,20 +1,26 @@
local config = os.getenv('GLUON_SITE_CONFIG') or '/lib/gluon/site.conf' local function get_site_config()
local config = '/lib/gluon/site.json'
local function loader() local json = require 'luci.jsonc'
coroutine.yield('return ') local ltn12 = require 'luci.ltn12'
coroutine.yield(io.open(config):read('*a'))
local file = assert(io.open(config))
local decoder = json.new()
ltn12.pump.all(ltn12.source.file(io.open(config)), decoder:sink())
file:close()
return assert(decoder:get())
end end
-- setfenv doesn't work with Lua 5.2 anymore, but we're using 5.1
local site_config = setfenv(assert(load(coroutine.wrap(loader), 'site.conf')), {})()
local setmetatable = setmetatable local setmetatable = setmetatable
module 'gluon.site_config' module 'gluon.site_config'
setmetatable(_M, setmetatable(_M,
{ {
__index = site_config, __index = get_site_config(),
} }
) )

View File

@ -1 +0,0 @@
rule 'MULTICAST_OUT -p IPv4 --ip-protocol icmp -j RETURN'

View File

@ -1,2 +1,5 @@
rule 'MULTICAST_OUT -p IPv6 --ip6-protocol 0 -j RETURN' -- hop-by-hop rule 'MULTICAST_OUT -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type echo-request -j DROP'
rule 'MULTICAST_OUT -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type 139 -j DROP'
rule 'MULTICAST_OUT -p IPv6 --ip6-protocol ipv6-icmp -j RETURN' rule 'MULTICAST_OUT -p IPv6 --ip6-protocol ipv6-icmp -j RETURN'
rule 'MULTICAST_OUT -p IPv6 --ip6-protocol 0 -j RETURN' -- hop-by-hop

View File

@ -44,7 +44,7 @@ if fs.access("/etc/config/dropbear") then
function keys.write(self, section, value) function keys.write(self, section, value)
if value then if value then
fs.writefile("/etc/dropbear/authorized_keys", value:gsub("\r\n", "\n")) fs.writefile("/etc/dropbear/authorized_keys", value:gsub("\r\n", "\n"):trim() .. "\n")
end end
end end

View File

@ -11,7 +11,7 @@ f.template = "admin/expertmode"
s = f:section(SimpleSection, nil, translate( s = f:section(SimpleSection, nil, translate(
'Your node can additionally extend your private network by bridging the WAN interface ' 'Your node can additionally extend your private network by bridging the WAN interface '
.. 'with a seperate WLAN. This feature is completely independent of the mesh functionality. ' .. 'with a separate WLAN. This feature is completely independent of the mesh functionality. '
.. 'Please note that the private WLAN and meshing on the WAN interface should not be enabled ' .. 'Please note that the private WLAN and meshing on the WAN interface should not be enabled '
.. 'at the same time.' .. 'at the same time.'
)) ))

View File

@ -1,12 +1,12 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"PO-Revision-Date: 2015-08-19 23:30+0100\n" "PO-Revision-Date: 2015-08-19 23:30+0100\n"
"Last-Translator:Tobias Bernot <tqbs@airmail.cc>\n" "Last-Translator:Tobias Bernot <tqbs@airmail.cc>\n"
"Language-Team: French\n" "Language-Team: French\n"
"Language: fr\n" "Language: fr\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
@ -25,6 +25,7 @@ msgid ""
"the mesh functionality. Please note that the private WLAN and meshing on the " "the mesh functionality. Please note that the private WLAN and meshing on the "
"WAN interface should not be enabled at the same time." "WAN interface should not be enabled at the same time."
msgstr "" msgstr ""
"Votre nœud peut étendre votre réseau privé en interfaçant le WAN avec un WLAN séparé. " "Votre nœud peut étendre votre réseau privé en interfaçant le WAN avec un "
"Cette fonction est complètement indépendante de les fonctions de MESH. " "WLAN séparé. Cette fonction est complètement indépendante de les fonctions "
"Il ne faut pas activer la fonction de MESH et de WLAN privé en même temps." "de MESH. Il ne faut pas activer la fonction de MESH et de WLAN privé en même "
"temps."

View File

@ -4,6 +4,7 @@ PKG_NAME:=gluon-mesh-batman-adv-core
PKG_VERSION:=1 PKG_VERSION:=1
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
PKG_BUILD_DEPENDS := respondd
include $(GLUONDIR)/include/package.mk include $(GLUONDIR)/include/package.mk
@ -11,21 +12,19 @@ define Package/gluon-mesh-batman-adv-core
SECTION:=gluon SECTION:=gluon
CATEGORY:=Gluon CATEGORY:=Gluon
TITLE:=Support for batman-adv meshing (core) TITLE:=Support for batman-adv meshing (core)
DEPENDS:=+gluon-core +gluon-client-bridge +firewall +libiwinfo-lua DEPENDS:=+gluon-core +libgluonutil +gluon-client-bridge +firewall +libiwinfo
endef endef
define Build/Prepare define Build/Prepare
mkdir -p $(PKG_BUILD_DIR) mkdir -p $(PKG_BUILD_DIR)
endef $(CP) ./src/* $(PKG_BUILD_DIR)/
define Build/Configure
endef
define Build/Compile
endef endef
define Package/gluon-mesh-batman-adv-core/install define Package/gluon-mesh-batman-adv-core/install
$(CP) ./files/* $(1)/ $(CP) ./files/* $(1)/
$(INSTALL_DIR) $(1)/lib/gluon/respondd
$(CP) $(PKG_BUILD_DIR)/respondd.so $(1)/lib/gluon/respondd/mesh-batman-adv-core.so
endef endef
define Package/gluon-mesh-batman-adv-core/postinst define Package/gluon-mesh-batman-adv-core/postinst

View File

@ -1,39 +0,0 @@
local ifname_address_cache = {}
function ifname2address(ifname)
local ifaddress
if ifname_address_cache[ifname] ~= nil then
ifaddress = ifname_address_cache[ifname]
else
ifaddress = util.readline(io.open("/sys/class/net/" .. ifname .. "/address"))
ifname_address_cache[ifname] = ifaddress
end
return ifaddress
end
function batadv()
local interfaces = {}
local list = io.lines("/sys/kernel/debug/batman_adv/bat0/originators")
for line in list do
local mac1, lastseen, tq, mac2, ifname =
line:match("^([0-9a-f:]+) +(%d+%.%d+)s +%( *(%d+)%) +([0-9a-f:]+) +%[ *(.-)%]")
if mac1 ~= nil and mac1 == mac2 then
ifaddress = ifname2address(ifname)
if interfaces[ifaddress] == nil then
interfaces[ifaddress] = { neighbours = { [{}] = true } }
end
interfaces[ifaddress].neighbours[mac1] = { tq = tonumber(tq)
, lastseen = tonumber(lastseen)
}
end
end
if next(interfaces) then
return interfaces
end
end
return batadv()

View File

@ -1,40 +0,0 @@
local batman_adv = require 'gluon.batman_adv'
local iwinfo = require 'iwinfo'
function neighbours(iface)
local stations = {}
for k, v in pairs(iface.iw.assoclist(iface.ifname)) do
stations[k:lower()] = { signal = v.signal
, noise = v.noise
, inactive = v.inactive
}
end
if next(stations) then
return stations
end
end
function interfaces()
local interfaces = {}
for ifname in batman_adv.interfaces('bat0') do
pcall(function()
local address = util.readline(io.open('/sys/class/net/' .. ifname .. '/address'))
local wifitype = iwinfo.type(ifname)
if wifitype ~= nil then
interfaces[address] = { ifname = ifname, iw = iwinfo[wifitype] }
end
end)
end
return interfaces
end
local wifi = {}
for address, iface in pairs(interfaces()) do
wifi[address] = { [{}] = true, neighbours = neighbours(iface) }
end
if next(wifi) then
return wifi
end

View File

@ -1,15 +0,0 @@
local ip = require 'luci.ip'
local bit = require 'nixio'.bit
local addresses = {}
for line in io.lines('/proc/net/if_inet6') do
local matches = { line:match('^' .. string.rep('(%x%x%x%x)', 8) .. string.rep(' %x%x', 3) .. ' (%x%x)%s+([^%s]+)$') }
-- exclude wrong interfaces and deprecated as well as tentative addresses
-- (see /include/uapi/linux/if_addr.h in linux source for flags)
if matches[10] == 'br-client' and bit.band(tonumber(matches[9], 16), 0x60) == 0 then
table.insert(addresses, ip.IPv6(string.format('%s:%s:%s:%s:%s:%s:%s:%s', unpack(matches))):string():lower())
end
end
return addresses

View File

@ -1,56 +0,0 @@
local batman_adv = require 'gluon.batman_adv'
local wireless = {}
local tunnel = {}
local other = {}
local function get_address(t, ifname)
pcall(
function()
table.insert(t, util.readline(io.open('/sys/class/net/' .. ifname .. '/address')))
end
)
end
local function file_exists(filename)
local f = io.open(filename)
if f == nil then
return false
else
f:close()
return true
end
end
local function is_wireless(ifname)
return file_exists('/sys/class/net/' .. ifname .. '/wireless')
end
local function is_tuntap(ifname)
return file_exists('/sys/class/net/' .. ifname .. '/tun_flags')
end
local function nil_table(t)
if next(t) ~= nil then
return t
else
return nil
end
end
for ifname in batman_adv.interfaces('bat0') do
if is_wireless(ifname) then
get_address(wireless, ifname)
elseif is_tuntap(ifname) then
get_address(tunnel, ifname)
else
get_address(other, ifname)
end
end
return {
wireless = nil_table(wireless),
tunnel = nil_table(tunnel),
other = nil_table(other),
[{}] = true
}

View File

@ -1,13 +0,0 @@
local batman_adv = require 'gluon.batman_adv'
local interfaces = {}
for ifname in batman_adv.interfaces('bat0') do
pcall(
function()
table.insert(interfaces, util.readline(io.open('/sys/class/net/' .. ifname .. '/address')))
end
)
end
return interfaces

View File

@ -1 +0,0 @@
return util.readline(io.open('/sys/module/batman_adv/version'))

View File

@ -1,55 +0,0 @@
local iwinfo = require 'iwinfo'
local counts = { total = 0
, wifi = 0
, wifi24 = 0
, wifi5 = 0
}
local list = io.lines("/sys/kernel/debug/batman_adv/bat0/transtable_local")
local clients = {}
for line in list do
local mac, _, flags, lastseen = line:match("^ %* ([0-9a-f:]+) *(.- )%[(.-)%] +(%d+%.%d+)")
if mac then
if not flags:match('P') then
counts.total = counts.total + 1
clients[mac:lower()] = true
if flags:match('W') then
counts.wifi = counts.wifi +1
end
end
end
end
function count_iface_stations(iface)
local wifitype = iwinfo.type(iface)
if wifitype == nil then
return
end
local freq = iwinfo[wifitype].frequency(iface)
local key
if freq >= 2400 and freq < 2500 then
key = "wifi24"
elseif freq >= 5000 and freq < 6000 then
key = "wifi5"
else
return
end
for k, v in pairs(iwinfo[wifitype].assoclist(iface)) do
if clients[k:lower()] then
counts[key] = counts[key] + 1
end
end
end
local ifaces = {}
uci:foreach("wireless", "wifi-iface", function(s)
if s.network == "client" and s.mode == "ap" then
count_iface_stations(s.ifname)
end
end)
return counts

View File

@ -1,12 +0,0 @@
local gateway = ''
for line in io.lines('/sys/kernel/debug/batman_adv/bat0/gateways') do
if line:sub(1, 3) == '=> ' then
gateway = line:sub(4, 20)
break
end
end
if gateway ~= '' then
return gateway
end

View File

@ -1,14 +0,0 @@
local ethtool = require 'ethtool_stats'
local fields = ethtool.interface_stats('bat0')
local traffic = {}
for _, class in ipairs({'rx', 'tx', 'forward', 'mgmt_rx', 'mgmt_tx'}) do
traffic[class] = {
bytes = fields[class .. '_bytes'],
packets = fields[class],
}
end
traffic['tx']['dropped'] = fields['tx_dropped']
return traffic

View File

@ -10,6 +10,7 @@ if not c:get('network', 'mesh_wan') then
{ ifname = 'br-wan' { ifname = 'br-wan'
, proto = 'batadv' , proto = 'batadv'
, mesh = 'bat0' , mesh = 'bat0'
, mesh_no_rebroadcast = '1'
, auto = site.mesh_on_wan and 1 or 0 , auto = site.mesh_on_wan and 1 or 0
}) })
end end

View File

@ -27,6 +27,7 @@ if sysconfig.lan_ifname and not uci:get('network', 'mesh_lan') then
{ ifname = sysconfig.lan_ifname { ifname = sysconfig.lan_ifname
, proto = 'batadv' , proto = 'batadv'
, mesh = 'bat0' , mesh = 'bat0'
, mesh_no_rebroadcast = '1'
, macaddr = util.generate_mac(1, 1) , macaddr = util.generate_mac(1, 1)
, auto = enable and 1 or 0 , auto = enable and 1 or 0
}) })
@ -34,4 +35,3 @@ if sysconfig.lan_ifname and not uci:get('network', 'mesh_lan') then
uci:save('network') uci:save('network')
uci:commit('network') uci:commit('network')
end end

View File

@ -0,0 +1,6 @@
all: respondd.so
CFLAGS += -Wall
respondd.so: respondd.c
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -o $@ $^ $(LDLIBS) -lgluonutil -liwinfo -luci

View File

@ -0,0 +1,604 @@
/*
Copyright (c) 2016, 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.h>
#include <iwinfo.h>
#include <json-c/json.h>
#include <libgluonutil.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 <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/ethtool.h>
#include <linux/if_addr.h>
#include <linux/sockios.h>
#define _STRINGIFY(s) #s
#define STRINGIFY(s) _STRINGIFY(s)
static struct json_object * get_addresses(void) {
FILE *f = fopen("/proc/net/if_inet6", "r");
if (!f)
return NULL;
char *line = NULL;
size_t len = 0;
struct json_object *ret = json_object_new_array();
while (getline(&line, &len, f) >= 0) {
/* IF_NAMESIZE would be enough, but adding 1 here is simpler than subtracting 1 in the format string */
char ifname[IF_NAMESIZE+1];
unsigned int flags;
struct in6_addr addr;
char buf[INET6_ADDRSTRLEN];
if (sscanf(line,
"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8
"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8
" %*2x %*2x %*2x %2x %"STRINGIFY(IF_NAMESIZE)"s",
&addr.s6_addr[0], &addr.s6_addr[1], &addr.s6_addr[2], &addr.s6_addr[3],
&addr.s6_addr[4], &addr.s6_addr[5], &addr.s6_addr[6], &addr.s6_addr[7],
&addr.s6_addr[8], &addr.s6_addr[9], &addr.s6_addr[10], &addr.s6_addr[11],
&addr.s6_addr[12], &addr.s6_addr[13], &addr.s6_addr[14], &addr.s6_addr[15],
&flags, ifname) != 18)
continue;
if (strcmp(ifname, "br-client"))
continue;
if (flags & (IFA_F_TENTATIVE|IFA_F_DEPRECATED))
continue;
inet_ntop(AF_INET6, &addr, buf, sizeof(buf));
json_object_array_add(ret, json_object_new_string(buf));
}
fclose(f);
free(line);
return ret;
}
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));
if (interface_file_exists(ifname, "wireless"))
json_object_array_add(wireless, address);
else if (interface_file_exists(ifname, "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 * get_batman_adv_compat(void) {
FILE *f = fopen("/lib/gluon/mesh-batman-adv-core/compat", "r");
if (!f)
return NULL;
struct json_object *ret = NULL;
int compat;
if (fscanf(f, "%i", &compat) == 1)
ret = json_object_new_int(compat);
fclose(f);
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", get_batman_adv_compat());
json_object_object_add(software, "batman-adv", software_batman_adv);
json_object_object_add(ret, "software", software);
return ret;
}
static void add_gateway(struct json_object *obj) {
FILE *f = fopen("/sys/kernel/debug/batman_adv/bat0/gateways", "r");
if (!f)
return;
char *line = NULL;
size_t len = 0;
while (getline(&line, &len, f) >= 0) {
char addr[18];
if (sscanf(line, "=> %17[0-9a-fA-F:]", addr) != 1)
continue;
json_object_object_add(obj, "gateway", json_object_new_string(addr));
break;
}
free(line);
fclose(f);
}
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++)
(*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 struct json_object * get_clients(void) {
size_t total = 0, wifi = 0, wifi24 = 0, wifi5 = 0;
FILE *f = fopen("/sys/kernel/debug/batman_adv/bat0/transtable_local", "r");
if (!f)
return NULL;
char *line = NULL;
size_t len = 0;
while (getline(&line, &len, f) >= 0) {
char flags[16];
if (sscanf(line, " * %*[^[] [%15[^]]]", flags) != 1)
continue;
if (strchr(flags, 'P'))
continue;
total++;
if (strchr(flags, 'W'))
wifi++;
}
free(line);
fclose(f);
count_stations(&wifi24, &wifi5);
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 struct json_object * get_batadv(void) {
FILE *f = fopen("/sys/kernel/debug/batman_adv/bat0/originators", "r");
if (!f)
return NULL;
char *line = NULL;
size_t len = 0;
struct json_object *interfaces = json_object_new_object();
while (getline(&line, &len, f) >= 0) {
char mac1[18], mac2[18];
/* IF_NAMESIZE would be enough, but adding 1 here is simpler than subtracting 1 in the format string */
char ifname[IF_NAMESIZE+1];
double lastseen;
int tq;
if (sscanf(line,
"%17[0-9a-fA-F:] %lfs ( %i ) %17[0-9a-fA-F:] [ %"STRINGIFY(IF_NAMESIZE)"[^]] ]",
mac1, &lastseen, &tq, mac2, ifname) != 5)
continue;
if (strcmp(mac1, mac2))
continue;
struct json_object *interface;
if (!json_object_object_get_ex(interfaces, ifname, &interface)) {
interface = json_object_new_object();
json_object_object_add(interfaces, ifname, interface);
}
struct json_object *obj = json_object_new_object();
json_object_object_add(obj, "tq", json_object_new_int(tq));
json_object_object_add(obj, "lastseen", json_object_new_double(lastseen));
json_object_object_add(interface, mac1, obj);
}
fclose(f);
free(line);
return ifnames2addrs(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++) {
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;
}
const struct respondd_provider_info respondd_providers[] = {
{"nodeinfo", respondd_provider_nodeinfo},
{"statistics", respondd_provider_statistics},
{"neighbours", respondd_provider_neighbours},
{}
};

View File

@ -4,6 +4,7 @@ PKG_NAME:=gluon-mesh-vpn-fastd
PKG_VERSION:=3 PKG_VERSION:=3
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
PKG_BUILD_DEPENDS := respondd
include $(GLUONDIR)/include/package.mk include $(GLUONDIR)/include/package.mk
@ -11,25 +12,19 @@ define Package/gluon-mesh-vpn-fastd
SECTION:=gluon SECTION:=gluon
CATEGORY:=Gluon CATEGORY:=Gluon
TITLE:=Support for connecting batman-adv meshes via fastd TITLE:=Support for connecting batman-adv meshes via fastd
DEPENDS:=+gluon-core gluon-mesh-batman-adv +gluon-wan-dnsmasq +fastd +iptables-mod-extra +simple-tc DEPENDS:=+gluon-core +libgluonutil gluon-mesh-batman-adv +gluon-wan-dnsmasq +fastd +iptables-mod-extra +simple-tc
endef
define Package/gluon-mesh-vpn-fastd/description
Gluon community wifi mesh firmware framework: fastd support
endef endef
define Build/Prepare define Build/Prepare
mkdir -p $(PKG_BUILD_DIR) mkdir -p $(PKG_BUILD_DIR)
endef $(CP) ./src/* $(PKG_BUILD_DIR)/
define Build/Configure
endef
define Build/Compile
endef endef
define Package/gluon-mesh-vpn-fastd/install define Package/gluon-mesh-vpn-fastd/install
$(CP) ./files/* $(1)/ $(CP) ./files/* $(1)/
$(INSTALL_DIR) $(1)/lib/gluon/respondd
$(CP) $(PKG_BUILD_DIR)/respondd.so $(1)/lib/gluon/respondd/mesh-vpn-fastd.so
endef endef
define Package/gluon-mesh-vpn-fastd/postinst define Package/gluon-mesh-vpn-fastd/postinst

View File

@ -1,5 +0,0 @@
local ret = {
enabled = uci:get('fastd', 'mesh_vpn', 'enabled') ~= 0,
version = util.readline(io.popen('exec fastd -v')):match('^[^%s]+%s+(.+)'),
}
return ret

View File

@ -1,70 +0,0 @@
local json = require 'luci.jsonc'
local ltn12 = require 'luci.ltn12'
local nixio = require 'nixio'
local site = require 'gluon.site_config'
local fastd_sock = nixio.socket('unix', 'stream')
local socket_path = uci:get('fastd', 'mesh_vpn', 'status_socket')
if not fastd_sock:connect(socket_path) then
return nil
end
local decoder = json.new()
ltn12.pump.all(ltn12.source.file(fastd_sock), decoder:sink())
local status = decoder:get()
local peer_groups
local function peer_connection(config)
local peer = status.peers[config.key]
if peer then
if peer.connection then
return {
established = peer.connection.established/1000
}
else
return function()end -- nil
end
end
end
local function peer_group(config)
local ret = {}
if config.peers then
local peers = {}
for peername, peerconfig in pairs(config.peers) do
peers[peername] = peer_connection(peerconfig)
end
if next(peers) then
ret.peers = peers
end
end
ret.groups = peer_groups(config.groups)
if next(ret) then
return ret
end
end
function peer_groups(groups)
if groups then
local ret = {}
for name, group in pairs(groups) do
ret[name] = peer_group(group)
end
if next(ret) then
return ret
end
end
end
return peer_group(site.fastd_mesh_vpn)

View File

@ -0,0 +1,6 @@
all: respondd.so
CFLAGS += -Wall
respondd.so: respondd.c
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -o $@ $^ $(LDLIBS) -lgluonutil -luci

View File

@ -0,0 +1,305 @@
/*
Copyright (c) 2016, 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.h>
#include <json-c/json.h>
#include <libgluonutil.h>
#include <uci.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
static struct json_object * get_peer_groups(struct json_object *groups, struct json_object *peers);
static struct json_object * get_fastd_version(void) {
FILE *f = popen("exec fastd -v", "r");
if (!f)
return NULL;
char *line = NULL;
size_t len = 0;
ssize_t r = getline(&line, &len, f);
pclose(f);
if (r >= 0) {
len = strlen(line); /* The len given by getline is the buffer size, not the string length */
if (len && line[len-1] == '\n')
line[len-1] = 0;
}
else {
free(line);
line = NULL;
}
const char *version = line;
if (strncmp(version, "fastd ", 6) == 0)
version += 6;
struct json_object *ret = gluonutil_wrap_string(version);
free(line);
return ret;
}
static struct json_object * get_fastd(void) {
bool enabled = false;
struct uci_context *ctx = uci_alloc_context();
ctx->flags &= ~UCI_FLAG_STRICT;
struct uci_package *p;
if (uci_load(ctx, "fastd", &p))
goto disabled;
struct uci_section *s = uci_lookup_section(ctx, p, "mesh_vpn");
if (!s)
goto disabled;
const char *enabled_str = uci_lookup_option_string(ctx, s, "enabled");
if (!enabled_str || !strcmp(enabled_str, "1"))
enabled = true;
disabled:
uci_free_context(ctx);
struct json_object *ret = json_object_new_object();
json_object_object_add(ret, "version", get_fastd_version());
json_object_object_add(ret, "enabled", json_object_new_boolean(enabled));
return ret;
}
static struct json_object * respondd_provider_nodeinfo(void) {
struct json_object *ret = json_object_new_object();
struct json_object *software = json_object_new_object();
json_object_object_add(software, "fastd", get_fastd());
json_object_object_add(ret, "software", software);
return ret;
}
static const char * get_status_socket(struct uci_context *ctx, struct uci_section *s) {
return uci_lookup_option_string(ctx, s, "status_socket");
}
static struct json_object * read_status(struct uci_context *ctx, struct uci_section *s) {
const char *path = get_status_socket(ctx, s);
size_t addrlen = strlen(path);
/* Allocate enough space for arbitrary-length paths */
char addrbuf[offsetof(struct sockaddr_un, sun_path) + addrlen + 1];
memset(addrbuf, 0, sizeof(addrbuf));
struct sockaddr_un *addr = (struct sockaddr_un *)addrbuf;
addr->sun_family = AF_UNIX;
memcpy(addr->sun_path, path, addrlen+1);
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0)
return NULL;
if (connect(fd, (struct sockaddr*)addr, sizeof(addrbuf)) < 0) {
close(fd);
return NULL;
}
struct json_object *ret = NULL;
struct json_tokener *tok = json_tokener_new();
do {
char buf[1024];
size_t len = read(fd, buf, sizeof(buf));
if (len <= 0)
break;
ret = json_tokener_parse_ex(tok, buf, len);
} while (!ret && json_tokener_get_error(tok) == json_tokener_continue);
json_tokener_free(tok);
close(fd);
return ret;
}
static struct json_object * get_status(void) {
struct json_object *ret = NULL;
struct uci_context *ctx = uci_alloc_context();
ctx->flags &= ~UCI_FLAG_STRICT;
struct uci_package *p;
if (!uci_load(ctx, "fastd", &p)) {
struct uci_section *s = uci_lookup_section(ctx, p, "mesh_vpn");
if (s)
ret = read_status(ctx, s);
}
uci_free_context(ctx);
return ret;
}
static bool get_peer_connection(struct json_object **ret, struct json_object *config, struct json_object *peers) {
struct json_object *key_object;
if (!json_object_object_get_ex(config, "key", &key_object))
return false;
const char *key = json_object_get_string(key_object);
if (!key)
return false;
struct json_object *peer, *connection, *established;
if (!json_object_object_get_ex(peers, key, &peer) ||
!json_object_object_get_ex(peer, "connection", &connection))
return false;
if (json_object_object_get_ex(connection, "established", &established)) {
int64_t established_time = json_object_get_int64(established);
*ret = json_object_new_object();
json_object_object_add(*ret, "established", json_object_new_double(established_time/1000.0));
}
else {
*ret = NULL;
}
return true;
}
static struct json_object * get_peer_group(struct json_object *config, struct json_object *peers) {
struct json_object *ret = json_object_new_object();
struct json_object *config_peers;
if (json_object_object_get_ex(config, "peers", &config_peers) &&
json_object_is_type(config_peers, json_type_object)) {
struct json_object *ret_peers = json_object_new_object();
json_object_object_foreach(config_peers, peername, peerconfig) {
struct json_object *obj;
if (get_peer_connection(&obj, peerconfig, peers))
json_object_object_add(ret_peers, peername, obj);
}
if (json_object_object_length(ret_peers))
json_object_object_add(ret, "peers", ret_peers);
else
json_object_put(ret_peers);
}
struct json_object *config_groups;
if (json_object_object_get_ex(config, "groups", &config_groups)) {
struct json_object *obj = get_peer_groups(config_groups, peers);
if (obj)
json_object_object_add(ret, "groups", obj);
}
if (!json_object_object_length(ret)) {
json_object_put(ret);
return NULL;
}
return ret;
}
static struct json_object * get_peer_groups(struct json_object *groups, struct json_object *peers) {
if (!json_object_is_type(groups, json_type_object))
return NULL;
struct json_object *ret = json_object_new_object();
json_object_object_foreach(groups, name, group) {
struct json_object *g = get_peer_group(group, peers);
if (g)
json_object_object_add(ret, name, g);
}
if (!json_object_object_length(ret)) {
json_object_put(ret);
return NULL;
}
return ret;
}
static struct json_object * get_mesh_vpn(void) {
struct json_object *ret = NULL;
struct json_object *status = NULL;
struct json_object *site = NULL;
status = get_status();
if (!status)
goto end;
struct json_object *peers;
if (!json_object_object_get_ex(status, "peers", &peers))
goto end;
site = gluonutil_load_site_config();
if (!site)
goto end;
struct json_object *fastd_mesh_vpn;
if (!json_object_object_get_ex(site, "fastd_mesh_vpn", &fastd_mesh_vpn))
goto end;
ret = get_peer_group(fastd_mesh_vpn, peers);
end:
json_object_put(site);
json_object_put(status);
return ret;
}
static struct json_object * respondd_provider_statistics(void) {
struct json_object *ret = json_object_new_object();
struct json_object *mesh_vpn = get_mesh_vpn();
if (mesh_vpn)
json_object_object_add(ret, "mesh_vpn", mesh_vpn);
return ret;
}
const struct respondd_provider_info respondd_providers[] = {
{"nodeinfo", respondd_provider_nodeinfo},
{"statistics", respondd_provider_statistics},
{}
};

View File

@ -32,6 +32,8 @@ define Build/Compile
endef endef
define Package/gluon-neighbour-info/install define Package/gluon-neighbour-info/install
$(CP) ./files/* $(1)/
$(INSTALL_DIR) $(1)/usr/bin $(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/gluon-neighbour-info $(1)/usr/bin/ $(INSTALL_BIN) $(PKG_BUILD_DIR)/gluon-neighbour-info $(1)/usr/bin/
endef endef

View File

@ -0,0 +1,20 @@
#!/usr/bin/lua
local uci = require('luci.model.uci').cursor()
-- Allow incoming respondd replies to queries on WAN
-- If the query was via multicast, the response isn't matched by --state RELATED
uci:section('firewall', 'rule', 'wan_respondd_reply',
{
name = 'wan_respondd_reply',
src = 'wan',
src_ip = 'fe80::/64',
src_port = '1001',
dest_port = '32768:61000', -- see /proc/sys/net/ipv4/ip_local_port_range
proto = 'udp',
target = 'ACCEPT',
}
)
uci:save('firewall')
uci:commit('firewall')

View File

@ -58,7 +58,7 @@ void getclock(struct timeval *tv) {
} }
/* Assumes a and b are normalized */ /* Assumes a and b are normalized */
void tv_subtract (struct timeval *r, struct timeval *a, struct timeval *b) { void tv_subtract (struct timeval *r, const struct timeval *a, const struct timeval *b) {
r->tv_usec = a->tv_usec - b->tv_usec; r->tv_usec = a->tv_usec - b->tv_usec;
r->tv_sec = a->tv_sec - b->tv_sec; r->tv_sec = a->tv_sec - b->tv_sec;
@ -68,18 +68,17 @@ void tv_subtract (struct timeval *r, struct timeval *a, struct timeval *b) {
} }
} }
ssize_t recvtimeout(int socket, void *buffer, size_t length, int flags, struct timeval *timeout, struct timeval *offset) { ssize_t recvtimeout(int socket, void *buffer, size_t length, int flags, const struct timeval *timeout) {
struct timeval now, delta; struct timeval now, timeout_left;
ssize_t ret;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, timeout, sizeof(*timeout));
ret = recv(socket, buffer, length, flags);
getclock(&now); getclock(&now);
tv_subtract(&delta, &now, offset); tv_subtract(&timeout_left, timeout, &now);
tv_subtract(timeout, timeout, &delta);
return ret; if (timeout_left.tv_sec < 0)
return -1;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &timeout_left, sizeof(timeout_left));
return recv(socket, buffer, length, flags);
} }
int request(const int sock, const struct sockaddr_in6 *client_addr, const char *request, const char *sse, double timeout, unsigned int max_count) { int request(const int sock, const struct sockaddr_in6 *client_addr, const char *request, const char *sse, double timeout, unsigned int max_count) {
@ -94,14 +93,18 @@ int request(const int sock, const struct sockaddr_in6 *client_addr, const char *
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
struct timeval tv_timeout, tv_offset; struct timeval tv_timeout;
tv_timeout.tv_sec = (int) timeout; getclock(&tv_timeout);
tv_timeout.tv_usec = ((int) (timeout * 1000000)) % 1000000;
getclock(&tv_offset); tv_timeout.tv_sec += (int) timeout;
tv_timeout.tv_usec += ((int) (timeout * 1000000)) % 1000000;
if (tv_timeout.tv_usec >= 1000000) {
tv_timeout.tv_usec -= 1000000;
tv_timeout.tv_sec += 1;
}
do { do {
ret = recvtimeout(sock, buffer, sizeof(buffer), 0, &tv_timeout, &tv_offset); ret = recvtimeout(sock, buffer, sizeof(buffer), 0, &tv_timeout);
if (ret < 0) if (ret < 0)
break; break;
@ -133,7 +136,6 @@ int main(int argc, char **argv) {
int sock; int sock;
struct sockaddr_in6 client_addr = {}; struct sockaddr_in6 client_addr = {};
char *request_string = NULL; char *request_string = NULL;
struct in6_addr mgroup_addr;
sock = socket(PF_INET6, SOCK_DGRAM, 0); sock = socket(PF_INET6, SOCK_DGRAM, 0);
@ -147,9 +149,7 @@ int main(int argc, char **argv) {
opterr = 0; opterr = 0;
int port_set = 0; int max_count = 0;
int destination_set = 0;
unsigned int max_count = 0;
double timeout = 3.0; double timeout = 3.0;
char *sse = NULL; char *sse = NULL;
bool loop = false; bool loop = false;
@ -179,6 +179,10 @@ int main(int argc, char **argv) {
break; break;
case 't': case 't':
timeout = atof(optarg); timeout = atof(optarg);
if (timeout < 0) {
perror("Negative timeout not supported");
exit(EXIT_FAILURE);
}
break; break;
case 's': case 's':
sse = optarg; sse = optarg;
@ -206,8 +210,10 @@ int main(int argc, char **argv) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (sse) if (sse) {
fputs("Content-Type: text/event-stream\n\n", stdout); fputs("Content-Type: text/event-stream\n\n", stdout);
fflush(stdout);
}
do { do {
ret = request(sock, &client_addr, request_string, sse, timeout, max_count); ret = request(sock, &client_addr, request_string, sse, timeout, max_count);

View File

@ -5,6 +5,7 @@ PKG_VERSION:=1
PKG_RELEASE:=1 PKG_RELEASE:=1
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
PKG_BUILD_DEPENDS := respondd
include $(GLUONDIR)/include/package.mk include $(GLUONDIR)/include/package.mk
@ -12,25 +13,19 @@ define Package/gluon-node-info
SECTION:=gluon SECTION:=gluon
CATEGORY:=Gluon CATEGORY:=Gluon
TITLE:=Add /etc/config/gluon-node-info to uci TITLE:=Add /etc/config/gluon-node-info to uci
DEPENDS:=+gluon-core DEPENDS:=+gluon-core +libgluonutil
endef
define Package/gluon-node-info/description
This packages creates /etc/config/gluon-node-info.
endef endef
define Build/Prepare define Build/Prepare
mkdir -p $(PKG_BUILD_DIR) mkdir -p $(PKG_BUILD_DIR)
endef $(CP) ./src/* $(PKG_BUILD_DIR)/
define Build/Configure
endef
define Build/Compile
endef endef
define Package/gluon-node-info/install define Package/gluon-node-info/install
$(CP) ./files/* $(1)/ $(CP) ./files/* $(1)/
$(INSTALL_DIR) $(1)/lib/gluon/respondd
$(CP) $(PKG_BUILD_DIR)/respondd.so $(1)/lib/gluon/respondd/node-info.so
endef endef
define Package/gluon-node-info/postinst define Package/gluon-node-info/postinst

View File

@ -1,7 +0,0 @@
if uci:get_first('gluon-node-info', 'location', 'share_location', false) then
return {
latitude = tonumber(uci:get_first('gluon-node-info', 'location', 'latitude')),
longitude = tonumber(uci:get_first('gluon-node-info', 'location', 'longitude')),
altitude = tonumber(uci:get_first('gluon-node-info', 'location', 'altitude')),
}
end

View File

@ -1,4 +0,0 @@
local contact = uci:get_first('gluon-node-info', 'owner', 'contact', '')
if contact ~= '' then
return { contact = contact }
end

View File

@ -1,4 +0,0 @@
local role = uci:get_first('gluon-node-info', 'system', 'role', '')
if role ~= '' then
return role
end

View File

@ -0,0 +1,6 @@
all: respondd.so
CFLAGS += -Wall
respondd.so: respondd.c
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -o $@ $^ $(LDLIBS) -lgluonutil -luci

View File

@ -0,0 +1,144 @@
/*
Copyright (c) 2016, 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.h>
#include <json-c/json.h>
#include <libgluonutil.h>
#include <uci.h>
#include <stdlib.h>
#include <string.h>
static struct uci_section * get_first_section(struct uci_package *p, const char *type) {
struct uci_element *e;
uci_foreach_element(&p->sections, e) {
struct uci_section *s = uci_to_section(e);
if (!strcmp(s->type, type))
return s;
}
return NULL;
}
static const char * get_first_option(struct uci_context *ctx, struct uci_package *p, const char *type, const char *option) {
struct uci_section *s = get_first_section(p, type);
if (s)
return uci_lookup_option_string(ctx, s, option);
else
return NULL;
}
static struct json_object * get_number(struct uci_context *ctx, struct uci_section *s, const char *name) {
const char *val = uci_lookup_option_string(ctx, s, name);
if (!val || !*val)
return NULL;
char *end;
double d = strtod(val, &end);
if (*end)
return NULL;
return json_object_new_double(d);
}
static struct json_object * get_location(struct uci_context *ctx, struct uci_package *p) {
struct uci_section *s = get_first_section(p, "location");
if (!s)
return NULL;
const char *share = uci_lookup_option_string(ctx, s, "share_location");
if (!share || strcmp(share, "1"))
return NULL;
struct json_object *ret = json_object_new_object();
struct json_object *latitude = get_number(ctx, s, "latitude");
if (latitude)
json_object_object_add(ret, "latitude", latitude);
struct json_object *longitude = get_number(ctx, s, "longitude");
if (longitude)
json_object_object_add(ret, "longitude", longitude);
struct json_object *altitude = get_number(ctx, s, "altitude");
if (altitude)
json_object_object_add(ret, "altitude", altitude);
return ret;
}
static struct json_object * get_owner(struct uci_context *ctx, struct uci_package *p) {
const char *contact = get_first_option(ctx, p, "owner", "contact");
if (!contact || !*contact)
return NULL;
struct json_object *ret = json_object_new_object();
json_object_object_add(ret, "contact", gluonutil_wrap_string(contact));
return ret;
}
static struct json_object * get_system(struct uci_context *ctx, struct uci_package *p) {
struct json_object *ret = json_object_new_object();
const char *role = get_first_option(ctx, p, "system", "role");
if (role && *role)
json_object_object_add(ret, "role", gluonutil_wrap_string(role));
return ret;
}
static struct json_object * respondd_provider_nodeinfo(void) {
struct json_object *ret = json_object_new_object();
struct uci_context *ctx = uci_alloc_context();
ctx->flags &= ~UCI_FLAG_STRICT;
struct uci_package *p;
if (!uci_load(ctx, "gluon-node-info", &p)) {
struct json_object *location = get_location(ctx, p);
if (location)
json_object_object_add(ret, "location", location);
struct json_object *owner = get_owner(ctx, p);
if (owner)
json_object_object_add(ret, "owner", owner);
json_object_object_add(ret, "system", get_system(ctx, p));
}
uci_free_context(ctx);
return ret;
}
const struct respondd_provider_info respondd_providers[] = {
{"nodeinfo", respondd_provider_nodeinfo},
{}
};

View File

@ -0,0 +1,6 @@
#!/bin/sh
. /lib/gluon/autoupdater/lib.sh
start_enabled gluon-radvd

View File

@ -0,0 +1,6 @@
#!/bin/sh
. /lib/gluon/autoupdater/lib.sh
stop gluon-radvd

View File

@ -0,0 +1,29 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=gluon-respondd
PKG_VERSION:=1
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)/package.mk
define Package/gluon-respondd
SECTION:=gluon
CATEGORY:=Gluon
TITLE:=Provides node information to the network
DEPENDS:=+gluon-core +libplatforminfo +libgluonutil +respondd
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Package/gluon-respondd/install
$(CP) ./files/* $(1)/
$(INSTALL_DIR) $(1)/lib/gluon/respondd
$(CP) $(PKG_BUILD_DIR)/respondd.so $(1)/lib/gluon/respondd/respondd.so
endef
$(eval $(call BuildPackage,gluon-respondd))

View File

@ -0,0 +1,34 @@
#!/bin/sh
. /usr/share/libubox/jshn.sh
. /lib/functions/service.sh
DEVLIST=/var/run/gluon-respondd.devs
ifname_to_dev () {
json_load "$(ubus call network.interface.$1 status)"
json_get_var dev device
echo "$dev"
}
case "$ACTION" in
ifdown)
sed "/ $INTERFACE$/d" $DEVLIST > $DEVLIST.new
mv $DEVLIST.new $DEVLIST
;;
ifup)
DEVICE="$(ifname_to_dev "$INTERFACE")"
MESH="$(cat "/sys/class/net/$DEVICE/batman_adv/mesh_iface" 2>/dev/null)"
[ "$MESH" = "bat0" -o "$INTERFACE" = "client" ] || exit 0
DEVS=$(cat $DEVLIST 2>/dev/null; echo $DEVICE $INTERFACE)
echo "$DEVS" | sort -u > $DEVLIST.new
mv $DEVLIST.new $DEVLIST
/etc/init.d/gluon-respondd restart_if_running &
;;
esac

View File

@ -0,0 +1,45 @@
#!/bin/sh /etc/rc.common
EXTRA_COMMANDS='restart_if_running'
START=50
SERVICE_WRITE_PID=1
SERVICE_DAEMONIZE=1
DEVLIST=/var/run/gluon-respondd.devs
DAEMON=/usr/bin/respondd
LOCK=/var/run/gluon-respondd.lock
do_start() {
DEVS=$(cat $DEVLIST 2>/dev/null | while read dev iface; do echo -n " -i $dev"; done)
service_start $DAEMON -g ff02::2:1001 -p 1001 -d /lib/gluon/respondd $DEVS
}
do_stop() {
service_stop $DAEMON
}
start() {
lock $LOCK
do_start
lock -u $LOCK
}
stop() {
lock $LOCK
do_stop
lock -u $LOCK
}
restart_if_running() {
lock $LOCK
if service_check $DAEMON; then
do_stop
do_start
fi
lock -u $LOCK
}

View File

@ -0,0 +1 @@
10000

View File

@ -0,0 +1 @@
300000

View File

@ -0,0 +1 @@
5000

Some files were not shown because too many files have changed in this diff Show More