Merge remote-tracking branch 'upstream/master'
This commit is contained in:
		
						commit
						a43d6bfc6e
					
				
							
								
								
									
										4
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								LICENSE
									
									
									
									
									
								
							| @ -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 | ||||||
|  | |||||||
							
								
								
									
										23
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								Makefile
									
									
									
									
									
								
							| @ -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) | ||||||
|  | |||||||
| @ -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. | ||||||
|  | |||||||
| @ -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" | ||||||
|  | |||||||
| @ -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. | ||||||
|  | |||||||
| @ -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: | ||||||
| 
 | 
 | ||||||
| :: | :: | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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" |  | ||||||
|         } |  | ||||||
|      } |  | ||||||
|   } |  | ||||||
| @ -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. | ||||||
|  | |||||||
							
								
								
									
										26
									
								
								docs/features/wlan-configuration.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								docs/features/wlan-configuration.rst
									
									
									
									
									
										Normal 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. | ||||||
| @ -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 | ||||||
| ------- | ------- | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										30
									
								
								docs/package/gluon-ebtables-filter-multicast.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								docs/package/gluon-ebtables-filter-multicast.rst
									
									
									
									
									
										Normal 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) | ||||||
							
								
								
									
										13
									
								
								docs/package/gluon-ebtables-filter-ra-dhcp.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								docs/package/gluon-ebtables-filter-ra-dhcp.rst
									
									
									
									
									
										Normal 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 | ||||||
| @ -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
									
								
							
							
						
						
									
										276
									
								
								docs/releases/v2016.1.rst
									
									
									
									
									
										Normal 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. | ||||||
| @ -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>" | ||||||
|  | |||||||
| @ -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. | ||||||
|  | |||||||
| @ -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 \
 | ||||||
|  | |||||||
| @ -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`:: | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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) | ||||||
|  | |||||||
| @ -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. | ||||||
|  | |||||||
| @ -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
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								modules
									
									
									
									
									
								
							| @ -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 | ||||||
|  | |||||||
| @ -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 | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										6
									
								
								package/gluon-alfred/files/usr/lib/autoupdater/abort.d/60gluon-alfred
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										6
									
								
								package/gluon-alfred/files/usr/lib/autoupdater/abort.d/60gluon-alfred
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | #!/bin/sh | ||||||
|  | 
 | ||||||
|  | . /lib/gluon/autoupdater/lib.sh | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | start_enabled alfred | ||||||
							
								
								
									
										6
									
								
								package/gluon-alfred/files/usr/lib/autoupdater/download.d/40gluon-alfred
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										6
									
								
								package/gluon-alfred/files/usr/lib/autoupdater/download.d/40gluon-alfred
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | #!/bin/sh | ||||||
|  | 
 | ||||||
|  | . /lib/gluon/autoupdater/lib.sh | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | stop alfred | ||||||
| @ -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)) |  | ||||||
| @ -1 +0,0 @@ | |||||||
| return require('gluon.util').node_id() |  | ||||||
| @ -1 +0,0 @@ | |||||||
| return require('platform_info').get_model() |  | ||||||
| @ -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 |  | ||||||
| @ -1 +0,0 @@ | |||||||
| return uci:get_first('system', 'system', 'hostname') |  | ||||||
| @ -1 +0,0 @@ | |||||||
| return require('gluon.sysconfig').primary_mac |  | ||||||
| @ -1 +0,0 @@ | |||||||
| return require('gluon.util').node_id() |  | ||||||
| @ -1,4 +0,0 @@ | |||||||
| return { |  | ||||||
| 	base = 'gluon-' .. util.readline(io.open('/lib/gluon/gluon-version')), |  | ||||||
| 	release = util.readline(io.open('/lib/gluon/release')), |  | ||||||
| } |  | ||||||
| @ -1 +0,0 @@ | |||||||
| return require('gluon.site_config').site_code |  | ||||||
| @ -1 +0,0 @@ | |||||||
| return tonumber(util.readline(io.open('/proc/uptime')):match('^[^ ]+ ([^ ]+)')) |  | ||||||
| @ -1 +0,0 @@ | |||||||
| return tonumber(util.readline(io.open('/proc/loadavg')):match('^([^ ]+) ')) |  | ||||||
| @ -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, |  | ||||||
| } |  | ||||||
| @ -1 +0,0 @@ | |||||||
| return require('gluon.util').node_id() |  | ||||||
| @ -1,3 +0,0 @@ | |||||||
| local running, total = util.readline(io.open('/proc/loadavg')):match('^[^ ]+ [^ ]+ [^ ]+ (%d+)/(%d+)') |  | ||||||
| 
 |  | ||||||
| return { running = tonumber(running), total = tonumber(total) } |  | ||||||
| @ -1,4 +0,0 @@ | |||||||
| local fs = require "nixio.fs" |  | ||||||
| 
 |  | ||||||
| local st = fs.statvfs("/") |  | ||||||
| return 1 - st.bfree / st.blocks |  | ||||||
| @ -1 +0,0 @@ | |||||||
| return tonumber(util.readline(io.open('/proc/uptime')):match('^([^ ]+) ')) |  | ||||||
| @ -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 |  | ||||||
| @ -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)) |  | ||||||
| @ -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 |  | ||||||
| 
 |  | ||||||
| @ -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') |  | ||||||
| @ -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 |  | ||||||
| @ -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; \
 | ||||||
|  | |||||||
| @ -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 |  | ||||||
							
								
								
									
										16
									
								
								package/gluon-autoupdater/files/lib/gluon/autoupdater/lib.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								package/gluon-autoupdater/files/lib/gluon/autoupdater/lib.sh
									
									
									
									
									
										Normal 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 | ||||||
|  | } | ||||||
| @ -0,0 +1,9 @@ | |||||||
|  | #!/bin/sh | ||||||
|  | 
 | ||||||
|  | . /lib/gluon/autoupdater/lib.sh | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | start_enabled cron | ||||||
|  | start_enabled haveged | ||||||
|  | start_enabled micrond | ||||||
|  | start_enabled sysntpd | ||||||
| @ -0,0 +1,9 @@ | |||||||
|  | #!/bin/sh | ||||||
|  | 
 | ||||||
|  | . /lib/gluon/autoupdater/lib.sh | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | stop cron | ||||||
|  | stop haveged | ||||||
|  | stop micrond | ||||||
|  | stop sysntpd | ||||||
							
								
								
									
										6
									
								
								package/gluon-autoupdater/src/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								package/gluon-autoupdater/src/Makefile
									
									
									
									
									
										Normal 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 | ||||||
							
								
								
									
										79
									
								
								package/gluon-autoupdater/src/respondd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								package/gluon-autoupdater/src/respondd.c
									
									
									
									
									
										Normal 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}, | ||||||
|  | 	{} | ||||||
|  | }; | ||||||
| @ -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 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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(), | ||||||
| 	} | 	} | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1 +0,0 @@ | |||||||
| rule 'MULTICAST_OUT -p IPv4 --ip-protocol icmp -j RETURN' |  | ||||||
| @ -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 | ||||||
|  | |||||||
| @ -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 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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.' | ||||||
| )) | )) | ||||||
|  | |||||||
| @ -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." | ||||||
|  | |||||||
| @ -1 +0,0 @@ | |||||||
| return 14 |  | ||||||
| @ -0,0 +1 @@ | |||||||
|  | 14 | ||||||
| @ -1 +0,0 @@ | |||||||
| return 15 |  | ||||||
| @ -0,0 +1 @@ | |||||||
|  | 15 | ||||||
| @ -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 | ||||||
|  | |||||||
| @ -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() |  | ||||||
| @ -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 |  | ||||||
| @ -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 |  | ||||||
| @ -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 |  | ||||||
| } |  | ||||||
| @ -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 |  | ||||||
| @ -1 +0,0 @@ | |||||||
| return util.readline(io.open('/sys/module/batman_adv/version')) |  | ||||||
| @ -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 |  | ||||||
| @ -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 |  | ||||||
| @ -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 |  | ||||||
| @ -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 | ||||||
|  | |||||||
| @ -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 | ||||||
| 
 |  | ||||||
|  | |||||||
							
								
								
									
										6
									
								
								package/gluon-mesh-batman-adv-core/src/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								package/gluon-mesh-batman-adv-core/src/Makefile
									
									
									
									
									
										Normal 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 | ||||||
							
								
								
									
										604
									
								
								package/gluon-mesh-batman-adv-core/src/respondd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										604
									
								
								package/gluon-mesh-batman-adv-core/src/respondd.c
									
									
									
									
									
										Normal 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}, | ||||||
|  | 	{} | ||||||
|  | }; | ||||||
| @ -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 | ||||||
|  | |||||||
| @ -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 |  | ||||||
| @ -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) |  | ||||||
							
								
								
									
										6
									
								
								package/gluon-mesh-vpn-fastd/src/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								package/gluon-mesh-vpn-fastd/src/Makefile
									
									
									
									
									
										Normal 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 | ||||||
							
								
								
									
										305
									
								
								package/gluon-mesh-vpn-fastd/src/respondd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										305
									
								
								package/gluon-mesh-vpn-fastd/src/respondd.c
									
									
									
									
									
										Normal 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}, | ||||||
|  | 	{} | ||||||
|  | }; | ||||||
| @ -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 | ||||||
|  | |||||||
| @ -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') | ||||||
| @ -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); | ||||||
|  | |||||||
| @ -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 | ||||||
|  | |||||||
| @ -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 |  | ||||||
| @ -1,4 +0,0 @@ | |||||||
| local contact = uci:get_first('gluon-node-info', 'owner', 'contact', '') |  | ||||||
| if contact ~= '' then |  | ||||||
| 	return { contact = contact } |  | ||||||
| end |  | ||||||
| @ -1,4 +0,0 @@ | |||||||
| local role = uci:get_first('gluon-node-info', 'system', 'role', '') |  | ||||||
| if role ~= '' then |  | ||||||
|         return role |  | ||||||
| end |  | ||||||
							
								
								
									
										6
									
								
								package/gluon-node-info/src/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								package/gluon-node-info/src/Makefile
									
									
									
									
									
										Normal 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 | ||||||
							
								
								
									
										144
									
								
								package/gluon-node-info/src/respondd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								package/gluon-node-info/src/respondd.c
									
									
									
									
									
										Normal 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}, | ||||||
|  | 	{} | ||||||
|  | }; | ||||||
							
								
								
									
										6
									
								
								package/gluon-radvd/files/usr/lib/autoupdater/abort.d/80gluon-radvd
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										6
									
								
								package/gluon-radvd/files/usr/lib/autoupdater/abort.d/80gluon-radvd
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | #!/bin/sh | ||||||
|  | 
 | ||||||
|  | . /lib/gluon/autoupdater/lib.sh | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | start_enabled gluon-radvd | ||||||
							
								
								
									
										6
									
								
								package/gluon-radvd/files/usr/lib/autoupdater/download.d/20gluon-radvd
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										6
									
								
								package/gluon-radvd/files/usr/lib/autoupdater/download.d/20gluon-radvd
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | #!/bin/sh | ||||||
|  | 
 | ||||||
|  | . /lib/gluon/autoupdater/lib.sh | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | stop gluon-radvd | ||||||
							
								
								
									
										29
									
								
								package/gluon-respondd/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								package/gluon-respondd/Makefile
									
									
									
									
									
										Normal 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)) | ||||||
| @ -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 | ||||||
							
								
								
									
										45
									
								
								package/gluon-respondd/files/etc/init.d/gluon-respondd
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										45
									
								
								package/gluon-respondd/files/etc/init.d/gluon-respondd
									
									
									
									
									
										Executable 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 | ||||||
|  | } | ||||||
| @ -0,0 +1 @@ | |||||||
|  | 10000 | ||||||
| @ -0,0 +1 @@ | |||||||
|  | 300000 | ||||||
| @ -0,0 +1 @@ | |||||||
|  | 5000 | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user