diff --git a/Makefile b/Makefile index b5f4305b..7f5fd437 100644 --- a/Makefile +++ b/Makefile @@ -200,7 +200,8 @@ feeds: FORCE rm -rf $(TOPDIR)/package/feeds mkdir $(TOPDIR)/package/feeds [ ! -f $(GLUON_SITEDIR)/modules ] || . $(GLUON_SITEDIR)/modules && for feed in $$GLUON_SITE_FEEDS; do ln -s ../../../packages/$$feed $(TOPDIR)/package/feeds/$$feed; done - . $(GLUONDIR)/modules && for feed in $$GLUON_FEEDS; do ln -s ../../../packages/$$feed $(TOPDIR)/package/feeds/$$feed; done + ln -s ../../../package $(TOPDIR)/package/feeds/gluon + . $(GLUONDIR)/modules && for feed in $$GLUON_FEEDS; do ln -s ../../../packages/$$feed $(TOPDIR)/package/feeds/module_$$feed; done +$(GLUONMAKE_EARLY) prepare-tmpinfo config: FORCE @@ -284,7 +285,7 @@ prepare-image: FORCE +$(SUBMAKE) -C $(TOPDIR)/target/linux/$(BOARD)/image -f $(GLUONDIR)/include/Makefile.image prepare KDIR="$(BOARD_KDIR)" prepare: FORCE - @$(STAGING_DIR_HOST)/bin/lua $(GLUONDIR)/packages/gluon/gluon/gluon-core/files/usr/lib/lua/gluon/site_config.lua \ + @$(STAGING_DIR_HOST)/bin/lua $(GLUONDIR)/package/gluon-core/files/usr/lib/lua/gluon/site_config.lua \ || (echo 'Your site configuration did not pass validation.'; false) mkdir -p $(GLUON_IMAGEDIR) $(BOARD_BUILDDIR) diff --git a/README.md b/README.md index 0bd1306d..acb027fb 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ our mailinglist to discuss it first. 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` -and switch to one by running `git checkout v2014.3;make update`. +and switch to one by running `git checkout v2014.4;make update`. If you're using the autoupdater, do not autoupdate nodes with anything but releases. If you upgrade using random master commits the nodes *will break* eventually. diff --git a/contrib/lsupgrade.sh b/contrib/lsupgrade.sh index ecf2f512..7fe11299 100755 --- a/contrib/lsupgrade.sh +++ b/contrib/lsupgrade.sh @@ -26,7 +26,7 @@ fi pushd "$(dirname "$0")/.." >/dev/null -find packages -name Makefile | while read makefile; do +find ./package packages -name Makefile | while read makefile; do dir="$(dirname "$makefile")" pushd "$dir" >/dev/null @@ -36,7 +36,7 @@ find packages -name Makefile | while read makefile; do package="$(basename "$dir")" for file in "${SUFFIX}"/*; do - echo "${GREEN}$(basename "${file}")${RESET}" "(${BLUE}${repo}${RESET}/${dirname}/${RED}${package}${RESET}/${SUFFIX})" + echo "${GREEN}$(basename "${file}")${RESET}" "(${BLUE}${repo}${RESET}/${dirname}${dirname:+/}${RED}${package}${RESET}/${SUFFIX})" done popd >/dev/null done | sort diff --git a/contrib/sign.sh b/contrib/sign.sh index a88c52df..082e967e 100755 --- a/contrib/sign.sh +++ b/contrib/sign.sh @@ -18,23 +18,23 @@ See also EOHELP exit 1 fi - -SECRET=$1 - -manifest=$2 -upper=$(mktemp) -lower=$(mktemp) - + +SECRET="$1" + +manifest="$2" +upper="$(mktemp)" +lower="$(mktemp)" + awk "BEGIN { sep=0 } /^---\$/ { sep=1; next } { if(sep==0) print > \"$upper\"; else print > \"$lower\"}" \ - $manifest - -ecdsasign $upper < $SECRET >> $lower - -cat $upper > $manifest -echo --- >> $manifest -cat $lower >> $manifest - -rm -f $upper $lower + "$manifest" + +ecdsasign "$upper" < "$SECRET" >> "$lower" + +cat "$upper" > "$manifest" +echo --- >> "$manifest" +cat "$lower" >> "$manifest" + +rm -f "$upper" "$lower" diff --git a/docs/conf.py b/docs/conf.py index 4cf0a96e..0856ed6f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -47,7 +47,7 @@ master_doc = 'index' # General information about the project. project = 'Gluon' -copyright = '2014, Project Gluon' +copyright = '2015, Project Gluon' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/docs/dev/i18n.rst b/docs/dev/i18n.rst new file mode 100644 index 00000000..536baf1a --- /dev/null +++ b/docs/dev/i18n.rst @@ -0,0 +1,88 @@ +Internationalization support +============================ + +General guidelines +------------------ + +* All config mode packages must be fully translatable, with complete English and German texts. +* All new expert mode packages be fully translatable. English texts are required, German texts recommended. +* Existing expert mode packages should be made translatable as soon as possible. +* The "message IDs" (which are the arguments to the ``translate`` function) should be the + English texts. + +i18n support in LuCI +-------------------- + +Internationalization support can be found in the ``luci.i18n`` package. +Strings are translated using the ``i18n.translate`` and ``i18n.translatef`` functions +(``translate`` for static strings, ``translatef`` for printf-like formatted string). + +Example from the ``gluon-config-mode-geo-location`` package:: + + local i18n = require "luci.i18n" + o = s:option(cbi.Flag, "_location", i18n.translate("Show node on the map")) + +Adding translation templates to Gluon packages +---------------------------------------------- + +The i18n support is based on the standard gettext system. For each translatable package, +a translation template with extension ``.pot`` can be created using the ``i18n-scan.pl`` +script from the LuCI repository:: + + cd package/gluon-config-mode-geo-location + mkdir i18n + cd i18n + ../../../packages/luci/build/i18n-scan.pl ../files > gluon-config-mode-geo-location.pot + +The entries in the template can be reordered after the generation if desirable. Lots of standard +translations like "Cancel" are already available in the LuCI base translation file (see +``packages/luci/po/templates/base.pot``) and can be removed from the template. + +In addition, some additions to the Makefile must be made. Instead of OpenWrt's default package.mk, +the Gluon version ``$(GLUONDIR)/include/package.mk`` must be used. The i18n files must be installed +and PKG_CONFIG_DEPENDS must be added:: + + ... + include $(GLUONDIR)/include/package.mk + + PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) + ... + define Build/Compile + $(call GluonBuildI18N,gluon-config-mode-geo-location,i18n) + endef + + define Package/gluon-config-mode-geo-location/install + ... + $(call GluonInstallI18N,gluon-config-mode-geo-location,$(1)) + endef + ... + + +Adding translations +------------------- + +A new translation file for a template can be added using the ``msginit`` command:: + + cd package/gluon-config-mode-geo-location/i18n + msginit -l de + +This will create the file ``de.po`` in which the translations can be added. + +The translation file can be updated to a new template version using the ``msgmerge`` command:: + + msgmerge -U de.po gluon-config-mode-geo-location.pot + +After the merge, the translation file should be checked for "fuzzy matched" entries where +the original English texts have changed. All entries from the the translation file should be +translated in the ``.po`` file (or removed from it, so the original English texts are displayed +instead). + +Adding support for new languages +-------------------------------- + +A list of all languages supported by LuCI can be found in the ``include/package.mk`` file of +the Gluon repository. Adding translations for these languages is straightforward using the ``msginit`` +command. + +For other languages, support must be added tu LuCI first, which constitutes completely translating +the ``base.pot``. Please contact the upstream LuCI maintainers if you'd like to do this. diff --git a/docs/index.rst b/docs/index.rst index a53c0a8d..bba84aad 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -40,57 +40,7 @@ Developer Documentation dev/upgrade dev/configmode dev/wan - -Supported Devices ------------------ - -* Buffalo - - - WZR-HP-AG300H / WZR-600DHP - - WZR-HP-G450H - -* D-Link - - - DIR-825 (B1) - -* Linksys - - - WRT160NL - -* TP-Link - - - CPE210 (v1) - - CPE220 (v1) - - CPE510 (v1) - - CPE520 (v1) - - TL-MR3020 (v1) - - TL-MR3040 (v1, v2) - - TL-MR3220 (v1) - - TL-MR3420 (v1, v2) - - TL-WA750RE (v1) - - TL-WA801N/ND (v2) - - TL-WA850RE (v1) - - TL-WA901N/ND (v2) - - TL-WDR3500 (v1) - - TL-WDR3600 (v1) - - TL-WDR4300 (v1) - - TL-WR1043N/ND (v1, v2) - - TL-WR703N (v1) - - TL-WR710N (v1) - - TL-WR740N (v1, v3, v4) - - TL-WR741N/ND (v1, v2, v4) - - TL-WR841N/ND (v3, v5, v7, v8, v9) - - TL-WR842N/ND (v1, v2) - - TL-WR941N/ND (v2, v3, v4) - -* Ubiquiti - - - Bullet M2 - - Nanostation M2 - - Picostation M2 - - UniFi AP - - UniFi AP Outdoor - + dev/i18n Releases -------- @@ -104,6 +54,107 @@ Releases releases/v2014.3 +Supported Devices & Architectures +--------------------------------- + +ar71xx-generic +^^^^^^^^^^^^^^ + +* Allnet + + - ALL0315N + +* Buffalo + + - WZR-HP-AG300H / WZR-600DHP + - WZR-HP-G450H + +* D-Link + + - DIR-825 (B1) + - DIR-615 (C1) + +* GL-Inet + + - 6408A (v1) + - 6416a (v1) + +* Linksys + + - WRT160NL + +* Netgear + + - WNDR3700 (v1, v2) + - WNDR3800 + +* TP-Link + + - CPE210 (v1) + - CPE220 (v1) + - CPE510 (v1) + - CPE520 (v1) + - TL-MR3020 (v1) + - TL-MR3040 (v1, v2) + - TL-MR3220 (v1, v2) + - TL-MR3420 (v1, v2) + - TL-WA701N/ND (v1) + - TL-WA750RE (v1) + - TL-WA801N/ND (v2) + - TL-WA850RE (v1) + - TL-WA860RE (v1) + - TL-WA901N/ND (v2, v3) + - TL-WDR3500 (v1) + - TL-WDR3600 (v1) + - TL-WDR4300 (v1) + - TL-WR1043N/ND (v1, v2) + - TL-WR703N (v1) + - TL-WR710N (v1) + - TL-WR740N (v1, v3, v4) + - TL-WR741N/ND (v1, v2, v4) + - TL-WR743N/ND (v1, v2) + - TL-WR841N/ND (v3, v5, v7, v8, v9) + - TL-WR842N/ND (v1, v2) + - TL-WR941N/ND (v2, v3, v4, v5) + - TL-WR2543N/ND (v1) + +* Ubiquiti + + - Bullet M2 + - Nanostation M2 + - Nanostation M XW + - Loco M XW + - Picostation M2 + - Rocket M2 + - UniFi AP + - UniFi AP Pro + - UniFi AP Outdoor + +ar71xx-nand +^^^^^^^^^^^ + +* Netgear + + - WNDR3700 (v4) + - WNDR3700 (v1) + +mpc85xx-generic +^^^^^^^^^^^^^^^ + +* TP-Link + + - TL-WDR4900 (v1) + +x86-generic +^^^^^^^^^^^ +* x86-generic +* x86-virtualbox +* x86-vmware + +x86-kvm_guest +^^^^^^^^^^^^^ +* x86-kvm + License ------- @@ -116,4 +167,3 @@ Indices and tables * :ref:`genindex` * :ref:`search` - diff --git a/docs/releases/v2015.1.rst b/docs/releases/v2015.1.rst index 8ce3db0f..a086dc7e 100644 --- a/docs/releases/v2015.1.rst +++ b/docs/releases/v2015.1.rst @@ -22,6 +22,45 @@ Site changes to keep the old behaviour, you have to append the hyphen to the ``hostname_prefix`` field of your ``site.conf``. + - ``mesh_vpn_fastd``: The default peer group name ``backbone`` isn't hardcoded anymore, any + group name can be used. Instead, the ``fastd_mesh_vpn`` table must now contain an element ``groups``, + for example:: + + fastd_mesh_vpn = { + methods = {'salsa2012+umac'}, + mtu = 1426, + groups = { + backbone = { + limit = 2, + peers = { + -- ... + } + } + } + } + + - ``roles``: The display strings for the node roles aren't configured in the ``site.conf`` anymore, but + in the site i18n files. The ``site.conf`` section becomes:: + + roles = { + default = 'foo', + list = { + 'foo', + 'bar', + } + } + + The display string use i18n message IDs like ``gluon-luci-node-role:role:foo`` and ``gluon-luci-node-role:role:bar``. + + +* ``site.mk`` + + - ``gluon-mesh-batman-adv-15`` is now the recommended batman-adv version for new Gluon deployments. + + - The packages ``gluon-setup-mode`` and ``gluon-config-mode-core`` must now be + added to ``GLUON_SITE_PACKAGES`` explicitly (to allow replacing them with + community-specific implementations). + Internals ~~~~~~~~~ diff --git a/docs/site-example/site.conf b/docs/site-example/site.conf index 48e651e9..845401c6 100644 --- a/docs/site-example/site.conf +++ b/docs/site-example/site.conf @@ -54,6 +54,8 @@ -- (optional) mesh VLAN on 802.11 ad-hoc interface (1-4095) -- mesh_vlan = 14, + -- client_disabled = true, + -- mesh_disabled = false, }, -- Wireless configuration for 5 GHz interfaces. @@ -67,6 +69,8 @@ mesh_bssid = 'xx:xx:xx:xx:xx:xx', mesh_mcast_rate = 12000, -- mesh_vlan = 14, + -- client_disabled = true, + -- mesh_disabled = false, }, -- The next node feature allows clients to always reach the node it is @@ -85,25 +89,41 @@ fastd_mesh_vpn = { -- List of crypto-methods to use. methods = {'salsa2012+umac'}, + -- configurable = true, + mtu = 1426, - backbone = { - -- Limit number of connected peers to reduce bandwidth. - limit = 2, + groups = { + backbone = { + -- Limit number of connected peers to reduce bandwidth. + limit = 2, - -- List of peers. - peers = { - peer1 = { - key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', + -- List of peers. + peers = { + peer1 = { + key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', - -- This is a list, so you might add multiple entries. - remotes = {'ipv4 "xxx.somehost.invalid" port xxxxxx'}, - }, - peer2 = { - key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', - -- You can also omit the ipv4 to allow both connection via ipv4 and ipv6 - remotes = {'"xxx.somehost2.invalid" port xxxxx'}, + -- This is a list, so you might add multiple entries. + remotes = {'ipv4 "xxx.somehost.invalid" port xxxxxx'}, + }, + peer2 = { + key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', + -- You can also omit the ipv4 to allow both connection via ipv4 and ipv6 + remotes = {'"xxx.somehost2.invalid" port xxxxx'}, + }, }, + + -- Optional: nested peer groups + -- groups = { + -- backbone_sub = { + -- ... + -- }, + -- ... + -- }, }, + -- Optional: additional peer groups, possibly with other limits + -- backbone2 = { + -- ... + -- }, }, }, @@ -136,13 +156,13 @@ }, -- Node roles - -- roles { + -- roles = { -- default = 'node', -- list = { - -- node = 'Normal Node', - -- test = 'Test Node', - -- backbone = 'Backbone Node', - -- service = 'Service Node', + -- 'node', + -- 'test', + -- 'backbone', + -- 'service', -- }, -- }, diff --git a/docs/site-example/site.mk b/docs/site-example/site.mk index e03be578..5e5a9f99 100644 --- a/docs/site-example/site.mk +++ b/docs/site-example/site.mk @@ -5,12 +5,13 @@ # The gluon-mesh-batman-adv-* package must come first because of the dependency resolution GLUON_SITE_PACKAGES := \ - gluon-mesh-batman-adv-14 \ + gluon-mesh-batman-adv-15 \ gluon-alfred \ gluon-announced \ gluon-autoupdater \ gluon-config-mode-autoupdater \ gluon-config-mode-contact-info \ + gluon-config-mode-core \ gluon-config-mode-geo-location \ gluon-config-mode-hostname \ gluon-config-mode-mesh-vpn \ @@ -22,6 +23,7 @@ GLUON_SITE_PACKAGES := \ gluon-next-node \ gluon-mesh-vpn-fastd \ gluon-radvd \ + gluon-setup-mode \ gluon-status-page \ haveged \ iptables \ diff --git a/docs/user/site.rst b/docs/user/site.rst index 2c4c6e8b..a5b31745 100644 --- a/docs/user/site.rst +++ b/docs/user/site.rst @@ -67,12 +67,14 @@ wifi24 ``htmode``, the adhoc ssid ``mesh_ssid`` used between devices, the adhoc bssid ``mesh_bssid`` and the adhoc multicast rate ``mesh_mcast_rate``. Optionally ``mesh_vlan`` can be used to setup VLAN on top of the 802.11 - ad-hoc interface. + ad-hoc interface. The options ``mesh_disabled`` and ``client_disabled`` + are optional, too. They allow to disable the SSID by default, e.g. for + preconfigured node. This only affects first configuraton. Combined in an dictionary, e.g.: :: wifi24 = { - ssid = 'http://kiel.freifunk.net/', + ssid = 'entenhausen.freifunk.net', channel = 11, htmode = 'HT40-', mesh_ssid = 'ff:ff:ff:ee:ba:be', @@ -90,24 +92,37 @@ next_node : package next_node = { ip4 = '10.23.42.1', ip6 = 'fdca:ffee:babe:1::1', - mac = 'ca:ff:ee:ba:be' + mac = 'ca:ff:ee:ba:be:00' } fastd_mesh_vpn - Remote server setup for vpn. + Remote server setup for the fastd-based mesh VPN. + + If `configurable` is 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 + add the method ``null`` to the front of the method list or remove ``null`` from it, + and make this change survive updates. Settings configurable is necessary for the + 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 + if it is supported at all. You should only set `configurable` to `true` if the + configured peers support both the ``null`` method and methods with encryption. :: fastd_mesh_vpn = { - methods = {'salsa2012+gmac'}, + methods = {'salsa2012+umac'}, + -- configurable = true, mtu = 1426, - backbone = { - limit = 2, - peers = { - ffki_rz = { - key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', - remotes = {'ipv4 "vpn1.entenhausen.freifunk.net" port 10000'}, - }, + groups = { + backbone = { + limit = 2, + peers = { + peer1 = { + key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', + remotes = {'ipv4 "vpn1.entenhausen.freifunk.net" port 10000'}, + }, + } } } } @@ -115,6 +130,9 @@ fastd_mesh_vpn mesh_on_wan : optional Enables the mesh on the WAN port (``true`` or ``false``). +mesh_on_lan : optional + Enables the mesh on the LAN port (``true`` or ``false``). + autoupdater : package Configuration for the autoupdater feature of Gluon. :: @@ -146,15 +164,19 @@ roles : optional ``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 the package ``gluon-luci-node-role`` to ``site.mk``. + + The strings to display in the LuCI interface can be configured per language in the + ``i18n/en.po``, ``i18n/de.po``, etc. files of the site repository using message IDs like + ``gluon-luci-node-role:role:node`` and ``gluon-luci-node-role:role:backbone``. :: roles = { default = 'node', list = { - node = 'Normal Node', - test = 'Test Node', - backbone = 'Backbone Node', - service = 'Service Node', + 'node', + 'test', + 'backbone', + 'service', }, }, @@ -176,7 +198,7 @@ setup_mode : package ``skip`` is set to ``true``. This is optional and may be left out. :: - setup_mode { + setup_mode = { skip = true, }, @@ -280,7 +302,7 @@ This is a non-exhaustive list of site-repos from various communities: * `site-ffgoe `_ (Göttingen) * `site-ffhh `_ (Hamburg) * `site-ffhgw `_ (Greifswald) -* `site-ffhl `_ (Lübeck) +* `site-ffhl `_ (Lübeck) * `site-ffmd `_ (Magdeburg) * `site-ffmwu `_ (Mainz, Wiesbaden & Umgebung) * `site-ffmyk `_ (Mayen-Koblenz) diff --git a/modules b/modules index 04b9b5b2..4776b64f 100644 --- a/modules +++ b/modules @@ -1,14 +1,14 @@ GLUON_FEEDS='openwrt gluon routing luci' OPENWRT_REPO=git://git.openwrt.org/14.07/openwrt.git -OPENWRT_COMMIT=64ae631f20eb349b47dae30c461ab33b5c4ac5c2 +OPENWRT_COMMIT=179bab8b1700d74b28cc6cd25322f9a1ad670107 PACKAGES_OPENWRT_REPO=git://github.com/openwrt/packages.git PACKAGES_OPENWRT_COMMIT=01fcd1f29174a56d6ddb59901ed8c67ea42c3a8f PACKAGES_OPENWRT_BRANCH=for-14.07 PACKAGES_GLUON_REPO=git://github.com/freifunk-gluon/packages.git -PACKAGES_GLUON_COMMIT=f5c0865d5025a7e6ad3ff6c21ca5206ac972ba75 +PACKAGES_GLUON_COMMIT=e8ee21d116a0abc2e328b0ee181d79845654582e PACKAGES_ROUTING_REPO=git://github.com/openwrt-routing/packages.git PACKAGES_ROUTING_COMMIT=5d4ad63897b435d5df0f39a49bd58962c22c33b8 diff --git a/package/gluon-alfred/Makefile b/package/gluon-alfred/Makefile new file mode 100644 index 00000000..bb6926a5 --- /dev/null +++ b/package/gluon-alfred/Makefile @@ -0,0 +1,32 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-alfred +PKG_VERSION:=1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + +define Package/gluon-alfred + SECTION:=gluon + CATEGORY:=Gluon + DEPENDS:=+gluon-core +gluon-announce +gluon-cron +alfred + TITLE:=Configure alfred +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-alfred/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,gluon-alfred)) diff --git a/package/gluon-alfred/files/lib/gluon/cron/alfred b/package/gluon-alfred/files/lib/gluon/cron/alfred new file mode 100644 index 00000000..9f79bc64 --- /dev/null +++ b/package/gluon-alfred/files/lib/gluon/cron/alfred @@ -0,0 +1 @@ +* * * * * /lib/gluon/announce/collect.lua nodeinfo | gzip | alfred -s 158; /lib/gluon/announce/collect.lua statistics | gzip | alfred -s 159; /lib/gluon/announce/collect.lua neighbours | gzip | alfred -s 160 diff --git a/package/gluon-alfred/files/lib/gluon/upgrade/500-enable-alfred b/package/gluon-alfred/files/lib/gluon/upgrade/500-enable-alfred new file mode 100755 index 00000000..8c52d8a6 --- /dev/null +++ b/package/gluon-alfred/files/lib/gluon/upgrade/500-enable-alfred @@ -0,0 +1,19 @@ +#!/usr/bin/lua + +local uci = require 'luci.model.uci' +local c = uci.cursor() + + +c:delete('alfred', 'alfred') +c:section('alfred', 'alfred', 'alfred', + { + interface = 'br-client', + mode = 'slave', + batmanif = 'bat0', + start_vis = '1', + run_facters = '0', + } +) + +c:save('alfred') +c:commit('alfred') diff --git a/package/gluon-announce/Makefile b/package/gluon-announce/Makefile new file mode 100644 index 00000000..3f62c889 --- /dev/null +++ b/package/gluon-announce/Makefile @@ -0,0 +1,32 @@ +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-json +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)) diff --git a/package/gluon-announce/files/lib/gluon/announce/collect.lua b/package/gluon-announce/files/lib/gluon/announce/collect.lua new file mode 100755 index 00000000..e2974b49 --- /dev/null +++ b/package/gluon-announce/files/lib/gluon/announce/collect.lua @@ -0,0 +1,10 @@ +#!/usr/bin/lua + +local announce = require 'gluon.announce' +local json = require 'luci.json' +local ltn12 = require 'luci.ltn12' + +local announce_dir = '/lib/gluon/announce/' .. arg[1] .. '.d' + +encoder = json.Encoder(announce.collect_dir(announce_dir)) +ltn12.pump.all(encoder:source(), ltn12.sink.file(io.stdout)) diff --git a/package/gluon-announce/files/lib/gluon/announce/neighbours.d/node_id b/package/gluon-announce/files/lib/gluon/announce/neighbours.d/node_id new file mode 100644 index 00000000..66303f4c --- /dev/null +++ b/package/gluon-announce/files/lib/gluon/announce/neighbours.d/node_id @@ -0,0 +1 @@ +return require('gluon.util').node_id() diff --git a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hardware/model b/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hardware/model new file mode 100644 index 00000000..aee3cd81 --- /dev/null +++ b/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hardware/model @@ -0,0 +1 @@ +return require('platform_info').get_model() diff --git a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hardware/nproc b/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hardware/nproc new file mode 100644 index 00000000..3072f8f8 --- /dev/null +++ b/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hardware/nproc @@ -0,0 +1,14 @@ +local n = 0 + +local cpus = util.trim(fs.readfile('/sys/devices/system/cpu/online')) + +for _, entry in ipairs(cpus:split(',')) 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 diff --git a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hostname b/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hostname new file mode 100644 index 00000000..7d4f0521 --- /dev/null +++ b/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hostname @@ -0,0 +1 @@ +return uci:get_first('system', 'system', 'hostname') diff --git a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/network/mac b/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/network/mac new file mode 100644 index 00000000..049eea58 --- /dev/null +++ b/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/network/mac @@ -0,0 +1 @@ +return require('gluon.sysconfig').primary_mac diff --git a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/node_id b/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/node_id new file mode 100644 index 00000000..66303f4c --- /dev/null +++ b/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/node_id @@ -0,0 +1 @@ +return require('gluon.util').node_id() diff --git a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/software/firmware b/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/software/firmware new file mode 100644 index 00000000..cf50f79f --- /dev/null +++ b/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/software/firmware @@ -0,0 +1,4 @@ +return { + base = 'gluon-' .. util.trim(fs.readfile('/lib/gluon/gluon-version')), + release = util.trim(fs.readfile('/lib/gluon/release')), +} diff --git a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/system/site_code b/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/system/site_code new file mode 100644 index 00000000..876fb6d8 --- /dev/null +++ b/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/system/site_code @@ -0,0 +1,3 @@ +local site = require 'gluon.site_config' + +return site.site_code diff --git a/package/gluon-announce/files/lib/gluon/announce/statistics.d/idletime b/package/gluon-announce/files/lib/gluon/announce/statistics.d/idletime new file mode 100644 index 00000000..845de268 --- /dev/null +++ b/package/gluon-announce/files/lib/gluon/announce/statistics.d/idletime @@ -0,0 +1 @@ +return tonumber(fs.readfile('/proc/uptime'):match('^[^ ]+ ([^ ]+)')) diff --git a/package/gluon-announce/files/lib/gluon/announce/statistics.d/loadavg b/package/gluon-announce/files/lib/gluon/announce/statistics.d/loadavg new file mode 100644 index 00000000..d79973aa --- /dev/null +++ b/package/gluon-announce/files/lib/gluon/announce/statistics.d/loadavg @@ -0,0 +1 @@ +return tonumber(fs.readfile('/proc/loadavg'):match('^([^ ]+) ')) diff --git a/package/gluon-announce/files/lib/gluon/announce/statistics.d/memory b/package/gluon-announce/files/lib/gluon/announce/statistics.d/memory new file mode 100644 index 00000000..7b07a107 --- /dev/null +++ b/package/gluon-announce/files/lib/gluon/announce/statistics.d/memory @@ -0,0 +1,13 @@ +local data = fs.readfile('/proc/meminfo') + +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, +} diff --git a/package/gluon-announce/files/lib/gluon/announce/statistics.d/node_id b/package/gluon-announce/files/lib/gluon/announce/statistics.d/node_id new file mode 100644 index 00000000..66303f4c --- /dev/null +++ b/package/gluon-announce/files/lib/gluon/announce/statistics.d/node_id @@ -0,0 +1 @@ +return require('gluon.util').node_id() diff --git a/package/gluon-announce/files/lib/gluon/announce/statistics.d/processes b/package/gluon-announce/files/lib/gluon/announce/statistics.d/processes new file mode 100644 index 00000000..33ecff66 --- /dev/null +++ b/package/gluon-announce/files/lib/gluon/announce/statistics.d/processes @@ -0,0 +1,3 @@ +local running, total = fs.readfile('/proc/loadavg'):match('^[^ ]+ [^ ]+ [^ ]+ (%d+)/(%d+)') + +return { running = tonumber(running), total = tonumber(total) } diff --git a/package/gluon-announce/files/lib/gluon/announce/statistics.d/rootfs_usage b/package/gluon-announce/files/lib/gluon/announce/statistics.d/rootfs_usage new file mode 100644 index 00000000..8426e9e1 --- /dev/null +++ b/package/gluon-announce/files/lib/gluon/announce/statistics.d/rootfs_usage @@ -0,0 +1,4 @@ +local fs = require "nixio.fs" + +local st = fs.statvfs("/") +return 1 - st.bfree / st.blocks diff --git a/package/gluon-announce/files/lib/gluon/announce/statistics.d/uptime b/package/gluon-announce/files/lib/gluon/announce/statistics.d/uptime new file mode 100644 index 00000000..0bc45bea --- /dev/null +++ b/package/gluon-announce/files/lib/gluon/announce/statistics.d/uptime @@ -0,0 +1 @@ +return tonumber(fs.readfile('/proc/uptime'):match('^([^ ]+) ')) diff --git a/package/gluon-announce/files/usr/lib/lua/gluon/announce.lua b/package/gluon-announce/files/usr/lib/lua/gluon/announce.lua new file mode 100644 index 00000000..7f3f62e2 --- /dev/null +++ b/package/gluon-announce/files/usr/lib/lua/gluon/announce.lua @@ -0,0 +1,33 @@ +#!/usr/bin/lua + +module('gluon.announce', package.seeall) + +fs = require 'luci.fs' +uci = require('luci.model.uci').cursor() +util = require 'luci.util' + +local function collect_entry(entry) + if fs.isdirectory(entry) then + return collect_dir(entry) + else + return setfenv(loadfile(entry), _M)() + end +end + +function collect_dir(dir) + local ret = {} + + for _, entry in ipairs(fs.dir(dir)) do + if entry:sub(1, 1) ~= '.' then + local ok, val = pcall(collect_entry, dir .. '/' .. entry) + if ok then + ret[entry] = val + else + io.stderr:write(val, '\n') + end + end + end + + return ret +end + diff --git a/package/gluon-announced/Makefile b/package/gluon-announced/Makefile new file mode 100644 index 00000000..d5b06dce --- /dev/null +++ b/package/gluon-announced/Makefile @@ -0,0 +1,32 @@ +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)) diff --git a/package/gluon-announced/files/etc/hotplug.d/iface/10-gluon-announced b/package/gluon-announced/files/etc/hotplug.d/iface/10-gluon-announced new file mode 100644 index 00000000..a1e2c45f --- /dev/null +++ b/package/gluon-announced/files/etc/hotplug.d/iface/10-gluon-announced @@ -0,0 +1,45 @@ +#!/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 + diff --git a/package/gluon-announced/files/lib/gluon/upgrade/400-announced-firewall b/package/gluon-announced/files/lib/gluon/upgrade/400-announced-firewall new file mode 100755 index 00000000..77acb1b9 --- /dev/null +++ b/package/gluon-announced/files/lib/gluon/upgrade/400-announced-firewall @@ -0,0 +1,18 @@ +#!/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') diff --git a/package/gluon-announced/files/usr/lib/lua/gluon/announced.lua b/package/gluon-announced/files/usr/lib/lua/gluon/announced.lua new file mode 100644 index 00000000..99116b81 --- /dev/null +++ b/package/gluon-announced/files/usr/lib/lua/gluon/announced.lua @@ -0,0 +1,33 @@ +local announce = require 'gluon.announce' +local deflate = require 'deflate' +local json = require 'luci.json' + + +local function collect(type) + return announce.collect_dir('/lib/gluon/announce/' .. type .. '.d') +end + + +module('gluon.announced', package.seeall) + +function handle_request(query) + if query:match('^nodeinfo$') then + return json.encode(collect('nodeinfo')) + end + + local m = query:match('^GET ([a-z ]+)$') + 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 + return deflate.compress(json.encode(data)) + end + end +end diff --git a/package/gluon-authorized-keys/Makefile b/package/gluon-authorized-keys/Makefile new file mode 100644 index 00000000..6ef90da3 --- /dev/null +++ b/package/gluon-authorized-keys/Makefile @@ -0,0 +1,36 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-authorized-keys +PKG_VERSION:=2 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +define Package/gluon-authorized-keys + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Fill /etc/dropbear/authorized_keys from site.conf + DEPENDS:=+gluon-core +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-authorized-keys/install + $(CP) ./files/* $(1)/ +endef + +define Package/gluon-authorized-keys/postinst +#!/bin/sh +$(call GluonCheckSite,check_site.lua) +endef + +$(eval $(call BuildPackage,gluon-authorized-keys)) diff --git a/package/gluon-authorized-keys/check_site.lua b/package/gluon-authorized-keys/check_site.lua new file mode 100644 index 00000000..d1acfabe --- /dev/null +++ b/package/gluon-authorized-keys/check_site.lua @@ -0,0 +1 @@ +need_string_array 'authorized_keys' diff --git a/package/gluon-authorized-keys/files/lib/gluon/upgrade/100-authorized-keys b/package/gluon-authorized-keys/files/lib/gluon/upgrade/100-authorized-keys new file mode 100755 index 00000000..643fa076 --- /dev/null +++ b/package/gluon-authorized-keys/files/lib/gluon/upgrade/100-authorized-keys @@ -0,0 +1,22 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local file = '/etc/dropbear/authorized_keys' + +local keys = {} + +function load_keys() + for line in io.lines(file) do + keys[line] = true + end +end + +pcall(load_keys) + +local f = io.open(file, 'a') +for _, key in ipairs(site.authorized_keys) do + if not keys[key] then + f:write(key .. '\n') + end +end +f:close() diff --git a/package/gluon-autoupdater/Makefile b/package/gluon-autoupdater/Makefile new file mode 100644 index 00000000..b33bada9 --- /dev/null +++ b/package/gluon-autoupdater/Makefile @@ -0,0 +1,42 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-autoupdater +PKG_VERSION:=4 +PKG_RELEASE:=$(GLUON_BRANCH) + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +define Package/gluon-autoupdater + SECTION:=gluon + CATEGORY:=Gluon + DEPENDS:=+gluon-core +gluon-cron +autoupdater + TITLE:=Automatically update firmware +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-autoupdater/install + $(CP) ./files/* $(1)/ + + if [ '$(GLUON_BRANCH)' ]; then \ + $(INSTALL_DIR) $(1)/lib/gluon/autoupdater; \ + echo '$(GLUON_BRANCH)' > $(1)/lib/gluon/autoupdater/default_branch; \ + fi +endef + +define Package/gluon-autoupdater/postinst +#!/bin/sh +$(call GluonCheckSite,check_site.lua) +endef + +$(eval $(call BuildPackage,gluon-autoupdater)) diff --git a/package/gluon-autoupdater/check_site.lua b/package/gluon-autoupdater/check_site.lua new file mode 100644 index 00000000..1d8996f0 --- /dev/null +++ b/package/gluon-autoupdater/check_site.lua @@ -0,0 +1,12 @@ +need_string 'autoupdater.branch' + +local function check_branch(k, _) + local prefix = string.format('autoupdater.branches[%q].', k) + + need_string(prefix .. 'name') + need_string_array(prefix .. 'mirrors') + need_number(prefix .. 'good_signatures') + need_string_array(prefix .. 'pubkeys') +end + +need_table('autoupdater.branches', check_branch) diff --git a/package/gluon-autoupdater/files/lib/gluon/announce/nodeinfo.d/software/autoupdater b/package/gluon-autoupdater/files/lib/gluon/announce/nodeinfo.d/software/autoupdater new file mode 100644 index 00000000..75a67578 --- /dev/null +++ b/package/gluon-autoupdater/files/lib/gluon/announce/nodeinfo.d/software/autoupdater @@ -0,0 +1,7 @@ +local autoupdater = uci:get_all('autoupdater', 'settings') +if autoupdater then + return { + branch = autoupdater['branch'], + enabled = uci:get_bool('autoupdater', 'settings', 'enabled'), + } +end diff --git a/package/gluon-autoupdater/files/lib/gluon/upgrade/500-autoupdater b/package/gluon-autoupdater/files/lib/gluon/upgrade/500-autoupdater new file mode 100755 index 00000000..fec313b3 --- /dev/null +++ b/package/gluon-autoupdater/files/lib/gluon/upgrade/500-autoupdater @@ -0,0 +1,57 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local uci = require 'luci.model.uci' + +local c = uci.cursor() + + +for name, config in pairs(site.autoupdater.branches) do + c:delete('autoupdater', name) + c:section('autoupdater', 'branch', name, + { + name = config.name, + mirror = config.mirrors, + good_signatures = config.good_signatures, + pubkey = config.pubkeys, + } + ) +end + +if not c:get('autoupdater', 'settings') then + local enabled = 0 + local branch = site.autoupdater.branch + + local f = io.open('/lib/gluon/autoupdater/default_branch') + if f then + enabled = 1 + branch = f:read('*line') + f:close() + end + + c:section('autoupdater', 'autoupdater', 'settings', + { + enabled = enabled, + branch = branch, + } + ) +end + +c:set('autoupdater', 'settings', 'version_file', '/lib/gluon/release') + +c:save('autoupdater') +c:commit('autoupdater') + + +local autoupdater_util = require 'autoupdater.util' +autoupdater_util.randomseed() + + +-- Perform updates at a random time between 04:00 and 05:00, and once an hour +-- a fallback update (used after the regular updates haven't +local minute = math.random(0, 59) + +local f = io.open('/lib/gluon/cron/autoupdater', 'w') +f:write(string.format('%i 4 * * * /usr/sbin/autoupdater\n', minute)) +f:write(string.format('%i 0-3,5-23 * * * /usr/sbin/autoupdater --fallback\n', minute)) +f:close() diff --git a/package/gluon-config-mode-autoupdater/Makefile b/package/gluon-config-mode-autoupdater/Makefile new file mode 100644 index 00000000..4303940b --- /dev/null +++ b/package/gluon-config-mode-autoupdater/Makefile @@ -0,0 +1,40 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-config-mode-autoupdater +PKG_VERSION:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) + + +define Package/gluon-config-mode-autoupdater + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Let the user know whether the autoupdater is enabled or not. + DEPENDS:=gluon-config-mode-core-virtual +gluon-autoupdater +endef + +define Package/gluon-config-mode-autoupdater/description + Luci based config mode +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile + $(call GluonBuildI18N,gluon-config-mode-autoupdater,i18n) +endef + +define Package/gluon-config-mode-autoupdater/install + $(CP) ./files/* $(1)/ + $(call GluonInstallI18N,gluon-config-mode-autoupdater,$(1)) +endef + +$(eval $(call BuildPackage,gluon-config-mode-autoupdater)) diff --git a/package/gluon-config-mode-autoupdater/files/lib/gluon/config-mode/wizard/0050-autoupdater-info.lua b/package/gluon-config-mode-autoupdater/files/lib/gluon/config-mode/wizard/0050-autoupdater-info.lua new file mode 100644 index 00000000..3bbe0390 --- /dev/null +++ b/package/gluon-config-mode-autoupdater/files/lib/gluon/config-mode/wizard/0050-autoupdater-info.lua @@ -0,0 +1,19 @@ +local cbi = require "luci.cbi" +local i18n = require "luci.i18n" +local uci = luci.model.uci.cursor() + +local M = {} + +function M.section(form) + local enabled = uci:get_bool("autoupdater", "settings", "enabled") + if enabled then + local s = form:section(cbi.SimpleSection, nil, + i18n.translate('This node will automatically update its firmware when a new version is available.')) + end +end + +function M.handle(data) + return +end + +return M diff --git a/package/gluon-config-mode-autoupdater/i18n/de.po b/package/gluon-config-mode-autoupdater/i18n/de.po new file mode 100644 index 00000000..5a55e349 --- /dev/null +++ b/package/gluon-config-mode-autoupdater/i18n/de.po @@ -0,0 +1,17 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2015-03-18 16:03+0100\n" +"Last-Translator: Matthias Schiffer \n" +"Language-Team: German\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "" +"This node will automatically update its firmware when a new version is " +"available." +msgstr "Dieser Knoten aktualisiert seine Firmware automatisch, sobald " +"eine neue Version vorliegt." diff --git a/package/gluon-config-mode-autoupdater/i18n/gluon-config-mode-autoupdater.pot b/package/gluon-config-mode-autoupdater/i18n/gluon-config-mode-autoupdater.pot new file mode 100644 index 00000000..9e6272cd --- /dev/null +++ b/package/gluon-config-mode-autoupdater/i18n/gluon-config-mode-autoupdater.pot @@ -0,0 +1,7 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "" +"This node will automatically update its firmware when a new version is " +"available." +msgstr "" diff --git a/package/gluon-config-mode-contact-info/Makefile b/package/gluon-config-mode-contact-info/Makefile new file mode 100644 index 00000000..ff9cb57f --- /dev/null +++ b/package/gluon-config-mode-contact-info/Makefile @@ -0,0 +1,36 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-config-mode-contact-info +PKG_VERSION:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) + + +define Package/gluon-config-mode-contact-info + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Set a custom string that will be distributed in the mesh. + DEPENDS:=gluon-config-mode-core-virtual +gluon-node-info +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile + $(call GluonBuildI18N,gluon-config-mode-contact-info,i18n) +endef + +define Package/gluon-config-mode-contact-info/install + $(CP) ./files/* $(1)/ + $(call GluonInstallI18N,gluon-config-mode-contact-info,$(1)) +endef + +$(eval $(call BuildPackage,gluon-config-mode-contact-info)) diff --git a/package/gluon-config-mode-contact-info/files/lib/gluon/config-mode/wizard/0500-contact-info.lua b/package/gluon-config-mode-contact-info/files/lib/gluon/config-mode/wizard/0500-contact-info.lua new file mode 100644 index 00000000..a2182f95 --- /dev/null +++ b/package/gluon-config-mode-contact-info/files/lib/gluon/config-mode/wizard/0500-contact-info.lua @@ -0,0 +1,34 @@ +local cbi = require "luci.cbi" +local i18n = require "luci.i18n" +local uci = luci.model.uci.cursor() + +local M = {} + +function M.section(form) + local s = form:section(cbi.SimpleSection, nil, i18n.translate( + 'You can provide your contact information here to ' + .. 'allow others to contact you. Please note that ' + .. 'this information will be visible publicly ' + .. 'on the internet together with your node\'s coordinates.' + ) + ) + + local o = s:option(cbi.Value, "_contact", i18n.translate("Contact info")) + o.default = uci:get_first("gluon-node-info", "owner", "contact", "") + o.rmempty = true + o.datatype = "string" + o.description = i18n.translate("e.g. E-mail or phone number") + o.maxlen = 140 +end + +function M.handle(data) + if data._contact ~= nil then + uci:set("gluon-node-info", uci:get_first("gluon-node-info", "owner"), "contact", data._contact) + else + uci:delete("gluon-node-info", uci:get_first("gluon-node-info", "owner"), "contact") + end + uci:save("gluon-node-info") + uci:commit("gluon-node-info") +end + +return M diff --git a/package/gluon-config-mode-contact-info/i18n/de.po b/package/gluon-config-mode-contact-info/i18n/de.po new file mode 100644 index 00000000..719246f4 --- /dev/null +++ b/package/gluon-config-mode-contact-info/i18n/de.po @@ -0,0 +1,27 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2015-03-19 01:32+0100\n" +"Last-Translator: Matthias Schiffer \n" +"Language-Team: German\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "Contact info" +msgstr "Kontakt" + +msgid "" +"You can provide your contact information here to allow others to contact " +"you. Please note that this information will be visible publicly on " +"the internet together with your node's coordinates." +msgstr "" +"Hier kannst du einen öffentlichen Hinweis hinterlegen, um anderen " +"zu ermöglichen, Kontakt mit dir aufzunehmen. Bitte beachte, dass " +"dieser Hinweis auch öffentlich im Internet, zusammen mit den Koordinaten " +"deines Knotens, einsehbar sein wird." + +msgid "e.g. E-mail or phone number" +msgstr "z.B. E-Mail oder Telefonnummer" diff --git a/package/gluon-config-mode-contact-info/i18n/gluon-config-mode-contact-info.pot b/package/gluon-config-mode-contact-info/i18n/gluon-config-mode-contact-info.pot new file mode 100644 index 00000000..63939a83 --- /dev/null +++ b/package/gluon-config-mode-contact-info/i18n/gluon-config-mode-contact-info.pot @@ -0,0 +1,14 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "Contact info" +msgstr "" + +msgid "" +"You can provide your contact information here to allow others to contact " +"you. Please note that this information will be visible publicly on " +"the internet together with your node's coordinates." +msgstr "" + +msgid "e.g. E-mail or phone number" +msgstr "" diff --git a/package/gluon-config-mode-core/Makefile b/package/gluon-config-mode-core/Makefile new file mode 100644 index 00000000..5d700f7f --- /dev/null +++ b/package/gluon-config-mode-core/Makefile @@ -0,0 +1,40 @@ +# Copyright (C) 2012 Nils Schneider +# This is free software, licensed under the Apache 2.0 license. + +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-config-mode-core +PKG_VERSION:=2 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) + + +define Package/gluon-config-mode-core + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Luci based config mode for user friendly setup of new mesh nodes + DEPENDS:=gluon-setup-mode-virtual +gluon-luci-theme +gluon-lock-password $(GLUON_I18N_PACKAGES) + PROVIDES:=gluon-config-mode-core-virtual +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile + $(call GluonBuildI18N,gluon-config-mode-core,i18n) +endef + +define Package/gluon-config-mode-core/install + $(CP) ./files/* $(1)/ + $(call GluonInstallI18N,gluon-config-mode-core,$(1)) +endef + +$(eval $(call BuildPackage,gluon-config-mode-core)) diff --git a/package/gluon-config-mode-core/files/lib/gluon/config-mode/reboot/0900-msg-reboot.lua b/package/gluon-config-mode-core/files/lib/gluon/config-mode/reboot/0900-msg-reboot.lua new file mode 100644 index 00000000..bf27c07f --- /dev/null +++ b/package/gluon-config-mode-core/files/lib/gluon/config-mode/reboot/0900-msg-reboot.lua @@ -0,0 +1,3 @@ +local i18n = require 'luci.i18n' + +return function () luci.template.render_string(i18n.translate('gluon-config-mode:reboot')) end diff --git a/package/gluon-config-mode-core/files/usr/lib/lua/luci/controller/gluon-config-mode/index.lua b/package/gluon-config-mode-core/files/usr/lib/lua/luci/controller/gluon-config-mode/index.lua new file mode 100644 index 00000000..c3ab070d --- /dev/null +++ b/package/gluon-config-mode-core/files/usr/lib/lua/luci/controller/gluon-config-mode/index.lua @@ -0,0 +1,89 @@ +--[[ +Copyright 2013 Nils Schneider + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +module("luci.controller.gluon-config-mode.index", package.seeall) + +function index() + local uci_state = luci.model.uci.cursor_state() + + if uci_state:get_first("gluon-setup-mode", "setup_mode", "running", "0") == "1" then + local root = node() + if not root.target then + root.target = alias("gluon-config-mode") + root.index = true + end + + page = node() + page.lock = true + page.target = alias("gluon-config-mode") + page.subindex = true + page.index = false + + page = node("gluon-config-mode") + page.title = _("Wizard") + page.target = alias("gluon-config-mode", "wizard") + page.order = 5 + page.setuser = "root" + page.setgroup = "root" + page.index = true + + entry({"gluon-config-mode", "wizard"}, form("gluon-config-mode/wizard")).index = true + entry({"gluon-config-mode", "reboot"}, call("action_reboot")) + end +end + +function action_reboot() + local uci = luci.model.uci.cursor() + + uci:set("gluon-setup-mode", uci:get_first("gluon-setup-mode", "setup_mode"), "configured", "1") + uci:save("gluon-setup-mode") + uci:commit("gluon-setup-mode") + + if nixio.fork() ~= 0 then + local fs = require "luci.fs" + + local parts_dir = "/lib/gluon/config-mode/reboot/" + local files = fs.dir(parts_dir) + + table.sort(files) + + local parts = {} + + for _, entry in ipairs(files) do + if entry:sub(1, 1) ~= '.' then + local f = dofile(parts_dir .. '/' .. entry) + if f ~= nil then + table.insert(parts, f) + end + end + end + + local hostname = uci:get_first("system", "system", "hostname") + + luci.template.render("gluon/config-mode/reboot", { parts=parts + , hostname=hostname + }) + else + debug.setfenv(io.stdout, debug.getfenv(io.open '/dev/null')) + io.stdout:close() + + -- Sleep a little so the browser can fetch everything required to + -- display the reboot page, then reboot the device. + nixio.nanosleep(2) + + -- Run reboot with popen so it gets its own std filehandles. + io.popen("reboot") + + -- Prevent any further execution in this child. + os.exit() + end +end diff --git a/package/gluon-config-mode-core/files/usr/lib/lua/luci/model/cbi/gluon-config-mode/wizard.lua b/package/gluon-config-mode-core/files/usr/lib/lua/luci/model/cbi/gluon-config-mode/wizard.lua new file mode 100644 index 00000000..101a02e3 --- /dev/null +++ b/package/gluon-config-mode-core/files/usr/lib/lua/luci/model/cbi/gluon-config-mode/wizard.lua @@ -0,0 +1,38 @@ +local wizard_dir = "/lib/gluon/config-mode/wizard/" +local i18n = luci.i18n +local uci = luci.model.uci.cursor() +local fs = require "luci.fs" +local f, s + +local wizard = {} +local files = fs.dir(wizard_dir) + +table.sort(files) + +for _, entry in ipairs(files) do + if entry:sub(1, 1) ~= '.' then + table.insert(wizard, dofile(wizard_dir .. '/' .. entry)) + end +end + +f = SimpleForm("wizard") +f.reset = false +f.template = "gluon/cbi/config-mode" + +for _, s in ipairs(wizard) do + s.section(f) +end + +function f.handle(self, state, data) + if state == FORM_VALID then + for _, s in ipairs(wizard) do + s.handle(data) + end + + luci.http.redirect(luci.dispatcher.build_url("gluon-config-mode", "reboot")) + end + + return true +end + +return f diff --git a/package/gluon-config-mode-core/files/usr/lib/lua/luci/view/gluon/cbi/config-mode.htm b/package/gluon-config-mode-core/files/usr/lib/lua/luci/view/gluon/cbi/config-mode.htm new file mode 100644 index 00000000..d2210eca --- /dev/null +++ b/package/gluon-config-mode-core/files/usr/lib/lua/luci/view/gluon/cbi/config-mode.htm @@ -0,0 +1,46 @@ +<%- + local sysconfig = require 'gluon.sysconfig' + local i18n = require 'luci.i18n' + local template = require 'luci.template' +-%> + +

<%:Welcome!%>

+

+ <%= template.render_string(i18n.translate('gluon-config-mode:welcome'), {hostname=hostname, sysconfig=sysconfig}) %> +

+ +<% if not self.embedded then %> +
+
+ + +
+<% end %> +
+ <% if self.title and #self.title > 0 then %>

<%=self.title%>

<% end %> + <% if self.description and #self.description > 0 then %>
<%=self.description%>
<% end %> + <% self:render_children() %> +
+
+<%- if self.message then %> +
<%=self.message%>
+<%- end %> +<%- if self.errmessage then %> +
<%=self.errmessage%>
+<%- end %> +<% if not self.embedded then %> +
+<%- + if type(self.hidden) == "table" then + for k, v in pairs(self.hidden) do +-%> + +<%- + end + end +%> + + +
+
+<% end %> diff --git a/package/gluon-config-mode-core/files/usr/lib/lua/luci/view/gluon/config-mode/reboot.htm b/package/gluon-config-mode-core/files/usr/lib/lua/luci/view/gluon/config-mode/reboot.htm new file mode 100644 index 00000000..e8f32d99 --- /dev/null +++ b/package/gluon-config-mode-core/files/usr/lib/lua/luci/view/gluon/config-mode/reboot.htm @@ -0,0 +1,17 @@ + + + + + + <%=hostname%> is rebooting + + + +
+
+

<%:Your node's setup is now complete.%>

+ <% for k, v in ipairs(parts) do v() end %> +
+
+ + diff --git a/package/gluon-config-mode-core/i18n/de.po b/package/gluon-config-mode-core/i18n/de.po new file mode 100644 index 00000000..58d23894 --- /dev/null +++ b/package/gluon-config-mode-core/i18n/de.po @@ -0,0 +1,24 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2015-03-19 02:07+0100\n" +"Last-Translator: Matthias Schiffer \n" +"Language-Team: German\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#, fuzzy +msgid "Save & restart" +msgstr "Speichern & Neustarten" + +msgid "Welcome!" +msgstr "Willkommen!" + +msgid "Wizard" +msgstr "Wizard" + +msgid "Your node's setup is now complete." +msgstr "Dein Knoten ist nun fertig eingerichtet." diff --git a/package/gluon-config-mode-core/i18n/gluon-config-mode-core.pot b/package/gluon-config-mode-core/i18n/gluon-config-mode-core.pot new file mode 100644 index 00000000..a80d3b97 --- /dev/null +++ b/package/gluon-config-mode-core/i18n/gluon-config-mode-core.pot @@ -0,0 +1,14 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "Save & restart" +msgstr "" + +msgid "Welcome!" +msgstr "" + +msgid "Wizard" +msgstr "" + +msgid "Your node's setup is now complete." +msgstr "" diff --git a/package/gluon-config-mode-geo-location/Makefile b/package/gluon-config-mode-geo-location/Makefile new file mode 100644 index 00000000..28d34764 --- /dev/null +++ b/package/gluon-config-mode-geo-location/Makefile @@ -0,0 +1,36 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-config-mode-geo-location +PKG_VERSION:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) + + +define Package/gluon-config-mode-geo-location + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Set geographic location of a node + DEPENDS:=gluon-config-mode-core-virtual +gluon-node-info +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile + $(call GluonBuildI18N,gluon-config-mode-geo-location,i18n) +endef + +define Package/gluon-config-mode-geo-location/install + $(CP) ./files/* $(1)/ + $(call GluonInstallI18N,gluon-config-mode-geo-location,$(1)) +endef + +$(eval $(call BuildPackage,gluon-config-mode-geo-location)) diff --git a/package/gluon-config-mode-geo-location/files/lib/gluon/config-mode/wizard/0400-geo-location.lua b/package/gluon-config-mode-geo-location/files/lib/gluon/config-mode/wizard/0400-geo-location.lua new file mode 100644 index 00000000..a3ac089d --- /dev/null +++ b/package/gluon-config-mode-geo-location/files/lib/gluon/config-mode/wizard/0400-geo-location.lua @@ -0,0 +1,60 @@ +local cbi = require "luci.cbi" +local i18n = require "luci.i18n" +local uci = luci.model.uci.cursor() + +local M = {} + +function M.section(form) + local s = form:section(cbi.SimpleSection, nil, i18n.translate( + 'If you want the location of your node to be displayed on the map, ' + .. 'you can enter its coordinates here. Specifying the altitude ' + .. 'is optional and should only be done if a proper value is known.')) + + + local o + + o = s:option(cbi.Flag, "_location", i18n.translate("Show node on the map")) + o.default = uci:get_first("gluon-node-info", "location", "share_location", o.disabled) + o.rmempty = false + + o = s:option(cbi.Value, "_latitude", i18n.translate("Latitude")) + o.default = uci:get_first("gluon-node-info", "location", "latitude") + o:depends("_location", "1") + o.rmempty = false + o.datatype = "float" + o.description = i18n.translatef("e.g. %s", "53.873621") + + o = s:option(cbi.Value, "_longitude", i18n.translate("Longitude")) + o.default = uci:get_first("gluon-node-info", "location", "longitude") + o:depends("_location", "1") + o.rmempty = false + o.datatype = "float" + o.description = i18n.translatef("e.g. %s", "10.689901") + + o = s:option(cbi.Value, "_altitude", i18n.translate("Altitude")) + o.default = uci:get_first("gluon-node-info", "location", "altitude") + o:depends("_location", "1") + o.rmempty = true + o.datatype = "float" + o.description = i18n.translatef("e.g. %s", "11.51") + +end + +function M.handle(data) + local sname = uci:get_first("gluon-node-info", "location") + + uci:set("gluon-node-info", sname, "share_location", data._location) + if data._location and data._latitude ~= nil and data._longitude ~= nil then + uci:set("gluon-node-info", sname, "latitude", data._latitude) + uci:set("gluon-node-info", sname, "longitude", data._longitude) + if data._altitude ~= nil then + uci:set("gluon-node-info", sname, "altitude", data._altitude) + else + uci:delete("gluon-node-info", sname, "altitude") + end + end + uci:save("gluon-node-info") + uci:commit("gluon-node-info") +end + +return M diff --git a/package/gluon-config-mode-geo-location/i18n/de.po b/package/gluon-config-mode-geo-location/i18n/de.po new file mode 100644 index 00000000..e83443dd --- /dev/null +++ b/package/gluon-config-mode-geo-location/i18n/de.po @@ -0,0 +1,36 @@ +msgid "" +msgstr "" +"Project-Id-Version: gluon-config-mode-geo-location\n" +"PO-Revision-Date: 2015-03-23 02:18+0100\n" +"Last-Translator: Martin Weinelt \n" +"Language-Team: German\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "" +"If you want the location of your node to be displayed on the map, you can " +"enter its coordinates here. Specifying the altitude is optional and should " +"only be done if a proper value is known." +msgstr "" +"Um deinen Knoten auf der Karte anzeigen zu können, benötigen wir seine " +"Koordinaten. Hier hast du die Möglichkeit, diese zu hinterlegen. Die " +"Höhenangabe ist optional und sollte nur gesetzt werden, wenn ein exakter " +"Wert bekannt ist." + +msgid "Latitude" +msgstr "Breitengrad" + +msgid "Longitude" +msgstr "Längengrad" + +msgid "Altitude" +msgstr "Höhenmeter über Normalnull" + +msgid "Show node on the map" +msgstr "Knoten auf der Karte anzeigen" + +msgid "e.g. %s" +msgstr "z.B. %s" diff --git a/package/gluon-config-mode-geo-location/i18n/gluon-config-mode-geo-location.pot b/package/gluon-config-mode-geo-location/i18n/gluon-config-mode-geo-location.pot new file mode 100644 index 00000000..a2be4fdf --- /dev/null +++ b/package/gluon-config-mode-geo-location/i18n/gluon-config-mode-geo-location.pot @@ -0,0 +1,23 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "" +"If you want the location of your node to be displayed on the map, you can " +"enter its coordinates here. Specifying the altitude is optional and should " +"only be done if a proper value is known." +msgstr "" + +msgid "Latitude" +msgstr "" + +msgid "Longitude" +msgstr "" + +msgid "Altitude" +msgstr "" + +msgid "Show node on the map" +msgstr "" + +msgid "e.g. %s" +msgstr "" diff --git a/package/gluon-config-mode-hostname/Makefile b/package/gluon-config-mode-hostname/Makefile new file mode 100644 index 00000000..803f018f --- /dev/null +++ b/package/gluon-config-mode-hostname/Makefile @@ -0,0 +1,36 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-config-mode-hostname +PKG_VERSION:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) + + +define Package/gluon-config-mode-hostname + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Set the hostname + DEPENDS:=gluon-config-mode-core-virtual +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile + $(call GluonBuildI18N,gluon-config-mode-hostname,i18n) +endef + +define Package/gluon-config-mode-hostname/install + $(CP) ./files/* $(1)/ + $(call GluonInstallI18N,gluon-config-mode-hostname,$(1)) +endef + +$(eval $(call BuildPackage,gluon-config-mode-hostname)) diff --git a/package/gluon-config-mode-hostname/files/lib/gluon/config-mode/wizard/0100-hostname.lua b/package/gluon-config-mode-hostname/files/lib/gluon/config-mode/wizard/0100-hostname.lua new file mode 100644 index 00000000..cf8bbf89 --- /dev/null +++ b/package/gluon-config-mode-hostname/files/lib/gluon/config-mode/wizard/0100-hostname.lua @@ -0,0 +1,21 @@ +local cbi = require "luci.cbi" +local i18n = require "luci.i18n" +local uci = luci.model.uci.cursor() + +local M = {} + +function M.section(form) + local s = form:section(cbi.SimpleSection, nil, nil) + local o = s:option(cbi.Value, "_hostname", i18n.translate("Node name")) + o.value = uci:get_first("system", "system", "hostname") + o.rmempty = false + o.datatype = "hostname" +end + +function M.handle(data) + uci:set("system", uci:get_first("system", "system"), "hostname", data._hostname) + uci:save("system") + uci:commit("system") +end + +return M diff --git a/package/gluon-config-mode-hostname/i18n/de.po b/package/gluon-config-mode-hostname/i18n/de.po new file mode 100644 index 00000000..f1d2a765 --- /dev/null +++ b/package/gluon-config-mode-hostname/i18n/de.po @@ -0,0 +1,14 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2015-03-19 00:54+0100\n" +"Last-Translator: Matthias Schiffer \n" +"Language-Team: German\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "Node name" +msgstr "Name dieses Knotens" diff --git a/package/gluon-config-mode-hostname/i18n/gluon-config-mode-hostname.pot b/package/gluon-config-mode-hostname/i18n/gluon-config-mode-hostname.pot new file mode 100644 index 00000000..dbaafc0b --- /dev/null +++ b/package/gluon-config-mode-hostname/i18n/gluon-config-mode-hostname.pot @@ -0,0 +1,5 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "Node name" +msgstr "" diff --git a/package/gluon-config-mode-mesh-vpn/Makefile b/package/gluon-config-mode-mesh-vpn/Makefile new file mode 100644 index 00000000..6a8a3f2c --- /dev/null +++ b/package/gluon-config-mode-mesh-vpn/Makefile @@ -0,0 +1,36 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-config-mode-mesh-vpn +PKG_VERSION:=2 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) + + +define Package/gluon-config-mode-mesh-vpn + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Toggle mesh-vpn and bandwidth limit + DEPENDS:=gluon-config-mode-core-virtual +gluon-mesh-vpn-fastd +gluon-simple-tc +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile + $(call GluonBuildI18N,gluon-config-mode-mesh-vpn,i18n) +endef + +define Package/gluon-config-mode-mesh-vpn/install + $(CP) ./files/* $(1)/ + $(call GluonInstallI18N,gluon-config-mode-mesh-vpn,$(1)) +endef + +$(eval $(call BuildPackage,gluon-config-mode-mesh-vpn)) diff --git a/package/gluon-config-mode-mesh-vpn/files/lib/gluon/config-mode/reboot/0100-mesh-vpn.lua b/package/gluon-config-mode-mesh-vpn/files/lib/gluon/config-mode/reboot/0100-mesh-vpn.lua new file mode 100644 index 00000000..1b32c731 --- /dev/null +++ b/package/gluon-config-mode-mesh-vpn/files/lib/gluon/config-mode/reboot/0100-mesh-vpn.lua @@ -0,0 +1,29 @@ +local uci = luci.model.uci.cursor() +local meshvpn_enabled = uci:get("fastd", "mesh_vpn", "enabled", "0") + +if meshvpn_enabled ~= "1" then + return nil +else + local i18n = require "luci.i18n" + local util = require "luci.util" + local site = require 'gluon.site_config' + local sysconfig = require 'gluon.sysconfig' + + local pubkey = util.trim(util.exec("/etc/init.d/fastd show_key " .. "mesh_vpn")) + local hostname = uci:get_first("system", "system", "hostname") + + local msg = [[

]] .. i18n.translate('gluon-config-mode:pubkey') .. [[

+
+ # <%= hostname %> +
+ <%= pubkey %> +
]] + + return function () + luci.template.render_string(msg, { pubkey=pubkey + , hostname=hostname + , site=site + , sysconfig=sysconfig + }) + end +end diff --git a/package/gluon-config-mode-mesh-vpn/files/lib/gluon/config-mode/wizard/0300-mesh-vpn.lua b/package/gluon-config-mode-mesh-vpn/files/lib/gluon/config-mode/wizard/0300-mesh-vpn.lua new file mode 100644 index 00000000..669a7bc3 --- /dev/null +++ b/package/gluon-config-mode-mesh-vpn/files/lib/gluon/config-mode/wizard/0300-mesh-vpn.lua @@ -0,0 +1,64 @@ +local cbi = require "luci.cbi" +local i18n = require "luci.i18n" +local uci = luci.model.uci.cursor() + +local M = {} + +function M.section(form) + local msg = i18n.translate('Your internet connection can be used to establish an ' .. + 'encrypted connection with other nodes. ' .. + 'Enable this option if there are no other nodes reachable ' .. + 'over WLAN in your vicinity or you want to make a part of ' .. + 'your connection\'s bandwidth available for the network. You can limit how ' .. + 'much bandwidth the node will use at most.') + local s = form:section(cbi.SimpleSection, nil, msg) + + local o + + o = s:option(cbi.Flag, "_meshvpn", i18n.translate("Use internet connection (mesh VPN)")) + o.default = uci:get_bool("fastd", "mesh_vpn", "enabled") and o.enabled or o.disabled + o.rmempty = false + + o = s:option(cbi.Flag, "_limit_enabled", i18n.translate("Limit bandwidth")) + o:depends("_meshvpn", "1") + o.default = uci:get_bool("gluon-simple-tc", "mesh_vpn", "enabled") and o.enabled or o.disabled + o.rmempty = false + + o = s:option(cbi.Value, "_limit_ingress", i18n.translate("Downstream (kbit/s)")) + o:depends("_limit_enabled", "1") + o.value = uci:get("gluon-simple-tc", "mesh_vpn", "limit_ingress") + o.rmempty = false + o.datatype = "integer" + + o = s:option(cbi.Value, "_limit_egress", i18n.translate("Upstream (kbit/s)")) + o:depends("_limit_enabled", "1") + o.value = uci:get("gluon-simple-tc", "mesh_vpn", "limit_egress") + o.rmempty = false + o.datatype = "integer" +end + +function M.handle(data) + uci:set("fastd", "mesh_vpn", "enabled", data._meshvpn) + uci:save("fastd") + uci:commit("fastd") + + -- checks for nil needed due to o:depends(...) + if data._limit_enabled ~= nil then + uci:set("gluon-simple-tc", "mesh_vpn", "interface") + uci:set("gluon-simple-tc", "mesh_vpn", "enabled", data._limit_enabled) + uci:set("gluon-simple-tc", "mesh_vpn", "ifname", "mesh-vpn") + + if data._limit_ingress ~= nil then + uci:set("gluon-simple-tc", "mesh_vpn", "limit_ingress", data._limit_ingress) + end + + if data._limit_egress ~= nil then + uci:set("gluon-simple-tc", "mesh_vpn", "limit_egress", data._limit_egress) + end + + uci:commit("gluon-simple-tc") + uci:commit("gluon-simple-tc") + end +end + +return M diff --git a/package/gluon-config-mode-mesh-vpn/i18n/de.po b/package/gluon-config-mode-mesh-vpn/i18n/de.po new file mode 100644 index 00000000..8c613aa0 --- /dev/null +++ b/package/gluon-config-mode-mesh-vpn/i18n/de.po @@ -0,0 +1,36 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2015-03-19 22:05+0100\n" +"Last-Translator: Matthias Schiffer \n" +"Language-Team: German\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "Downstream (kbit/s)" +msgstr "Downstream (kbit/s)" + +msgid "Limit bandwidth" +msgstr "Bandbreite begrenzen" + +msgid "Upstream (kbit/s)" +msgstr "Upstream (kbit/s)" + +msgid "Use internet connection (mesh VPN)" +msgstr "Internetverbindung nutzen (Mesh-VPN)" + +msgid "" +"Your internet connection can be used to establish an encrypted connection " +"with other nodes. Enable this option if there are no other nodes reachable " +"over WLAN in your vicinity or you want to make a part of your connection's " +"bandwidth available for the network. You can limit how much bandwidth the " +"node will use at most." +msgstr "" +"Dein Knoten kann deine Internetverbindung nutzen um darüber eine " +"verschlüsselte Verbindung zu anderen Knoten aufzubauen. Die dafür " +"genutzte Bandbreite kannst du beschränken. Aktiviere die Option, falls keine " +"per WLAN erreichbaren Nachbarknoten in deiner Nähe sind oder du deine " +"Internetverbindung für das Mesh-Netzwerk zur Verfügung stellen möchtest." diff --git a/package/gluon-config-mode-mesh-vpn/i18n/gluon-config-mode-mesh-vpn.pot b/package/gluon-config-mode-mesh-vpn/i18n/gluon-config-mode-mesh-vpn.pot new file mode 100644 index 00000000..52e2eef8 --- /dev/null +++ b/package/gluon-config-mode-mesh-vpn/i18n/gluon-config-mode-mesh-vpn.pot @@ -0,0 +1,22 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "Downstream (kbit/s)" +msgstr "" + +msgid "Limit bandwidth" +msgstr "" + +msgid "Upstream (kbit/s)" +msgstr "" + +msgid "Use internet connection (mesh VPN)" +msgstr "" + +msgid "" +"Your internet connection can be used to establish an encrypted connection " +"with other nodes. Enable this option if there are no other nodes reachable " +"over WLAN in your vicinity or you want to make a part of your connection's " +"bandwidth available for the network. You can limit how much bandwidth the " +"node will use at most." +msgstr "" diff --git a/package/gluon-core/Makefile b/package/gluon-core/Makefile new file mode 100644 index 00000000..2c632a00 --- /dev/null +++ b/package/gluon-core/Makefile @@ -0,0 +1,59 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-core +PKG_VERSION:=3 +PKG_RELEASE:=$(GLUON_VERSION) + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +define Package/gluon-core + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Base files of Gluon + DEPENDS:=+gluon-site +lua-platform-info +luci-lib-nixio +odhcp6c +firewall +endef + + +define LangConfig +config GLUON_LANG_$(1) + bool "$(GLUON_LANG_$(1)) language support" + depends on PACKAGE_gluon-core + default n + +endef + + +define Package/gluon-core/config +$(foreach lang,$(GLUON_SUPPORTED_LANGS),$(call LangConfig,$(lang))) +endef + + +define Package/gluon-core/description + Gluon community wifi mesh firmware framework: core +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-core/install + $(CP) ./files/* $(1)/ + + $(INSTALL_DIR) $(1)/lib/gluon + echo "$(GLUON_VERSION)" > $(1)/lib/gluon/gluon-version +endef + +define Package/gluon-core/postinst +#!/bin/sh +$(call GluonCheckSite,check_site.lua) +endef + +$(eval $(call BuildPackage,gluon-core)) diff --git a/package/gluon-core/check_site.lua b/package/gluon-core/check_site.lua new file mode 100644 index 00000000..1a6987a0 --- /dev/null +++ b/package/gluon-core/check_site.lua @@ -0,0 +1,10 @@ +need_string 'site_code' +need_string 'site_name' + +need_string('hostname_prefix', false) +need_string 'timezone' + +need_string_array('ntp_servers', false) + +need_string_match('prefix4', '^%d+.%d+.%d+.%d+/%d+$') +need_string_match('prefix6', '^[%x:]+/%d+$') diff --git a/package/gluon-core/files/etc/uci-defaults/zzz-gluon-upgrade b/package/gluon-core/files/etc/uci-defaults/zzz-gluon-upgrade new file mode 100755 index 00000000..a12ce78e --- /dev/null +++ b/package/gluon-core/files/etc/uci-defaults/zzz-gluon-upgrade @@ -0,0 +1,5 @@ +#!/bin/sh + +for script in /lib/gluon/upgrade/*; do + "$script" +done diff --git a/package/gluon-core/files/lib/gluon/core/sysconfig/.keep b/package/gluon-core/files/lib/gluon/core/sysconfig/.keep new file mode 100644 index 00000000..e69de29b diff --git a/package/gluon-core/files/lib/gluon/upgrade/001-upgrade b/package/gluon-core/files/lib/gluon/upgrade/001-upgrade new file mode 100755 index 00000000..6caba148 --- /dev/null +++ b/package/gluon-core/files/lib/gluon/upgrade/001-upgrade @@ -0,0 +1,10 @@ +#!/usr/bin/lua + +local fs = require 'luci.fs' +local sysconfig = require 'gluon.sysconfig' + + +if fs.isfile('/lib/gluon/version/core') and not sysconfig.gluon_version then + -- This isn't an initial upgrade, so set gluon_version + sysconfig.gluon_version = '' +end diff --git a/package/gluon-core/files/lib/gluon/upgrade/010-primary-mac b/package/gluon-core/files/lib/gluon/upgrade/010-primary-mac new file mode 100755 index 00000000..70aee39d --- /dev/null +++ b/package/gluon-core/files/lib/gluon/upgrade/010-primary-mac @@ -0,0 +1,42 @@ +#!/usr/bin/lua + +local sysconfig = require 'gluon.sysconfig' + + +if sysconfig.primary_mac then + os.exit(0) +end + + +local platform = require 'gluon.platform' + +local fs = require 'luci.fs' +local util = require 'luci.util' + + +local try_files = { + '/sys/class/ieee80211/phy0/macaddress', + '/sys/class/net/eth0/address', +} + +if platform.match('ar71xx', 'generic', {'tl-wdr3600', 'tl-wdr4300'}) then + table.insert(try_files, 1, '/sys/class/ieee80211/phy1/macaddress') +end + +if platform.match('ar71xx', 'generic', {'unifi-outdoor-plus'}) then + table.insert(try_files, 1, '/sys/class/net/eth0/address') +end + +if platform.match('ar71xx', 'generic', {'archer-c5', 'archer-c7'}) then + table.insert(try_files, 1, '/sys/class/net/eth1/address') +end + + +for _, file in ipairs(try_files) do + local addr = fs.readfile(file) + + if addr then + sysconfig.primary_mac = util.trim(addr) + break + end +end diff --git a/package/gluon-core/files/lib/gluon/upgrade/020-interfaces b/package/gluon-core/files/lib/gluon/upgrade/020-interfaces new file mode 100755 index 00000000..a051c738 --- /dev/null +++ b/package/gluon-core/files/lib/gluon/upgrade/020-interfaces @@ -0,0 +1,36 @@ +#!/usr/bin/lua + +local sysconfig = require 'gluon.sysconfig' +local gluon_util = require 'gluon.util' +local platform = require 'gluon.platform' + +local uci = require('luci.model.uci').cursor() + + +if not (sysconfig.lan_ifname or sysconfig.wan_ifname) then + local function iface_exists(name) + return (gluon_util.exec('ip', 'link', 'show', 'dev', (name:gsub('%..*$', ''))) == 0) + end + + + local lan_ifname = uci:get('network', 'lan', 'ifname') + local wan_ifname = uci:get('network', 'wan', 'ifname') + + if platform.match('ar71xx', 'generic', {'cpe510', 'nanostation-m', 'nanostation-m-xw', 'unifi-outdoor-plus'}) then + lan_ifname, wan_ifname = wan_ifname, lan_ifname + end + + if wan_ifname and iface_exists(wan_ifname) then + sysconfig.wan_ifname = wan_ifname + sysconfig.lan_ifname = lan_ifname + else + sysconfig.wan_ifname = lan_ifname + end + + + uci:delete('network', 'lan') + uci:delete('network', 'wan') + + uci:save('network') + uci:commit('network') +end diff --git a/package/gluon-core/files/lib/gluon/upgrade/030-system b/package/gluon-core/files/lib/gluon/upgrade/030-system new file mode 100755 index 00000000..d7a66605 --- /dev/null +++ b/package/gluon-core/files/lib/gluon/upgrade/030-system @@ -0,0 +1,18 @@ +#!/usr/bin/lua + +local sysconfig = require 'gluon.sysconfig' + +-- Initial +if not sysconfig.gluon_version then + local site = require 'gluon.site_config' + local util = require 'gluon.util' + local uci = require('luci.model.uci').cursor() + + local system = uci:get_first('system', 'system') + + uci:set('system', system, 'hostname', (site.hostname_prefix or '') .. util.node_id()) + uci:set('system', system, 'timezone', site.timezone) + + uci:save('system') + uci:commit('system') +end diff --git a/package/gluon-core/files/lib/gluon/upgrade/100-dnsmasq b/package/gluon-core/files/lib/gluon/upgrade/100-dnsmasq new file mode 100755 index 00000000..3636fbf6 --- /dev/null +++ b/package/gluon-core/files/lib/gluon/upgrade/100-dnsmasq @@ -0,0 +1,5 @@ +#!/bin/sh + +if [ -e /etc/dnsmasq.conf ]; then + sed -i -e '/^conf-dir=\/lib\/gluon\/dnsmasq\.d$/d' -e '/^conf-dir=\/var\/gluon\/dnsmasq\.d$/d' /etc/dnsmasq.conf +fi diff --git a/package/gluon-core/files/lib/gluon/upgrade/110-network b/package/gluon-core/files/lib/gluon/upgrade/110-network new file mode 100755 index 00000000..07961788 --- /dev/null +++ b/package/gluon-core/files/lib/gluon/upgrade/110-network @@ -0,0 +1,59 @@ +#!/usr/bin/lua + +local uci = require('luci.model.uci').cursor() +local sysctl = require 'gluon.sysctl' +local sysconfig = require 'gluon.sysconfig' + + +uci:section('network', 'interface', 'wan', + { + ifname = sysconfig.wan_ifname, + type = 'bridge', + igmp_snooping = 0, + peerdns = 0, + auto = 1, + } +) + +if not uci:get('network', 'wan', 'proto') then + uci:set('network', 'wan', 'proto', 'dhcp') +end + + +uci:section('network', 'interface', 'wan6', + { + ifname = 'br-wan', + peerdns = 0, + ip6table = 1, + } +) + +if not uci:get('network', 'wan6', 'proto') then + uci:set('network', 'wan6', 'proto', 'dhcpv6') +end + + +uci:section('network', 'rule6', 'wan6_lookup', + { + mark = '0x01/0x01', + lookup = 1, + } +) + +uci:section('network', 'route6', 'wan6_unreachable', + { + type = 'unreachable', + interface = 'loopback', + target = '::/0', + gateway = '::', + table = 1, + metric = 65535, + } +) + +uci:save('network') +uci:commit('network') + + +sysctl.set('net.ipv6.conf.all.accept_ra', 0) +sysctl.set('net.ipv6.conf.default.accept_ra', 0) diff --git a/package/gluon-core/files/lib/gluon/upgrade/120-ntp-servers b/package/gluon-core/files/lib/gluon/upgrade/120-ntp-servers new file mode 100755 index 00000000..2b3a2df6 --- /dev/null +++ b/package/gluon-core/files/lib/gluon/upgrade/120-ntp-servers @@ -0,0 +1,14 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local uci = require 'luci.model.uci' + +if not site.ntp_servers or #site.ntp_servers == 0 then + os.exit(0) +end + +local c = uci.cursor() +c:delete('system', 'ntp', 'server') +c:set_list('system', 'ntp', 'server', site.ntp_servers) +c:save('system') +c:commit('system') diff --git a/package/gluon-core/files/lib/gluon/upgrade/130-reboot-on-oom b/package/gluon-core/files/lib/gluon/upgrade/130-reboot-on-oom new file mode 100755 index 00000000..48cfc5a8 --- /dev/null +++ b/package/gluon-core/files/lib/gluon/upgrade/130-reboot-on-oom @@ -0,0 +1,5 @@ +#!/usr/bin/lua + +local sysctl = require 'gluon.sysctl' + +sysctl.set('vm.panic_on_oom', 1) diff --git a/package/gluon-core/files/lib/gluon/upgrade/140-firewall-rules b/package/gluon-core/files/lib/gluon/upgrade/140-firewall-rules new file mode 100755 index 00000000..792e06a2 --- /dev/null +++ b/package/gluon-core/files/lib/gluon/upgrade/140-firewall-rules @@ -0,0 +1,30 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local uci = require 'luci.model.uci' + +local c = uci.cursor() + + +local function reject_input_on_wan(zone) + if zone.name == 'wan' then + c:set('firewall', zone['.name'], 'input', 'REJECT') + c:set('firewall', zone['.name'], 'conntrack', '1') + end + + return true +end +c:foreach('firewall', 'zone', reject_input_on_wan) + +c:section('firewall', 'rule', 'wan_ssh', + { + name = 'wan_ssh', + src = 'wan', + dest_port = '22', + proto = 'tcp', + target = 'ACCEPT', + } +) + +c:save('firewall') +c:commit('firewall') diff --git a/package/gluon-core/files/lib/gluon/upgrade/200-wireless b/package/gluon-core/files/lib/gluon/upgrade/200-wireless new file mode 100755 index 00000000..219e505d --- /dev/null +++ b/package/gluon-core/files/lib/gluon/upgrade/200-wireless @@ -0,0 +1,12 @@ +#!/usr/bin/lua + +local sysconfig = require 'gluon.sysconfig' + +-- Initial +if not sysconfig.gluon_version then + local uci = require('luci.model.uci').cursor() + + uci:delete_all('wireless', 'wifi-iface') + uci:save('wireless') + uci:commit('wireless') +end diff --git a/package/gluon-core/files/lib/gluon/upgrade/999-version b/package/gluon-core/files/lib/gluon/upgrade/999-version new file mode 100755 index 00000000..62f08206 --- /dev/null +++ b/package/gluon-core/files/lib/gluon/upgrade/999-version @@ -0,0 +1,11 @@ +#!/usr/bin/lua + +local sysconfig = require 'gluon.sysconfig' + +local fs = require 'luci.fs' +local util = require 'luci.util' + + +-- Save the Gluon version in the sysconfig so we know which version we +-- upgraded from after the next upgrade +sysconfig.gluon_version = util.trim(fs.readfile('/lib/gluon/gluon-version')) diff --git a/package/gluon-core/files/lib/upgrade/keep.d/gluon b/package/gluon-core/files/lib/upgrade/keep.d/gluon new file mode 100644 index 00000000..bc82c775 --- /dev/null +++ b/package/gluon-core/files/lib/upgrade/keep.d/gluon @@ -0,0 +1 @@ +/lib/gluon/core/sysconfig/ diff --git a/package/gluon-core/files/usr/lib/lua/gluon/platform.lua b/package/gluon-core/files/usr/lib/lua/gluon/platform.lua new file mode 100644 index 00000000..3d56f081 --- /dev/null +++ b/package/gluon-core/files/usr/lib/lua/gluon/platform.lua @@ -0,0 +1,31 @@ +local platform_info = require 'platform_info' +local util = require 'luci.util' + +local setmetatable = setmetatable + + +module 'gluon.platform' + +setmetatable(_M, + { + __index = platform_info, + } +) + +function match(target, subtarget, boards) + if get_target() ~= target then + return false + end + + if get_subtarget() ~= subtarget then + return false + end + + if not util.contains(boards, get_board_name()) then + return false + end + + return true +end + + diff --git a/package/gluon-core/files/usr/lib/lua/gluon/site_config.lua b/package/gluon-core/files/usr/lib/lua/gluon/site_config.lua new file mode 100644 index 00000000..cf151483 --- /dev/null +++ b/package/gluon-core/files/usr/lib/lua/gluon/site_config.lua @@ -0,0 +1,21 @@ +local config = os.getenv('GLUON_SITE_CONFIG') or '/lib/gluon/site.conf' + +local function loader() + coroutine.yield('return ') + coroutine.yield(io.open(config):read('*a')) +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 + +module 'gluon.site_config' + +setmetatable(_M, + { + __index = site_config, + } +) + +return _M diff --git a/package/gluon-core/files/usr/lib/lua/gluon/sysconfig.lua b/package/gluon-core/files/usr/lib/lua/gluon/sysconfig.lua new file mode 100644 index 00000000..ff61f05b --- /dev/null +++ b/package/gluon-core/files/usr/lib/lua/gluon/sysconfig.lua @@ -0,0 +1,34 @@ +local sysconfigdir = '/lib/gluon/core/sysconfig/' + +local function get(_, name) + local f = io.open(sysconfigdir .. name) + if f then + local ret = f:read('*line') + f:close() + return (ret or '') + end + return nil +end + +local function set(_, name, val) + if val then + local f = io.open(sysconfigdir .. name, 'w+') + f:write(val) + f:close() + else + os.remove(sysconfigdir .. name) + end +end + +local setmetatable = setmetatable + +module 'gluon.sysconfig' + +setmetatable(_M, + { + __index = get, + __newindex = set, + } +) + +return _M diff --git a/package/gluon-core/files/usr/lib/lua/gluon/sysctl.lua b/package/gluon-core/files/usr/lib/lua/gluon/sysctl.lua new file mode 100644 index 00000000..44b0c217 --- /dev/null +++ b/package/gluon-core/files/usr/lib/lua/gluon/sysctl.lua @@ -0,0 +1,8 @@ +local util = require 'gluon.util' + + +module 'gluon.sysctl' + +function set(name, value) + util.replace_prefix('/etc/sysctl.conf', name .. '=', name .. '=' .. value .. '\n') +end diff --git a/package/gluon-core/files/usr/lib/lua/gluon/users.lua b/package/gluon-core/files/usr/lib/lua/gluon/users.lua new file mode 100644 index 00000000..8e618d88 --- /dev/null +++ b/package/gluon-core/files/usr/lib/lua/gluon/users.lua @@ -0,0 +1,33 @@ +local util = require 'gluon.util' + +local os = os +local string = string + + +module 'gluon.users' + +function add_user(username, uid, gid) + util.lock('/var/lock/passwd') + util.replace_prefix('/etc/passwd', username .. ':', string.format('%s:*:%u:%u::/var:/bin/false\n', username, uid, gid)) + util.replace_prefix('/etc/shadow', username .. ':', string.format('%s:*:0:0:99999:7:::\n', username)) + util.unlock('/var/lock/passwd') +end + +function remove_user(username) + util.lock('/var/lock/passwd') + util.replace_prefix('/etc/passwd', username .. ':') + util.replace_prefix('/etc/shadow', username .. ':') + util.unlock('/var/lock/passwd') +end + +function add_group(groupname, gid) + util.lock('/var/lock/group') + util.replace_prefix('/etc/group', groupname .. ':', string.format('%s:x:%u:\n', groupname, gid)) + util.unlock('/var/lock/group') +end + +function remove_group(groupname) + util.lock('/var/lock/group') + util.replace_prefix('/etc/group', groupname .. ':') + util.unlock('/var/lock/group') +end diff --git a/package/gluon-core/files/usr/lib/lua/gluon/util.lua b/package/gluon-core/files/usr/lib/lua/gluon/util.lua new file mode 100644 index 00000000..cf3677cb --- /dev/null +++ b/package/gluon-core/files/usr/lib/lua/gluon/util.lua @@ -0,0 +1,79 @@ +-- Writes all lines from the file input to the file output except those starting with prefix +-- Doesn't close the output file, but returns the file object +local function do_filter_prefix(input, output, prefix) + local f = io.open(output, 'w+') + local l = prefix:len() + + for line in io.lines(input) do + if line:sub(1, l) ~= prefix then + f:write(line, '\n') + end + end + + return f +end + + +local function escape_args(ret, arg0, ...) + if not arg0 then + return ret + end + + return escape_args(ret .. "'" .. string.gsub(arg0, "'", "'\\''") .. "' ", ...) +end + + +local os = os +local string = string +local tonumber = tonumber + +local nixio = require 'nixio' +local sysconfig = require 'gluon.sysconfig' + + +module 'gluon.util' + +function exec(...) + return os.execute(escape_args('', ...)) +end + +-- Removes all lines starting with a prefix from a file, optionally adding a new one +function replace_prefix(file, prefix, add) + local tmp = file .. '.tmp' + local f = do_filter_prefix(file, tmp, prefix) + if add then + f:write(add) + end + f:close() + os.rename(tmp, file) +end + +function lock(file) + exec('lock', file) +end + +function unlock(file) + exec('lock', '-u', file) +end + +function node_id() + return string.gsub(sysconfig.primary_mac, ':', '') +end + +-- Generates a (hopefully) unique MAC address +-- The first parameter defines the function and the second +-- parameter an ID to add to the MAC address +-- Functions and IDs defined so far: +-- (1, 0): WAN (for mesh-on-WAN) +-- (1, 1): LAN (for mesh-on-LAN) +-- (2, n): client interface for the n'th radio +-- (3, n): adhoc interface for n'th radio +-- (4, 0): mesh VPN +function generate_mac(f, i) + local m1, m2, m3, m4, m5, m6 = string.match(sysconfig.primary_mac, '(%x%x):(%x%x):(%x%x):(%x%x):(%x%x):(%x%x)') + m1 = nixio.bit.bor(tonumber(m1, 16), 0x02) + m2 = (tonumber(m2, 16)+f) % 0x100 + m3 = (tonumber(m3, 16)+i) % 0x100 + + return string.format('%02x:%02x:%02x:%s:%s:%s', m1, m2, m3, m4, m5, m6) +end diff --git a/package/gluon-cron/Makefile b/package/gluon-cron/Makefile new file mode 100644 index 00000000..ac92a92d --- /dev/null +++ b/package/gluon-cron/Makefile @@ -0,0 +1,40 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-cron +PKG_VERSION:=1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + +define Package/gluon-cron + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Cron support + DEPENDS:=+gluon-core +endef + +define Package/gluon-cron/description + Gluon community wifi mesh firmware framework: cron support +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ +endef + +define Build/Configure +endef + +define Build/Compile + CFLAGS="$(TARGET_CFLAGS)" CPPFLAGS="$(TARGET_CPPFLAGS)" $(MAKE) -C $(PKG_BUILD_DIR) $(TARGET_CONFIGURE_OPTS) +endef + +define Package/gluon-cron/install + $(CP) ./files/* $(1)/ + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/gluon-crond $(1)/usr/sbin/ +endef + +$(eval $(call BuildPackage,gluon-cron)) diff --git a/package/gluon-cron/files/etc/init.d/gluon-cron b/package/gluon-cron/files/etc/init.d/gluon-cron new file mode 100755 index 00000000..27a05e1d --- /dev/null +++ b/package/gluon-cron/files/etc/init.d/gluon-cron @@ -0,0 +1,18 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2013 Project Gluon + +START=50 + +SERVICE_USE_PID=1 +SERVICE_WRITE_PID=1 +SERVICE_DAEMONIZE=1 + +CRONDIR=/lib/gluon/cron + +start () { + service_start /usr/sbin/gluon-crond "$CRONDIR" +} + +stop() { + service_stop /usr/sbin/gluon-crond +} diff --git a/package/gluon-cron/files/lib/gluon/cron/.keep b/package/gluon-cron/files/lib/gluon/cron/.keep new file mode 100644 index 00000000..e69de29b diff --git a/package/gluon-cron/src/Makefile b/package/gluon-cron/src/Makefile new file mode 100644 index 00000000..3f4c7a50 --- /dev/null +++ b/package/gluon-cron/src/Makefile @@ -0,0 +1,3 @@ +all: gluon-crond + +gluon-crond: gluon-crond.c diff --git a/package/gluon-cron/src/gluon-crond.c b/package/gluon-cron/src/gluon-crond.c new file mode 100644 index 00000000..11a87c42 --- /dev/null +++ b/package/gluon-cron/src/gluon-crond.c @@ -0,0 +1,316 @@ +/* + Copyright (c) 2013, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +typedef struct job { + struct job *next; + + uint64_t minutes; + uint32_t hours; + uint32_t doms; + uint16_t months; + uint8_t dows; + + char *command; +} job_t; + + +static const char const *const MONTHS[12] = { + "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" +}; + +static const char const *const WEEKDAYS[7] = { + "sun", "mon", "tue", "wed", "thu", "fri", "sat" +}; + + +static const char *crondir; + +static job_t *jobs = NULL; + + +static void usage(void) { + fprintf(stderr, "Usage: gluon-crond \n"); +} + + +static inline uint64_t bit(unsigned b) { + return ((uint64_t)1) << b; +} + +static int strict_atoi(const char *s) { + char *end; + int ret = strtol(s, &end, 10); + + if (*end) + return -1; + else + return ret; +} + +static uint64_t parse_strings(const char *input, const char *const *strings, size_t n) { + size_t i; + for (i = 0; i < n; i++) { + if (strcasecmp(input, strings[i]) == 0) + return bit(i); + } + + return 0; +} + +static uint64_t parse_times(char *input, int min, int n) { + uint64_t ret = 0; + int step = 1; + + char *comma = strchr(input, ','); + if (comma) { + *comma = 0; + ret = parse_times(comma+1, min, n); + + if (!ret) + return 0; + } + + char *slash = strchr(input, '/'); + if (slash) { + *slash = 0; + step = strict_atoi(slash+1); + + if (step <= 0) + return 0; + } + + int begin, end; + char *minus = strchr(input, '-'); + if (minus) { + *minus = 0; + begin = strict_atoi(input); + end = strict_atoi(minus+1); + } + else if (strcmp(input, "*") == 0) { + begin = min; + end = min+n-1; + } + else { + begin = end = strict_atoi(input); + } + + if (begin < min || end < min) + return 0; + + int i; + for (i = begin-min; i <= end-min; i += step) + ret |= bit(i % n); + + return ret; +} + +static int handle_line(const char *line) { + job_t job = {}; + int ret = -1; + char *columns[5]; + int i; + int len; + + int matches = sscanf(line, "%ms %ms %ms %ms %ms %n", &columns[0], &columns[1], &columns[2], &columns[3], &columns[4], &len); + if (matches != 5 && matches != 6) { + if (matches <= 0) + ret = 0; + + goto end; + } + + job.minutes = parse_times(columns[0], 0, 60); + if (!job.minutes) + goto end; + + job.hours = parse_times(columns[1], 0, 24); + if (!job.hours) + goto end; + + job.doms = parse_times(columns[2], 1, 31); + if (!job.doms) + goto end; + + + job.months = parse_strings(columns[3], MONTHS, 12); + + if (!job.months) + job.months = parse_times(columns[3], 1, 12); + if (!job.months) + goto end; + + job.dows = parse_strings(columns[4], WEEKDAYS, 7); + if (!job.dows) + job.dows = parse_times(columns[4], 0, 7); + if (!job.dows) + goto end; + + job.command = strdup(line+len); + + job_t *jobp = malloc(sizeof(job_t)); + *jobp = job; + + jobp->next = jobs; + jobs = jobp; + + ret = 0; + + end: + for (i = 0; i < matches && i < 5; i++) + free(columns[i]); + + return ret; +} + + +static void read_crontab(const char *name) { + FILE *file = fopen(name, "r"); + if (!file) { + syslog(LOG_WARNING, "unable to read crontab `%s'", name); + return; + } + + char line[16384]; + unsigned lineno = 0; + + while (fgets(line, sizeof(line), file)) { + lineno++; + + char *comment = strchr(line, '#'); + if (comment) + *comment = 0; + + if (handle_line(line)) + syslog(LOG_WARNING, "syntax error in `%s', line %u", name, lineno); + } + + fclose(file); +} + + +static void read_crondir(void) { + DIR *dir; + + if (chdir(crondir) || ((dir = opendir(".")) == NULL)) { + fprintf(stderr, "Unable to read crondir `%s'\n", crondir); + usage(); + exit(1); + } + + struct dirent *ent; + while ((ent = readdir(dir)) != NULL) { + if (ent->d_name[0] == '.') + continue; + + read_crontab(ent->d_name); + } + + closedir(dir); +} + + +static void run_job(const job_t *job) { + pid_t pid = fork(); + if (pid == 0) { + execl("/bin/sh", "/bin/sh", "-c", job->command, (char*)NULL); + syslog(LOG_ERR, "unable to run job: exec failed"); + _exit(1); + } + else if (pid < 0) { + syslog(LOG_ERR, "unable to run job: fork failed"); + } +} + + +static void check_job(const job_t *job, const struct tm *tm) { + if (!(job->minutes & bit(tm->tm_min))) + return; + + if (!(job->hours & bit(tm->tm_hour))) + return; + + if (!(job->doms & bit(tm->tm_mday-1))) + return; + + if (!(job->months & bit(tm->tm_mon))) + return; + + if (!(job->dows & bit(tm->tm_wday))) + return; + + run_job(job); +} + + +int main(int argc, char *argv[]) { + if (argc != 2) { + usage(); + + exit(argc < 2 ? 0 : 1); + } + + crondir = argv[1]; + + signal(SIGCHLD, SIG_IGN); + + read_crondir(); + + time_t t = time(NULL); + struct tm *tm = localtime(&t); + int minute = tm->tm_min; + + while (1) { + sleep(60 - t%60); + + t = time(NULL); + tm = localtime(&t); + + minute = (minute+1)%60; + if (tm->tm_min != minute) { + /* clock has moved, don't execute jobs */ + minute = tm->tm_min; + continue; + } + + job_t *job; + for (job = jobs; job; job = job->next) + check_job(job, tm); + } +} diff --git a/package/gluon-ebtables-filter-multicast/Makefile b/package/gluon-ebtables-filter-multicast/Makefile new file mode 100644 index 00000000..93b7f9a5 --- /dev/null +++ b/package/gluon-ebtables-filter-multicast/Makefile @@ -0,0 +1,40 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-ebtables-filter-multicast +PKG_VERSION:=1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + +define Package/gluon-ebtables-filter-multicast + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Ebtables filters for multicast packets + DEPENDS:=+gluon-core +gluon-ebtables +endef + +define Package/gluon-ebtables-filter-multicast/description + Gluon community wifi mesh firmware framework: Ebtables filters for multicast packets + + These filters drop non-essential multicast traffic before it enters the mesh. + + Allowed protocols are: DHCP, DHCPv6, ARP, ICMP, ICMPv6, BitTorrent local peer discovery, BABEL and OSPF +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-ebtables-filter-multicast/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,gluon-ebtables-filter-multicast)) diff --git a/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/100-mcast-chain b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/100-mcast-chain new file mode 100644 index 00000000..ec0013a3 --- /dev/null +++ b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/100-mcast-chain @@ -0,0 +1 @@ +chain('MULTICAST_OUT', 'DROP') diff --git a/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-arp b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-arp new file mode 100644 index 00000000..8af1900a --- /dev/null +++ b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-arp @@ -0,0 +1,3 @@ +rule 'MULTICAST_OUT -p ARP --arp-opcode Reply --arp-ip-src 0.0.0.0 -j DROP' +rule 'MULTICAST_OUT -p ARP --arp-opcode Request --arp-ip-dst 0.0.0.0 -j DROP' +rule 'MULTICAST_OUT -p ARP -j RETURN' diff --git a/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-babel b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-babel new file mode 100644 index 00000000..d5b81771 --- /dev/null +++ b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-babel @@ -0,0 +1 @@ +rule 'MULTICAST_OUT -p IPv6 --ip6-protocol udp --ip6-destination-port 6696 -j RETURN' diff --git a/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-btlpd b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-btlpd new file mode 100644 index 00000000..20b709f8 --- /dev/null +++ b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-btlpd @@ -0,0 +1 @@ +rule 'MULTICAST_OUT -p IPv4 --ip-destination 239.192.152.143 --ip-protocol udp --ip-destination-port 6771 -j RETURN' diff --git a/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-dhcpv4 b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-dhcpv4 new file mode 100644 index 00000000..2fca2223 --- /dev/null +++ b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-dhcpv4 @@ -0,0 +1 @@ +rule 'MULTICAST_OUT -p IPv4 --ip-protocol udp --ip-destination-port 67 -j RETURN' diff --git a/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-dhcpv6 b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-dhcpv6 new file mode 100644 index 00000000..6d7f0f55 --- /dev/null +++ b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-dhcpv6 @@ -0,0 +1 @@ +rule 'MULTICAST_OUT -p IPv6 --ip6-protocol udp --ip6-destination-port 547 -j RETURN' diff --git a/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-icmp b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-icmp new file mode 100644 index 00000000..25a95f39 --- /dev/null +++ b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-icmp @@ -0,0 +1 @@ +rule 'MULTICAST_OUT -p IPv4 --ip-protocol icmp -j RETURN' diff --git a/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-icmpv6 b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-icmpv6 new file mode 100644 index 00000000..a7b67414 --- /dev/null +++ b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-icmpv6 @@ -0,0 +1,2 @@ +rule 'MULTICAST_OUT -p IPv6 --ip6-protocol 0 -j RETURN' -- hop-by-hop +rule 'MULTICAST_OUT -p IPv6 --ip6-protocol ipv6-icmp -j RETURN' diff --git a/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-igmp b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-igmp new file mode 100644 index 00000000..2d3814ae --- /dev/null +++ b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-igmp @@ -0,0 +1 @@ +rule 'MULTICAST_OUT -p IPv4 --ip-protocol igmp -j RETURN' diff --git a/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-ospf b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-ospf new file mode 100644 index 00000000..da928d4b --- /dev/null +++ b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-ospf @@ -0,0 +1,2 @@ +rule 'MULTICAST_OUT -p IPv4 --ip-protocol ospf -j RETURN' +rule 'MULTICAST_OUT -p IPv6 --ip6-protocol ospf -j RETURN' diff --git a/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-ripng b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-ripng new file mode 100644 index 00000000..37d31877 --- /dev/null +++ b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-ripng @@ -0,0 +1 @@ +rule 'MULTICAST_OUT -p IPv6 --ip6-protocol udp --ip6-destination ff02::9 --ip6-destination-port 521 -j RETURN' diff --git a/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/300-mcast b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/300-mcast new file mode 100644 index 00000000..c52f122f --- /dev/null +++ b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/300-mcast @@ -0,0 +1,2 @@ +rule 'FORWARD --logical-out br-client -o bat0 -d Multicast -j MULTICAST_OUT' +rule 'OUTPUT --logical-out br-client -o bat0 -d Multicast -j MULTICAST_OUT' diff --git a/package/gluon-ebtables-filter-ra-dhcp/Makefile b/package/gluon-ebtables-filter-ra-dhcp/Makefile new file mode 100644 index 00000000..ea6a737d --- /dev/null +++ b/package/gluon-ebtables-filter-ra-dhcp/Makefile @@ -0,0 +1,39 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-ebtables-filter-ra-dhcp +PKG_VERSION:=1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + +define Package/gluon-ebtables-filter-ra-dhcp + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Ebtables filters for Router Advertisement and DHCP packets + DEPENDS:=+gluon-core +gluon-ebtables +endef + +define Package/gluon-ebtables-filter-ra-dhcp/description + Gluon community wifi mesh firmware framework: Ebtables filters for Router Advertisement and DHCP packets + + These filters ensure that RA and DHCP packets are only forwarded from the mesh into the + client network, and not vice-versa. +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-ebtables-filter-ra-dhcp/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,gluon-ebtables-filter-ra-dhcp)) diff --git a/package/gluon-ebtables-filter-ra-dhcp/files/lib/gluon/ebtables/200-dir-dhcpv4 b/package/gluon-ebtables-filter-ra-dhcp/files/lib/gluon/ebtables/200-dir-dhcpv4 new file mode 100644 index 00000000..ec56ff1d --- /dev/null +++ b/package/gluon-ebtables-filter-ra-dhcp/files/lib/gluon/ebtables/200-dir-dhcpv4 @@ -0,0 +1,5 @@ +rule 'FORWARD -p IPv4 --ip-protocol udp --ip-destination-port 67 -j OUT_ONLY' +rule 'OUTPUT -p IPv4 --ip-protocol udp --ip-destination-port 67 -j OUT_ONLY' + +rule 'FORWARD -p IPv4 --ip-protocol udp --ip-destination-port 68 -j IN_ONLY' +rule 'INPUT -p IPv4 --ip-protocol udp --ip-destination-port 68 -j IN_ONLY' diff --git a/package/gluon-ebtables-filter-ra-dhcp/files/lib/gluon/ebtables/200-dir-dhcpv6 b/package/gluon-ebtables-filter-ra-dhcp/files/lib/gluon/ebtables/200-dir-dhcpv6 new file mode 100644 index 00000000..470a7648 --- /dev/null +++ b/package/gluon-ebtables-filter-ra-dhcp/files/lib/gluon/ebtables/200-dir-dhcpv6 @@ -0,0 +1,5 @@ +rule 'FORWARD -p IPv6 --ip6-protocol udp --ip6-destination-port 547 -j OUT_ONLY' +rule 'OUTPUT -p IPv6 --ip6-protocol udp --ip6-destination-port 547 -j OUT_ONLY' + +rule 'FORWARD -p IPv6 --ip6-protocol udp --ip6-destination-port 546 -j IN_ONLY' +rule 'INPUT -p IPv6 --ip6-protocol udp --ip6-destination-port 546 -j IN_ONLY' diff --git a/package/gluon-ebtables-filter-ra-dhcp/files/lib/gluon/ebtables/200-dir-radv b/package/gluon-ebtables-filter-ra-dhcp/files/lib/gluon/ebtables/200-dir-radv new file mode 100644 index 00000000..b34d4c76 --- /dev/null +++ b/package/gluon-ebtables-filter-ra-dhcp/files/lib/gluon/ebtables/200-dir-radv @@ -0,0 +1,5 @@ +rule 'FORWARD -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type router-solicitation -j OUT_ONLY' +rule 'OUTPUT -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type router-solicitation -j OUT_ONLY' + +rule 'FORWARD -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type router-advertisement -j IN_ONLY' +rule 'INPUT -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type router-advertisement -j IN_ONLY' diff --git a/package/gluon-ebtables/Makefile b/package/gluon-ebtables/Makefile new file mode 100644 index 00000000..39c654c1 --- /dev/null +++ b/package/gluon-ebtables/Makefile @@ -0,0 +1,36 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-ebtables +PKG_VERSION:=1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + +define Package/gluon-ebtables + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Ebtables support + DEPENDS:=+gluon-core +ebtables +kmod-ebtables-ipv4 +kmod-ebtables-ipv6 +kmod-ipt-core +endef + +define Package/gluon-ebtables/description + Gluon community wifi mesh firmware framework: ebtables support +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-ebtables/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,gluon-ebtables)) diff --git a/package/gluon-ebtables/files/etc/init.d/gluon-ebtables b/package/gluon-ebtables/files/etc/init.d/gluon-ebtables new file mode 100755 index 00000000..5a770452 --- /dev/null +++ b/package/gluon-ebtables/files/etc/init.d/gluon-ebtables @@ -0,0 +1,73 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2013 Project Gluon +# +# Firewall script for inserting and removing ebtables rules. +# +# Example format, for filtering any IPv4 multicast packets to the SSDP UDP port: +# rule FORWARD --logical-out br-client -d Multicast -p IPv4 --ip-protocol udp --ip-destination-port 5355 -j DROP +# +# Removing all rules: +# $ ./firewall-ebtables stop +# Inserting all rules: +# $ ./firewall-ebtables start +# Inserting a specific rule file: +# $ ./firewall-ebtables start /lib/gluon/ebtables/100-mcast-chain +# Removing a specific rule file: +# $ ./firewall-ebtables stop /lib/gluon/ebtables/100-mcast-chain + + +START=19 +STOP=91 + + +exec_file() { + local file="$1" + + /usr/bin/lua -e " + function rule(command) + os.execute($EBTABLES_RULE) + end + function chain(name, policy) + os.execute($EBTABLES_CHAIN) + end + " "$file" +} + +exec_all() { + local sort_arg="$1" + + local old_ifs="$IFS" + IFS=' +' + for file in `find /lib/gluon/ebtables -type f | sort $sort_arg`; do + exec_file "$file" + done + IFS="$old_ifs" +} + + +start() { + ( + export EBTABLES_RULE='"ebtables -A " .. command' + export EBTABLES_CHAIN='"ebtables -N " .. name .. " -P " .. policy' + + if [ -z "$1" ]; then + exec_all '' + else + exec_file "$1" + fi + ) +} + +stop() { + ( + export EBTABLES_RULE='"ebtables -D " .. command' + export EBTABLES_CHAIN='"ebtables -X " .. name' + + if [ -z "$1" ]; then + exec_all '-r' + else + exec_file "$1" + fi + ) +} diff --git a/package/gluon-ebtables/files/lib/gluon/ebtables/100-dir-chain b/package/gluon-ebtables/files/lib/gluon/ebtables/100-dir-chain new file mode 100644 index 00000000..31c19c53 --- /dev/null +++ b/package/gluon-ebtables/files/lib/gluon/ebtables/100-dir-chain @@ -0,0 +1,2 @@ +chain('IN_ONLY', 'RETURN') +chain('OUT_ONLY', 'RETURN') diff --git a/package/gluon-ebtables/files/lib/gluon/ebtables/101-dir-rules b/package/gluon-ebtables/files/lib/gluon/ebtables/101-dir-rules new file mode 100644 index 00000000..b1cd4e24 --- /dev/null +++ b/package/gluon-ebtables/files/lib/gluon/ebtables/101-dir-rules @@ -0,0 +1,2 @@ +rule 'IN_ONLY --logical-in br-client -i ! bat0 -j DROP' +rule 'OUT_ONLY --logical-out br-client -o ! bat0 -j DROP' diff --git a/package/gluon-legacy/Makefile b/package/gluon-legacy/Makefile new file mode 100644 index 00000000..7320fba6 --- /dev/null +++ b/package/gluon-legacy/Makefile @@ -0,0 +1,40 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-legacy +PKG_VERSION:=2 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +define Package/gluon-legacy + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Legacy update scripts + DEPENDS:=+gluon-core +endef + +define Package/gluon-legacy/description + Gluon community wifi mesh firmware framework: legacy update scripts +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-legacy/install + $(CP) ./files/* $(1)/ +endef + +define Package/gluon-legacy/postinst +#!/bin/sh +$(call GluonCheckSite,check_site.lua) +endef + +$(eval $(call BuildPackage,gluon-legacy)) diff --git a/package/gluon-legacy/check_site.lua b/package/gluon-legacy/check_site.lua new file mode 100644 index 00000000..1ec26de0 --- /dev/null +++ b/package/gluon-legacy/check_site.lua @@ -0,0 +1,8 @@ +need_string_array 'legacy.version_files' +need_string_array 'legacy.old_files' + +need_string_array 'legacy.config_mode_configs' +need_string_array 'legacy.fastd_configs' +need_string 'legacy.mesh_ifname' +need_string_array 'legacy.tc_configs' +need_string_array 'legacy.wifi_names' diff --git a/package/gluon-legacy/files/lib/gluon/upgrade/000-legacy b/package/gluon-legacy/files/lib/gluon/upgrade/000-legacy new file mode 100755 index 00000000..78436676 --- /dev/null +++ b/package/gluon-legacy/files/lib/gluon/upgrade/000-legacy @@ -0,0 +1,11 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local sysconfig = require 'gluon.sysconfig' + +for _, file in ipairs(site.legacy.version_files) do + if os.remove(file) then + -- Set version being upgraded from to 'legacy' + sysconfig.gluon_version = 'legacy' + end +end diff --git a/package/gluon-legacy/files/lib/gluon/upgrade/019-legacy-interfaces b/package/gluon-legacy/files/lib/gluon/upgrade/019-legacy-interfaces new file mode 100755 index 00000000..b48e42b8 --- /dev/null +++ b/package/gluon-legacy/files/lib/gluon/upgrade/019-legacy-interfaces @@ -0,0 +1,40 @@ +#!/usr/bin/lua + +local gluon_util = require 'gluon.util' +local platform = require 'gluon.platform' +local site = require 'gluon.site_config' +local sysconfig = require 'gluon.sysconfig' + +local uci = require('luci.model.uci').cursor() +local util = require 'luci.util' + + +if sysconfig.gluon_version == 'legacy' then + local function iface_exists(name) + return (gluon_util.exec('ip', 'link', 'show', 'dev', (name:gsub('%..*$', ''))) == 0) + end + + local function remove_bat0(iface) + return util.trim(string.gsub(' ' .. iface .. ' ', ' bat0 ', ' ')) + end + + + local lan_ifname = remove_bat0(uci:get('network', site.legacy.mesh_ifname, 'ifname')) + local wan_ifname = uci:get('network', 'wan', 'ifname') + + if wan_ifname and iface_exists(wan_ifname) then + sysconfig.wan_ifname = wan_ifname + sysconfig.lan_ifname = lan_ifname + else + sysconfig.wan_ifname = lan_ifname + end + + + uci:delete('network', site.legacy.mesh_ifname) + uci:delete('network', 'wan') + + uci:save('network') + uci:commit('network') +end + + diff --git a/package/gluon-legacy/files/lib/gluon/upgrade/210-legacy-wireless b/package/gluon-legacy/files/lib/gluon/upgrade/210-legacy-wireless new file mode 100755 index 00000000..36da0632 --- /dev/null +++ b/package/gluon-legacy/files/lib/gluon/upgrade/210-legacy-wireless @@ -0,0 +1,24 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local sysconfig = require 'gluon.sysconfig' + +local uci = require('luci.model.uci').cursor() + + +if sysconfig.gluon_version == 'legacy' then + function delete_legacy_iface(iface) + for _, wifi in pairs(site.legacy.wifi_names) do + if wifi == iface['.name'] then + return true + end + end + + return false + end + + uci:delete_all('wireless', 'wifi-iface', delete_legacy_iface) + + uci:save('wireless') + uci:commit('wireless') +end diff --git a/package/gluon-legacy/files/lib/gluon/upgrade/290-legacy-setup-mode b/package/gluon-legacy/files/lib/gluon/upgrade/290-legacy-setup-mode new file mode 100755 index 00000000..0b97e120 --- /dev/null +++ b/package/gluon-legacy/files/lib/gluon/upgrade/290-legacy-setup-mode @@ -0,0 +1,22 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local sysconfig = require 'gluon.sysconfig' + +local uci = require('luci.model.uci').cursor() + + +if sysconfig.gluon_version == 'legacy' then + for _, config in ipairs(site.legacy.config_mode_configs) do + local old = uci:get_first(config, 'wizard', 'configured') + if old == '1' then + local setup_mode = uci:get_first('gluon-setup-mode', 'setup_mode') + uci:set('gluon-setup-mode', setup_mode, 'configured', '1') + + uci:save('gluon-setup-mode') + uci:commit('gluon-setup-mode') + + break + end + end +end diff --git a/package/gluon-legacy/files/lib/gluon/upgrade/290-legacy-simple-tc b/package/gluon-legacy/files/lib/gluon/upgrade/290-legacy-simple-tc new file mode 100755 index 00000000..c67afe14 --- /dev/null +++ b/package/gluon-legacy/files/lib/gluon/upgrade/290-legacy-simple-tc @@ -0,0 +1,29 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local sysconfig = require 'gluon.sysconfig' + +local uci = require('luci.model.uci').cursor() + + +if sysconfig.gluon_version == 'legacy' then + for _, config in ipairs(site.legacy.tc_configs) do + local s = uci:get_first(config, 'bandwidth') + if s then + old = uci:get_all(config, s) + uci:section('gluon-simple-tc', 'interface', 'mesh_vpn', + { + ifname = 'mesh-vpn', + enabled = old.enabled, + limit_ingress = old.downstream, + limit_egress = old.upstream, + } + ) + + uci:save('gluon-simple-tc') + uci:commit('gluon-simple-tc') + + break + end + end +end diff --git a/package/gluon-legacy/files/lib/gluon/upgrade/390-legacy-mesh-vpn-fastd b/package/gluon-legacy/files/lib/gluon/upgrade/390-legacy-mesh-vpn-fastd new file mode 100755 index 00000000..468a35a6 --- /dev/null +++ b/package/gluon-legacy/files/lib/gluon/upgrade/390-legacy-mesh-vpn-fastd @@ -0,0 +1,37 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local sysconfig = require 'gluon.sysconfig' + +local uci = require('luci.model.uci').cursor() + + +if sysconfig.gluon_version == 'legacy' then + local secret + local enabled + + + for _, config in ipairs(site.legacy.fastd_configs) do + if not secret then + local s = uci:get_all('fastd', config) + if s then + secret = s.secret + enabled = s.enabled + end + end + + uci:delete('fastd', config) + end + + if secret then + uci:section('fastd', 'fastd', 'mesh_vpn', + { + secret = secret, + enabled = enabled, + } + ) + end + + uci:save('fastd') + uci:commit('fastd') +end diff --git a/package/gluon-legacy/files/lib/gluon/upgrade/990-legacy-late b/package/gluon-legacy/files/lib/gluon/upgrade/990-legacy-late new file mode 100755 index 00000000..efb6b675 --- /dev/null +++ b/package/gluon-legacy/files/lib/gluon/upgrade/990-legacy-late @@ -0,0 +1,11 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local sysconfig = require 'gluon.sysconfig' + + +if sysconfig.gluon_version == 'legacy' then + for _, file in ipairs(site.legacy.old_files) do + os.remove(file) + end +end diff --git a/package/gluon-lock-password/Makefile b/package/gluon-lock-password/Makefile new file mode 100644 index 00000000..d0e99373 --- /dev/null +++ b/package/gluon-lock-password/Makefile @@ -0,0 +1,36 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-lock-password +PKG_VERSION:=1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + +define Package/gluon-lock-password + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Locks the root account by default + DEPENDS:=+gluon-core +endef + +define Package/gluon-lock-password/description + This packages locks the root account by default. +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-lock-password/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,gluon-lock-password)) diff --git a/package/gluon-lock-password/files/lib/gluon/upgrade/100-lock-password b/package/gluon-lock-password/files/lib/gluon/upgrade/100-lock-password new file mode 100755 index 00000000..3204f638 --- /dev/null +++ b/package/gluon-lock-password/files/lib/gluon/upgrade/100-lock-password @@ -0,0 +1,13 @@ +#!/bin/sh + +has_root_pwd() { + local pwd + + pwd=$([ -f "$1" ] && cat "$1") + pwd="${pwd#*root:}" + pwd="${pwd%%:*}" + + test -n "${pwd}" +} + +has_root_pwd /etc/shadow || passwd -l root diff --git a/package/gluon-luci-admin/Makefile b/package/gluon-luci-admin/Makefile new file mode 100644 index 00000000..3e20d179 --- /dev/null +++ b/package/gluon-luci-admin/Makefile @@ -0,0 +1,39 @@ +# Copyright (C) 2013 Nils Schneider +# This is free software, licensed under the Apache 2.0 license. + +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-luci-admin +PKG_VERSION:=1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) + +define Package/gluon-luci-admin + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Luci based simple administration interface for mesh nodes + DEPENDS:=gluon-config-mode-core-virtual +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile + $(call GluonBuildI18N,gluon-luci-admin,i18n) +endef + +define Package/gluon-luci-admin/install + $(CP) ./files/* $(1)/ + $(call GluonInstallI18N,gluon-luci-admin,$(1)) +endef + +$(eval $(call BuildPackage,gluon-luci-admin)) diff --git a/package/gluon-luci-admin/files/usr/lib/lua/luci/controller/admin/index.lua b/package/gluon-luci-admin/files/usr/lib/lua/luci/controller/admin/index.lua new file mode 100644 index 00000000..55c0a248 --- /dev/null +++ b/package/gluon-luci-admin/files/usr/lib/lua/luci/controller/admin/index.lua @@ -0,0 +1,39 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +module("luci.controller.admin.index", package.seeall) + +function index() + local uci_state = luci.model.uci.cursor_state() + + -- Disable gluon-luci-admin when setup mode is not enabled + if uci_state:get_first('gluon-setup-mode', 'setup_mode', 'running', '0') ~= '1' then + return + end + + local root = node() + if not root.lock then + root.target = alias("admin") + root.index = true + end + + local page = entry({"admin"}, alias("admin", "index"), _("Expert Mode"), 10) + page.sysauth = "root" + page.sysauth_authenticator = function() return "root" end + page.index = true + + entry({"admin", "index"}, cbi("admin/info"), _("Information"), 1).ignoreindex = true + entry({"admin", "remote"}, cbi("admin/remote"), _("Remote access"), 10) +end diff --git a/package/gluon-luci-admin/files/usr/lib/lua/luci/controller/admin/upgrade.lua b/package/gluon-luci-admin/files/usr/lib/lua/luci/controller/admin/upgrade.lua new file mode 100644 index 00000000..29aecb95 --- /dev/null +++ b/package/gluon-luci-admin/files/usr/lib/lua/luci/controller/admin/upgrade.lua @@ -0,0 +1,135 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +module("luci.controller.admin.upgrade", package.seeall) + +function index() + local has_platform = nixio.fs.access("/lib/upgrade/platform.sh") + if has_platform then + entry({"admin", "upgrade"}, call("action_upgrade"), _("Upgrade firmware"), 90) + entry({"admin", "upgrade", "reboot"}, template("admin/upgrade_reboot"), nil, nil) + end +end + +function action_upgrade() + local tmpfile = "/tmp/firmware.img" + + -- Install upload handler + local file + luci.http.setfilehandler( + function(meta, chunk, eof) + if not nixio.fs.access(tmpfile) and not file and chunk and #chunk > 0 then + file = io.open(tmpfile, "w") + end + if file and chunk then + file:write(chunk) + end + if file and eof then + file:close() + end + end + ) + + -- Determine state + local step = tonumber(luci.http.formvalue("step") or 1) + local has_image = nixio.fs.access(tmpfile) + local has_support = image_supported(tmpfile) + + -- Step 1: file upload, error on unsupported image format + if not has_image or not has_support or step == 1 then + -- If there is an image but user has requested step 1 + -- or type is not supported, then remove it. + if has_image then + nixio.fs.unlink(tmpfile) + end + + luci.template.render("admin/upgrade", { + bad_image=(has_image and not has_support or false) + } ) + + -- Step 2: present uploaded file, show checksum, confirmation + elseif step == 2 then + luci.template.render("admin/upgrade_confirm", { + checksum=image_checksum(tmpfile), + filesize=nixio.fs.stat(tmpfile).size, + flashsize=storage_size(), + keepconfig=luci.http.formvalue("keepcfg") == "1" + } ) + elseif step == 3 then + local keepcfg = luci.http.formvalue("keepcfg") == "1" + fork_exec("/sbin/sysupgrade %s %q" % { keepcfg and "" or "-n", tmpfile }) + luci.http.redirect(luci.dispatcher.build_url("admin", "upgrade", "reboot")) + end +end + +function fork_exec(command) + local pid = nixio.fork() + if pid > 0 then + return + elseif pid == 0 then + -- change to root dir + nixio.chdir("/") + + -- patch stdin, out, err to /dev/null + local null = nixio.open("/dev/null", "w+") + if null then + nixio.dup(null, nixio.stderr) + nixio.dup(null, nixio.stdout) + nixio.dup(null, nixio.stdin) + if null:fileno() > 2 then + null:close() + end + end + + -- replace with target command + nixio.exec("/bin/sh", "-c", command) + end +end + +function image_supported(tmpfile) + -- XXX: yay... + return ( 0 == os.execute( + ". /lib/functions.sh; " .. + "include /lib/upgrade; " .. + "platform_check_image %q >/dev/null" + % tmpfile + ) ) +end + +function storage_size() + local size = 0 + if nixio.fs.access("/proc/mtd") then + for l in io.lines("/proc/mtd") do + local d, s, e, n = l:match('^([^%s]+)%s+([^%s]+)%s+([^%s]+)%s+"([^%s]+)"') + if n == "linux" then + size = tonumber(s, 16) + break + end + end + elseif nixio.fs.access("/proc/partitions") then + for l in io.lines("/proc/partitions") do + local x, y, b, n = l:match('^%s*(%d+)%s+(%d+)%s+([^%s]+)%s+([^%s]+)') + if b and n and not n:match('[0-9]') then + size = tonumber(b) * 1024 + break + end + end + end + return size +end + +function image_checksum(tmpfile) + return (luci.sys.exec("md5sum %q" % tmpfile):match("^([^%s]+)")) +end diff --git a/package/gluon-luci-admin/files/usr/lib/lua/luci/model/cbi/admin/info.lua b/package/gluon-luci-admin/files/usr/lib/lua/luci/model/cbi/admin/info.lua new file mode 100644 index 00000000..e9ceba70 --- /dev/null +++ b/package/gluon-luci-admin/files/usr/lib/lua/luci/model/cbi/admin/info.lua @@ -0,0 +1,4 @@ +local t = Template('admin/info') +t.pageaction = false + +return t diff --git a/package/gluon-luci-admin/files/usr/lib/lua/luci/model/cbi/admin/remote.lua b/package/gluon-luci-admin/files/usr/lib/lua/luci/model/cbi/admin/remote.lua new file mode 100644 index 00000000..5797b623 --- /dev/null +++ b/package/gluon-luci-admin/files/usr/lib/lua/luci/model/cbi/admin/remote.lua @@ -0,0 +1,105 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2011 Jo-Philipp Wich +Copyright 2013 Nils Schneider + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +local fs = require "nixio.fs" + +local m = Map("system", translate("SSH keys")) +m.pageaction = false +m.template = "admin/expertmode" + +if fs.access("/etc/config/dropbear") then + local s = m:section(TypedSection, "_dummy1", nil, + translate("You can provide your SSH keys here (one per line):")) + + s.addremove = false + s.anonymous = true + + function s.cfgsections() + return { "_keys" } + end + + local keys + + keys = s:option(TextValue, "_data", "") + keys.wrap = "off" + keys.rows = 5 + keys.rmempty = true + + function keys.cfgvalue() + return fs.readfile("/etc/dropbear/authorized_keys") or "" + end + + function keys.write(self, section, value) + if value then + fs.writefile("/etc/dropbear/authorized_keys", value:gsub("\r\n", "\n")) + end + end + + function keys.remove(self, section) + if keys:formvalue("_keys") then + fs.remove("/etc/dropbear/authorized_keys") + end + end +end + +local m2 = Map("system", translate("Password")) +m2.reset = false +m2.pageaction = false +m2.template = "admin/expertmode" + +local s = m2:section(TypedSection, "_dummy2", nil, translate( + "Alternatively, you can set a password to access you node. Please choose a secure password you don't use anywhere else.

" + .. "If you set an empty password, login via password will be disabled. This is the default.")) + +s.addremove = false +s.anonymous = true + +local pw1 = s:option(Value, "pw1", translate("Password")) +pw1.password = true + +local pw2 = s:option(Value, "pw2", translate("Confirmation")) +pw2.password = true + +function s.cfgsections() + return { "_pass" } +end + +function m2.on_commit(map) + local v1 = pw1:formvalue("_pass") + local v2 = pw2:formvalue("_pass") + + if v1 and v2 then + if v1 == v2 then + if #v1 > 0 then + if luci.sys.user.setpasswd(luci.dispatcher.context.authuser, v1) == 0 then + m2.message = translate("Password changed.") + else + m2.errmessage = translate("Unable to change the password.") + end + else + -- We don't check the return code here as the error 'password for root is already locked' is normal... + os.execute('passwd -l root >/dev/null') + m2.message = translate("Password removed.") + end + else + m2.errmessage = translate("The password and the confirmation differ.") + end + end +end + +local c = Compound(m, m2) +c.pageaction = false +return c diff --git a/package/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/expertmode.htm b/package/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/expertmode.htm new file mode 100644 index 00000000..53947f3c --- /dev/null +++ b/package/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/expertmode.htm @@ -0,0 +1,56 @@ +<% if not self.embedded then %> +
+
+ + +
+<% end %> +
+ <% if self.title and #self.title > 0 then %>

<%=self.title%>

<% end %> + <%- if self.message then %> +

<%=self.message%>

+ <%- end %> + <%- if self.errmessage then %> +

<%=self.errmessage%>

+ <%- end %> + <% if self.description and #self.description > 0 then %>
<%=self.description%>
<% end %> + <% self:render_children() %> +
+<% if not self.embedded then %> +
+<%- + if type(self.hidden) == "table" then + for k, v in pairs(self.hidden) do +-%> + +<%- + end + end +%> +<% if redirect then %> +
+ +
+<% end %> +<%- if self.flow and self.flow.skip then %> + +<% end %> +<%- if self.submit ~= false then %> + +<% end %> +<%- if self.reset ~= false then %> + +<% end %> +<%- if self.cancel ~= false and self.on_cancel then %> + +<% end %> + +
+
+<% end %> diff --git a/package/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/info.htm b/package/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/info.htm new file mode 100644 index 00000000..a04a834d --- /dev/null +++ b/package/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/info.htm @@ -0,0 +1,45 @@ +<%- + local fs = require 'luci.fs' + local uci = require('luci.model.uci').cursor() + local util = require 'luci.util' + local i18n = require 'luci.i18n' + + local site = require 'gluon.site_config' + local sysconfig = require 'gluon.sysconfig' + local platform = require 'gluon.platform' + + + local keys = { + hostname = i18n.translate('Hostname'), + primary_mac = i18n.translate('MAC address'), + model = i18n.translate('Hardware model'), + version = i18n.translate('Gluon version'), + release = i18n.translate('Firmware release'), + site = i18n.translate('Site'), + pubkey = i18n.translate('Public VPN key'), + } + + local values = { + hostname = uci:get_first('system', 'system', 'hostname'), + primary_mac = sysconfig.primary_mac, + model = platform.get_model(), + version = util.trim(fs.readfile('/lib/gluon/gluon-version')), + release = util.trim(fs.readfile('/lib/gluon/release')), + site = site.site_name, + pubkey = 'n/a', + } + + local meshvpn_enabled = uci:get("fastd", "mesh_vpn", "enabled", "0") + if meshvpn_enabled == "1" then + local pubkey = util.trim(util.exec('/etc/init.d/fastd show_key mesh_vpn')) + if pubkey ~= '' then + values.pubkey = pubkey + end + end +-%> +

<%:Information%>

+<% for _, key in ipairs({'hostname', 'primary_mac', 'model', 'version', 'release', 'site', 'pubkey'}) do %> +
+
<%=keys[key]%>
<%=values[key] or 'n/a'%>
+
+<% end %> diff --git a/package/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/upgrade.htm b/package/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/upgrade.htm new file mode 100644 index 00000000..a2b82235 --- /dev/null +++ b/package/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/upgrade.htm @@ -0,0 +1,55 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008-2009 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ + +-%> + +<%+header%> + +

<%:Upgrade firmware%>

+ +
+

+ <%:You can manually upgrade your firmware here.%> +

+ <% if bad_image then %> +

<%:The provided firmware image is not valid for this device.%>

+ <% end %> +
+
+ +
+ +
+
+ +
+ + +
+ + +
+
+
+ +
+ + +
+
+<%+footer%> + diff --git a/package/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/upgrade_confirm.htm b/package/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/upgrade_confirm.htm new file mode 100644 index 00000000..5618728f --- /dev/null +++ b/package/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/upgrade_confirm.htm @@ -0,0 +1,67 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008-2009 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ + +-%> + +<%+header%> + +

<%:Upgrade firmware%>

+ +

+ <%:The firmware image has been transmitted. Please ensure the MD5 checksum and image size are correct and click "continue".%> +

+ +<% if flashsize > 0 and filesize > flashsize then %> +

<%:The firmware is too big for your device's storage.%>

+<% end %> + +

+

    +
  • md5sum: <%=checksum%>
  • +
  • <%:Size%>: <% + function byte_format(byte) + local suff = {"B", "KB", "MB", "GB", "TB"} + for i=1, 5 do + if byte > 1024 and i < 5 then + byte = byte / 1024 + else + return string.format("%.2f %s", byte, suff[i]) + end + end + end + + write(byte_format(filesize)) + + if flashsize > 0 then + write(luci.i18n.translatef( + " (%s available)", + w.byte_format(flashsize) + )) + end + %>
  • +
+

+
+
+ + " /> + +
+
+ + " /> + +
+
+<%+footer%> + diff --git a/package/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/upgrade_reboot.htm b/package/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/upgrade_reboot.htm new file mode 100644 index 00000000..3e89e778 --- /dev/null +++ b/package/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/upgrade_reboot.htm @@ -0,0 +1,20 @@ + + + + + + <%:Upgrading firmware%> + + + +
+
+

+ <%:The firmware is currently being upgraded.%> + <%:Don't switch off the device in any circumstance!%> + <%:The upgrade will take a few minutes. When it is finished, your node will reboot automatically.%> +

+
+
+ + diff --git a/package/gluon-luci-admin/i18n/de.po b/package/gluon-luci-admin/i18n/de.po new file mode 100644 index 00000000..e3a1aa20 --- /dev/null +++ b/package/gluon-luci-admin/i18n/de.po @@ -0,0 +1,111 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2015-05-04 00:34+0200\n" +"Last-Translator: \n" +"Language-Team: German\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "" +"Alternatively, you can set a password to access you node. Please choose a " +"secure password you don't use anywhere else.

If you set an empty " +"password, login via password will be disabled. This is the default." +msgstr "" +"Alternativ kannst du auch ein Passwort setzen. Wähle bitte ein sicheres " +"Passwort, das du nirgendwo anders verwendest.

Beim Setzen eines " +"leeren Passworts wird der Login per Passwort gesperrt (dies ist die Standard-" +"Einstellung)." + +msgid "Continue" +msgstr "Fortfahren" + +msgid "Don't switch off the device in any circumstance!" +msgstr "Unterbrich auf keinen Fall die Stromversorgung!" + +msgid "Expert Mode" +msgstr "Export Mode" + +msgid "Firmware image" +msgstr "Firmware-Datei" + +msgid "Firmware release" +msgstr "Firmware-Release" + +msgid "Gluon version" +msgstr "Gluon-Version" + +msgid "Hardware model" +msgstr "Hardware-Modell" + +msgid "Information" +msgstr "Info" + +msgid "MAC address" +msgstr "MAC-Adresse" + +msgid "Password changed." +msgstr "Passwort geändert." + +msgid "Password removed." +msgstr "Passwort gelöscht." + +msgid "Public VPN key" +msgstr "Öffentlicher VPN-Schlüssel" + +msgid "Remote access" +msgstr "Remotezugriff" + +msgid "SSH keys" +msgstr "SSH-Schlüssel" + +msgid "Site" +msgstr "Site" + +msgid "" +"The firmware image has been transmitted. Please ensure the MD5 checksum and " +"image size are correct and click \"continue\"." +msgstr "" +"Die Firmwaredatei wurde übermittelt. Bitte vergleiche MD5-Checksumme und " +"Dateigröße und klicke anschließend auf \"fortfahren\"." + +msgid "The firmware is currently being upgraded." +msgstr "Die Firmware wird jetzt aktualisiert." + +msgid "The firmware is too big for your device's storage." +msgstr "Die Firmware passt nicht in den Speicher des Gerätes." + +msgid "The password and the confirmation differ." +msgstr "Die beiden Passwörter stimmen nicht überein." + +msgid "The provided firmware image is not valid for this device." +msgstr "Die übermittelte Datei ist keine gültige Firmware für dieses Gerät." + +msgid "" +"The upgrade will take a few minutes. When it is finished, your node will " +"reboot automatically." +msgstr "" +"Dieser Vorgang wird einige Minuten dauern. Anschließend startet das Gerät " +"automatisch neu." + +msgid "Unable to change the password." +msgstr "Das Passwort konnte nicht geändert werden." + +msgid "Upgrade firmware" +msgstr "Firmware aktualisieren" + +msgid "Upgrading firmware" +msgstr "Firmware wird aktualisiert" + +msgid "Upload image" +msgstr "Datei hochladen" + +msgid "You can manually upgrade your firmware here." +msgstr "Hier kannst du ein manuelles Firmwareupdate durchführen." + +msgid "You can provide your SSH keys here (one per line):" +msgstr "" +"Hier hast du die Möglichkeit, SSH-Keys zu hinterlegen (einen pro Zeile):" diff --git a/package/gluon-luci-admin/i18n/gluon-luci-admin.pot b/package/gluon-luci-admin/i18n/gluon-luci-admin.pot new file mode 100644 index 00000000..197b6367 --- /dev/null +++ b/package/gluon-luci-admin/i18n/gluon-luci-admin.pot @@ -0,0 +1,93 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "" +"Alternatively, you can set a password to access you node. Please choose a " +"secure password you don't use anywhere else.

If you set an empty " +"password, login via password will be disabled. This is the default." +msgstr "" + +msgid "Continue" +msgstr "" + +msgid "Don't switch off the device in any circumstance!" +msgstr "" + +msgid "Expert Mode" +msgstr "" + +msgid "Firmware image" +msgstr "" + +msgid "Firmware release" +msgstr "" + +msgid "Gluon version" +msgstr "" + +msgid "Hardware model" +msgstr "" + +msgid "Information" +msgstr "" + +msgid "MAC address" +msgstr "" + +msgid "Password changed." +msgstr "" + +msgid "Password removed." +msgstr "" + +msgid "Public VPN key" +msgstr "" + +msgid "Remote access" +msgstr "" + +msgid "SSH keys" +msgstr "" + +msgid "Site" +msgstr "" + +msgid "" +"The firmware image has been transmitted. Please ensure the MD5 checksum and " +"image size are correct and click \"continue\"." +msgstr "" + +msgid "The firmware is currently being upgraded." +msgstr "" + +msgid "The firmware is too big for your device's storage." +msgstr "" + +msgid "The password and the confirmation differ." +msgstr "" + +msgid "The provided firmware image is not valid for this device." +msgstr "" + +msgid "" +"The upgrade will take a few minutes. When it is finished, your node will " +"reboot automatically." +msgstr "" + +msgid "Unable to change the password." +msgstr "" + +msgid "Upgrade firmware" +msgstr "" + +msgid "Upgrading firmware" +msgstr "" + +msgid "Upload image" +msgstr "" + +msgid "You can manually upgrade your firmware here." +msgstr "" + +msgid "You can provide your SSH keys here (one per line):" +msgstr "" diff --git a/package/gluon-luci-autoupdater/Makefile b/package/gluon-luci-autoupdater/Makefile new file mode 100644 index 00000000..650c4692 --- /dev/null +++ b/package/gluon-luci-autoupdater/Makefile @@ -0,0 +1,39 @@ +# Copyright (C) 2013 Nils Schneider +# This is free software, licensed under the Apache 2.0 license. + +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-luci-autoupdater +PKG_VERSION:=1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) + +define Package/gluon-luci-autoupdater + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Luci module for gluon-autoupdater + DEPENDS:=+gluon-luci-admin +gluon-autoupdater +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile + $(call GluonBuildI18N,gluon-luci-autoupdater,i18n) +endef + +define Package/gluon-luci-autoupdater/install + $(CP) ./files/* $(1)/ + $(call GluonInstallI18N,gluon-luci-autoupdater,$(1)) +endef + +$(eval $(call BuildPackage,gluon-luci-autoupdater)) diff --git a/package/gluon-luci-autoupdater/files/usr/lib/lua/luci/controller/admin/autoupdater.lua b/package/gluon-luci-autoupdater/files/usr/lib/lua/luci/controller/admin/autoupdater.lua new file mode 100644 index 00000000..64e1acbd --- /dev/null +++ b/package/gluon-luci-autoupdater/files/usr/lib/lua/luci/controller/admin/autoupdater.lua @@ -0,0 +1,19 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2013 Nils Schneider + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +module("luci.controller.admin.autoupdater", package.seeall) + +function index() + entry({"admin", "autoupdater"}, cbi("admin/autoupdater"), _("Automatic updates"), 80) +end diff --git a/package/gluon-luci-autoupdater/files/usr/lib/lua/luci/model/cbi/admin/autoupdater.lua b/package/gluon-luci-autoupdater/files/usr/lib/lua/luci/model/cbi/admin/autoupdater.lua new file mode 100644 index 00000000..a8f9d3b3 --- /dev/null +++ b/package/gluon-luci-autoupdater/files/usr/lib/lua/luci/model/cbi/admin/autoupdater.lua @@ -0,0 +1,29 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2013 Nils Schneider + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +m = Map("autoupdater", translate("Automatic updates")) +m.pageaction = false +m.template = "admin/expertmode" + +s = m:section(TypedSection, "autoupdater", nil) +s.addremove = false +s.anonymous = true + +s:option(Flag, "enabled", translate("Enable")) +f = s:option(ListValue, "branch", translate("Branch")) + +uci.cursor():foreach("autoupdater", "branch", function (section) f:value(section[".name"]) end) + +return m + diff --git a/package/gluon-luci-autoupdater/i18n/de.po b/package/gluon-luci-autoupdater/i18n/de.po new file mode 100644 index 00000000..9fd4cf53 --- /dev/null +++ b/package/gluon-luci-autoupdater/i18n/de.po @@ -0,0 +1,17 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2015-05-04 01:55+0200\n" +"Last-Translator: \n" +"Language-Team: German\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "Automatic updates" +msgstr "Automatische Updates" + +msgid "Branch" +msgstr "Branch" diff --git a/package/gluon-luci-autoupdater/i18n/gluon-luci-autoupdater.pot b/package/gluon-luci-autoupdater/i18n/gluon-luci-autoupdater.pot new file mode 100644 index 00000000..678bdbaf --- /dev/null +++ b/package/gluon-luci-autoupdater/i18n/gluon-luci-autoupdater.pot @@ -0,0 +1,8 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "Automatic updates" +msgstr "" + +msgid "Branch" +msgstr "" diff --git a/package/gluon-luci-mesh-vpn-fastd/Makefile b/package/gluon-luci-mesh-vpn-fastd/Makefile new file mode 100644 index 00000000..1be12ccc --- /dev/null +++ b/package/gluon-luci-mesh-vpn-fastd/Makefile @@ -0,0 +1,41 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-luci-mesh-vpn-fastd +PKG_VERSION:=1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) + +define Package/gluon-luci-mesh-vpn-fastd + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Luci module to enable and disable encryption for the mesh VPN + DEPENDS:=+gluon-luci-admin +gluon-mesh-vpn-fastd +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile + $(call GluonBuildI18N,gluon-mesh-vpn-fastd,i18n) +endef + +define Package/gluon-luci-mesh-vpn-fastd/install + $(CP) ./files/* $(1)/ + $(call GluonInstallI18N,gluon-mesh-vpn-fastd,$(1)) +endef + +define Package/gluon-luci-mesh-vpn-fastd/postinst +#!/bin/sh +$(call GluonCheckSite,check_site.lua) +endef + +$(eval $(call BuildPackage,gluon-luci-mesh-vpn-fastd)) diff --git a/package/gluon-luci-mesh-vpn-fastd/check_site.lua b/package/gluon-luci-mesh-vpn-fastd/check_site.lua new file mode 100644 index 00000000..42ff5a50 --- /dev/null +++ b/package/gluon-luci-mesh-vpn-fastd/check_site.lua @@ -0,0 +1,2 @@ +assert(need_boolean('fastd_mesh_vpn.configurable') == true, + "site.conf error: expected `fastd_mesh_vpn.configurable' to be true") diff --git a/package/gluon-luci-mesh-vpn-fastd/files/usr/lib/lua/luci/controller/admin/mesh_vpn_fastd.lua b/package/gluon-luci-mesh-vpn-fastd/files/usr/lib/lua/luci/controller/admin/mesh_vpn_fastd.lua new file mode 100644 index 00000000..8141c44a --- /dev/null +++ b/package/gluon-luci-mesh-vpn-fastd/files/usr/lib/lua/luci/controller/admin/mesh_vpn_fastd.lua @@ -0,0 +1,5 @@ +module("luci.controller.admin.mesh_vpn_fastd", package.seeall) + +function index() + entry({"admin", "mesh_vpn_fastd"}, cbi("admin/mesh_vpn_fastd"), _("Mesh VPN"), 20) +end diff --git a/package/gluon-luci-mesh-vpn-fastd/files/usr/lib/lua/luci/model/cbi/admin/mesh_vpn_fastd.lua b/package/gluon-luci-mesh-vpn-fastd/files/usr/lib/lua/luci/model/cbi/admin/mesh_vpn_fastd.lua new file mode 100644 index 00000000..14bb5783 --- /dev/null +++ b/package/gluon-luci-mesh-vpn-fastd/files/usr/lib/lua/luci/model/cbi/admin/mesh_vpn_fastd.lua @@ -0,0 +1,41 @@ +local uci = luci.model.uci.cursor() +local util = luci.util + +local f = SimpleForm('mesh_vpn', translate('Mesh VPN')) +f.template = "admin/expertmode" + +local s = f:section(SimpleSection) + +local o = s:option(Value, 'mode') +o.template = "gluon/cbi/mesh-vpn-fastd-mode" + +local methods = uci:get('fastd', 'mesh_vpn', 'method') +if util.contains(methods, 'null') then + o.default = 'performance' +else + o.default = 'security' +end + +function f.handle(self, state, data) + if state == FORM_VALID then + local site = require 'gluon.site_config' + + local methods = {} + if data.mode == 'performance' then + table.insert(methods, 'null') + end + + for _, method in ipairs(site.fastd_mesh_vpn.methods) do + if method ~= 'null' then + table.insert(methods, method) + end + end + + uci:set('fastd', 'mesh_vpn', 'method', methods) + + uci:save('fastd') + uci:commit('fastd') + end +end + +return f diff --git a/package/gluon-luci-mesh-vpn-fastd/files/usr/lib/lua/luci/view/gluon/cbi/mesh-vpn-fastd-mode.htm b/package/gluon-luci-mesh-vpn-fastd/files/usr/lib/lua/luci/view/gluon/cbi/mesh-vpn-fastd-mode.htm new file mode 100644 index 00000000..0899fa1d --- /dev/null +++ b/package/gluon-luci-mesh-vpn-fastd/files/usr/lib/lua/luci/view/gluon/cbi/mesh-vpn-fastd-mode.htm @@ -0,0 +1,32 @@ +
+
+ /> +
+
+ class="cbi-value-title"><%:Security mode%> +
+ <%= translate( + 'In security mode, the mesh VPN uses an encrypted tunnel to connect to the VPN servers. ' .. + 'The encryption ensures that it is impossible for your internet access provider to see what ' .. + 'data is exchanged over your node.' + ) %> +
+
+
+
+ +
+
+ /> +
+
+ class="cbi-value-title"><%:Performance mode%> +
+ <%= translate( + 'In performance mode, no encryption is used. This usually allows for higher throughput, but the data exchanged over your node is not ' .. + 'protected against eavesdropping.' + ) %> +
+
+
+
diff --git a/package/gluon-luci-mesh-vpn-fastd/i18n/de.po b/package/gluon-luci-mesh-vpn-fastd/i18n/de.po new file mode 100644 index 00000000..12e48439 --- /dev/null +++ b/package/gluon-luci-mesh-vpn-fastd/i18n/de.po @@ -0,0 +1,38 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2015-05-03 20:39+0200\n" +"Last-Translator: \n" +"Language-Team: German\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "" +"In performance mode, no encryption is used. This usually allows for higher " +"throughput, but the data exchanged over your node is not protected against " +"eavesdropping." +msgstr "" +"Im Modus „Hohe Geschwindigkeit“ wird auf Verschlüsselung " +"verzichtet. Dies erlaubt häufig eine höhere Bandbreite als mit " +"Verschlüsselung, aber die Verbindung ist nicht gegen Abhören geschützt." + +msgid "" +"In security mode, the mesh VPN uses an encrypted tunnel to connect to the " +"VPN servers. The encryption ensures that it is impossible for your internet " +"access provider to see what data is exchanged over your node." +msgstr "" +"Im Modus „Hohe Sicherheit“ wird ein verschlüsselter Tunnel " +"verwendet. Dies schließt aus, dass dein Internetzugangsprovider herausfinden " +"kann, was für Daten über deinen Knoten übertragen werden." + +msgid "Mesh VPN" +msgstr "Mesh-VPN" + +msgid "Performance mode" +msgstr "Hohe Geschwindigkeit" + +msgid "Security mode" +msgstr "Hohe Sicherheit" diff --git a/package/gluon-luci-mesh-vpn-fastd/i18n/gluon-luci-mesh-vpn-fastd.pot b/package/gluon-luci-mesh-vpn-fastd/i18n/gluon-luci-mesh-vpn-fastd.pot new file mode 100644 index 00000000..878a1959 --- /dev/null +++ b/package/gluon-luci-mesh-vpn-fastd/i18n/gluon-luci-mesh-vpn-fastd.pot @@ -0,0 +1,23 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "" +"In performance mode, no encryption is used. This usually allows for higher " +"throughput, but the data exchanged over your node is not protected against " +"eavesdropping." +msgstr "" + +msgid "" +"In security mode, the mesh VPN uses an encrypted tunnel to connect to the " +"VPN servers. The encryption ensures that it is impossible for your internet " +"access provider to see what data is exchanged over your node." +msgstr "" + +msgid "Mesh VPN" +msgstr "" + +msgid "Performance mode" +msgstr "" + +msgid "Security mode" +msgstr "" diff --git a/package/gluon-luci-node-role/Makefile b/package/gluon-luci-node-role/Makefile new file mode 100644 index 00000000..ded7bd3f --- /dev/null +++ b/package/gluon-luci-node-role/Makefile @@ -0,0 +1,41 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-luci-node-role +PKG_VERSION:=0.1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) + +define Package/gluon-luci-node-role + SECTION:=gluon + CATEGORY:=Gluon + DEPENDS:=+gluon-luci-admin +gluon-node-info + TITLE:=UI for specifying node role +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile + $(call GluonBuildI18N,gluon-luci-node-role,i18n) +endef + +define Package/gluon-luci-node-role/install + $(CP) ./files/* $(1)/ + $(call GluonInstallI18N,gluon-luci-node-role,$(1)) +endef + +define Package/gluon-luci-node-role/postinst +#!/bin/sh +$(call GluonCheckSite,check_site.lua) +endef + +$(eval $(call BuildPackage,gluon-luci-node-role)) diff --git a/package/gluon-luci-node-role/check_site.lua b/package/gluon-luci-node-role/check_site.lua new file mode 100644 index 00000000..ab01eeb5 --- /dev/null +++ b/package/gluon-luci-node-role/check_site.lua @@ -0,0 +1,2 @@ +need_string 'roles.default' +need_string_array 'roles.list' diff --git a/package/gluon-luci-node-role/files/usr/lib/lua/luci/controller/admin/noderole.lua b/package/gluon-luci-node-role/files/usr/lib/lua/luci/controller/admin/noderole.lua new file mode 100644 index 00000000..cfca1275 --- /dev/null +++ b/package/gluon-luci-node-role/files/usr/lib/lua/luci/controller/admin/noderole.lua @@ -0,0 +1,5 @@ +module("luci.controller.admin.noderole", package.seeall) + +function index() + entry({"admin", "noderole"}, cbi("admin/noderole"), "Node role", 20) +end diff --git a/package/gluon-luci-node-role/files/usr/lib/lua/luci/model/cbi/admin/noderole.lua b/package/gluon-luci-node-role/files/usr/lib/lua/luci/model/cbi/admin/noderole.lua new file mode 100644 index 00000000..e7832ad9 --- /dev/null +++ b/package/gluon-luci-node-role/files/usr/lib/lua/luci/model/cbi/admin/noderole.lua @@ -0,0 +1,34 @@ +local f, s, o +local site = require 'gluon.site_config' +local i18n = require "luci.i18n" +local uci = luci.model.uci.cursor() +local config = 'gluon-node-info' + +-- where to read the configuration from +local role = uci:get(config, uci:get_first(config, "system"), "role") + +f = SimpleForm("role", i18n.translate("Node role")) +f.template = "admin/expertmode" + +s = f:section(SimpleSection, nil, i18n.translate( + "If this node has a special role within the freifunk network you can specify this role here. " + .. "Please find out about the available roles and their impact first. " + .. "Only change the role if you know what you are doing.")) + +o = s:option(ListValue, "role", i18n.translate("Role")) +o.default = role +o.rmempty = false +for _, role in ipairs(site.roles.list) do + o:value(role, i18n.translate('gluon-luci-node-role:role:' .. role)) +end + +function f.handle(self, state, data) + if state == FORM_VALID then + uci:set(config, uci:get_first(config, "system"), "role", data.role) + + uci:save(config) + uci:commit(config) + end +end + +return f diff --git a/package/gluon-luci-node-role/i18n/de.po b/package/gluon-luci-node-role/i18n/de.po new file mode 100644 index 00000000..e3037b26 --- /dev/null +++ b/package/gluon-luci-node-role/i18n/de.po @@ -0,0 +1,27 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2015-04-26 17:18+0200\n" +"Last-Translator: Tobias Hachmer \n" +"Language-Team: German\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "Node role" +msgstr "Verwendungszweck" + +msgid "Role" +msgstr "Rolle" + +msgid "" +"If this node has a special role within the freifunk network you can specify " +"this role here. Please find out about the available roles and their impact " +"first. Only change the role if you know what you are doing." +msgstr "" +"Wenn dein Freifunk-Knoten eine besondere Rolle im Freifunk Netz einnimmt, " +"kannst du diese hier angeben. Bringe bitte zuvor in Erfahrung, welche " +"Auswirkungen die zur Verfügung stehenden Rollen im Freifunk-Netz haben. " +"Setze die Rolle nur, wenn du weißt was du machst." diff --git a/package/gluon-luci-node-role/i18n/gluon-luci-node-role.pot b/package/gluon-luci-node-role/i18n/gluon-luci-node-role.pot new file mode 100644 index 00000000..acf6dd79 --- /dev/null +++ b/package/gluon-luci-node-role/i18n/gluon-luci-node-role.pot @@ -0,0 +1,14 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "Node role" +msgstr "" + +msgid "Role" +msgstr "" + +msgid "" +"If this node has a special role within the freifunk network you can specify this role here. " +"Please find out about the available roles and their impact first. " +"Only change the role if you know what you are doing." +msgstr "" diff --git a/package/gluon-luci-portconfig/Makefile b/package/gluon-luci-portconfig/Makefile new file mode 100644 index 00000000..007c5fea --- /dev/null +++ b/package/gluon-luci-portconfig/Makefile @@ -0,0 +1,39 @@ +# Copyright (C) 2013 Nils Schneider +# This is free software, licensed under the Apache 2.0 license. + +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-luci-portconfig +PKG_VERSION:=1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) + +define Package/gluon-luci-portconfig + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Luci module for advanced ethernet port configuration + DEPENDS:=+gluon-luci-admin +gluon-mesh-batman-adv +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile + $(call GluonBuildI18N,gluon-luci-portconfig,i18n) +endef + +define Package/gluon-luci-portconfig/install + $(CP) ./files/* $(1)/ + $(call GluonInstallI18N,gluon-luci-portconfig,$(1)) +endef + +$(eval $(call BuildPackage,gluon-luci-portconfig)) diff --git a/package/gluon-luci-portconfig/files/usr/lib/lua/luci/controller/admin/portconfig.lua b/package/gluon-luci-portconfig/files/usr/lib/lua/luci/controller/admin/portconfig.lua new file mode 100644 index 00000000..037b56c8 --- /dev/null +++ b/package/gluon-luci-portconfig/files/usr/lib/lua/luci/controller/admin/portconfig.lua @@ -0,0 +1,19 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2013 Nils Schneider + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +module("luci.controller.admin.portconfig", package.seeall) + +function index() + entry({"admin", "portconfig"}, cbi("admin/portconfig"), _("Network"), 20) +end diff --git a/package/gluon-luci-portconfig/files/usr/lib/lua/luci/model/cbi/admin/portconfig.lua b/package/gluon-luci-portconfig/files/usr/lib/lua/luci/model/cbi/admin/portconfig.lua new file mode 100644 index 00000000..8166539c --- /dev/null +++ b/package/gluon-luci-portconfig/files/usr/lib/lua/luci/model/cbi/admin/portconfig.lua @@ -0,0 +1,149 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2014 Nils Schneider + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +local uci = luci.model.uci.cursor() +local sysconfig = require 'gluon.sysconfig' + +local wan = uci:get_all("network", "wan") +local wan6 = uci:get_all("network", "wan6") +local dns = uci:get_first("gluon-wan-dnsmasq", "static") + +local f = SimpleForm("portconfig", translate("WAN connection")) +f.template = "admin/expertmode" + +local s +local o + +s = f:section(SimpleSection, nil, nil) + +o = s:option(ListValue, "ipv4", translate("IPv4")) +o:value("dhcp", translate("Automatic (DHCP)")) +o:value("static", translate("Static")) +o:value("none", translate("Disabled")) +o.default = wan.proto + +o = s:option(Value, "ipv4_addr", translate("IP address")) +o:depends("ipv4", "static") +o.value = wan.ipaddr +o.datatype = "ip4addr" +o.rmempty = false + +o = s:option(Value, "ipv4_netmask", translate("Netmask")) +o:depends("ipv4", "static") +o.value = wan.netmask or "255.255.255.0" +o.datatype = "ip4addr" +o.rmempty = false + +o = s:option(Value, "ipv4_gateway", translate("Gateway")) +o:depends("ipv4", "static") +o.value = wan.gateway +o.datatype = "ip4addr" +o.rmempty = false + + +s = f:section(SimpleSection, nil, nil) + +o = s:option(ListValue, "ipv6", translate("IPv6")) +o:value("dhcpv6", translate("Automatic (RA/DHCPv6)")) +o:value("static", translate("Static")) +o:value("none", translate("Disabled")) +o.default = wan6.proto + +o = s:option(Value, "ipv6_addr", translate("IP address")) +o:depends("ipv6", "static") +o.value = wan6.ip6addr +o.datatype = "ip6addr" +o.rmempty = false + +o = s:option(Value, "ipv6_gateway", translate("Gateway")) +o:depends("ipv6", "static") +o.value = wan6.ip6gw +o.datatype = "ip6addr" +o.rmempty = false + + +if dns then + s = f:section(SimpleSection, nil, nil) + + o = s:option(DynamicList, "dns", translate("Static DNS servers")) + o:write(nil, uci:get("gluon-wan-dnsmasq", dns, "server")) + o.datatype = "ipaddr" +end + +s = f:section(SimpleSection, nil, nil) + +o = s:option(Flag, "mesh_wan", translate("Enable meshing on the WAN interface")) +o.default = uci:get_bool("network", "mesh_wan", "auto") and o.enabled or o.disabled +o.rmempty = false + +if sysconfig.lan_ifname then + o = s:option(Flag, "mesh_lan", translate("Enable meshing on the LAN interface")) + o.default = uci:get_bool("network", "mesh_lan", "auto") and o.enabled or o.disabled + o.rmempty = false +end + + +function f.handle(self, state, data) + if state == FORM_VALID then + uci:set("network", "wan", "proto", data.ipv4) + if data.ipv4 == "static" then + uci:set("network", "wan", "ipaddr", data.ipv4_addr) + uci:set("network", "wan", "netmask", data.ipv4_netmask) + uci:set("network", "wan", "gateway", data.ipv4_gateway) + else + uci:delete("network", "wan", "ipaddr") + uci:delete("network", "wan", "netmask") + uci:delete("network", "wan", "gateway") + end + + uci:set("network", "wan6", "proto", data.ipv6) + if data.ipv6 == "static" then + uci:set("network", "wan6", "ip6addr", data.ipv6_addr) + uci:set("network", "wan6", "ip6gw", data.ipv6_gateway) + else + uci:delete("network", "wan6", "ip6addr") + uci:delete("network", "wan6", "ip6gw") + end + + uci:set("network", "mesh_wan", "auto", data.mesh_wan) + + if sysconfig.lan_ifname then + uci:set("network", "mesh_lan", "auto", data.mesh_lan) + + if data.mesh_lan == '1' then + uci:set("network", "client", "ifname", "bat0") + else + uci:set("network", "client", "ifname", sysconfig.lan_ifname .. " bat0") + end + end + + uci:save("network") + uci:commit("network") + + if dns then + if #data.dns > 0 then + uci:set("gluon-wan-dnsmasq", dns, "server", data.dns) + else + uci:delete("gluon-wan-dnsmasq", dns, "server") + end + + uci:save("gluon-wan-dnsmasq") + uci:commit("gluon-wan-dnsmasq") + end + end + + return true +end + +return f diff --git a/package/gluon-luci-portconfig/i18n/de.po b/package/gluon-luci-portconfig/i18n/de.po new file mode 100644 index 00000000..2197fdbe --- /dev/null +++ b/package/gluon-luci-portconfig/i18n/de.po @@ -0,0 +1,32 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2015-05-04 02:08+0200\n" +"Last-Translator: \n" +"Language-Team: German\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "Automatic (DHCP)" +msgstr "Automatisch (DHCP)" + +msgid "Automatic (RA/DHCPv6)" +msgstr "Automatisch (RA/DHCPv6)" + +msgid "Enable meshing on the WAN interface" +msgstr "Mesh auf dem WAN-Port aktivieren" + +msgid "Enable meshing on the LAN interface" +msgstr "Mesh auf dem LAN-Port aktivieren" + +msgid "Static" +msgstr "Statisch" + +msgid "Static DNS servers" +msgstr "Statische DNS-Server" + +msgid "WAN connection" +msgstr "WAN-Verbindung" diff --git a/package/gluon-luci-portconfig/i18n/gluon-luci-portconfig.pot b/package/gluon-luci-portconfig/i18n/gluon-luci-portconfig.pot new file mode 100644 index 00000000..31ac71d3 --- /dev/null +++ b/package/gluon-luci-portconfig/i18n/gluon-luci-portconfig.pot @@ -0,0 +1,23 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "Automatic (DHCP)" +msgstr "" + +msgid "Automatic (RA/DHCPv6)" +msgstr "" + +msgid "Enable meshing on the WAN interface" +msgstr "" + +msgid "Enable meshing on the LAN interface" +msgstr "" + +msgid "Static" +msgstr "" + +msgid "Static DNS servers" +msgstr "" + +msgid "WAN connection" +msgstr "" diff --git a/package/gluon-luci-private-wifi/Makefile b/package/gluon-luci-private-wifi/Makefile new file mode 100644 index 00000000..604929dd --- /dev/null +++ b/package/gluon-luci-private-wifi/Makefile @@ -0,0 +1,36 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-luci-private-wifi +PKG_VERSION:=1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) + +define Package/gluon-luci-private-wifi + SECTION:=gluon + CATEGORY:=Gluon + DEPENDS:=+gluon-luci-admin + TITLE:=UI for activating a private WLAN +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile + $(call GluonBuildI18N,gluon-luci-private-wifi,i18n) +endef + +define Package/gluon-luci-private-wifi/install + $(CP) ./files/* $(1)/ + $(call GluonInstallI18N,gluon-luci-private-wifi,$(1)) +endef + +$(eval $(call BuildPackage,gluon-luci-private-wifi)) diff --git a/package/gluon-luci-private-wifi/files/usr/lib/lua/luci/controller/admin/privatewifi.lua b/package/gluon-luci-private-wifi/files/usr/lib/lua/luci/controller/admin/privatewifi.lua new file mode 100644 index 00000000..e11ba58b --- /dev/null +++ b/package/gluon-luci-private-wifi/files/usr/lib/lua/luci/controller/admin/privatewifi.lua @@ -0,0 +1,5 @@ +module("luci.controller.admin.privatewifi", package.seeall) + +function index() + entry({"admin", "privatewifi"}, cbi("admin/privatewifi"), _("Private WLAN"), 10) +end diff --git a/package/gluon-luci-private-wifi/files/usr/lib/lua/luci/model/cbi/admin/privatewifi.lua b/package/gluon-luci-private-wifi/files/usr/lib/lua/luci/model/cbi/admin/privatewifi.lua new file mode 100644 index 00000000..d3ddcd72 --- /dev/null +++ b/package/gluon-luci-private-wifi/files/usr/lib/lua/luci/model/cbi/admin/privatewifi.lua @@ -0,0 +1,63 @@ +local f, s, o, ssid +local uci = luci.model.uci.cursor() +local config = 'wireless' + +-- where to read the configuration from +local primary_iface = 'wan_radio0' +local ssid = uci:get(config, primary_iface, "ssid") + +f = SimpleForm("wifi", translate("Private WLAN")) +f.template = "admin/expertmode" + +s = f:section(SimpleSection, nil, translate( + '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. ' + .. 'Please note that the private WLAN and meshing on the WAN interface should not be enabled ' + .. 'at the same time.' +)) + +o = s:option(Flag, "enabled", translate("Enabled")) +o.default = (ssid and not uci:get_bool(config, primary_iface, "disabled")) and o.enabled or o.disabled +o.rmempty = false + +o = s:option(Value, "ssid", translate("Name (SSID)")) +o:depends("enabled", '1') +o.default = ssid + +o = s:option(Value, "key", translate("Key"), translate("8-63 characters")) +o:depends("enabled", '1') +o.datatype = "wpakey" +o.default = uci:get(config, primary_iface, "key") + +function f.handle(self, state, data) + if state == FORM_VALID then + uci:foreach(config, "wifi-device", + function(s) + local device = s['.name'] + local name = "wan_" .. device + + if data.enabled == '1' then + -- set up WAN wifi-iface + uci:section(config, "wifi-iface", name, + { + device = device, + network = "wan", + mode = 'ap', + encryption = 'psk2', + ssid = data.ssid, + key = data.key, + disabled = 0, + } + ) + else + -- disable WAN wifi-iface + uci:set(config, name, "disabled", 1) + end + end) + + uci:save(config) + uci:commit(config) + end +end + +return f diff --git a/package/gluon-luci-private-wifi/i18n/de.po b/package/gluon-luci-private-wifi/i18n/de.po new file mode 100644 index 00000000..ccf51341 --- /dev/null +++ b/package/gluon-luci-private-wifi/i18n/de.po @@ -0,0 +1,32 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2015-05-04 02:25+0200\n" +"Last-Translator: \n" +"Language-Team: German\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "8-63 characters" +msgstr "8-63 Zeichen" + +msgid "Name (SSID)" +msgstr "Name (SSID)" + +msgid "Private WLAN" +msgstr "Privates WLAN" + +msgid "" +"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. Please note that the private WLAN and meshing on the " +"WAN interface should not be enabled at the same time." +msgstr "" +"Dein Knoten kann zusätzlich die Reichweite deines privaten Netzes erweitern. " +"Hierfür wird der WAN-Port mit einem seperaten WLAN gebridged. Diese " +"Funktionalität ist völlig unabhängig von den Mesh-Funktionen des Knotens. " +"Beachte, dass du nicht gleichzeitig das Meshen über den WAN-Port aktiviert " +"haben solltest." diff --git a/package/gluon-luci-private-wifi/i18n/gluon-luci-private-wifi.pot b/package/gluon-luci-private-wifi/i18n/gluon-luci-private-wifi.pot new file mode 100644 index 00000000..4051319f --- /dev/null +++ b/package/gluon-luci-private-wifi/i18n/gluon-luci-private-wifi.pot @@ -0,0 +1,18 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "8-63 characters" +msgstr "" + +msgid "Name (SSID)" +msgstr "" + +msgid "Private WLAN" +msgstr "" + +msgid "" +"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. Please note that the private WLAN and meshing on the " +"WAN interface should not be enabled at the same time." +msgstr "" diff --git a/package/gluon-luci-theme/Makefile b/package/gluon-luci-theme/Makefile new file mode 100644 index 00000000..4fc947c4 --- /dev/null +++ b/package/gluon-luci-theme/Makefile @@ -0,0 +1,39 @@ +# Copyright (C) 2013 Nils Schneider +# This is free software, licensed under the Apache 2.0 license. + +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-luci-theme +PKG_VERSION:=0.1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + +define Package/gluon-luci-theme + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Luci theme for Gluon + DEPENDS:= +endef + +define Package/gluon-luci-theme/description + Luci based config mode +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-luci-theme/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,gluon-luci-theme)) diff --git a/package/gluon-luci-theme/files/etc/uci-defaults/luci-theme-gluon b/package/gluon-luci-theme/files/etc/uci-defaults/luci-theme-gluon new file mode 100755 index 00000000..795bd186 --- /dev/null +++ b/package/gluon-luci-theme/files/etc/uci-defaults/luci-theme-gluon @@ -0,0 +1,6 @@ +#!/bin/sh +uci batch <<-EOF + set luci.themes.Gluon=/luci-static/gluon + commit luci +EOF + diff --git a/package/gluon-luci-theme/files/usr/lib/lua/luci/view/themes/gluon/footer.htm b/package/gluon-luci-theme/files/usr/lib/lua/luci/view/themes/gluon/footer.htm new file mode 100644 index 00000000..6b709030 --- /dev/null +++ b/package/gluon-luci-theme/files/usr/lib/lua/luci/view/themes/gluon/footer.htm @@ -0,0 +1,19 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ + +-%> + + + + + diff --git a/package/gluon-luci-theme/files/usr/lib/lua/luci/view/themes/gluon/header.htm b/package/gluon-luci-theme/files/usr/lib/lua/luci/view/themes/gluon/header.htm new file mode 100644 index 00000000..730647bc --- /dev/null +++ b/package/gluon-luci-theme/files/usr/lib/lua/luci/view/themes/gluon/header.htm @@ -0,0 +1,169 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008-2010 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ + +-%> +<% + local sys = require "luci.sys" + local http = require "luci.http" + local disp = require "luci.dispatcher" + local fs = require "nixio.fs" + + local hostname = sys.hostname() + local release = fs.readfile("/lib/gluon/release") + local load1, load5, load15 = sys.loadavg() + + local request = disp.context.path + local request2 = disp.context.request + + local category = request[1] + local cattree = category and disp.node(category) + + local leaf = request2[#request2] + + local tree = disp.node() + local node = disp.context.dispatched + + local categories = disp.node_childs(tree) + + local c = tree + local i, r + + -- tag all nodes leading to this page + for i, r in ipairs(request) do + if c.nodes and c.nodes[r] then + c = c.nodes[r] + c._menu_selected = true + end + end + + http.prepare_content("application/xhtml+xml") + + local function nodeurl(prefix, name, query) + local url = controller .. prefix .. name .. "/" + if query then + url = url .. http.build_querystring(query) + end + return pcdata(url) + end + + local function subtree(prefix, node, level) + if not level then + level = 1 + end + + local childs = disp.node_childs(node) + if #childs > 0 then +%> +
+
    + <% + local selected_node + local selected_name + local i, v + + for i, v in ipairs(childs) do + local nnode = node.nodes[v] + if nnode._menu_selected then + selected_node = nnode + selected_name = v + end + %> +
  • + <%=striptags(translate(nnode.title))%> +
  • + <% + end + %> +
+
+<% + if selected_node then + subtree(prefix .. selected_name .. "/", selected_node, level + 1) + end +%> +
+<% + end + end +-%> + + + + + + + + +<% if node and node.css then %> +<% end -%> +<% if css then %> +<% end -%> + +<%=striptags( hostname .. ( (node and node.title) and ' - ' .. translate(node.title) or '')) %> - LuCI + + + + + +
+ <% if category then subtree("/" .. category .. "/", cattree) end %> + +
+ diff --git a/package/gluon-luci-theme/files/www/luci-static/gluon/cascade.css b/package/gluon-luci-theme/files/www/luci-static/gluon/cascade.css new file mode 100644 index 00000000..eb9833df --- /dev/null +++ b/package/gluon-luci-theme/files/www/luci-static/gluon/cascade.css @@ -0,0 +1,2 @@ +.lang_he{direction:RTL;unicode-bidi:embed}.hidden{display:none}html{min-height:100%;height:auto;position:relative}body,input,select,option{font-family:'Open Sans', Arial, sans-serif;font-size:12pt}body{color:#4d4e53;line-height:1.5em;margin:0;display:flex;flex-direction:column;min-height:100vh;background-color:#f3f3f3}a img{border:none;text-decoration:none}.tabmenu1{text-align:center}ul.tabmenu{list-style:none;padding:0;margin:2em 0;display:inline-flex}ul.tabmenu li{white-space:nowrap;margin:0 0.5em;padding:0;text-align:center}ul.tabmenu li a{display:block;text-decoration:none;padding:1em;margin:0;color:#333;border-radius:2em}ul.tabmenu li a:hover{background:#ffe9b3}ul.tabmenu li.active a{font-weight:bold;background:white;color:#333}abbr,acronym{font-style:normal;font-variant:normal}abbr[title],acronym[title]{border-bottom:1px dotted;cursor:help}a:link abbr[title],a:visited abbr[title],a:link acronym[title],a:visited acronym[title]{cursor:pointer}code{font-family:monospace;white-space:pre}#maincontent ul{margin-left:2em}.warning{color:red;background-color:white;font-weight:bold}.clear{clear:both}.error{color:#ff0000;background-color:white}div.hostinfo{margin:0;padding:0;font-size:80%;padding:0.5em;flex:1;font-weight:bold}#xhr_poll_status{cursor:pointer}#xhr_poll_status #xhr_poll_status_off{font-weight:bold;color:#FF0000}#xhr_poll_status #xhr_poll_status_on{font-weight:bold;color:#00FF00}#menubar{display:flex;background:#dc0067;color:#ffffff}#menubar .warning{color:red;background-color:#557788}#menubar a:link,#menubar a:visited{position:relative;display:block;padding:0.5em;text-decoration:none;font-size:80%;font-weight:normal;color:white}#menubar a:link:hover,#menubar a:visited:hover,#menubar a:link:focus,#menubar a:visited:focus{background:#ffb400;color:black}#menubar a:link.active,#menubar a:visited.active{background:#ffb400;color:black;font-weight:bold}#menubar a:link.warning,#menubar a:visited.warning{background:#000000;color:red;font-weight:bold}#modemenu{list-style:none;margin:0;padding:0}#modemenu li{display:inline-block}.lang_de #submenu_admin_uci{width:12em}.lang_ru #submenu_admin_uci{width:11.5em}textarea#syslog{width:98%;min-height:500px;border:3px solid #cccccc;padding:5px;font-family:monospace}#maincontent{padding:0 1em 2em;max-width:60em;min-width:40em;margin:1em auto}.lang_he #maincontent{direction:rtl}#maincontent p{margin-bottom:1em}.cbi-section{margin:0;padding:0;border:none}.cbi-section legend{font-size:1.4em;font-weight:bold;position:relative;padding:0;margin-bottom:0.5em}.cbi-section h2{margin:0em 0 0.5em -0.5em !important}.cbi-section h3{text-decoration:none !important;font-weight:bold !important;color:#555555 !important;margin:0.25em !important;font-size:100% !important}.cbi-section-descr{margin-bottom:2em}.cbi-title-ref{color:inherit;text-decoration:none;padding-right:18px;background:url("../resources/cbi/link.gif") no-repeat scroll right center;background-color:inherit}ul.cbi-apply{font-size:90%}input:-webkit-input-placeholder{color:#AAAAAA}input:-moz-placeholder{color:#AAAAAA}input:-ms-input-placeholder{color:#AAAAAA}input[type=checkbox]{display:none}input[type=checkbox]+label{display:inline-block;width:1em;height:1em;margin:0}input[type=checkbox]:checked+label:after{content:'✔';color:#dc0067;vertical-align:middle;position:absolute;top:50%;left:0;margin-top:-0.5em;width:100%;text-align:center;font-size:1.7em}input[type=submit],input[type=reset],input[type=image],input[type=button]{cursor:pointer}select,input,textarea,input[type=checkbox]+label{color:#003247;border:none;background:#ffe199;border-radius:3pt;padding:0.5em}input[type=image]{border:none}select,input[type=text],input[type=password]{width:20em}td select,td input[type=text],td input[type=password]{width:99%}img.cbi-image-button{cursor:pointer;margin:0 2px;vertical-align:middle}input.cbi-button{display:inline-block;zoom:1;line-height:normal;white-space:nowrap;vertical-align:baseline;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-size:100%;padding:0.5em 1em;color:rgba(0,0,0,0.8);border:none transparent;background-color:#E6E6E6;text-decoration:none;border-radius:2px;-webkit-transition:0.1s linear -webkit-box-shadow;-moz-transition:0.1s linear -moz-box-shadow;-ms-transition:0.1s linear box-shadow;-o-transition:0.1s linear box-shadow;transition:0.1s linear box-shadow;margin-left:0.5em;background-repeat:no-repeat}input.cbi-button::-moz-focus-inner{padding:0;border:0}input.cbi-button:active{box-shadow:0 0 0 1px rgba(0,0,0,0.15) inset,0 0 6px rgba(0,0,0,0.2) inset}input.cbi-button:focus{outline:0}input.cbi-button:hover,input.cbi-button:focus{background-image:-webkit-gradient(linear, 0 0, 0 100%, from(transparent), color-stop(40%, rgba(0,0,0,0.05)), to(rgba(0,0,0,0.1)));background-image:-webkit-linear-gradient(transparent, rgba(0,0,0,0.05) 40%, rgba(0,0,0,0.1));background-image:-moz-linear-gradient(top, rgba(0,0,0,0.05) 0%, rgba(0,0,0,0.1));background-image:-o-linear-gradient(transparent, rgba(0,0,0,0.05) 40%, rgba(0,0,0,0.1));background-image:linear-gradient(transparent, rgba(0,0,0,0.05) 40%, rgba(0,0,0,0.1))}input.cbi-button[disabled]{border:none;background-image:none;opacity:0.40;cursor:not-allowed;box-shadow:none}input.cbi-input-user{background-image:url("../resources/cbi/user.gif");background-repeat:no-repeat;background-position:1px center;color:#000000;text-indent:17px}input.cbi-input-find,input.cbi-button-find{background-image:url("../resources/cbi/find.gif");color:#000000;padding-left:17px}input.cbi-input-reload{background-image:url("../resources/cbi/reload.gif");color:#000000;padding-left:17px}input.cbi-input-add,input.cbi-button-add{background-image:url("../resources/cbi/add.gif");color:#000000;padding-left:17px;padding-right:1px}input.cbi-input-fieldadd,input.cbi-button-fieldadd{background-image:url(../resources/cbi/fieldadd.gif);color:#000000;padding-left:17px;padding-right:1px}input.cbi-input-reset,input.cbi-button-reset{background-color:#e30;color:#fff}input.cbi-input-save,input.cbi-button-save{background-color:#009ee0;color:#fff}input.cbi-input-apply,input.cbi-button-apply{background-color:#009ee0;color:#fff}input.cbi-input-link,input.cbi-button-link{background-image:url("../resources/cbi/link.gif");color:#000000;padding-left:17px;padding-right:1px}input.cbi-input-download,input.cbi-button-download{background-image:url("../resources/cbi/download.gif");color:#000000;padding-left:17px;padding-right:1px}input.cbi-input-remove,div.cbi-section-remove input{background-image:url("../resources/cbi/remove.gif");color:#000000;padding-left:17px;padding-right:1px}input.cbi-button-up{background-image:url("../resources/cbi/up.gif");padding-left:11px;padding-right:1px}input.cbi-button-down{background-image:url("../resources/cbi/down.gif");padding-left:11px;padding-right:1px}input.cbi-button-edit{background-image:url("../resources/cbi/edit.gif");color:#000000;padding-left:17px;padding-right:1px}input.cbi-button-reload{background-image:url("../resources/cbi/reload.gif");color:#000000;padding-left:17px;padding-right:1px}input.cbi-button-remove{background-image:url("../resources/cbi/remove.gif");color:#000000;padding-left:17px;padding-right:1px}.cbi-input-invalid{background:#e30 !important;color:white}div.cbi-section-remove input{border-bottom:none}textarea{margin-left:-1px;margin-bottom:0.5em}table td,table th{color:#000000}table.smalltext{background:#f5f5f5;color:#000000;border-top:1px solid #666666;border-right:1px solid #666666;border-bottom:1px solid #666666;font-size:90%;width:80%;margin-left:auto;margin-right:auto;border-collapse:collapse}table.smalltext tr:hover td{background-color:#bbddee;color:#000000}table.smalltext tr th{padding:0 0.25em;border-left:1px solid #666666;text-align:left}table.smalltext tr td{padding:0 0.25em;border-top:1px solid #666666;border-left:1px solid #666666}table.cbi-section-table .cbi-rowstyle-1{background-color:#eeeeff;color:#000000}table.cbi-section-table .cbi-rowstyle-1:hover,table.cbi-section-table .cbi-rowstyle-2:hover{background-color:#b2c8d4;color:#000000}table.cbi-section-table .cbi-section-table-cell{padding:3px;white-space:nowrap}.cbi-section .cbi-rowstyle-1 h3{background-color:#eeeeff;color:#555555}.cbi-rowstyle-2{color:#000000}div.cbi-value{display:flex;flex-direction:row;margin-bottom:0.5em}.cbi-value-title{flex:2;text-align:right;padding-right:1em;font-weight:bold}div.cbi-value-field{flex:3;position:relative}div.cbi-value-field input,div.cbi-value-field select,div.cbi-value-field input+label{position:relative;top:-0.39em}div.cbi-value-field-long{flex:10;position:relative}div.cbi-value-field-long input,div.cbi-value-field-long select,div.cbi-value-field-long input+label{position:relative;top:-0.39em}div.cbi-value-field-long-after{flex:2}div.cbi-value-description{font-size:8pt}div.cbi-section-create{clear:left;white-space:nowrap;vertical-align:top}div.cbi-section-create .cbi-button{margin:0.25em}input.cbi-section-create-name{margin-right:-0.25em}div.cbi-map-descr{margin-bottom:1em}.cbi-map-descr:empty,.cbi-section-descr:empty{display:none}.cbi-map-descr,.cbi-section-descr,.cbi-page-actions{padding:1em;background:#ececec}.cbi-page-actions{text-align:right;display:flex;display:-moz-flex;-moz-flex-flow:row-reverse;flex-flow:row-reverse}div.cbi-optionals{padding:0.25em;border-bottom:1px dotted #bbbbbb}div.cbi-section-remove{float:right}.cbi-section-node{clear:both;position:relative;border:none}.cbi-section-node-tabbed{border-top-left-radius:0}.cbi-section-node .cbi-value-last{border-bottom:none}.cbi-section-node table div{padding-bottom:0;border-bottom:none}.cbi-section-node div.cbi-section-table-row{margin:0.25em}table.cbi-section-table{width:100%;font-size:95%}table.cbi-section-table th,table.cbi-section-table td{text-align:center}tr.cbi-section-table-descr th{font-weight:normal;font-size:90%;vertical-align:top}td.cbi-section-table-optionals{text-align:left !important;padding-top:1em}.cbi-value-helpicon img{display:none}div.cbi-error{font-size:95%;font-weight:bold;color:#ff0000;background-color:#ffffff}td.cbi-value-error{border-color:red}.cbi-value-error input,.cbi-value-error select{background-color:#ffcccc}.cbi-section-error{color:red;background-color:white;font-size:95%;border:1px dotted red;margin:3px;padding:3px}.cbi-value-field var{color:#2222FF}ul.cbi-tabmenu{padding:3px 0;margin-left:0 !important;list-style-type:none;position:relative;z-index:10;top:4px;line-height:20px}ul.cbi-tabmenu li.cbi-tab,ul.cbi-tabmenu li.cbi-tab-disabled{display:inline;margin:0}ul.cbi-tabmenu li.cbi-tab a,ul.cbi-tabmenu li.cbi-tab-disabled a{text-decoration:none;padding:3px 7px;margin-right:3px;border:1px solid #BBBBBB;border-bottom:none;border-radius:3px 3px 0 0;background-color:#EEEEEE;color:#BBBBBB}ul.cbi-tabmenu li.cbi-tab-highlighted a{color:#000000;background-color:#FFEEAA}ul.cbi-tabmenu li a:hover{color:#000000}ul.cbi-tabmenu li.cbi-tab a{padding-top:4px;color:#000000;background-color:#FFFFFF}div.cbi-tab-descr{background-image:url(/luci-static/resources/cbi/help.gif);background-position:0.25em 50%;background-repeat:no-repeat;border-bottom:1px solid #CCCCCC;margin:0.25em 0.25em 2em;padding:0.5em 0.5em 0.5em 2em}.left{text-align:left !important}.right{text-align:right !important}.luci{position:absolute;bottom:0;left:1em;height:1.5em;font-size:80%}.luci a:link,.luci a:visited{background-color:transparent;color:#666666;text-decoration:none;font-size:70%}.inline{display:inline}.error500{white-space:normal;border:1px dotted #ff0000;background-color:#ffffff;color:#000000;padding:0.5em}.errorbox{border:1px solid #FF0000;background-color:#FFCCCC;padding:5px;margin-bottom:5px}.errorbox a{color:#000000 !important}.ifacebox{background-color:#FFFFFF;border:1px solid #CCCCCC;margin:0 10px;text-align:center;white-space:nowrap}.ifacebox .ifacebox-head{border-bottom:1px solid #CCCCCC;padding:2px}.ifacebox .ifacebox-body{padding:2px}.ifacebadge{background-color:#FFFFFF;border:1px solid #CCCCCC;padding:2px;margin-left:2px;display:inline-block}.ifacebadge-active{border-color:#000000;font-weight:bold}.zonebadge{padding:2px;display:inline-block;white-space:nowrap;cursor:pointer}.zonebadge em,.zonebadge strong{margin:3px;display:inline-block}.zonebadge input{width:6em;height:1.5em}.zonebadge-empty{border:1px dashed #AAAAAA;color:#AAAAAA;font-style:italic;font-size:smaller}.uci-change-list{font-family:monospace}.uci-change-list ins,.uci-change-legend-label ins{text-decoration:none;border:1px solid #00FF00;background-color:#CCFFCC;display:block;padding:2px}.uci-change-list del,.uci-change-legend-label del{text-decoration:none;border:1px solid #FF0000;background-color:#FFCCCC;display:block;font-style:normal;padding:2px}.uci-change-list var,.uci-change-legend-label var{text-decoration:none;border:1px solid #CCCCCC;background-color:#EEEEEE;display:block;font-style:normal;padding:2px}.uci-change-list var ins,.uci-change-list var del{border:none;white-space:pre;font-style:normal;padding:0px}.uci-change-legend{padding:5px}.uci-change-legend-label{width:150px;float:left;font-size:80%}.uci-change-legend-label>ins,.uci-change-legend-label>del,.uci-change-legend-label>var{float:left;margin-right:4px;width:10px;height:10px;display:block}.uci-change-legend-label var ins,.uci-change-legend-label var del{line-height:6px;border:none}.cbi-input-password+img{display:none}.the-key{text-align:left;font-size:1.4em;background:#ffe9b3;border:3pt dashed #dc0067;margin-bottom:0.5em;padding:0.5em} +/*# sourceMappingURL=cascade.css.map */ diff --git a/package/gluon-luci-theme/sass/cascade.scss b/package/gluon-luci-theme/sass/cascade.scss new file mode 100644 index 00000000..bfcfc58c --- /dev/null +++ b/package/gluon-luci-theme/sass/cascade.scss @@ -0,0 +1,1029 @@ +/* ATTENTION: This file is not compiled when building gluon. + The compiled version is at ../files/www/luci-static/gluon/cascade.css + + Use sass like this to update it: + + sass cascade.scss ../files/www/luci-static/gluon/cascade.css + + When commiting changes to this file make sure to commit the respective + changes to the compilid version within the same commit! + */ + +@charset "utf-8"; + +$ffyellow: #ffb400; +$ffmagenta: #dc0067; +$ffzusatz: #009ee0; +$red: #ee3300; + +@mixin button { + &::-moz-focus-inner { + padding: 0; + border: 0; + } + + display: inline-block; + zoom: 1; + line-height: normal; + white-space: nowrap; + vertical-align: baseline; + text-align: center; + cursor: pointer; + -webkit-user-drag: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + + font-size: 100%; + padding: 0.5em 1em; + color: rgba(0, 0, 0, 0.80); + border: none rgba(0, 0, 0, 0); + background-color: #E6E6E6; + text-decoration: none; + border-radius: 2px; + + /* Transitions */ + -webkit-transition: 0.1s linear -webkit-box-shadow; + -moz-transition: 0.1s linear -moz-box-shadow; + -ms-transition: 0.1s linear box-shadow; + -o-transition: 0.1s linear box-shadow; + transition: 0.1s linear box-shadow; + + &:active { + box-shadow: 0 0 0 1px rgba(0,0,0, 0.15) inset, 0 0 6px rgba(0,0,0, 0.20) inset; + } + + &:focus { + outline: 0; + } + + &:hover, &:focus { + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(transparent), color-stop(40%, rgba(0,0,0, 0.05)), to(rgba(0,0,0, 0.10))); + background-image: -webkit-linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.10)); + background-image: -moz-linear-gradient(top, rgba(0,0,0, 0.05) 0%, rgba(0,0,0, 0.10)); + background-image: -o-linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.10)); + background-image: linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.10)); + } + + &[disabled] { + border: none; + background-image: none; + opacity: 0.40; + cursor: not-allowed; + box-shadow: none; + } +} + +@mixin button-primary { + background-color: $ffzusatz; + color: #fff; +} + +.lang_he { + direction: RTL; + unicode-bidi: embed; +} + +.hidden { + display: none; +} + +html { + min-height: 100%; + height: auto; + position:relative; +} + +body, input, select, option { + font-family: 'Open Sans', Arial, sans-serif; + font-size: 12pt; +} + +body { + color: rgb(77, 78, 83); + line-height: 1.5em; + margin: 0; + display: flex; + flex-direction: column; + min-height: 100vh; + background-color: #f3f3f3; +} + +a img { + border: none; + text-decoration: none; +} + +.tabmenu1 { + text-align: center; +} + +ul.tabmenu { + list-style: none; + padding: 0; + margin: 2em 0; + display: inline-flex; +} + +ul.tabmenu li { + white-space: nowrap; + margin: 0 0.5em; + padding: 0; + text-align: center; + + a { + display: block; + text-decoration: none; + padding: 1em; + margin: 0; + color: #333; + border-radius: 2em; + + &:hover { + background: lighten($ffyellow, 35); + } + } + + &.active a { + font-weight: bold; + background: white; + color: #333; + } +} + +abbr, +acronym { + font-style: normal; + font-variant: normal; +} + +abbr[title], +acronym[title] { + border-bottom: 1px dotted; + cursor: help; +} + +a:link abbr[title], +a:visited abbr[title], +a:link acronym[title], +a:visited acronym[title] { + cursor: pointer; +} + +code { + font-family: monospace; + white-space: pre; +} + +#maincontent ul { + margin-left: 2em; +} + +.warning { + color: red; + background-color: white; + font-weight: bold; +} + +.clear { + clear: both; +} + +.error { + color: #ff0000; + background-color: white; +} + +div.hostinfo { + margin: 0; + padding: 0; + font-size: 80%; + padding: 0.5em; + flex: 1; + font-weight: bold; +} + +#xhr_poll_status { + cursor: pointer; +} + +#xhr_poll_status #xhr_poll_status_off { + font-weight: bold; + color: #FF0000; +} + +#xhr_poll_status #xhr_poll_status_on { + font-weight: bold; + color: #00FF00; +} + +#menubar { + display: flex; + background: $ffmagenta; + color: #ffffff; +} + +#menubar .warning { + color: red; + background-color: #557788; +} + +#menubar a:link, +#menubar a:visited { + position: relative; + display: block; + padding: 0.5em; + text-decoration: none; + font-size: 80%; + font-weight: normal; + color: white; +} + +#menubar a:link:hover, +#menubar a:visited:hover, +#menubar a:link:focus, +#menubar a:visited:focus { + background: $ffyellow; + color: black; +} + +#menubar a:link.active, +#menubar a:visited.active { + background: $ffyellow; + color: black; + font-weight: bold; +} + +#menubar a:link.warning, +#menubar a:visited.warning { + background: #000000; + color: red; + font-weight: bold; +} + +#modemenu { + list-style: none; + margin: 0; + padding: 0; +} + +#modemenu li { + display: inline-block; +} + +#savemenu { +} + +.lang_he #savemenu { +} + +.lang_de #submenu_admin_uci { + width: 12em; +} + +.lang_ru #submenu_admin_uci { + width: 11.5em; +} + +textarea#syslog { + width: 98%; + min-height: 500px; + border: 3px solid #cccccc; + padding: 5px; + font-family: monospace; +} + +#maincontent { + padding: 0 1em 2em; + max-width: 60em; + min-width: 40em; + margin: 1em auto; +} + +.lang_he #maincontent { + direction: rtl; +} + +#maincontent h2 { +} + +#maincontent h3 { +} + +#maincontent p { + margin-bottom: 1em; +} + +.cbi-section { + margin: 0; + padding: 0; + border: none; +} + +.cbi-section legend { + font-size: 1.4em; + font-weight: bold; + position: relative; + padding: 0; + margin-bottom: 0.5em; +} + +.cbi-section h2 { + margin: 0em 0 0.5em -0.5em !important; +} + +.cbi-section h3 { + text-decoration: none !important; + font-weight: bold !important; + color: #555555 !important; + margin: 0.25em !important; + font-size: 100% !important; +} + +.cbi-section-descr { + margin-bottom: 2em; +} + +.cbi-title-ref { + color: inherit; + text-decoration: none; + padding-right: 18px; + background: url('../resources/cbi/link.gif') no-repeat scroll right center; + background-color: inherit; +} + +ul.cbi-apply { + font-size: 90%; +} + +input:-webkit-input-placeholder { + color: #AAAAAA; +} + +input:-moz-placeholder { + color: #AAAAAA; +} + +input:-ms-input-placeholder { + color: #AAAAAA; +} + +input[type=checkbox] { + display: none; + + & + label { + display: inline-block; + width: 1em; + height: 1em; + margin: 0; + } + + &:checked + label:after { + content: '✔'; + color: $ffmagenta; + vertical-align: middle; + position: absolute; + top: 50%; + left: 0; + margin-top: -0.5em; + width: 100%; + text-align: center; + font-size: 1.7em; + } +} + +input[type=submit], +input[type=reset], +input[type=image], +input[type=button] { + cursor: pointer; +} + +select, +input, +textarea, +input[type=checkbox] + label { + color: darken($ffzusatz, 30); + border: none; + background: lighten($ffyellow, 30); + border-radius: 3pt; + padding: 0.5em; +} + +input[type=image] { + border: none; +} + +select, +input[type=text], +input[type=password] { + width: 20em; +} + +td select, +td input[type=text], +td input[type=password] { + width: 99%; +} + +img.cbi-image-button { + cursor: pointer; + margin: 0 2px; + vertical-align: middle; +} + +input.cbi-button { + @include button; + + margin-left: 0.5em; + background-repeat: no-repeat; +} + +input.cbi-input-user { + background-image: url('../resources/cbi/user.gif'); + background-repeat: no-repeat; + background-position: 1px center; + color: #000000; + text-indent: 17px; +} + +input.cbi-input-find, +input.cbi-button-find { + background-image: url('../resources/cbi/find.gif'); + color: #000000; + padding-left: 17px; +} + +input.cbi-input-reload { + background-image: url('../resources/cbi/reload.gif'); + color: #000000; + padding-left: 17px; +} + +input.cbi-input-add, +input.cbi-button-add { + background-image: url('../resources/cbi/add.gif'); + color: #000000; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-fieldadd, +input.cbi-button-fieldadd { + background-image: url(../resources/cbi/fieldadd.gif); + color: #000000; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-reset, +input.cbi-button-reset { + background-color: $red; + color: #fff; +} + +input.cbi-input-save, +input.cbi-button-save { + @include button-primary; +} + +input.cbi-input-apply, +input.cbi-button-apply { + @include button-primary; +} + +input.cbi-input-link, +input.cbi-button-link { + background-image: url('../resources/cbi/link.gif'); + color: #000000; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-download, +input.cbi-button-download { + background-image: url('../resources/cbi/download.gif'); + color: #000000; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-remove, +div.cbi-section-remove input { + background-image: url('../resources/cbi/remove.gif'); + color: #000000; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-button-up { + background-image: url('../resources/cbi/up.gif'); + padding-left: 11px; + padding-right: 1px; +} + +input.cbi-button-down { + background-image: url('../resources/cbi/down.gif'); + padding-left: 11px; + padding-right: 1px; +} + +input.cbi-button-edit { + background-image: url('../resources/cbi/edit.gif'); + color: #000000; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-button-reload { + background-image: url('../resources/cbi/reload.gif'); + color: #000000; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-button-remove { + background-image: url('../resources/cbi/remove.gif'); + color: #000000; + padding-left: 17px; + padding-right: 1px; +} + +.cbi-input-invalid { + background: $red !important; + color: white; +} + +div.cbi-section-remove input { + border-bottom: none; +} + +textarea { + margin-left: -1px; + margin-bottom: 0.5em; +} + +table td, +table th { + color: #000000; +} + +table.smalltext { + background: #f5f5f5; + color: #000000; + border-top: 1px solid #666666; + border-right: 1px solid #666666; + border-bottom: 1px solid #666666; + font-size: 90%; + width: 80%; + margin-left: auto; + margin-right: auto; + border-collapse: collapse; +} + +table.smalltext tr:hover td { + background-color: #bbddee; + color: #000000; +} + +table.smalltext tr th { + padding: 0 0.25em; + border-left: 1px solid #666666; + text-align: left; +} + +table.smalltext tr td { + padding: 0 0.25em; + border-top: 1px solid #666666; + border-left: 1px solid #666666; +} + +table.cbi-section-table .cbi-rowstyle-1 { + background-color: #eeeeff; + color: #000000; +} + +table.cbi-section-table .cbi-rowstyle-1:hover, +table.cbi-section-table .cbi-rowstyle-2:hover { + background-color: #b2c8d4; + color: #000000; +} + +table.cbi-section-table .cbi-section-table-cell { + padding: 3px; + white-space: nowrap; +} + +.cbi-section .cbi-rowstyle-1 h3 { + background-color: #eeeeff; + color: #555555; +} + +.cbi-rowstyle-2 { + color: #000000; +} + +div.cbi-value { + display: flex; + flex-direction: row; + margin-bottom: 0.5em; +} + +.cbi-value-title { + flex: 2; + text-align: right; + padding-right: 1em; + font-weight: bold; +} + +div.cbi-value-field { + flex: 3; + position: relative; + + input, select, input + label { + position: relative; + top: -0.39em; + } +} + +div.cbi-value-field-long { + flex: 10; + position: relative; + + + input, select, input + label { + position: relative; + top: -0.39em; + } +} + +div.cbi-value-field-long-after { + flex: 2; +} + +div.cbi-value-description { + font-size: 8pt; +} + +div.cbi-section-create { + clear: left; + white-space: nowrap; + vertical-align: top; +} + +div.cbi-section-create .cbi-button { + margin: 0.25em; +} + +input.cbi-section-create-name { + margin-right: -0.25em; +} + +div.cbi-map-descr { + margin-bottom: 1em; +} + +.cbi-map-descr:empty, .cbi-section-descr:empty { + display: none; +} + +.cbi-map-descr, .cbi-section-descr, .cbi-page-actions { + padding: 1em; + background: #ececec; +} + +.cbi-page-actions { + text-align: right; + display: flex; + display: -moz-flex; + -moz-flex-flow: row-reverse; + flex-flow: row-reverse; +} + +div.cbi-optionals { + padding: 0.25em; + border-bottom: 1px dotted #bbbbbb; +} + +div.cbi-section-remove { + float: right; +} + +.cbi-section-node { + clear: both; + position: relative; + border: none; +} + +.cbi-section-node-tabbed { + border-top-left-radius: 0; +} + +.cbi-section-node .cbi-value-last { + border-bottom: none; +} + +.cbi-section-node table div { + padding-bottom: 0; + border-bottom: none; +} + +.cbi-section-node div.cbi-section-table-row { + margin: 0.25em; +} + +table.cbi-section-table { + width: 100%; + font-size: 95%; +} + +table.cbi-section-table th, +table.cbi-section-table td { + text-align: center; +} + +tr.cbi-section-table-descr th { + font-weight: normal; + font-size: 90%; + vertical-align: top; +} + +td.cbi-section-table-optionals { + text-align: left !important; + padding-top: 1em; +} + +.cbi-value-helpicon img { + display: none; +} + +div.cbi-error { + font-size: 95%; + font-weight: bold; + color: #ff0000; + background-color: #ffffff; +} + +td.cbi-value-error { + border-color: red; +} + +.cbi-value-error input, +.cbi-value-error select { + background-color: #ffcccc; +} + +.cbi-section-error { + color: red; + background-color: white; + font-size: 95%; + border: 1px dotted red; + margin: 3px; + padding: 3px; +} + +.cbi-value-field var { + color: #2222FF; +} + +ul.cbi-tabmenu { + padding: 3px 0; + margin-left: 0 !important; + list-style-type: none; + position: relative; + z-index: 10; + top: 4px; + line-height: 20px; +} + +ul.cbi-tabmenu li.cbi-tab, +ul.cbi-tabmenu li.cbi-tab-disabled { + display: inline; + margin: 0; +} + +ul.cbi-tabmenu li.cbi-tab a, +ul.cbi-tabmenu li.cbi-tab-disabled a { + text-decoration: none; + padding: 3px 7px; + margin-right: 3px; + border: 1px solid #BBBBBB; + border-bottom: none; + border-radius: 3px 3px 0 0; + background-color: #EEEEEE; + color: #BBBBBB; +} + +ul.cbi-tabmenu li.cbi-tab-highlighted a { + color: #000000; + background-color: #FFEEAA; +} + +ul.cbi-tabmenu li a:hover { + color: #000000; +} + +ul.cbi-tabmenu li.cbi-tab a { + padding-top: 4px; + color: #000000; + background-color: #FFFFFF; +} + +div.cbi-tab-descr { + background-image: url(/luci-static/resources/cbi/help.gif); + background-position: 0.25em 50%; + background-repeat: no-repeat; + border-bottom: 1px solid #CCCCCC; + margin: 0.25em 0.25em 2em; + padding: 0.5em 0.5em 0.5em 2em; +} + +.left { + text-align: left !important; +} + +.right { + text-align: right !important; +} + +.luci { + position: absolute; + bottom: 0; + left: 1em; + height: 1.5em; + font-size: 80%; +} + +.luci a:link, +.luci a:visited { + background-color: transparent; + color: #666666; + text-decoration: none; + font-size: 70%; +} + +.inline { + display: inline; +} + +.error500 { + white-space: normal; + border: 1px dotted #ff0000; + background-color: #ffffff; + color: #000000; + padding: 0.5em; +} + +.errorbox { + border: 1px solid #FF0000; + background-color: #FFCCCC; + padding: 5px; + margin-bottom: 5px; +} + +.errorbox a { + color: #000000 !important; +} + + +.ifacebox { + background-color: #FFFFFF; + border: 1px solid #CCCCCC; + margin: 0 10px; + text-align: center; + white-space: nowrap; +} + +.ifacebox .ifacebox-head { + border-bottom: 1px solid #CCCCCC; + padding: 2px; +} + +.ifacebox .ifacebox-body { + padding: 2px; +} + + +.ifacebadge { + background-color: #FFFFFF; + border: 1px solid #CCCCCC; + padding: 2px; + margin-left: 2px; + display: inline-block; +} + +.ifacebadge-active { + border-color: #000000; + font-weight: bold; +} + + +.zonebadge { + padding: 2px; + display: inline-block; + white-space: nowrap; + cursor: pointer; +} + +.zonebadge em, +.zonebadge strong { + margin: 3px; + display: inline-block; +} + +.zonebadge input { + width: 6em; + height: 1.5em; +} + +.zonebadge-empty { + border: 1px dashed #AAAAAA; + color: #AAAAAA; + font-style: italic; + font-size: smaller; +} + + +.uci-change-list { + font-family: monospace; +} + +.uci-change-list ins, +.uci-change-legend-label ins { + text-decoration: none; + border: 1px solid #00FF00; + background-color: #CCFFCC; + display: block; + padding: 2px; +} + +.uci-change-list del, +.uci-change-legend-label del { + text-decoration: none; + border: 1px solid #FF0000; + background-color: #FFCCCC; + display: block; + font-style: normal; + padding: 2px; +} + +.uci-change-list var, +.uci-change-legend-label var { + text-decoration: none; + border: 1px solid #CCCCCC; + background-color: #EEEEEE; + display: block; + font-style: normal; + padding: 2px; +} + +.uci-change-list var ins, +.uci-change-list var del { + /*display: inline;*/ + border: none; + white-space: pre; + font-style: normal; + padding: 0px; +} + +.uci-change-legend { + padding: 5px; +} + +.uci-change-legend-label { + width: 150px; + float: left; + font-size: 80%; +} + +.uci-change-legend-label>ins, +.uci-change-legend-label>del, +.uci-change-legend-label>var { + float: left; + margin-right: 4px; + width: 10px; + height: 10px; + display: block; +} + +.uci-change-legend-label var ins, +.uci-change-legend-label var del { + line-height: 6px; + border: none; +} + +// Hide show/hide password toggle image +.cbi-input-password + img { + display: none; +} + +.the-key { + text-align: left; + font-size: 1.4em; + background: lighten($ffyellow, 35); + border: 3pt dashed $ffmagenta; + margin-bottom: 0.5em; + padding: 0.5em +} diff --git a/package/gluon-luci-wifi-config/Makefile b/package/gluon-luci-wifi-config/Makefile new file mode 100644 index 00000000..462eab9f --- /dev/null +++ b/package/gluon-luci-wifi-config/Makefile @@ -0,0 +1,36 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-luci-wifi-config +PKG_VERSION:=1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) + +define Package/gluon-luci-wifi-config + SECTION:=gluon + CATEGORY:=Gluon + DEPENDS:=+gluon-luci-admin +libiwinfo-lua + TITLE:=UI for Wifi Settings +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile + $(call GluonBuildI18N,gluon-luci-wifi-config,i18n) +endef + +define Package/gluon-luci-wifi-config/install + $(CP) ./files/* $(1)/ + $(call GluonInstallI18N,gluon-luci-wifi-config,$(1)) +endef + +$(eval $(call BuildPackage,gluon-luci-wifi-config)) diff --git a/package/gluon-luci-wifi-config/files/usr/lib/lua/luci/controller/admin/wifi-config.lua b/package/gluon-luci-wifi-config/files/usr/lib/lua/luci/controller/admin/wifi-config.lua new file mode 100644 index 00000000..2ff1cb84 --- /dev/null +++ b/package/gluon-luci-wifi-config/files/usr/lib/lua/luci/controller/admin/wifi-config.lua @@ -0,0 +1,5 @@ +module("luci.controller.admin.wifi-config", package.seeall) + +function index() + entry({"admin", "wifi-config"}, cbi("admin/wifi-config"), _("WLAN"), 20) +end diff --git a/package/gluon-luci-wifi-config/files/usr/lib/lua/luci/model/cbi/admin/wifi-config.lua b/package/gluon-luci-wifi-config/files/usr/lib/lua/luci/model/cbi/admin/wifi-config.lua new file mode 100644 index 00000000..591e944e --- /dev/null +++ b/package/gluon-luci-wifi-config/files/usr/lib/lua/luci/model/cbi/admin/wifi-config.lua @@ -0,0 +1,150 @@ +local uci = luci.model.uci.cursor() +local fs = require 'nixio.fs' +local iwinfo = require 'iwinfo' + + +local function find_phy_by_path(path) + for phy in fs.glob("/sys/devices/" .. path .. "/ieee80211/phy*") do + return phy:match("([^/]+)$") + end +end + +local function find_phy_by_macaddr(macaddr) + local addr = macaddr:lower() + for file in fs.glob("/sys/class/ieee80211/*/macaddress") do + if luci.util.trim(fs.readfile(file)) == addr then + return file:match("([^/]+)/macaddress$") + end + end +end + +local function txpower_list(phy) + local list = iwinfo.nl80211.txpwrlist(phy) or { } + local off = tonumber(iwinfo.nl80211.txpower_offset(phy)) or 0 + local new = { } + local prev = -1 + local _, val + for _, val in ipairs(list) do + local dbm = val.dbm + off + local mw = math.floor(10 ^ (dbm / 10)) + if mw ~= prev then + prev = mw + table.insert(new, { + display_dbm = dbm, + display_mw = mw, + driver_dbm = val.dbm, + }) + end + end + return new +end + + +local f = SimpleForm("wifi", translate("WLAN")) +f.template = "admin/expertmode" + +local s = f:section(SimpleSection, nil, translate( + "You can enable or disable your node's client and mesh network " + .. "SSIDs here. Please don't disable the mesh network without " + .. "a good reason, so other nodes can mesh with yours.

" + .. "It is also possible to configure the WLAN adapters transmission power " + .. "here. Please note that the transmission power values include the antenna gain " + .. "where available, but there are many devices for which the gain is unavailable or inaccurate." +)) + +local radios = {} + +-- look for wifi interfaces and add them to the array +uci:foreach('wireless', 'wifi-device', + function(s) + table.insert(radios, s['.name']) + end +) + +-- add a client and mesh checkbox for each interface +for _, radio in ipairs(radios) do + local config = uci:get_all('wireless', radio) + local p + + if config.hwmode == '11g' or config.hwmode == '11ng' then + p = f:section(SimpleSection, translate("2.4GHz WLAN")) + elseif config.hwmode == '11a' or config.hwmode == '11na' then + p = f:section(SimpleSection, translate("5GHz WLAN")) + end + + if p then + local o + + --box for the client network + o = p:option(Flag, radio .. '_client_enabled', translate("Enable client network")) + o.default = uci:get_bool('wireless', 'client_' .. radio, "disabled") and o.disabled or o.enabled + o.rmempty = false + + --box for the mesh network + o = p:option(Flag, radio .. '_mesh_enabled', translate("Enable mesh network")) + o.default = uci:get_bool('wireless', 'mesh_' .. radio, "disabled") and o.disabled or o.enabled + o.rmempty = false + + local phy + + if config.path then + phy = find_phy_by_path(config.path) + elseif config.macaddr then + phy = find_phy_by_path(config.macaddr) + end + + if phy then + local txpowers = txpower_list(phy) + + if #txpowers > 1 then + local tp = p:option(ListValue, radio .. '_txpower', translate("Transmission power")) + tp.rmempty = true + tp.default = uci:get('wireless', radio, 'txpower') or 'default' + + tp:value('default', translate("(default)")) + + table.sort(txpowers, function(a, b) return a.driver_dbm > b.driver_dbm end) + + for _, entry in ipairs(txpowers) do + tp:value(entry.driver_dbm, "%i dBm (%i mW)" % {entry.display_dbm, entry.display_mw}) + end + end + end + end + +end + +--when the save-button is pushed +function f.handle(self, state, data) + if state == FORM_VALID then + + for _, radio in ipairs(radios) do + + local clientdisabled = 0 + if data[radio .. '_client_enabled'] == '0' then + clientdisabled = 1 + end + uci:set('wireless', 'client_' .. radio, "disabled", clientdisabled) + + local meshdisabled = 0 + if data[radio .. '_client_enabled'] == '0' then + meshdisabled = 1 + end + uci:set('wireless', 'mesh_' .. radio, "disabled", meshdisabled) + + if data[radio .. '_txpower'] then + if data[radio .. '_txpower'] == 'default' then + uci:delete('wireless', radio, 'txpower') + else + uci:set('wireless', radio, 'txpower', data[radio .. '_txpower']) + end + end + + end + + uci:save('wireless') + uci:commit('wireless') + end +end + +return f diff --git a/package/gluon-luci-wifi-config/i18n/de.po b/package/gluon-luci-wifi-config/i18n/de.po new file mode 100644 index 00000000..d633d84c --- /dev/null +++ b/package/gluon-luci-wifi-config/i18n/de.po @@ -0,0 +1,46 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2015-05-04 02:54+0200\n" +"Last-Translator: \n" +"Language-Team: German\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "(default)" +msgstr "(Standard)" + +msgid "2.4GHz WLAN" +msgstr "2,4GHz-WLAN" + +msgid "5GHz WLAN" +msgstr "5GHz-WLAN" + +msgid "Enable client network" +msgstr "Client-Netz aktivieren" + +msgid "Enable mesh network" +msgstr "Mesh-Netz aktivieren" + +msgid "Transmission power" +msgstr "Sendeleistung" + +msgid "" +"You can enable or disable your node's client and mesh network SSIDs here. " +"Please don't disable the mesh network without a good reason, so other nodes " +"can mesh with yours.

It is also possible to configure the WLAN " +"adapters transmission power here. Please note that the transmission power " +"values include the antenna gain where available, but there are many devices " +"for which the gain is unavailable or inaccurate." +msgstr "" +"In diesem Abschnitt hast du die Möglichkeit, die SSIDs des Client- und " +"des Mesh-Netzes zu aktivieren bzw. deaktivieren. Bitte lass die SSID des " +"Mesh-Netzes aktiviert, damit sich andere Knoten mit deinem verbinden " +"können.

" +"Außerdem kann hier die Sendeleistung des WLAN-Adapters konfiguriert werden. " +"Wenn möglich, ist in den Werten der Sendeleistung der Antennengewinn " +"enthalten; diese Werte sind allerdings für viele Geräte nicht verfügbar oder " +"fehlerhaft." diff --git a/package/gluon-luci-wifi-config/i18n/gluon-luci-wifi-config.pot b/package/gluon-luci-wifi-config/i18n/gluon-luci-wifi-config.pot new file mode 100644 index 00000000..fa61df18 --- /dev/null +++ b/package/gluon-luci-wifi-config/i18n/gluon-luci-wifi-config.pot @@ -0,0 +1,29 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "(default)" +msgstr "" + +msgid "2.4GHz WLAN" +msgstr "" + +msgid "5GHz WLAN" +msgstr "" + +msgid "Enable client network" +msgstr "" + +msgid "Enable mesh network" +msgstr "" + +msgid "Transmission power" +msgstr "" + +msgid "" +"You can enable or disable your node's client and mesh network SSIDs here. " +"Please don't disable the mesh network without a good reason, so other nodes " +"can mesh with yours.

It is also possible to configure the WLAN " +"adapters transmission power here. Please note that the transmission power " +"values include the antenna gain where available, but there are many devices " +"for which the gain is unavailable or inaccurate." +msgstr "" diff --git a/package/gluon-mesh-batman-adv-14/Makefile b/package/gluon-mesh-batman-adv-14/Makefile new file mode 100644 index 00000000..be65cafa --- /dev/null +++ b/package/gluon-mesh-batman-adv-14/Makefile @@ -0,0 +1,32 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-mesh-batman-adv-14 +PKG_VERSION:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +define Package/gluon-mesh-batman-adv-14 + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Support for batman-adv meshing (compat level 14) + DEPENDS:=+gluon-mesh-batman-adv-core +kmod-batman-adv-legacy + PROVIDES:=gluon-mesh-batman-adv +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-mesh-batman-adv-14/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,gluon-mesh-batman-adv-14)) diff --git a/package/gluon-mesh-batman-adv-14/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/compat b/package/gluon-mesh-batman-adv-14/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/compat new file mode 100644 index 00000000..84137237 --- /dev/null +++ b/package/gluon-mesh-batman-adv-14/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/compat @@ -0,0 +1 @@ +return 14 diff --git a/package/gluon-mesh-batman-adv-14/files/lib/gluon/upgrade/350-gluon-mesh-batman-adv-14 b/package/gluon-mesh-batman-adv-14/files/lib/gluon/upgrade/350-gluon-mesh-batman-adv-14 new file mode 100755 index 00000000..b3ed1e88 --- /dev/null +++ b/package/gluon-mesh-batman-adv-14/files/lib/gluon/upgrade/350-gluon-mesh-batman-adv-14 @@ -0,0 +1,40 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' + +local uci = require('luci.model.uci').cursor() + + +local function configure_mtu(radio, config) + local mesh = 'mesh_' .. radio + + if config.mesh_vlan then + uci:set('network', mesh, 'mtu', 1532) + uci:set('network', mesh .. '_vlan', 'mtu', 1528) + else + uci:set('network', mesh, 'mtu', 1528) + end +end + + +local radios = {} + +uci:foreach('wireless', 'wifi-device', + function(s) + table.insert(radios, s['.name']) + end +) + +for _, radio in ipairs(radios) do + local hwmode = uci:get('wireless', radio, 'hwmode') + + if hwmode == '11g' or hwmode == '11ng' then + configure_mtu(radio, site.wifi24) + elseif hwmode == '11a' or hwmode == '11na' then + configure_mtu(radio, site.wifi5) + end +end + + +uci:save('network') +uci:commit('network') diff --git a/package/gluon-mesh-batman-adv-15/Makefile b/package/gluon-mesh-batman-adv-15/Makefile new file mode 100644 index 00000000..14a39a61 --- /dev/null +++ b/package/gluon-mesh-batman-adv-15/Makefile @@ -0,0 +1,32 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-mesh-batman-adv-15 +PKG_VERSION:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +define Package/gluon-mesh-batman-adv-15 + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Support for batman-adv meshing (compat level 15) + DEPENDS:=+gluon-mesh-batman-adv-core +kmod-batman-adv +batctl + PROVIDES:=gluon-mesh-batman-adv +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-mesh-batman-adv-15/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,gluon-mesh-batman-adv-15)) diff --git a/package/gluon-mesh-batman-adv-15/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/compat b/package/gluon-mesh-batman-adv-15/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/compat new file mode 100644 index 00000000..d44224b3 --- /dev/null +++ b/package/gluon-mesh-batman-adv-15/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/compat @@ -0,0 +1 @@ +return 15 diff --git a/package/gluon-mesh-batman-adv-15/files/lib/gluon/upgrade/350-gluon-mesh-batman-adv-15 b/package/gluon-mesh-batman-adv-15/files/lib/gluon/upgrade/350-gluon-mesh-batman-adv-15 new file mode 100755 index 00000000..96f7d310 --- /dev/null +++ b/package/gluon-mesh-batman-adv-15/files/lib/gluon/upgrade/350-gluon-mesh-batman-adv-15 @@ -0,0 +1,40 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' + +local uci = require('luci.model.uci').cursor() + + +local function configure_mtu(radio, config) + local mesh = 'mesh_' .. radio + + if config.mesh_vlan then + uci:set('network', mesh, 'mtu', 1536) + uci:set('network', mesh .. '_vlan', 'mtu', 1532) + else + uci:set('network', mesh, 'mtu', 1532) + end +end + + +local radios = {} + +uci:foreach('wireless', 'wifi-device', + function(s) + table.insert(radios, s['.name']) + end +) + +for _, radio in ipairs(radios) do + local hwmode = uci:get('wireless', radio, 'hwmode') + + if hwmode == '11g' or hwmode == '11ng' then + configure_mtu(radio, site.wifi24) + elseif hwmode == '11a' or hwmode == '11na' then + configure_mtu(radio, site.wifi5) + end +end + + +uci:save('network') +uci:commit('network') diff --git a/package/gluon-mesh-batman-adv-core/Makefile b/package/gluon-mesh-batman-adv-core/Makefile new file mode 100644 index 00000000..fc4bc224 --- /dev/null +++ b/package/gluon-mesh-batman-adv-core/Makefile @@ -0,0 +1,37 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-mesh-batman-adv-core +PKG_VERSION:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +define Package/gluon-mesh-batman-adv-core + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Support for batman-adv meshing (core) + DEPENDS:=+gluon-core +firewall +kmod-ipt-nathelper +libiwinfo-lua +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-mesh-batman-adv-core/install + $(CP) ./files/* $(1)/ +endef + +define Package/gluon-mesh-batman-adv-core/postinst +#!/bin/sh +$(call GluonCheckSite,check_site.lua) +endef + + +$(eval $(call BuildPackage,gluon-mesh-batman-adv-core)) diff --git a/package/gluon-mesh-batman-adv-core/check_site.lua b/package/gluon-mesh-batman-adv-core/check_site.lua new file mode 100644 index 00000000..e76ca9e9 --- /dev/null +++ b/package/gluon-mesh-batman-adv-core/check_site.lua @@ -0,0 +1,16 @@ +need_string('regdom') + +for _, config in ipairs({'wifi24', 'wifi5'}) do + need_string(config .. '.ssid') + need_number(config .. '.channel') + need_string(config .. '.htmode') + need_string(config .. '.mesh_ssid') + need_string_match(config .. '.mesh_bssid', '^%x[02468aAcCeE]:%x%x:%x%x:%x%x:%x%x:%x%x$') + need_number(config .. '.mesh_mcast_rate') + need_number(config .. '.mesh_vlan', false) + need_boolean(config .. '.client_disabled', false) + need_boolean(config .. '.mesh_disabled', false) +end + +need_boolean('mesh_on_wan', false) +need_boolean('mesh_on_lan', false) diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/batadv b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/batadv new file mode 100644 index 00000000..f93a11f9 --- /dev/null +++ b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/batadv @@ -0,0 +1,41 @@ +local json = require 'luci.json' +local util = require 'luci.util' +local fs = require 'nixio.fs' + +local ifname_address_cache = {} + +function ifname2address(ifname) + local ifaddress + if ifname_address_cache[ifname] ~= nil then + ifaddress = ifname_address_cache[ifname] + else + ifaddress = util.trim(fs.readfile("/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 = {} } + end + + interfaces[ifaddress].neighbours[mac1] = { tq = tonumber(tq) + , lastseen = tonumber(lastseen) + } + end + end + + return interfaces +end + +return batadv() diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/wifi b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/wifi new file mode 100644 index 00000000..d3754222 --- /dev/null +++ b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/wifi @@ -0,0 +1,41 @@ +local json = require 'luci.json' +local util = require 'luci.util' +local fs = require 'nixio.fs' +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 + + return stations +end + +function interfaces() + local interfaces = {} + for _, line in ipairs(util.split(util.exec('batctl if'))) do + ifname = line:match('^(.-): active') + if ifname ~= nil then + pcall(function() + local address = util.trim(fs.readfile('/sys/class/net/' .. ifname .. '/address')) + local wifitype = iwinfo.type(ifname) + if wifitype ~= nil then + interfaces[address] = { ifname = ifname, iw = iwinfo[wifitype] } + end + end) + end + end + + return interfaces +end + +local wifi = {} +for address, iface in pairs(interfaces()) do + wifi[address] = { neighbours = neighbours(iface) } +end + +return wifi diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/addresses b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/addresses new file mode 100644 index 00000000..d55f8340 --- /dev/null +++ b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/addresses @@ -0,0 +1,12 @@ +local ip = require 'luci.ip' + +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', 4) .. '%s+([^%s]+)$') } + if matches[9] == 'br-client' then + table.insert(addresses, ip.IPv6(string.format('%s:%s:%s:%s:%s:%s:%s:%s', unpack(matches))):string():lower()) + end +end + +return addresses diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh/bat0/interfaces b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh/bat0/interfaces new file mode 100644 index 00000000..97180b81 --- /dev/null +++ b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh/bat0/interfaces @@ -0,0 +1,52 @@ +local list = util.exec('batctl if') + +local wireless = {} +local tunnel = {} +local other = {} + +local function get_address(t, ifname) + pcall( + function() + table.insert(t, util.trim(fs.readfile('/sys/class/net/' .. ifname .. '/address'))) + end + ) +end + +local function is_wireless(ifname) + local type = fs.stat('/sys/class/net/' .. ifname .. '/wireless', 'type') + + return type == 'directory' +end + +local function is_tuntap(ifname) + local type = fs.stat('/sys/class/net/' .. ifname .. '/tun_flags', 'type') + + return type == 'regular' +end + +local function nil_table(t) + if next(t) ~= nil then + return t + else + return nil + end +end + +for _, line in ipairs(util.split(list)) do + local ifname = line:match('^(.-):') + if ifname ~= nil then + 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 +end + +return { + wireless = nil_table(wireless), + tunnel = nil_table(tunnel), + other = nil_table(other) +} diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh_interfaces b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh_interfaces new file mode 100644 index 00000000..1fef5e10 --- /dev/null +++ b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh_interfaces @@ -0,0 +1,15 @@ +local list = util.exec('batctl if') + +local interfaces = {} +for _, line in ipairs(util.split(list)) do + local ifname = line:match('^(.-):') + if ifname ~= nil then + pcall( + function() + table.insert(interfaces, util.trim(fs.readfile('/sys/class/net/' .. ifname .. '/address'))) + end + ) + end +end + +return interfaces diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/version b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/version new file mode 100644 index 00000000..abb317e9 --- /dev/null +++ b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/version @@ -0,0 +1 @@ +return util.trim(fs.readfile('/sys/module/batman_adv/version')) diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/clients b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/clients new file mode 100644 index 00000000..235865ed --- /dev/null +++ b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/clients @@ -0,0 +1,20 @@ +local list = io.lines("/sys/kernel/debug/batman_adv/bat0/transtable_local") + +local count = 0 +local wifi = 0 +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 + count = count + 1 + + if flags:match('W') then + wifi = wifi +1 + end + end + end +end + +return { total = count + , wifi = wifi + } diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/gateway b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/gateway new file mode 100644 index 00000000..a1be9ac0 --- /dev/null +++ b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/gateway @@ -0,0 +1,5 @@ +local gateway = util.trim(util.exec("batctl -m bat0 gateways | awk '/^=>/ { print $2 }'")) + +if gateway ~= '' then + return gateway +end diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/traffic b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/traffic new file mode 100644 index 00000000..01f6b4ab --- /dev/null +++ b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/traffic @@ -0,0 +1,14 @@ +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 diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/upgrade/300-gluon-mesh-batman-adv-core-wan b/package/gluon-mesh-batman-adv-core/files/lib/gluon/upgrade/300-gluon-mesh-batman-adv-core-wan new file mode 100755 index 00000000..f84a104d --- /dev/null +++ b/package/gluon-mesh-batman-adv-core/files/lib/gluon/upgrade/300-gluon-mesh-batman-adv-core-wan @@ -0,0 +1,14 @@ +#!/usr/bin/lua + +local sysconfig = require 'gluon.sysconfig' +local util = require 'gluon.util' +local uci = require('luci.model.uci').cursor() + + +if sysconfig.wan_ifname:match('%.') then + -- fix up duplicate mac addresses (for mesh-on-WAN) + uci:set('network', 'wan', 'macaddr', util.generate_mac(1, 0)) + uci:save('network') + uci:commit('network') +end + diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/upgrade/310-gluon-mesh-batman-adv-core-mesh b/package/gluon-mesh-batman-adv-core/files/lib/gluon/upgrade/310-gluon-mesh-batman-adv-core-mesh new file mode 100755 index 00000000..a51b20e2 --- /dev/null +++ b/package/gluon-mesh-batman-adv-core/files/lib/gluon/upgrade/310-gluon-mesh-batman-adv-core-mesh @@ -0,0 +1,98 @@ +#!/usr/bin/lua + +local sysconfig = require 'gluon.sysconfig' +local sysctl = require 'gluon.sysctl' +local site = require 'gluon.site_config' +local uci = require('luci.model.uci').cursor() + + +uci:delete('batman-adv', 'bat0') +uci:section('batman-adv', 'mesh', 'bat0', + { + orig_interval = 5000, + gw_mode = 'client', + multicast_mode = 0, + } +) +uci:save('batman-adv') +uci:commit('batman-adv') + + +if not uci:get('network', 'client') then + local ifname + + if sysconfig.lan_ifname and not site.mesh_on_lan then + ifname = sysconfig.lan_ifname .. ' bat0' + else + ifname = 'bat0' + end + + uci:section('network', 'interface', 'client', + { + ifname = ifname, + type = 'bridge', + proto = 'dhcpv6', + reqprefix = 'no', + } + ) +end + +uci:set('network', 'client', 'igmp_snooping', 0) +uci:set('network', 'client', 'macaddr', sysconfig.primary_mac) +uci:set('network', 'client', 'peerdns', 1) + +uci:delete('network', 'bat0') +uci:section('network', 'interface', 'bat0', + { + ifname = 'bat0', + proto = 'none', + macaddr = sysconfig.primary_mac, + } +) + +uci:save('network') +uci:commit('network') + + +uci:delete('firewall', 'client') +uci:section('firewall', 'zone', 'client', + { + name = 'client', + network = {'client'}, + input = 'ACCEPT', + output = 'ACCEPT', + forward = 'REJECT', + } +) + +uci:section('firewall', 'rule', 'client_dns', + { + name = 'client_dns', + src = 'client', + dest_port = '53', + target = 'REJECT', + } +) + +uci:save('firewall') +uci:commit('firewall') + + +local dnsmasq = uci:get_first('dhcp', 'dnsmasq') +uci:set('dhcp', dnsmasq, 'boguspriv', 0) +uci:set('dhcp', dnsmasq, 'localise_queries', 0) +uci:set('dhcp', dnsmasq, 'rebind_protection', 0) + +uci:delete('dhcp', 'client') +uci:section('dhcp', 'dhcp', 'client', + { + interface = 'client', + ignore = 1, + } +) + +uci:save('dhcp') +uci:commit('dhcp') + + +sysctl.set('net.ipv6.conf.br-client.forwarding', 0) diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/upgrade/320-gluon-mesh-batman-adv-core-wireless b/package/gluon-mesh-batman-adv-core/files/lib/gluon/upgrade/320-gluon-mesh-batman-adv-core-wireless new file mode 100755 index 00000000..50753c8b --- /dev/null +++ b/package/gluon-mesh-batman-adv-core/files/lib/gluon/upgrade/320-gluon-mesh-batman-adv-core-wireless @@ -0,0 +1,119 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local util = require 'gluon.util' + +local uci = require('luci.model.uci').cursor() + + +local function configure_radio(radio, index, config) + uci:delete('wireless', radio, 'disabled') + + uci:set('wireless', radio, 'channel', config.channel) + uci:set('wireless', radio, 'htmode', config.htmode) + uci:set('wireless', radio, 'country', site.regdom) + + local client = 'client_' .. radio + local mesh = 'mesh_' .. radio + + local disable_state_client = false + local disable_state_mesh = false + + if uci:get('wireless', client) then + disable_state_client = uci:get_bool('wireless', client, "disabled") + elseif config.client_disabled then + disable_state_client = true + end + + if uci:get('wireless', mesh) then + disable_state_mesh = uci:get_bool('wireless', mesh, "disabled") + elseif config.mesh_disabled then + disable_state_mesh = true + end + + local client_ifname + local mesh_ifname + local radio_suffix = radio:match('^radio(%d+)$') + if radio_suffix then + client_ifname = 'client' .. radio_suffix + mesh_ifname = 'mesh' .. radio_suffix + end + + uci:delete('wireless', client) + uci:section('wireless', 'wifi-iface', client, + { + device = radio, + network = 'client', + mode = 'ap', + ssid = config.ssid, + macaddr = util.generate_mac(2, index), + ifname = client_ifname, + disabled = disable_state_client and 1 or 0, + } + ) + + uci:delete('network', mesh) + uci:delete('network', mesh .. '_vlan') + + if config.mesh_vlan then + uci:section('network', 'interface', mesh, + { + proto = 'none', + } + ) + uci:section('network', 'interface', mesh .. '_vlan', + { + ifname = '@' .. mesh .. '.' .. config.mesh_vlan, + proto = 'batadv', + mesh = 'bat0', + } + ) + else + uci:section('network', 'interface', mesh, + { + proto = 'batadv', + mesh = 'bat0', + } + ) + end + + uci:delete('wireless', mesh) + uci:section('wireless', 'wifi-iface', mesh, + { + device = radio, + network = mesh, + mode = 'adhoc', + ssid = config.mesh_ssid, + bssid = config.mesh_bssid, + macaddr = util.generate_mac(3, index), + mcast_rate = config.mesh_mcast_rate, + ifname = mesh_ifname, + disabled = disable_state_mesh and 1 or 0, + } + ) +end + + +local radios = {} + +uci:foreach('wireless', 'wifi-device', + function(s) + table.insert(radios, s['.name']) + end +) + +for index, radio in ipairs(radios) do + local hwmode = uci:get('wireless', radio, 'hwmode') + + if hwmode == '11g' or hwmode == '11ng' then + configure_radio(radio, index, site.wifi24) + elseif hwmode == '11a' or hwmode == '11na' then + configure_radio(radio, index, site.wifi5) + end +end + + +uci:save('wireless') +uci:save('network') +uci:commit('wireless') +uci:commit('network') diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/upgrade/330-gluon-mesh-batman-adv-core-mesh-on-wan b/package/gluon-mesh-batman-adv-core/files/lib/gluon/upgrade/330-gluon-mesh-batman-adv-core-mesh-on-wan new file mode 100755 index 00000000..d40c5729 --- /dev/null +++ b/package/gluon-mesh-batman-adv-core/files/lib/gluon/upgrade/330-gluon-mesh-batman-adv-core-mesh-on-wan @@ -0,0 +1,18 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local uci = require 'luci.model.uci' + +local c = uci.cursor() + +if not c:get('network', 'mesh_wan') then + c:section('network', 'interface', 'mesh_wan', + { ifname = 'br-wan' + , proto = 'batadv' + , mesh = 'bat0' + , auto = site.mesh_on_wan and 1 or 0 + }) +end + +c:save('network') +c:commit('network') diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/upgrade/340-gluon-mesh-batman-adv-core-mesh-on-lan b/package/gluon-mesh-batman-adv-core/files/lib/gluon/upgrade/340-gluon-mesh-batman-adv-core-mesh-on-lan new file mode 100755 index 00000000..f9cbde03 --- /dev/null +++ b/package/gluon-mesh-batman-adv-core/files/lib/gluon/upgrade/340-gluon-mesh-batman-adv-core-mesh-on-lan @@ -0,0 +1,23 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local uci = require 'luci.model.uci' +local util = require 'gluon.util' +local sysconfig = require 'gluon.sysconfig' + +local c = uci.cursor() + +if sysconfig.lan_ifname then + if not c:get('network', 'mesh_lan') then + c:section('network', 'interface', 'mesh_lan', + { ifname = sysconfig.lan_ifname + , proto = 'batadv' + , mesh = 'bat0' + , macaddr = util.generate_mac(1, 1) + , auto = site.mesh_on_lan and 1 or 0 + }) + end +end + +c:save('network') +c:commit('network') diff --git a/package/gluon-mesh-vpn-fastd/Makefile b/package/gluon-mesh-vpn-fastd/Makefile new file mode 100644 index 00000000..775f92f1 --- /dev/null +++ b/package/gluon-mesh-vpn-fastd/Makefile @@ -0,0 +1,40 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-mesh-vpn-fastd +PKG_VERSION:=3 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +define Package/gluon-mesh-vpn-fastd + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Support for connecting batman-adv meshes via fastd + DEPENDS:=+gluon-core gluon-mesh-batman-adv +gluon-wan-dnsmasq +fastd +iptables-mod-extra +endef + +define Package/gluon-mesh-vpn-fastd/description + Gluon community wifi mesh firmware framework: fastd support +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-mesh-vpn-fastd/install + $(CP) ./files/* $(1)/ +endef + +define Package/gluon-mesh-vpn-fastd/postinst +#!/bin/sh +$(call GluonCheckSite,check_site.lua) +endef + +$(eval $(call BuildPackage,gluon-mesh-vpn-fastd)) diff --git a/package/gluon-mesh-vpn-fastd/check_site.lua b/package/gluon-mesh-vpn-fastd/check_site.lua new file mode 100644 index 00000000..7a2c4913 --- /dev/null +++ b/package/gluon-mesh-vpn-fastd/check_site.lua @@ -0,0 +1,26 @@ +need_string_array('fastd_mesh_vpn.methods') +need_number('fastd_mesh_vpn.mtu') +need_boolean('fastd_mesh_vpn.enabled', false) +need_boolean('fastd_mesh_vpn.configurable', false) + + +local function check_peer(prefix) + return function(k, _) + local table = string.format('%s[%q].', prefix, k) + + need_string(table .. 'key') + need_string_array(table .. 'remotes') + end +end + +local function check_group(prefix) + return function(k, _) + local table = string.format('%s[%q].', prefix, k) + + need_number(table .. 'limit', false) + need_table(table .. 'peers', check_peer(table .. 'peers'), false) + need_table(table .. 'groups', check_group(table .. 'groups'), false) + end +end + +need_table('fastd_mesh_vpn.groups', check_group('fastd_mesh_vpn.groups')) diff --git a/package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/nodeinfo.d/software/fastd b/package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/nodeinfo.d/software/fastd new file mode 100644 index 00000000..bbfbda08 --- /dev/null +++ b/package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/nodeinfo.d/software/fastd @@ -0,0 +1,4 @@ +return { + enabled = uci:get_bool('fastd', 'mesh_vpn', 'enabled'), + version = util.exec('fastd -v'):match('^[^%s]+%s+([^\n]+)'), +} diff --git a/package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/statistics.d/mesh_vpn b/package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/statistics.d/mesh_vpn new file mode 100644 index 00000000..a67b9a07 --- /dev/null +++ b/package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/statistics.d/mesh_vpn @@ -0,0 +1,71 @@ +local json = require 'luci.json' +local ltn12 = require 'luci.ltn12' +local nixio = require 'nixio' +local site = require 'gluon.site_config' +local uci = require('luci.model.uci').cursor() + +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.Decoder() +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 json.null + 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) diff --git a/package/gluon-mesh-vpn-fastd/files/lib/gluon/mesh-vpn-fastd/iptables.rules b/package/gluon-mesh-vpn-fastd/files/lib/gluon/mesh-vpn-fastd/iptables.rules new file mode 100644 index 00000000..c1a16ee1 --- /dev/null +++ b/package/gluon-mesh-vpn-fastd/files/lib/gluon/mesh-vpn-fastd/iptables.rules @@ -0,0 +1,3 @@ +*nat +-I OUTPUT -m owner --gid-owner gluon-fastd -o lo -d 127.0.0.1 -p udp --dport 53 -j DNAT --to-destination :54 +COMMIT diff --git a/package/gluon-mesh-vpn-fastd/files/lib/gluon/upgrade/400-mesh-vpn-fastd b/package/gluon-mesh-vpn-fastd/files/lib/gluon/upgrade/400-mesh-vpn-fastd new file mode 100755 index 00000000..316546bc --- /dev/null +++ b/package/gluon-mesh-vpn-fastd/files/lib/gluon/upgrade/400-mesh-vpn-fastd @@ -0,0 +1,148 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local users = require 'gluon.users' +local util = require 'gluon.util' + +local uci = require('luci.model.uci').cursor() +local lutil = require 'luci.util' + + +-- The previously used user is removed, we need root privileges to use the packet_mark option +users.remove_user('gluon-fastd') + +-- Group for iptables rule +users.add_group('gluon-fastd', 800) + + +local enabled = uci:get('fastd', 'mesh_vpn', 'enabled') +if not enabled then + enabled = site.fastd_mesh_vpn.enabled and 1 or 0 +end + + +local methods + +if site.fastd_mesh_vpn.configurable then + local has_null = lutil.contains(site.fastd_mesh_vpn.methods, 'null') + + local old_methods = uci:get('fastd', 'mesh_vpn', 'method') + if old_methods then + has_null = lutil.contains(old_methods, 'null') + end + + + methods = {} + if has_null then + table.insert(methods, 'null') + end + + for _, method in ipairs(site.fastd_mesh_vpn.methods) do + if method ~= 'null' then + table.insert(methods, method) + end + end + +else + methods = site.fastd_mesh_vpn.methods +end + + +uci:section('fastd', 'fastd', 'mesh_vpn', + { + enabled = enabled, + group = 'gluon-fastd', + syslog_level = 'verbose', + interface = 'mesh-vpn', + mode = 'tap', + mtu = site.fastd_mesh_vpn.mtu, + secure_handshakes = 1, + method = methods, + packet_mark = 1, + status_socket = '/var/run/fastd.mesh_vpn.socket', + } +) +uci:delete('fastd', 'mesh_vpn', 'user') + + +local add_groups + +local function add_peer(group, name, config) + uci:section('fastd', 'peer', group .. '_peer_' .. name, + { + enabled = 1, + net = 'mesh_vpn', + group = group, + key = config.key, + remote = config.remotes, + } + ) +end + +local function add_group(name, config, parent) + uci:delete('fastd', name) + uci:delete_all('fastd', 'peer', + function(peer) + return (peer.net == 'mesh_vpn' and peer.group == name) + end + ) + + + uci:section('fastd', 'peer_group', name, + { + enabled = 1, + net = 'mesh_vpn', + parent = parent, + peer_limit = config.limit, + } + ) + + if config.peers then + for peername, peerconfig in pairs(config.peers) do + add_peer(name, peername, peerconfig) + end + end + + add_groups(name, config.groups, name) +end + +-- declared local above +function add_groups(prefix, groups, parent) + if groups then + for name, group in pairs(groups) do + add_group(prefix .. '_' .. name, group, parent) + end + end +end + +add_groups('mesh_vpn', site.fastd_mesh_vpn.groups) + + +uci:save('fastd') +uci:commit('fastd') + + +uci:section('network', 'interface', 'mesh_vpn', + { + ifname = 'mesh-vpn', + proto = 'batadv', + mesh = 'bat0', + mesh_no_rebroadcast = 1, + macaddr = util.generate_mac(4, 0), + } +) + +uci:save('network') +uci:commit('network') + + +uci:section('firewall', 'include', 'mesh_vpn_dns', + { + type = 'restore', + path = '/lib/gluon/mesh-vpn-fastd/iptables.rules', + family = 'ipv4', + } +) + +uci:save('firewall') +uci:commit('firewall') diff --git a/package/gluon-mesh-vpn-fastd/files/lib/gluon/upgrade/410-mesh-vpn-fastd-generate-secret b/package/gluon-mesh-vpn-fastd/files/lib/gluon/upgrade/410-mesh-vpn-fastd-generate-secret new file mode 100755 index 00000000..68a2fe67 --- /dev/null +++ b/package/gluon-mesh-vpn-fastd/files/lib/gluon/upgrade/410-mesh-vpn-fastd-generate-secret @@ -0,0 +1,13 @@ +#!/usr/bin/lua + +local uci = require 'luci.model.uci' + +local c = uci.cursor() + +local secret = c:get("fastd", "mesh_vpn", "secret") + +if not secret or not secret:match(("%x"):rep(64)) then + c:set("fastd", "mesh_vpn", "secret", "generate") + c:save("fastd") + c:commit("fastd") +end diff --git a/package/gluon-neighbour-info/Makefile b/package/gluon-neighbour-info/Makefile new file mode 100644 index 00000000..74aa6e8f --- /dev/null +++ b/package/gluon-neighbour-info/Makefile @@ -0,0 +1,39 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-neighbour-info +PKG_VERSION:=1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + +define Package/gluon-neighbour-info + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=neighbour-info + DEPENDS:= +endef + +define Package/gluon-neighbour-info/description + Gluon community wifi mesh firmware framework: neighbour-info +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ +endef + +define Build/Configure +endef + +define Build/Compile + CFLAGS="$(TARGET_CFLAGS)" CPPFLAGS="$(TARGET_CPPFLAGS)" $(MAKE) -C $(PKG_BUILD_DIR) $(TARGET_CONFIGURE_OPTS) +endef + +define Package/gluon-neighbour-info/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/gluon-neighbour-info $(1)/usr/bin/ +endef + +$(eval $(call BuildPackage,gluon-neighbour-info)) diff --git a/package/gluon-neighbour-info/src/Makefile b/package/gluon-neighbour-info/src/Makefile new file mode 100644 index 00000000..16a3e95f --- /dev/null +++ b/package/gluon-neighbour-info/src/Makefile @@ -0,0 +1,6 @@ +all: gluon-neighbour-info + +gluon-neighbour-info: gluon-neighbour-info.c + +clean: + rm gluon-neighbour-info diff --git a/package/gluon-neighbour-info/src/gluon-neighbour-info.c b/package/gluon-neighbour-info/src/gluon-neighbour-info.c new file mode 100644 index 00000000..d8536de6 --- /dev/null +++ b/package/gluon-neighbour-info/src/gluon-neighbour-info.c @@ -0,0 +1,191 @@ +/* + Copyright (c) 2014, Nils Schneider + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void usage() { + puts("Usage: gluon-neighbour-info [-h] [-s] [-t ] -d -p -i -r "); + puts(" -p UDP port"); + puts(" -d multicast group, e.g. ff02:0:0:0:0:0:2:1001"); + puts(" -i interface, e.g. eth0 "); + puts(" -r request, e.g. nodeinfo"); + puts(" -t timeout in seconds (default: 3)"); + puts(" -s output as server-sent events"); + puts(" -h this help\n"); +} + +void getclock(struct timeval *tv) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / 1000; +} + +/* Assumes a and b are normalized */ +void tv_subtract (struct timeval *r, struct timeval *a, struct timeval *b) { + r->tv_usec = a->tv_usec - b->tv_usec; + r->tv_sec = a->tv_sec - b->tv_sec; + + if (r->tv_usec < 0) { + r->tv_usec += 1000000; + r->tv_sec -= 1; + } +} + +ssize_t recvtimeout(int socket, void *buffer, size_t length, int flags, struct timeval *timeout, struct timeval *offset) { + struct timeval now, delta; + ssize_t ret; + + setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, timeout, sizeof(*timeout)); + ret = recv(socket, buffer, length, flags); + + getclock(&now); + tv_subtract(&delta, &now, offset); + tv_subtract(timeout, timeout, &delta); + + return ret; +} + +int request(const int sock, const struct sockaddr_in6 *client_addr, const char *request, bool sse, int timeout) { + ssize_t ret; + char buffer[8192]; + + ret = sendto(sock, request, strlen(request), 0, (struct sockaddr *)client_addr, sizeof(struct sockaddr_in6)); + + if (ret < 0) { + perror("Error in sendto()"); + exit(EXIT_FAILURE); + } + + struct timeval tv_timeout, tv_offset; + tv_timeout.tv_sec = timeout; + tv_timeout.tv_usec = 0; + + getclock(&tv_offset); + + while (1) { + ret = recvtimeout(sock, buffer, sizeof(buffer), 0, &tv_timeout, &tv_offset); + + if (ret < 0) + break; + + if (sse) + fputs("event: neighbour\ndata: ", stdout); + + fwrite(buffer, sizeof(char), ret, stdout); + + if (sse) + fputs("\n\n", stdout); + else + fputs("\n", stdout); + + fflush(stdout); + } + + return 0; +} + +int main(int argc, char **argv) { + int sock; + struct sockaddr_in6 client_addr = {}; + char *request_string = NULL; + struct in6_addr mgroup_addr; + + sock = socket(PF_INET6, SOCK_DGRAM, 0); + + if (sock < 0) { + perror("creating socket"); + exit(EXIT_FAILURE); + } + + client_addr.sin6_family = AF_INET6; + client_addr.sin6_addr = in6addr_any; + + opterr = 0; + + int port_set = 0; + int destination_set = 0; + int timeout = 3; + bool sse = false; + + int c; + while ((c = getopt(argc, argv, "p:d:r:i:t:sh")) != -1) + switch (c) { + case 'p': + client_addr.sin6_port = htons(atoi(optarg)); + break; + case 'd': + if (!inet_pton(AF_INET6, optarg, &client_addr.sin6_addr)) { + perror("Invalid IPv6 address. This message will probably confuse you"); + exit(EXIT_FAILURE); + } + break; + case 'i': + client_addr.sin6_scope_id = if_nametoindex(optarg); + if (client_addr.sin6_scope_id == 0) { + perror("Can not use interface"); + exit(EXIT_FAILURE); + } + break; + case 'r': + request_string = optarg; + break; + case 't': + timeout = atoi(optarg); + break; + case 's': + sse = true; + break; + case 'h': + usage(); + exit(EXIT_SUCCESS); + break; + default: + fprintf(stderr, "Invalid parameter %c ignored.\n", c); + } + + if (request_string == NULL) + error(EXIT_FAILURE, 0, "No request string supplied"); + + if (sse) + fputs("Content-Type: text/event-stream\n\n", stdout); + + request(sock, &client_addr, request_string, sse, timeout); + + if (sse) + fputs("event: eot\ndata: null\n\n", stdout); + + return EXIT_SUCCESS; +} diff --git a/package/gluon-next-node/Makefile b/package/gluon-next-node/Makefile new file mode 100644 index 00000000..df27ecbe --- /dev/null +++ b/package/gluon-next-node/Makefile @@ -0,0 +1,40 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-next-node +PKG_VERSION:=3 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +define Package/gluon-next-node + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Next-node anycast address + DEPENDS:=+gluon-core +gluon-ebtables +gluon-mesh-batman-adv +kmod-macvlan +endef + +define Package/gluon-next-node/description + Gluon community wifi mesh firmware framework: next-node anycast address +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-next-node/install + $(CP) ./files/* $(1)/ +endef + +define Package/gluon-next-node/postinst +#!/bin/sh +$(call GluonCheckSite,check_site.lua) +endef + +$(eval $(call BuildPackage,gluon-next-node)) diff --git a/package/gluon-next-node/check_site.lua b/package/gluon-next-node/check_site.lua new file mode 100644 index 00000000..83889a8e --- /dev/null +++ b/package/gluon-next-node/check_site.lua @@ -0,0 +1,4 @@ +need_string_match('next_node.ip4', '^%d+.%d+.%d+.%d+$') +need_string_match('next_node.ip6', '^[%x:]+$') + +need_string_match('next_node.mac', '^%x[02468aAcCeE]:%x%x:%x%x:%x%x:%x%x:%x%x$') diff --git a/package/gluon-next-node/files/lib/gluon/ebtables/250-next-node b/package/gluon-next-node/files/lib/gluon/ebtables/250-next-node new file mode 100644 index 00000000..0df7abcc --- /dev/null +++ b/package/gluon-next-node/files/lib/gluon/ebtables/250-next-node @@ -0,0 +1,20 @@ +local site = require 'gluon.site_config' +local next_node = site.next_node + +rule('FORWARD --logical-in br-client -p ARP --arp-ip-src ' .. next_node.ip4 .. ' -j DROP') +rule('FORWARD --logical-in br-client -p ARP --arp-ip-dst ' .. next_node.ip4 .. ' -j DROP') + +rule('FORWARD --logical-out br-client -o bat0 -d ' .. next_node.mac .. ' -j DROP') +rule('OUTPUT --logical-out br-client -o bat0 -d ' .. next_node.mac .. ' -j DROP') +rule('FORWARD --logical-out br-client -o bat0 -s ' .. next_node.mac .. ' -j DROP') +rule('OUTPUT --logical-out br-client -o bat0 -s ' .. next_node.mac .. ' -j DROP') + +rule('FORWARD --logical-out br-client -o bat0 -p IPv4 --ip-destination ' .. next_node.ip4 .. ' -j DROP') +rule('OUTPUT --logical-out br-client -o bat0 -p IPv4 --ip-destination ' .. next_node.ip4 .. ' -j DROP') +rule('FORWARD --logical-out br-client -o bat0 -p IPv4 --ip-source ' .. next_node.ip4 .. ' -j DROP') +rule('OUTPUT --logical-out br-client -o bat0 -p IPv4 --ip-source ' .. next_node.ip4 .. ' -j DROP') + +rule('FORWARD --logical-out br-client -o bat0 -p IPv6 --ip6-destination ' .. next_node.ip6 .. ' -j DROP') +rule('OUTPUT --logical-out br-client -o bat0 -p IPv6 --ip6-destination ' .. next_node.ip6 .. ' -j DROP') +rule('FORWARD --logical-out br-client -o bat0 -p IPv6 --ip6-source ' .. next_node.ip6 .. ' -j DROP') +rule('OUTPUT --logical-out br-client -o bat0 -p IPv6 --ip6-source ' .. next_node.ip6 .. ' -j DROP') diff --git a/package/gluon-next-node/files/lib/gluon/upgrade/400-next-node b/package/gluon-next-node/files/lib/gluon/upgrade/400-next-node new file mode 100755 index 00000000..0ff959fe --- /dev/null +++ b/package/gluon-next-node/files/lib/gluon/upgrade/400-next-node @@ -0,0 +1,55 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local uci = require 'luci.model.uci' +local ip = require 'luci.ip' + +local c = uci.cursor() + + +c:delete('network', 'local_node_dev') +c:section('network', 'device', 'local_node_dev', + { + name = 'local-node', + ifname = 'br-client', + type = 'macvlan', + macaddr = site.next_node.mac, + } +) + +local prefix4 = ip.IPv4(site.prefix4) +c:delete('network', 'local_node') +c:section('network', 'interface', 'local_node', + { + ifname = 'local-node', + proto = 'static', + ipaddr = site.next_node.ip4, + netmask = prefix4:mask():string(), + ip6addr = site.next_node.ip6 .. '/128', + } +) + +c:delete('network', 'local_node_route6') +c:section('network', 'route6', 'local_node_route6', + { + interface = 'client', + target = site.prefix6, + gateway = '::', + } +) + +c:save('network') +c:commit('network') + +c:delete('firewall', 'local_node') +c:section('firewall', 'zone', 'local_node', + { + name = 'local_node', + network = {'local_node'}, + input = 'ACCEPT', + output = 'ACCEPT', + forward = 'REJECT', + } +) +c:save('firewall') +c:commit('firewall') diff --git a/package/gluon-node-info/Makefile b/package/gluon-node-info/Makefile new file mode 100644 index 00000000..0fe8a8dd --- /dev/null +++ b/package/gluon-node-info/Makefile @@ -0,0 +1,41 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-node-info +PKG_VERSION:=1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +define Package/gluon-node-info + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Add /etc/config/gluon-node-info to uci + DEPENDS:=+gluon-core +endef + +define Package/gluon-node-info/description + This packages creates /etc/config/gluon-node-info. +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-node-info/install + $(CP) ./files/* $(1)/ +endef + +define Package/gluon-node-info/postinst +#!/bin/sh +$(call GluonCheckSite,check_site.lua) +endef + +$(eval $(call BuildPackage,gluon-node-info)) diff --git a/package/gluon-node-info/check_site.lua b/package/gluon-node-info/check_site.lua new file mode 100644 index 00000000..7e50edfc --- /dev/null +++ b/package/gluon-node-info/check_site.lua @@ -0,0 +1 @@ +need_string('roles.default', false) diff --git a/package/gluon-node-info/files/etc/config/gluon-node-info b/package/gluon-node-info/files/etc/config/gluon-node-info new file mode 100644 index 00000000..8f6f472f --- /dev/null +++ b/package/gluon-node-info/files/etc/config/gluon-node-info @@ -0,0 +1,6 @@ +config location + option share_location '0' + +config owner + +config system diff --git a/package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/location b/package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/location new file mode 100644 index 00000000..72bf8878 --- /dev/null +++ b/package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/location @@ -0,0 +1,7 @@ +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 diff --git a/package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/owner b/package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/owner new file mode 100644 index 00000000..8a2a611d --- /dev/null +++ b/package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/owner @@ -0,0 +1,4 @@ +local contact = uci:get_first('gluon-node-info', 'owner', 'contact', '') +if contact ~= '' then + return { contact = contact } +end diff --git a/package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/system/role b/package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/system/role new file mode 100644 index 00000000..38de47d7 --- /dev/null +++ b/package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/system/role @@ -0,0 +1,4 @@ +local role = uci:get_first('gluon-node-info', 'system', 'role', '') +if role ~= '' then + return role +end diff --git a/package/gluon-node-info/files/lib/gluon/upgrade/500-node-info-system b/package/gluon-node-info/files/lib/gluon/upgrade/500-node-info-system new file mode 100755 index 00000000..a17b9461 --- /dev/null +++ b/package/gluon-node-info/files/lib/gluon/upgrade/500-node-info-system @@ -0,0 +1,11 @@ +#!/usr/bin/lua + +local uci = require('luci.model.uci').cursor() + +local config = 'gluon-node-info' + +if not uci:get_first(config, 'system') then + uci:section(config, 'system') + uci:save(config) + uci:commit(config) +end diff --git a/package/gluon-node-info/files/lib/gluon/upgrade/510-node-info-role b/package/gluon-node-info/files/lib/gluon/upgrade/510-node-info-role new file mode 100755 index 00000000..6e54a234 --- /dev/null +++ b/package/gluon-node-info/files/lib/gluon/upgrade/510-node-info-role @@ -0,0 +1,19 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local uci = require('luci.model.uci').cursor() + +local config = 'gluon-node-info' +local role = uci:get(config, uci:get_first(config, 'system'), 'role') + +if site.roles then + default_role = site.roles.default +else + default_role = '' +end + +if not role then + uci:set(config, uci:get_first(config, 'system'), 'role', default_role) + uci:save(config) + uci:commit(config) +end diff --git a/package/gluon-radvd/Makefile b/package/gluon-radvd/Makefile new file mode 100644 index 00000000..4736af60 --- /dev/null +++ b/package/gluon-radvd/Makefile @@ -0,0 +1,39 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-radvd +PKG_VERSION:=3 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + +define Package/gluon-radvd + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Advertise an IPv6 prefix from the node + DEPENDS:=+gluon-core +gluon-ebtables +gluon-mesh-batman-adv +librt +endef + +define Package/gluon-radvd/description + Gluon community wifi mesh firmware framework: Advertise an IPv6 prefix from the node +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ +endef + +define Build/Configure +endef + +define Build/Compile + CFLAGS="$(TARGET_CFLAGS)" CPPFLAGS="$(TARGET_CPPFLAGS)" $(MAKE) -C $(PKG_BUILD_DIR) $(TARGET_CONFIGURE_OPTS) +endef + +define Package/gluon-radvd/install + $(CP) ./files/* $(1)/ + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/gluon-radvd $(1)/usr/sbin/ +endef + +$(eval $(call BuildPackage,gluon-radvd)) diff --git a/package/gluon-radvd/files/etc/init.d/gluon-radvd b/package/gluon-radvd/files/etc/init.d/gluon-radvd new file mode 100755 index 00000000..14815e76 --- /dev/null +++ b/package/gluon-radvd/files/etc/init.d/gluon-radvd @@ -0,0 +1,15 @@ +#!/bin/sh /etc/rc.common + +START=50 + +SERVICE_WRITE_PID=1 +SERVICE_DAEMONIZE=1 + + +start() { + service_start /usr/sbin/gluon-radvd -i br-client -p $(lua -e 'print(require("gluon.site_config").prefix6)') +} + +stop() { + service_stop /usr/sbin/gluon-radvd +} diff --git a/package/gluon-radvd/files/lib/gluon/ebtables/300-radv-input-output b/package/gluon-radvd/files/lib/gluon/ebtables/300-radv-input-output new file mode 100644 index 00000000..377d11cd --- /dev/null +++ b/package/gluon-radvd/files/lib/gluon/ebtables/300-radv-input-output @@ -0,0 +1,2 @@ +rule 'INPUT -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type router-solicitation -i bat0 -j DROP' +rule 'OUTPUT -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type router-advertisement -o bat0 -j DROP' diff --git a/package/gluon-radvd/files/lib/gluon/upgrade/500-radvd-remove-user b/package/gluon-radvd/files/lib/gluon/upgrade/500-radvd-remove-user new file mode 100755 index 00000000..036406af --- /dev/null +++ b/package/gluon-radvd/files/lib/gluon/upgrade/500-radvd-remove-user @@ -0,0 +1,5 @@ +#!/usr/bin/lua + +local users = require 'gluon.users' + +users.remove_user('gluon-radvd') diff --git a/package/gluon-radvd/src/Makefile b/package/gluon-radvd/src/Makefile new file mode 100644 index 00000000..f0bc9034 --- /dev/null +++ b/package/gluon-radvd/src/Makefile @@ -0,0 +1,4 @@ +all: gluon-radvd + +gluon-radvd: gluon-radvd.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -Wall -o $@ $^ $(LDLIBS) -lrt diff --git a/package/gluon-radvd/src/gluon-radvd.c b/package/gluon-radvd/src/gluon-radvd.c new file mode 100644 index 00000000..bd57eabc --- /dev/null +++ b/package/gluon-radvd/src/gluon-radvd.c @@ -0,0 +1,647 @@ +/* + Copyright (c) 2014, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include + + +#define MAX_PREFIXES 8 + +/* These are in seconds */ +#define AdvValidLifetime 86400u +#define AdvPreferredLifetime 14400u +#define AdvDefaultLifetime 0u +#define AdvCurHopLimit 64u + +#define MinRtrAdvInterval 200u +#define MaxRtrAdvInterval 600u + +/* And these in milliseconds */ +#define MAX_RA_DELAY_TIME 500u +#define MIN_DELAY_BETWEEN_RAS 3000u + + +struct icmpv6_opt { + uint8_t type; + uint8_t length; + uint8_t data[6]; +}; + + +struct iface { + bool ok; + unsigned int ifindex; + struct in6_addr ifaddr; + uint8_t mac[6]; +}; + +static struct global { + struct iface iface; + + struct timespec time; + struct timespec next_advert; + struct timespec next_advert_earliest; + + int icmp_sock; + int rtnl_sock; + + const char *ifname; + + size_t n_prefixes; + struct in6_addr prefixes[MAX_PREFIXES]; +} G = { + .rtnl_sock = -1, + .icmp_sock = -1, +}; + + +static inline void exit_errno(const char *message) { + error(1, errno, "error: %s", message); +} + +static inline void warn_errno(const char *message) { + error(0, errno, "warning: %s", message); +} + + +static inline void update_time(void) { + clock_gettime(CLOCK_MONOTONIC, &G.time); +} + +/* Compares two timespecs and returns true if tp1 is after tp2 */ +static inline bool timespec_after(const struct timespec *tp1, const struct timespec *tp2) { + return (tp1->tv_sec > tp2->tv_sec || + (tp1->tv_sec == tp2->tv_sec && tp1->tv_nsec > tp2->tv_nsec)); +} + +/* Returns (tp1 - tp2) in milliseconds */ +static inline int timespec_diff(const struct timespec *tp1, const struct timespec *tp2) { + return ((tp1->tv_sec - tp2->tv_sec))*1000 + (tp1->tv_nsec - tp2->tv_nsec)/1e6; +} + +static inline void timespec_add(struct timespec *tp, unsigned int ms) { + tp->tv_sec += ms/1000; + tp->tv_nsec += (ms%1000) * 1e6; + + if (tp->tv_nsec >= 1e9) { + tp->tv_nsec -= 1e9; + tp->tv_sec++; + } +} + + +static inline int setsockopt_int(int socket, int level, int option, int value) { + return setsockopt(socket, level, option, &value, sizeof(value)); +} + + +static void init_random(void) { + unsigned int seed; + int fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) + exit_errno("can't open /dev/urandom"); + + if (read(fd, &seed, sizeof(seed)) != sizeof(seed)) + exit_errno("can't read from /dev/urandom"); + + close(fd); + + srandom(seed); +} + +static inline int rand_range(int min, int max) { + unsigned int r = (unsigned int)random(); + return (r%(max-min) + min); +} + +static void init_icmp(void) { + G.icmp_sock = socket(AF_INET6, SOCK_RAW|SOCK_NONBLOCK, IPPROTO_ICMPV6); + if (G.icmp_sock < 0) + exit_errno("can't open ICMP socket"); + + setsockopt_int(G.icmp_sock, IPPROTO_RAW, IPV6_CHECKSUM, 2); + + setsockopt_int(G.icmp_sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 255); + setsockopt_int(G.icmp_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 1); + + setsockopt_int(G.icmp_sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, 1); + + struct icmp6_filter filter; + ICMP6_FILTER_SETBLOCKALL(&filter); + ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter); + setsockopt(G.icmp_sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)); +} + +static void init_rtnl(void) { + G.rtnl_sock = socket(AF_NETLINK, SOCK_DGRAM|SOCK_NONBLOCK, NETLINK_ROUTE); + if (G.rtnl_sock < 0) + exit_errno("can't open RTNL socket"); + + struct sockaddr_nl snl = { + .nl_family = AF_NETLINK, + .nl_groups = RTMGRP_LINK | RTMGRP_IPV6_IFADDR, + }; + if (bind(G.rtnl_sock, (struct sockaddr *)&snl, sizeof(snl)) < 0) + exit_errno("can't bind RTNL socket"); +} + + +static void schedule_advert(bool nodelay) { + struct timespec t = G.time; + + if (nodelay) + timespec_add(&t, rand_range(0, MAX_RA_DELAY_TIME)); + else + timespec_add(&t, rand_range(MinRtrAdvInterval*1000, MaxRtrAdvInterval*1000)); + + if (timespec_after(&G.next_advert_earliest, &t)) + t = G.next_advert_earliest; + + if (!nodelay || timespec_after(&G.next_advert, &t)) + G.next_advert = t; +} + + +static int join_multicast(void) { + struct ipv6_mreq mreq = { + .ipv6mr_multiaddr = { + .s6_addr = { + /* all-routers address */ + 0xff, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, + } + }, + .ipv6mr_interface = G.iface.ifindex, + }; + + if (setsockopt(G.icmp_sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == 0) { + return 2; + } + else if (errno != EADDRINUSE) { + warn_errno("can't join multicast group"); + return 0; + } + + return 1; +} + +static void update_interface(void) { + struct iface old; + + memcpy(&old, &G.iface, sizeof(struct iface)); + memset(&G.iface, 0, sizeof(struct iface)); + + /* Update ifindex */ + G.iface.ifindex = if_nametoindex(G.ifname); + if (!G.iface.ifindex) + return; + + /* Update MAC address */ + struct ifreq ifr = {}; + strncpy(ifr.ifr_name, G.ifname, sizeof(ifr.ifr_name)-1); + if (ioctl(G.icmp_sock, SIOCGIFHWADDR, &ifr) < 0) + return; + + memcpy(G.iface.mac, ifr.ifr_hwaddr.sa_data, sizeof(G.iface.mac)); + + struct ifaddrs *addrs, *addr; + if (getifaddrs(&addrs) < 0) { + warn_errno("getifaddrs"); + return; + } + + memset(&G.iface.ifaddr, 0, sizeof(G.iface.ifaddr)); + + for (addr = addrs; addr; addr = addr->ifa_next) { + if (!addr->ifa_addr || addr->ifa_addr->sa_family != AF_INET6) + continue; + + const struct sockaddr_in6 *in6 = (const struct sockaddr_in6 *)addr->ifa_addr; + if (!IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) + continue; + + if (strncmp(addr->ifa_name, G.ifname, IFNAMSIZ-1) != 0) + continue; + + G.iface.ifaddr = in6->sin6_addr; + } + + freeifaddrs(addrs); + + if (IN6_IS_ADDR_UNSPECIFIED(&G.iface.ifaddr)) + return; + + int joined = join_multicast(); + if (!joined) + return; + + setsockopt(G.icmp_sock, SOL_SOCKET, SO_BINDTODEVICE, G.ifname, strnlen(G.ifname, IFNAMSIZ-1)); + + G.iface.ok = true; + + if (memcmp(&old, &G.iface, sizeof(struct iface)) != 0 || joined == 2) + schedule_advert(true); +} + + +static bool handle_rtnl_link(uint16_t type, const struct ifinfomsg *msg) { + switch (type) { + case RTM_NEWLINK: + if (!G.iface.ok) + return true; + + break; + + case RTM_SETLINK: + if ((unsigned)msg->ifi_index == G.iface.ifindex) + return true; + + if (!G.iface.ok) + return true; + + break; + + case RTM_DELLINK: + if (G.iface.ok && (unsigned)msg->ifi_index == G.iface.ifindex) + return true; + } + + return false; +} + +static bool handle_rtnl_addr(uint16_t type, const struct ifaddrmsg *msg) { + switch (type) { + case RTM_NEWADDR: + if (!G.iface.ok && (unsigned)msg->ifa_index == G.iface.ifindex) + return true; + + break; + + case RTM_DELADDR: + if (G.iface.ok && (unsigned)msg->ifa_index == G.iface.ifindex) + return true; + } + + return false; +} + +static bool handle_rtnl_msg(uint16_t type, const void *data) { + switch (type) { + case RTM_NEWLINK: + case RTM_DELLINK: + case RTM_SETLINK: + return handle_rtnl_link(type, data); + + case RTM_NEWADDR: + case RTM_DELADDR: + return handle_rtnl_addr(type, data); + + default: + return false; + } +} + +static void handle_rtnl(void) { + char buffer[4096]; + + ssize_t len = recv(G.rtnl_sock, buffer, sizeof(buffer), 0); + if (len < 0) { + warn_errno("recv"); + return; + } + + const struct nlmsghdr *nh; + for (nh = (struct nlmsghdr *)buffer; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) { + switch (nh->nlmsg_type) { + case NLMSG_DONE: + return; + + case NLMSG_ERROR: + error(1, 0, "error: netlink error"); + + default: + if (handle_rtnl_msg(nh->nlmsg_type, NLMSG_DATA(nh))) { + update_interface(); + return; + } + } + } +} + +static void add_pktinfo(struct msghdr *msg) { + struct cmsghdr *cmsg = (struct cmsghdr*)((char*)msg->msg_control + msg->msg_controllen); + + cmsg->cmsg_level = IPPROTO_IPV6; + cmsg->cmsg_type = IPV6_PKTINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + + msg->msg_controllen += cmsg->cmsg_len; + + struct in6_pktinfo pktinfo = { + .ipi6_addr = G.iface.ifaddr, + .ipi6_ifindex = G.iface.ifindex, + }; + + memcpy(CMSG_DATA(cmsg), &pktinfo, sizeof(pktinfo)); +} + + +static void handle_solicit(void) { + struct sockaddr_in6 addr; + + uint8_t buffer[1500] __attribute__((aligned(8))); + struct iovec vec = { .iov_base = buffer, .iov_len = sizeof(buffer) }; + + uint8_t cbuf[1024] __attribute__((aligned(8))); + + + struct msghdr msg = { + .msg_name = &addr, + .msg_namelen = sizeof(addr), + .msg_iov = &vec, + .msg_iovlen = 1, + .msg_control = cbuf, + .msg_controllen = sizeof(cbuf), + }; + + ssize_t len = recvmsg(G.icmp_sock, &msg, 0); + if (len < (ssize_t)sizeof(struct nd_router_solicit)) { + if (len < 0) + warn_errno("recvmsg"); + + return; + } + + struct cmsghdr *cmsg; + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level != IPPROTO_IPV6) + continue; + + if (cmsg->cmsg_type != IPV6_HOPLIMIT) + continue; + + if (*(int*)CMSG_DATA(cmsg) != 255) + return; + + break; + } + + const struct nd_router_solicit *s = (struct nd_router_solicit *)buffer; + if (s->nd_rs_hdr.icmp6_type != ND_ROUTER_SOLICIT || s->nd_rs_hdr.icmp6_code != 0) + return; + + const struct icmpv6_opt *opt = (struct icmpv6_opt *)(buffer + sizeof(struct nd_router_solicit)), *end = (struct icmpv6_opt *)(buffer+len); + + for (; opt < end; opt += opt->length) { + if (opt+1 < end) + return; + + if (!opt->length) + return; + + if (opt+opt->length < end) + return; + + if (opt->type == ND_OPT_SOURCE_LINKADDR && IN6_IS_ADDR_UNSPECIFIED(&addr.sin6_addr)) + return; + } + + if (opt != end) + return; + + schedule_advert(true); +} + +static void send_advert(void) { + if (!G.iface.ok) + return; + + struct nd_router_advert advert = { + .nd_ra_hdr = { + .icmp6_type = ND_ROUTER_ADVERT, + .icmp6_dataun.icmp6_un_data8 = {AdvCurHopLimit, 0 /* Flags */, (AdvDefaultLifetime>>8) & 0xff, AdvDefaultLifetime & 0xff }, + }, + }; + + struct icmpv6_opt lladdr = {ND_OPT_SOURCE_LINKADDR, 1, {}}; + memcpy(lladdr.data, G.iface.mac, sizeof(G.iface.mac)); + + struct nd_opt_prefix_info prefixes[G.n_prefixes]; + + size_t i; + for (i = 0; i < G.n_prefixes; i++) { + prefixes[i] = (struct nd_opt_prefix_info){ + .nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION, + .nd_opt_pi_len = 4, + .nd_opt_pi_prefix_len = 64, + .nd_opt_pi_flags_reserved = ND_OPT_PI_FLAG_AUTO|ND_OPT_PI_FLAG_ONLINK, + .nd_opt_pi_valid_time = htonl(AdvValidLifetime), + .nd_opt_pi_preferred_time = htonl(AdvPreferredLifetime), + .nd_opt_pi_prefix = G.prefixes[i], + }; + } + + struct iovec vec[3] = { + { .iov_base = &advert, .iov_len = sizeof(advert) }, + { .iov_base = &lladdr, .iov_len = sizeof(lladdr) }, + { .iov_base = prefixes, .iov_len = sizeof(prefixes) }, + }; + + struct sockaddr_in6 addr = { + .sin6_family = AF_INET6, + .sin6_addr = { + .s6_addr = { + /* all-nodes address */ + 0xff, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, + } + }, + .sin6_scope_id = G.iface.ifindex, + }; + + uint8_t cbuf[1024] __attribute__((aligned(8))) = {}; + + struct msghdr msg = { + .msg_name = &addr, + .msg_namelen = sizeof(addr), + .msg_iov = vec, + .msg_iovlen = 3, + .msg_control = cbuf, + .msg_controllen = 0, + .msg_flags = 0, + }; + + add_pktinfo(&msg); + + if (sendmsg(G.icmp_sock, &msg, 0) < 0) { + G.iface.ok = false; + return; + } + + G.next_advert_earliest = G.time; + timespec_add(&G.next_advert_earliest, MIN_DELAY_BETWEEN_RAS); + + schedule_advert(false); +} + + +static void usage(void) { + fprintf(stderr, "Usage: gluon-radvd [-h] -i -p [ -p ... ]\n"); +} + +static void add_prefix(const char *prefix) { + if (G.n_prefixes == MAX_PREFIXES) + error(1, 0, "maximum number of prefixes is %i.", MAX_PREFIXES); + + const size_t len = strlen(prefix)+1; + char prefix2[len]; + memcpy(prefix2, prefix, len); + + char *slash = strchr(prefix2, '/'); + if (slash) { + *slash = 0; + if (strcmp(slash+1, "64") != 0) + goto error; + } + + if (inet_pton(AF_INET6, prefix2, &G.prefixes[G.n_prefixes]) != 1) + goto error; + + static const uint8_t zero[8] = {}; + if (memcmp(G.prefixes[G.n_prefixes].s6_addr + 8, zero, 8) != 0) + goto error; + + G.n_prefixes++; + return; + + error: + error(1, 0, "invalid prefix %s (only prefixes of length 64 are supported).", prefix); +} + +static void parse_cmdline(int argc, char *argv[]) { + int c; + while ((c = getopt(argc, argv, "i:p:h")) != -1) { + switch(c) { + case 'i': + if (G.ifname) + error(1, 0, "multiple interfaces are not supported."); + + G.ifname = optarg; + + break; + + case 'p': + add_prefix(optarg); + break; + + case 'h': + usage(); + exit(0); + + default: + usage(); + exit(1); + } + } +} + +int main(int argc, char *argv[]) { + parse_cmdline(argc, argv); + + if (!G.ifname || !G.n_prefixes) + error(1, 0, "interface and prefix arguments are required."); + + init_random(); + init_icmp(); + init_rtnl(); + + update_time(); + G.next_advert = G.next_advert_earliest = G.time; + + update_interface(); + + while (true) { + struct pollfd fds[2] = { + { .fd = G.icmp_sock, .events = POLLIN }, + { .fd = G.rtnl_sock, .events = POLLIN }, + }; + + int timeout = -1; + + if (G.iface.ok) { + timeout = timespec_diff(&G.next_advert, &G.time); + + if (timeout < 0) + timeout = 0; + } + + int ret = poll(fds, 2, timeout); + if (ret < 0) + exit_errno("poll"); + + update_time(); + + if (fds[0].revents & POLLIN) + handle_solicit(); + if (fds[1].revents & POLLIN) + handle_rtnl(); + + if (timespec_after(&G.time, &G.next_advert)) + send_advert(); + } +} diff --git a/package/gluon-setup-mode/Makefile b/package/gluon-setup-mode/Makefile new file mode 100644 index 00000000..55370abe --- /dev/null +++ b/package/gluon-setup-mode/Makefile @@ -0,0 +1,44 @@ +# Copyright (C) 2012 Nils Schneider +# This is free software, licensed under the Apache 2.0 license. + +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-setup-mode +PKG_VERSION:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +define Package/gluon-setup-mode + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Setup mode + DEPENDS:=+gluon-core +uhttpd +dnsmasq + PROVIDES:=gluon-setup-mode-virtual +endef + +define Package/gluon-setup-mode/description + Offline mode to perform basic setup in a secure manner. +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-setup-mode/install + $(CP) ./files/* $(1)/ +endef + +define Package/gluon-setup-mode/postinst +#!/bin/sh +$(call GluonCheckSite,check_site.lua) +endef + +$(eval $(call BuildPackage,gluon-setup-mode)) diff --git a/package/gluon-setup-mode/check_site.lua b/package/gluon-setup-mode/check_site.lua new file mode 100644 index 00000000..07baaad3 --- /dev/null +++ b/package/gluon-setup-mode/check_site.lua @@ -0,0 +1,2 @@ +need_boolean('setup_mode.skip', false) + diff --git a/package/gluon-setup-mode/files/etc/config/gluon-setup-mode b/package/gluon-setup-mode/files/etc/config/gluon-setup-mode new file mode 100644 index 00000000..c652728f --- /dev/null +++ b/package/gluon-setup-mode/files/etc/config/gluon-setup-mode @@ -0,0 +1,3 @@ +config setup_mode + option enabled '0' + option configured '0' diff --git a/package/gluon-setup-mode/files/etc/hotplug.d/button/50-gluon-setup-mode b/package/gluon-setup-mode/files/etc/hotplug.d/button/50-gluon-setup-mode new file mode 100755 index 00000000..9a1ccf2f --- /dev/null +++ b/package/gluon-setup-mode/files/etc/hotplug.d/button/50-gluon-setup-mode @@ -0,0 +1,29 @@ +#!/bin/sh + + +wait=3 + + +wait_setup_mode() { + sleep $wait + uci set 'gluon-setup-mode.@setup_mode[0].enabled=1' + uci commit gluon-setup-mode + reboot +} + + +if [ "$BUTTON" = wps -o "$BUTTON" = reset ]; then + case "$ACTION" in + pressed) + wait_setup_mode & + PID=$! + echo $PID > /tmp/.wait_setup_mode + ;; + released) + if [ -r /tmp/.wait_setup_mode ]; then + kill $(cat /tmp/.wait_setup_mode) + rm /tmp/.wait_setup_mode + fi + ;; + esac +fi diff --git a/package/gluon-setup-mode/files/lib/gluon/setup-mode/ash-login b/package/gluon-setup-mode/files/lib/gluon/setup-mode/ash-login new file mode 100755 index 00000000..3349c444 --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/ash-login @@ -0,0 +1,3 @@ +#!/bin/sh + +exec /bin/ash --login diff --git a/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/K50dropbear b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/K50dropbear new file mode 120000 index 00000000..066549b3 --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/K50dropbear @@ -0,0 +1 @@ +/etc/init.d/dropbear \ No newline at end of file diff --git a/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/K89log b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/K89log new file mode 120000 index 00000000..1e0c5ac0 --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/K89log @@ -0,0 +1 @@ +/etc/init.d/log \ No newline at end of file diff --git a/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/K90network b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/K90network new file mode 120000 index 00000000..0a43e66b --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/K90network @@ -0,0 +1 @@ +S20network \ No newline at end of file diff --git a/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/K98boot b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/K98boot new file mode 120000 index 00000000..64aea5e8 --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/K98boot @@ -0,0 +1 @@ +/etc/init.d/boot \ No newline at end of file diff --git a/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/K99umount b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/K99umount new file mode 120000 index 00000000..b02f4892 --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/K99umount @@ -0,0 +1 @@ +/etc/init.d/umount \ No newline at end of file diff --git a/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S00sysfixtime b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S00sysfixtime new file mode 120000 index 00000000..a4fb1d5b --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S00sysfixtime @@ -0,0 +1 @@ +/etc/init.d/sysfixtime \ No newline at end of file diff --git a/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S10boot b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S10boot new file mode 120000 index 00000000..64aea5e8 --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S10boot @@ -0,0 +1 @@ +/etc/init.d/boot \ No newline at end of file diff --git a/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S10system b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S10system new file mode 120000 index 00000000..81e8836f --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S10system @@ -0,0 +1 @@ +/etc/init.d/system \ No newline at end of file diff --git a/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S11sysctl b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S11sysctl new file mode 120000 index 00000000..b4ac535e --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S11sysctl @@ -0,0 +1 @@ +/etc/init.d/sysctl \ No newline at end of file diff --git a/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S12log b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S12log new file mode 120000 index 00000000..1e0c5ac0 --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S12log @@ -0,0 +1 @@ +/etc/init.d/log \ No newline at end of file diff --git a/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S13haveged b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S13haveged new file mode 100755 index 00000000..b4af677a --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S13haveged @@ -0,0 +1,5 @@ +#!/bin/sh /etc/rc.common + +if /etc/init.d/haveged enabled; then + . /etc/init.d/haveged +fi diff --git a/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S15gluon-setup-mode b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S15gluon-setup-mode new file mode 100755 index 00000000..df8a0e2b --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S15gluon-setup-mode @@ -0,0 +1,21 @@ +#!/bin/sh /etc/rc.common + +START=15 + + +boot() { + local enabled="$(uci -q get 'gluon-setup-mode.@setup_mode[0].enabled')" + local configured="$(uci -q get 'gluon-setup-mode.@setup_mode[0].configured')" + + uci set 'gluon-setup-mode.@setup_mode[0].enabled=0' + uci commit gluon-setup-mode + + if [ "$enabled" = 1 -o "$configured" != 1 ]; then + lua -e 'uci_state=require("luci.model.uci").cursor_state(); uci_state:section("gluon-setup-mode", "setup_mode", nil, { running = "1" }); uci_state:save("gluon-setup-mode")' + else + # This can happen after an upgrade from a version before the config file was called gluon-setup-mode + # We'll just reboot to return to the normal mode... + /etc/init.d/done boot + reboot + fi +} diff --git a/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S20network b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S20network new file mode 100755 index 00000000..ef4cc4ad --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S20network @@ -0,0 +1,88 @@ +#!/bin/sh /etc/rc.common + +SETUP_MODE_ADDR=192.168.1.1 +SETUP_MODE_NETMASK=255.255.255.0 + +START=20 +STOP=90 + +USE_PROCD=1 + + +delete_interface() { + [ "$1" = 'loopback' ] || uci_remove network "$1" +} + +prepare_config() { +( + export UCI_CONFIG_DIR=/var/gluon/setup-mode/config + + mkdir -p "$UCI_CONFIG_DIR" + + cp /etc/config/network "$UCI_CONFIG_DIR" + + config_load network + config_foreach delete_interface interface + + uci_add network interface setup + uci_set network setup ifname "$(lua -e 'print(require("gluon.sysconfig").setup_ifname)')" + uci_set network setup macaddr "$(lua -e 'print(require("gluon.sysconfig").primary_mac)')" + uci_set network setup type 'bridge' + uci_set network setup proto 'static' + uci_set network setup ipaddr "$SETUP_MODE_ADDR" + uci_set network setup netmask "$SETUP_MODE_NETMASK" + + uci_commit network +) +} + +init_switch() { + setup_switch() { return 0; } + + include /lib/network + setup_switch +} + +start_service() { + prepare_config + init_switch + iw reg set "$(lua -e 'print(require("gluon.site_config").regdom)')" + + procd_open_instance + procd_set_param command /sbin/netifd -c /var/gluon/setup-mode/config + procd_set_param respawn + procd_set_param watch network.interface + [ -e /proc/sys/kernel/core_pattern ] && { + procd_set_param limits core="unlimited" + echo '/tmp/%e.%p.%s.%t.core' > /proc/sys/kernel/core_pattern + } + procd_close_instance +} + +reload_service() { + init_switch + ubus call network reload + /sbin/wifi reload_legacy +} + +stop_service() { + /sbin/wifi down +} + +service_running() { + ubus -t 30 wait_for network.interface + /sbin/wifi reload_legacy +} + +restart() { + ifdown -a + sleep 1 + trap '' TERM + stop "$@" + start "$@" +} + +shutdown() { + ifdown -a + stop +} diff --git a/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S50dropbear b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S50dropbear new file mode 120000 index 00000000..066549b3 --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S50dropbear @@ -0,0 +1 @@ +/etc/init.d/dropbear \ No newline at end of file diff --git a/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S50telnet b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S50telnet new file mode 100755 index 00000000..b524b2ce --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S50telnet @@ -0,0 +1,12 @@ +#!/bin/sh /etc/rc.common + +START=50 + +USE_PROCD=1 +PROG=/usr/sbin/telnetd + +start_service() { + procd_open_instance + procd_set_param command "$PROG" -F -l /lib/gluon/setup-mode/ash-login + procd_close_instance +} diff --git a/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S50uhttpd b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S50uhttpd new file mode 100755 index 00000000..53118704 --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S50uhttpd @@ -0,0 +1,14 @@ +#!/bin/sh /etc/rc.common + +START=50 + +USE_PROCD=1 + +UHTTPD_BIN="/usr/sbin/uhttpd" + +start_service() { + procd_open_instance + procd_set_param respawn + procd_set_param command "$UHTTPD_BIN" -f -h /lib/gluon/setup-mode/www -x /cgi-bin -A 1 -R -p 0.0.0.0:80 + procd_close_instance +} diff --git a/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S60dnsmasq b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S60dnsmasq new file mode 100755 index 00000000..d275b4bf --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S60dnsmasq @@ -0,0 +1,17 @@ +#!/bin/sh /etc/rc.common + +SETUP_MODE_DHCP_RANGE=192.168.1.2,192.168.1.254 + + +START=60 + +USE_PROCD=1 +PROG=/usr/sbin/dnsmasq + + +start_service() { + procd_open_instance + procd_set_param command $PROG -k -p 0 -F $SETUP_MODE_DHCP_RANGE -l /tmp/dhcp.leases -O option:router + procd_set_param respawn + procd_close_instance +} diff --git a/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S95done b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S95done new file mode 120000 index 00000000..c9f30277 --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S95done @@ -0,0 +1 @@ +/etc/init.d/done \ No newline at end of file diff --git a/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S96led b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S96led new file mode 100755 index 00000000..b01ae599 --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S96led @@ -0,0 +1,11 @@ +#!/bin/sh /etc/rc.common + +START=96 + +start() { + /etc/init.d/led start + + . /etc/diag.sh + get_status_led + status_led_set_timer 1000 300 +} diff --git a/package/gluon-setup-mode/files/lib/gluon/setup-mode/www/cgi-bin/luci b/package/gluon-setup-mode/files/lib/gluon/setup-mode/www/cgi-bin/luci new file mode 100755 index 00000000..c5c98473 --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/www/cgi-bin/luci @@ -0,0 +1,5 @@ +#!/usr/bin/lua +require "luci.cacheloader" +require "luci.sgi.cgi" +luci.dispatcher.indexcache = "/tmp/luci-indexcache" +luci.sgi.cgi.run() diff --git a/package/gluon-setup-mode/files/lib/gluon/setup-mode/www/index.html b/package/gluon-setup-mode/files/lib/gluon/setup-mode/www/index.html new file mode 100644 index 00000000..0a7238b5 --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/www/index.html @@ -0,0 +1,10 @@ + + + + + + + +LuCI - Lua Configuration Interface + + diff --git a/package/gluon-setup-mode/files/lib/gluon/setup-mode/www/luci-static b/package/gluon-setup-mode/files/lib/gluon/setup-mode/www/luci-static new file mode 120000 index 00000000..aea80e05 --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/www/luci-static @@ -0,0 +1 @@ +/www/luci-static \ No newline at end of file diff --git a/package/gluon-setup-mode/files/lib/gluon/upgrade/300-setup-mode b/package/gluon-setup-mode/files/lib/gluon/upgrade/300-setup-mode new file mode 100755 index 00000000..ae59c7aa --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/upgrade/300-setup-mode @@ -0,0 +1,16 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local uci = require 'luci.model.uci' + +local c = uci.cursor() + +if site.setup_mode + and site.setup_mode.skip + and not c:get_first('gluon-setup-mode', 'setup_mode', 'configured', false) then + local name = c:get_first("gluon-setup-mode", "setup_mode") + c:set("gluon-setup-mode", name, "configured", 1) + c:save('gluon-setup-mode') + c:commit('gluon-setup-mode') +end + diff --git a/package/gluon-setup-mode/files/lib/gluon/upgrade/310-setup-mode-migrate b/package/gluon-setup-mode/files/lib/gluon/upgrade/310-setup-mode-migrate new file mode 100755 index 00000000..9d3b9b0a --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/upgrade/310-setup-mode-migrate @@ -0,0 +1,18 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local uci = require 'luci.model.uci' + +local c = uci.cursor() + + +local old = c:get_first('gluon-config-mode', 'wizard', 'configured') +if old == '1' then + local setup_mode = c:get_first('gluon-setup-mode', 'setup_mode') + c:set('gluon-setup-mode', setup_mode, 'configured', '1') + + c:save('gluon-setup-mode') + c:commit('gluon-setup-mode') +end + +os.remove('/etc/config/gluon-config-mode') diff --git a/package/gluon-setup-mode/files/lib/gluon/upgrade/320-setup-ifname b/package/gluon-setup-mode/files/lib/gluon/upgrade/320-setup-ifname new file mode 100755 index 00000000..3c4a8afe --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/upgrade/320-setup-ifname @@ -0,0 +1,18 @@ +#!/usr/bin/lua + +local platform = require 'gluon.platform' +local sysconfig = require 'gluon.sysconfig' + + +if sysconfig.setup_ifname then + os.exit(0) +end + +if platform.match('ar71xx', 'generic', {'cpe510', 'nanostation-m', 'nanostation-m-xw', 'unifi-outdoor-plus'}) then + sysconfig.setup_ifname = sysconfig.config_ifname or sysconfig.wan_ifname or sysconfig.lan_ifname +else + sysconfig.setup_ifname = sysconfig.config_ifname or sysconfig.lan_ifname or sysconfig.wan_ifname +end + +-- Remove the old sysconfig setting +sysconfig.config_ifname = nil diff --git a/package/gluon-setup-mode/files/lib/preinit/90_setup_mode b/package/gluon-setup-mode/files/lib/preinit/90_setup_mode new file mode 100644 index 00000000..396b4f76 --- /dev/null +++ b/package/gluon-setup-mode/files/lib/preinit/90_setup_mode @@ -0,0 +1,13 @@ +#!/bin/sh + + +setup_mode_enable() { + local enabled="$(uci -q get 'gluon-setup-mode.@setup_mode[0].enabled')" + local configured="$(uci -q get 'gluon-setup-mode.@setup_mode[0].configured')" + + if [ "$enabled" = 1 -o "$configured" != 1 ]; then + echo '/lib/gluon/setup-mode/rc.d' > /tmp/rc_d_path + fi +} + +boot_hook_add preinit_main setup_mode_enable diff --git a/package/gluon-simple-tc/Makefile b/package/gluon-simple-tc/Makefile new file mode 100644 index 00000000..b01b9641 --- /dev/null +++ b/package/gluon-simple-tc/Makefile @@ -0,0 +1,47 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-simple-tc +PKG_VERSION:=4 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +define Package/gluon-simple-tc + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Bandwidth limit support + DEPENDS:=+gluon-core +kmod-sched +libnl-tiny +endef + +define Package/gluon-simple-tc/description + Gluon community wifi mesh firmware framework: tc support +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ +endef + +define Build/Configure +endef + + +TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include/libnl-tiny + +define Build/Compile + CFLAGS="$(TARGET_CFLAGS)" CPPFLAGS="$(TARGET_CPPFLAGS)" $(MAKE) -C $(PKG_BUILD_DIR) $(TARGET_CONFIGURE_OPTS) +endef + +define Package/gluon-simple-tc/install + $(CP) ./files/* $(1)/ + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/gluon-simple-tc $(1)/usr/sbin/ +endef + +define Package/gluon-simple-tc/postinst +#!/bin/sh +$(call GluonCheckSite,check_site.lua) +endef + +$(eval $(call BuildPackage,gluon-simple-tc)) diff --git a/package/gluon-simple-tc/check_site.lua b/package/gluon-simple-tc/check_site.lua new file mode 100644 index 00000000..95d4fd81 --- /dev/null +++ b/package/gluon-simple-tc/check_site.lua @@ -0,0 +1,10 @@ +local function check_entry(k, _) + local prefix = string.format('simple_tc[%q].', k) + + need_string(prefix .. 'ifname') + need_boolean(prefix .. 'enabled') + need_number(prefix .. 'limit_egress') + need_number(prefix .. 'limit_ingress') +end + +need_table('simple_tc', check_entry) diff --git a/package/gluon-simple-tc/files/etc/config/gluon-simple-tc b/package/gluon-simple-tc/files/etc/config/gluon-simple-tc new file mode 100644 index 00000000..c9b784c6 --- /dev/null +++ b/package/gluon-simple-tc/files/etc/config/gluon-simple-tc @@ -0,0 +1,7 @@ +# Example config + +config interface 'example' + option enabled '0' + option ifname 'eth0' + option limit_egress '1000' # 1000 Kbit/s + option limit_ingress '5000' # 5000 Kbit/s diff --git a/package/gluon-simple-tc/files/etc/hotplug.d/net/50-gluon-simple-tc b/package/gluon-simple-tc/files/etc/hotplug.d/net/50-gluon-simple-tc new file mode 100644 index 00000000..8dd82781 --- /dev/null +++ b/package/gluon-simple-tc/files/etc/hotplug.d/net/50-gluon-simple-tc @@ -0,0 +1,26 @@ +[ "$ACTION" = 'add' ] || exit 0 + +config_load gluon-simple-tc + + +tc_interface() { + local iface="$1" + + config_get ifname "$iface" ifname + + [ "$INTERFACE" = "$ifname" ] || return + + config_get_bool enabled "$iface" enabled 0 + + [ "$enabled" -eq 1 ] || return + + config_get limit_ingress "$iface" limit_ingress + config_get limit_egress "$iface" limit_egress + + [ "$limit_ingress" ] || limit_ingress=- + [ "$limit_egress" ] || limit_egress=- + + gluon-simple-tc "$INTERFACE" "$limit_ingress" "$limit_egress" +} + +config_foreach tc_interface 'interface' diff --git a/package/gluon-simple-tc/files/etc/modules-boot.d/30-gluon-simple-tc b/package/gluon-simple-tc/files/etc/modules-boot.d/30-gluon-simple-tc new file mode 120000 index 00000000..44318d6e --- /dev/null +++ b/package/gluon-simple-tc/files/etc/modules-boot.d/30-gluon-simple-tc @@ -0,0 +1 @@ +../modules.d/30-gluon-simple-tc \ No newline at end of file diff --git a/package/gluon-simple-tc/files/etc/modules.d/30-gluon-simple-tc b/package/gluon-simple-tc/files/etc/modules.d/30-gluon-simple-tc new file mode 100644 index 00000000..72b238c7 --- /dev/null +++ b/package/gluon-simple-tc/files/etc/modules.d/30-gluon-simple-tc @@ -0,0 +1,4 @@ +sch_ingress +sch_tbf +cls_basic +act_police diff --git a/package/gluon-simple-tc/files/lib/gluon/upgrade/300-simple-tc-site-defaults b/package/gluon-simple-tc/files/lib/gluon/upgrade/300-simple-tc-site-defaults new file mode 100755 index 00000000..037cb45f --- /dev/null +++ b/package/gluon-simple-tc/files/lib/gluon/upgrade/300-simple-tc-site-defaults @@ -0,0 +1,23 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local uci = require 'luci.model.uci' + +local c = uci.cursor() + + +for name, config in pairs(site.simple_tc) do + if not c:get('gluon-simple-tc', name) then + c:section('gluon-simple-tc', 'interface', name, + { + ifname = config.ifname, + enabled = config.enabled and 1 or 0, + limit_egress = config.limit_egress, + limit_ingress = config.limit_ingress, + } + ) + end +end + +c:save('gluon-simple-tc') +c:commit('gluon-simple-tc') diff --git a/package/gluon-simple-tc/src/Makefile b/package/gluon-simple-tc/src/Makefile new file mode 100644 index 00000000..502c6232 --- /dev/null +++ b/package/gluon-simple-tc/src/Makefile @@ -0,0 +1,4 @@ +all: gluon-simple-tc + +gluon-simple-tc: gluon-simple-tc.c + $(CC) -Iinclude $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -Wall -o $@ $^ $(LDLIBS) -lnl-tiny diff --git a/package/gluon-simple-tc/src/gluon-simple-tc.c b/package/gluon-simple-tc/src/gluon-simple-tc.c new file mode 100644 index 00000000..9e5bb206 --- /dev/null +++ b/package/gluon-simple-tc/src/gluon-simple-tc.c @@ -0,0 +1,292 @@ +/* + Copyright (c) 2014, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include +#include +#include +#include + + +#include +#include +#include + + +static struct nl_cb *cb; +static struct nl_sock *sock; +static double ticks; + +static unsigned ifindex; + +static bool nlexpect; +static int nlerror; + + +static inline void exit_errno(const char *message) { + error(1, errno, "error: %s", message); +} + +static inline void warn_errno(const char *message) { + error(0, errno, "warning: %s", message); +} + + +static void read_psched(void) { + uint32_t clock_res; + uint32_t t2us; + uint32_t us2t; + + FILE *f = fopen("/proc/net/psched", "r"); + if (!f || fscanf(f, "%08x %08x %08x", &t2us, &us2t, &clock_res) != 3) + exit_errno("error reading /proc/net/psched"); + fclose(f); + + /* compatibility hack from iproute... */ + if (clock_res == 1000000000) + t2us = us2t; + + ticks = (double)t2us / us2t * clock_res; +} + + +static struct nl_msg * prepare_tcmsg(int type, int flags, uint32_t parent, uint32_t handle, uint32_t info) { + struct nl_msg *msg = nlmsg_alloc_simple(type, flags); + if (!msg) + exit_errno("nlmsg_alloc_simple"); + + struct tcmsg tcmsg; + memset(&tcmsg, 0, sizeof(tcmsg)); + + tcmsg.tcm_family = AF_UNSPEC; + tcmsg.tcm_ifindex = ifindex; + tcmsg.tcm_parent = parent; + tcmsg.tcm_handle = handle; + tcmsg.tcm_info = info; + + nlmsg_append(msg, &tcmsg, sizeof(tcmsg), NLMSG_ALIGNTO); + + return msg; +} + + +static int error_handler(struct sockaddr_nl *nla __attribute__((unused)), struct nlmsgerr *nlerr, void *arg __attribute__((unused))) { + if (!nlexpect || (nlerr->error != -ENOENT && nlerr->error != -EINVAL)) + nlerror = -nlerr->error; + + return NL_STOP; +} + +static bool do_send(struct nl_msg *msg, bool expect) { + nlerror = 0; + nlexpect = expect; + + nl_send_auto_complete(sock, msg); + nlmsg_free(msg); + nl_wait_for_ack(sock); + + if (nlerror) { + error(0, nlerror, "netlink"); + errno = nlerror; + return false; + } + + return true; +} + + +static inline unsigned get_xmittime(double rate, unsigned size) { + return ticks * (size/rate); +} + + +static void complete_rate(struct tc_ratespec *r, uint32_t rtab[256]) { + r->linklayer = TC_LINKLAYER_ETHERNET; + r->cell_align = -1; + r->cell_log = 3; + + unsigned i; + for (i = 0; i < 256; i++) + rtab[i] = get_xmittime(r->rate, (i + 1) << 3); +} + + +static void do_ingress(double rate) { + if (!do_send(prepare_tcmsg(RTM_DELQDISC, 0, TC_H_INGRESS, 0xffff0000, 0), true)) + return; + + if (rate < 0) + return; + + + struct nl_msg *msg = prepare_tcmsg(RTM_NEWQDISC, NLM_F_CREATE | NLM_F_EXCL, TC_H_INGRESS, 0xffff0000, 0); + nla_put_string(msg, TCA_KIND, "ingress"); + + if (!do_send(msg, false)) + return; + + + msg = prepare_tcmsg(RTM_NEWTFILTER, NLM_F_CREATE | NLM_F_EXCL, 0xffff0000, 0, TC_H_MAKE(0, htons(ETH_P_ALL))); + + const unsigned buffer = 10240; + + struct tc_police p; + memset(&p, 0, sizeof(p)); + + /* Range check has been done in main() */ + p.rate.rate = rate; + p.burst = get_xmittime(p.rate.rate, buffer); + p.action = TC_POLICE_SHOT; + + uint32_t rtab[256]; + complete_rate(&p.rate, rtab); + + nla_put_string(msg, TCA_KIND, "basic"); + + struct nlattr *opts = nla_nest_start(msg, TCA_OPTIONS); + struct nlattr *police = nla_nest_start(msg, TCA_BASIC_POLICE); + + nla_put(msg, TCA_POLICE_TBF, sizeof(p), &p); + nla_put(msg, TCA_POLICE_RATE, sizeof(rtab), rtab); + + nla_nest_end(msg, police); + nla_nest_end(msg, opts); + + do_send(msg, false); +} + +static void do_egress(double rate) { + if (!do_send(prepare_tcmsg(RTM_DELQDISC, 0, TC_H_ROOT, 0, 0), true)) + return; + + if (rate < 0) + return; + + + struct nl_msg *msg = prepare_tcmsg(RTM_NEWQDISC, NLM_F_CREATE | NLM_F_EXCL, TC_H_ROOT, 0, 0); + const unsigned buffer = 2048; + + struct tc_tbf_qopt opt; + memset(&opt, 0, sizeof(opt)); + + /* Range check has been done in main() */ + opt.rate.rate = rate; + opt.limit = 0.05*rate + buffer; + opt.buffer = get_xmittime(opt.rate.rate, buffer); + + uint32_t rtab[256]; + complete_rate(&opt.rate, rtab); + + nla_put_string(msg, TCA_KIND, "tbf"); + + struct nlattr *opts = nla_nest_start(msg, TCA_OPTIONS); + nla_put(msg, TCA_TBF_PARMS, sizeof(opt), &opt); + nla_put(msg, TCA_TBF_BURST, sizeof(buffer), &buffer); + nla_put(msg, TCA_TBF_RTAB, sizeof(rtab), rtab); + nla_nest_end(msg, opts); + + do_send(msg, false); +} + + +static inline void usage(void) { + fprintf(stderr, "Usage: gluon-simple-tc |- |-\n"); + exit(1); +} + +static inline void maxrate(void) { + error(1, 0, "error: maximum allowed rate it about 2^25 Kbit/s"); +} + + +int main(int argc, char *argv[]) { + if (argc != 4) + usage(); + + double ingress = -1, egress = -1; + char *end; + + ifindex = if_nametoindex(argv[1]); + if (!ifindex) + error(1, 0, "invalid interface: %s", argv[1]); + + if (strcmp(argv[2], "-") != 0) { + ingress = strtod(argv[2], &end); + if (*end || ingress < 0) + usage(); + + ingress *= 125; + + if (ingress >= (1ull << 32)) + maxrate(); + } + + if (strcmp(argv[3], "-") != 0) { + egress = strtod(argv[3], &end); + if (*end || egress < 0) + usage(); + + egress *= 125; + + if (egress >= (1ull << 32)) + maxrate(); + } + + read_psched(); + + cb = nl_cb_alloc(NL_CB_DEFAULT); + nl_cb_err(cb, NL_CB_CUSTOM, error_handler, NULL); + + sock = nl_socket_alloc_cb(cb); + if (!sock) + exit_errno("nl_socket_alloc"); + + if (nl_connect(sock, NETLINK_ROUTE)) + exit_errno("nl_connect"); + + do_ingress(ingress); + do_egress(egress); + + nl_socket_free(sock); + nl_cb_put(cb); + + return 0; +} diff --git a/package/gluon-simple-tc/src/include/linux/pkt_cls.h b/package/gluon-simple-tc/src/include/linux/pkt_cls.h new file mode 100644 index 00000000..25731dfb --- /dev/null +++ b/package/gluon-simple-tc/src/include/linux/pkt_cls.h @@ -0,0 +1,483 @@ +#ifndef __LINUX_PKT_CLS_H +#define __LINUX_PKT_CLS_H + +#include +#include + +/* I think i could have done better macros ; for now this is stolen from + * some arch/mips code - jhs +*/ +#define _TC_MAKE32(x) ((x)) + +#define _TC_MAKEMASK1(n) (_TC_MAKE32(1) << _TC_MAKE32(n)) +#define _TC_MAKEMASK(v,n) (_TC_MAKE32((_TC_MAKE32(1)<<(v))-1) << _TC_MAKE32(n)) +#define _TC_MAKEVALUE(v,n) (_TC_MAKE32(v) << _TC_MAKE32(n)) +#define _TC_GETVALUE(v,n,m) ((_TC_MAKE32(v) & _TC_MAKE32(m)) >> _TC_MAKE32(n)) + +/* verdict bit breakdown + * +bit 0: when set -> this packet has been munged already + +bit 1: when set -> It is ok to munge this packet + +bit 2,3,4,5: Reclassify counter - sort of reverse TTL - if exceeded +assume loop + +bit 6,7: Where this packet was last seen +0: Above the transmit example at the socket level +1: on the Ingress +2: on the Egress + +bit 8: when set --> Request not to classify on ingress. + +bits 9,10,11: redirect counter - redirect TTL. Loop avoidance + + * + * */ + +#define TC_MUNGED _TC_MAKEMASK1(0) +#define SET_TC_MUNGED(v) ( TC_MUNGED | (v & ~TC_MUNGED)) +#define CLR_TC_MUNGED(v) ( v & ~TC_MUNGED) + +#define TC_OK2MUNGE _TC_MAKEMASK1(1) +#define SET_TC_OK2MUNGE(v) ( TC_OK2MUNGE | (v & ~TC_OK2MUNGE)) +#define CLR_TC_OK2MUNGE(v) ( v & ~TC_OK2MUNGE) + +#define S_TC_VERD _TC_MAKE32(2) +#define M_TC_VERD _TC_MAKEMASK(4,S_TC_VERD) +#define G_TC_VERD(x) _TC_GETVALUE(x,S_TC_VERD,M_TC_VERD) +#define V_TC_VERD(x) _TC_MAKEVALUE(x,S_TC_VERD) +#define SET_TC_VERD(v,n) ((V_TC_VERD(n)) | (v & ~M_TC_VERD)) + +#define S_TC_FROM _TC_MAKE32(6) +#define M_TC_FROM _TC_MAKEMASK(2,S_TC_FROM) +#define G_TC_FROM(x) _TC_GETVALUE(x,S_TC_FROM,M_TC_FROM) +#define V_TC_FROM(x) _TC_MAKEVALUE(x,S_TC_FROM) +#define SET_TC_FROM(v,n) ((V_TC_FROM(n)) | (v & ~M_TC_FROM)) +#define AT_STACK 0x0 +#define AT_INGRESS 0x1 +#define AT_EGRESS 0x2 + +#define TC_NCLS _TC_MAKEMASK1(8) +#define SET_TC_NCLS(v) ( TC_NCLS | (v & ~TC_NCLS)) +#define CLR_TC_NCLS(v) ( v & ~TC_NCLS) + +#define S_TC_RTTL _TC_MAKE32(9) +#define M_TC_RTTL _TC_MAKEMASK(3,S_TC_RTTL) +#define G_TC_RTTL(x) _TC_GETVALUE(x,S_TC_RTTL,M_TC_RTTL) +#define V_TC_RTTL(x) _TC_MAKEVALUE(x,S_TC_RTTL) +#define SET_TC_RTTL(v,n) ((V_TC_RTTL(n)) | (v & ~M_TC_RTTL)) + +#define S_TC_AT _TC_MAKE32(12) +#define M_TC_AT _TC_MAKEMASK(2,S_TC_AT) +#define G_TC_AT(x) _TC_GETVALUE(x,S_TC_AT,M_TC_AT) +#define V_TC_AT(x) _TC_MAKEVALUE(x,S_TC_AT) +#define SET_TC_AT(v,n) ((V_TC_AT(n)) | (v & ~M_TC_AT)) + +/* Action attributes */ +enum { + TCA_ACT_UNSPEC, + TCA_ACT_KIND, + TCA_ACT_OPTIONS, + TCA_ACT_INDEX, + TCA_ACT_STATS, + __TCA_ACT_MAX +}; + +#define TCA_ACT_MAX __TCA_ACT_MAX +#define TCA_OLD_COMPAT (TCA_ACT_MAX+1) +#define TCA_ACT_MAX_PRIO 32 +#define TCA_ACT_BIND 1 +#define TCA_ACT_NOBIND 0 +#define TCA_ACT_UNBIND 1 +#define TCA_ACT_NOUNBIND 0 +#define TCA_ACT_REPLACE 1 +#define TCA_ACT_NOREPLACE 0 +#define MAX_REC_LOOP 4 +#define MAX_RED_LOOP 4 + +#define TC_ACT_UNSPEC (-1) +#define TC_ACT_OK 0 +#define TC_ACT_RECLASSIFY 1 +#define TC_ACT_SHOT 2 +#define TC_ACT_PIPE 3 +#define TC_ACT_STOLEN 4 +#define TC_ACT_QUEUED 5 +#define TC_ACT_REPEAT 6 +#define TC_ACT_JUMP 0x10000000 + +/* Action type identifiers*/ +enum { + TCA_ID_UNSPEC=0, + TCA_ID_POLICE=1, + /* other actions go here */ + __TCA_ID_MAX=255 +}; + +#define TCA_ID_MAX __TCA_ID_MAX + +struct tc_police { + __u32 index; + int action; +#define TC_POLICE_UNSPEC TC_ACT_UNSPEC +#define TC_POLICE_OK TC_ACT_OK +#define TC_POLICE_RECLASSIFY TC_ACT_RECLASSIFY +#define TC_POLICE_SHOT TC_ACT_SHOT +#define TC_POLICE_PIPE TC_ACT_PIPE + + __u32 limit; + __u32 burst; + __u32 mtu; + struct tc_ratespec rate; + struct tc_ratespec peakrate; + int refcnt; + int bindcnt; + __u32 capab; +}; + +struct tcf_t { + __u64 install; + __u64 lastuse; + __u64 expires; +}; + +struct tc_cnt { + int refcnt; + int bindcnt; +}; + +#define tc_gen \ + __u32 index; \ + __u32 capab; \ + int action; \ + int refcnt; \ + int bindcnt + +enum { + TCA_POLICE_UNSPEC, + TCA_POLICE_TBF, + TCA_POLICE_RATE, + TCA_POLICE_PEAKRATE, + TCA_POLICE_AVRATE, + TCA_POLICE_RESULT, + __TCA_POLICE_MAX +#define TCA_POLICE_RESULT TCA_POLICE_RESULT +}; + +#define TCA_POLICE_MAX (__TCA_POLICE_MAX - 1) + +/* U32 filters */ + +#define TC_U32_HTID(h) ((h)&0xFFF00000) +#define TC_U32_USERHTID(h) (TC_U32_HTID(h)>>20) +#define TC_U32_HASH(h) (((h)>>12)&0xFF) +#define TC_U32_NODE(h) ((h)&0xFFF) +#define TC_U32_KEY(h) ((h)&0xFFFFF) +#define TC_U32_UNSPEC 0 +#define TC_U32_ROOT (0xFFF00000) + +enum { + TCA_U32_UNSPEC, + TCA_U32_CLASSID, + TCA_U32_HASH, + TCA_U32_LINK, + TCA_U32_DIVISOR, + TCA_U32_SEL, + TCA_U32_POLICE, + TCA_U32_ACT, + TCA_U32_INDEV, + TCA_U32_PCNT, + TCA_U32_MARK, + __TCA_U32_MAX +}; + +#define TCA_U32_MAX (__TCA_U32_MAX - 1) + +struct tc_u32_key { + __be32 mask; + __be32 val; + int off; + int offmask; +}; + +struct tc_u32_sel { + unsigned char flags; + unsigned char offshift; + unsigned char nkeys; + + __be16 offmask; + __u16 off; + short offoff; + + short hoff; + __be32 hmask; + struct tc_u32_key keys[0]; +}; + +struct tc_u32_mark { + __u32 val; + __u32 mask; + __u32 success; +}; + +struct tc_u32_pcnt { + __u64 rcnt; + __u64 rhit; + __u64 kcnts[0]; +}; + +/* Flags */ + +#define TC_U32_TERMINAL 1 +#define TC_U32_OFFSET 2 +#define TC_U32_VAROFFSET 4 +#define TC_U32_EAT 8 + +#define TC_U32_MAXDEPTH 8 + + +/* RSVP filter */ + +enum { + TCA_RSVP_UNSPEC, + TCA_RSVP_CLASSID, + TCA_RSVP_DST, + TCA_RSVP_SRC, + TCA_RSVP_PINFO, + TCA_RSVP_POLICE, + TCA_RSVP_ACT, + __TCA_RSVP_MAX +}; + +#define TCA_RSVP_MAX (__TCA_RSVP_MAX - 1 ) + +struct tc_rsvp_gpi { + __u32 key; + __u32 mask; + int offset; +}; + +struct tc_rsvp_pinfo { + struct tc_rsvp_gpi dpi; + struct tc_rsvp_gpi spi; + __u8 protocol; + __u8 tunnelid; + __u8 tunnelhdr; + __u8 pad; +}; + +/* ROUTE filter */ + +enum { + TCA_ROUTE4_UNSPEC, + TCA_ROUTE4_CLASSID, + TCA_ROUTE4_TO, + TCA_ROUTE4_FROM, + TCA_ROUTE4_IIF, + TCA_ROUTE4_POLICE, + TCA_ROUTE4_ACT, + __TCA_ROUTE4_MAX +}; + +#define TCA_ROUTE4_MAX (__TCA_ROUTE4_MAX - 1) + + +/* FW filter */ + +enum { + TCA_FW_UNSPEC, + TCA_FW_CLASSID, + TCA_FW_POLICE, + TCA_FW_INDEV, /* used by CONFIG_NET_CLS_IND */ + TCA_FW_ACT, /* used by CONFIG_NET_CLS_ACT */ + TCA_FW_MASK, + __TCA_FW_MAX +}; + +#define TCA_FW_MAX (__TCA_FW_MAX - 1) + +/* TC index filter */ + +enum { + TCA_TCINDEX_UNSPEC, + TCA_TCINDEX_HASH, + TCA_TCINDEX_MASK, + TCA_TCINDEX_SHIFT, + TCA_TCINDEX_FALL_THROUGH, + TCA_TCINDEX_CLASSID, + TCA_TCINDEX_POLICE, + TCA_TCINDEX_ACT, + __TCA_TCINDEX_MAX +}; + +#define TCA_TCINDEX_MAX (__TCA_TCINDEX_MAX - 1) + +/* Flow filter */ + +enum { + FLOW_KEY_SRC, + FLOW_KEY_DST, + FLOW_KEY_PROTO, + FLOW_KEY_PROTO_SRC, + FLOW_KEY_PROTO_DST, + FLOW_KEY_IIF, + FLOW_KEY_PRIORITY, + FLOW_KEY_MARK, + FLOW_KEY_NFCT, + FLOW_KEY_NFCT_SRC, + FLOW_KEY_NFCT_DST, + FLOW_KEY_NFCT_PROTO_SRC, + FLOW_KEY_NFCT_PROTO_DST, + FLOW_KEY_RTCLASSID, + FLOW_KEY_SKUID, + FLOW_KEY_SKGID, + FLOW_KEY_VLAN_TAG, + FLOW_KEY_RXHASH, + __FLOW_KEY_MAX, +}; + +#define FLOW_KEY_MAX (__FLOW_KEY_MAX - 1) + +enum { + FLOW_MODE_MAP, + FLOW_MODE_HASH, +}; + +enum { + TCA_FLOW_UNSPEC, + TCA_FLOW_KEYS, + TCA_FLOW_MODE, + TCA_FLOW_BASECLASS, + TCA_FLOW_RSHIFT, + TCA_FLOW_ADDEND, + TCA_FLOW_MASK, + TCA_FLOW_XOR, + TCA_FLOW_DIVISOR, + TCA_FLOW_ACT, + TCA_FLOW_POLICE, + TCA_FLOW_EMATCHES, + TCA_FLOW_PERTURB, + __TCA_FLOW_MAX +}; + +#define TCA_FLOW_MAX (__TCA_FLOW_MAX - 1) + +/* Basic filter */ + +enum { + TCA_BASIC_UNSPEC, + TCA_BASIC_CLASSID, + TCA_BASIC_EMATCHES, + TCA_BASIC_ACT, + TCA_BASIC_POLICE, + __TCA_BASIC_MAX +}; + +#define TCA_BASIC_MAX (__TCA_BASIC_MAX - 1) + + +/* Cgroup classifier */ + +enum { + TCA_CGROUP_UNSPEC, + TCA_CGROUP_ACT, + TCA_CGROUP_POLICE, + TCA_CGROUP_EMATCHES, + __TCA_CGROUP_MAX, +}; + +#define TCA_CGROUP_MAX (__TCA_CGROUP_MAX - 1) + +/* BPF classifier */ + +enum { + TCA_BPF_UNSPEC, + TCA_BPF_ACT, + TCA_BPF_POLICE, + TCA_BPF_CLASSID, + TCA_BPF_OPS_LEN, + TCA_BPF_OPS, + __TCA_BPF_MAX, +}; + +#define TCA_BPF_MAX (__TCA_BPF_MAX - 1) + +/* Extended Matches */ + +struct tcf_ematch_tree_hdr { + __u16 nmatches; + __u16 progid; +}; + +enum { + TCA_EMATCH_TREE_UNSPEC, + TCA_EMATCH_TREE_HDR, + TCA_EMATCH_TREE_LIST, + __TCA_EMATCH_TREE_MAX +}; +#define TCA_EMATCH_TREE_MAX (__TCA_EMATCH_TREE_MAX - 1) + +struct tcf_ematch_hdr { + __u16 matchid; + __u16 kind; + __u16 flags; + __u16 pad; /* currently unused */ +}; + +/* 0 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * +-----------------------+-+-+---+ + * | Unused |S|I| R | + * +-----------------------+-+-+---+ + * + * R(2) ::= relation to next ematch + * where: 0 0 END (last ematch) + * 0 1 AND + * 1 0 OR + * 1 1 Unused (invalid) + * I(1) ::= invert result + * S(1) ::= simple payload + */ +#define TCF_EM_REL_END 0 +#define TCF_EM_REL_AND (1<<0) +#define TCF_EM_REL_OR (1<<1) +#define TCF_EM_INVERT (1<<2) +#define TCF_EM_SIMPLE (1<<3) + +#define TCF_EM_REL_MASK 3 +#define TCF_EM_REL_VALID(v) (((v) & TCF_EM_REL_MASK) != TCF_EM_REL_MASK) + +enum { + TCF_LAYER_LINK, + TCF_LAYER_NETWORK, + TCF_LAYER_TRANSPORT, + __TCF_LAYER_MAX +}; +#define TCF_LAYER_MAX (__TCF_LAYER_MAX - 1) + +/* Ematch type assignments + * 1..32767 Reserved for ematches inside kernel tree + * 32768..65535 Free to use, not reliable + */ +#define TCF_EM_CONTAINER 0 +#define TCF_EM_CMP 1 +#define TCF_EM_NBYTE 2 +#define TCF_EM_U32 3 +#define TCF_EM_META 4 +#define TCF_EM_TEXT 5 +#define TCF_EM_VLAN 6 +#define TCF_EM_CANID 7 +#define TCF_EM_IPSET 8 +#define TCF_EM_MAX 8 + +enum { + TCF_EM_PROG_TC +}; + +enum { + TCF_EM_OPND_EQ, + TCF_EM_OPND_GT, + TCF_EM_OPND_LT +}; + +#endif diff --git a/package/gluon-simple-tc/src/include/linux/pkt_sched.h b/package/gluon-simple-tc/src/include/linux/pkt_sched.h new file mode 100644 index 00000000..d62316ba --- /dev/null +++ b/package/gluon-simple-tc/src/include/linux/pkt_sched.h @@ -0,0 +1,846 @@ +#ifndef __LINUX_PKT_SCHED_H +#define __LINUX_PKT_SCHED_H + +#include + +/* Logical priority bands not depending on specific packet scheduler. + Every scheduler will map them to real traffic classes, if it has + no more precise mechanism to classify packets. + + These numbers have no special meaning, though their coincidence + with obsolete IPv6 values is not occasional :-). New IPv6 drafts + preferred full anarchy inspired by diffserv group. + + Note: TC_PRIO_BESTEFFORT does not mean that it is the most unhappy + class, actually, as rule it will be handled with more care than + filler or even bulk. + */ + +#define TC_PRIO_BESTEFFORT 0 +#define TC_PRIO_FILLER 1 +#define TC_PRIO_BULK 2 +#define TC_PRIO_INTERACTIVE_BULK 4 +#define TC_PRIO_INTERACTIVE 6 +#define TC_PRIO_CONTROL 7 + +#define TC_PRIO_MAX 15 + +/* Generic queue statistics, available for all the elements. + Particular schedulers may have also their private records. + */ + +struct tc_stats { + __u64 bytes; /* Number of enqueued bytes */ + __u32 packets; /* Number of enqueued packets */ + __u32 drops; /* Packets dropped because of lack of resources */ + __u32 overlimits; /* Number of throttle events when this + * flow goes out of allocated bandwidth */ + __u32 bps; /* Current flow byte rate */ + __u32 pps; /* Current flow packet rate */ + __u32 qlen; + __u32 backlog; +}; + +struct tc_estimator { + signed char interval; + unsigned char ewma_log; +}; + +/* "Handles" + --------- + + All the traffic control objects have 32bit identifiers, or "handles". + + They can be considered as opaque numbers from user API viewpoint, + but actually they always consist of two fields: major and + minor numbers, which are interpreted by kernel specially, + that may be used by applications, though not recommended. + + F.e. qdisc handles always have minor number equal to zero, + classes (or flows) have major equal to parent qdisc major, and + minor uniquely identifying class inside qdisc. + + Macros to manipulate handles: + */ + +#define TC_H_MAJ_MASK (0xFFFF0000U) +#define TC_H_MIN_MASK (0x0000FFFFU) +#define TC_H_MAJ(h) ((h)&TC_H_MAJ_MASK) +#define TC_H_MIN(h) ((h)&TC_H_MIN_MASK) +#define TC_H_MAKE(maj,min) (((maj)&TC_H_MAJ_MASK)|((min)&TC_H_MIN_MASK)) + +#define TC_H_UNSPEC (0U) +#define TC_H_ROOT (0xFFFFFFFFU) +#define TC_H_INGRESS (0xFFFFFFF1U) + +/* Need to corrospond to iproute2 tc/tc_core.h "enum link_layer" */ +enum tc_link_layer { + TC_LINKLAYER_UNAWARE, /* Indicate unaware old iproute2 util */ + TC_LINKLAYER_ETHERNET, + TC_LINKLAYER_ATM, +}; +#define TC_LINKLAYER_MASK 0x0F /* limit use to lower 4 bits */ + +struct tc_ratespec { + unsigned char cell_log; + __u8 linklayer; /* lower 4 bits */ + unsigned short overhead; + short cell_align; + unsigned short mpu; + __u32 rate; +}; + +#define TC_RTAB_SIZE 1024 + +struct tc_sizespec { + unsigned char cell_log; + unsigned char size_log; + short cell_align; + int overhead; + unsigned int linklayer; + unsigned int mpu; + unsigned int mtu; + unsigned int tsize; +}; + +enum { + TCA_STAB_UNSPEC, + TCA_STAB_BASE, + TCA_STAB_DATA, + __TCA_STAB_MAX +}; + +#define TCA_STAB_MAX (__TCA_STAB_MAX - 1) + +/* FIFO section */ + +struct tc_fifo_qopt { + __u32 limit; /* Queue length: bytes for bfifo, packets for pfifo */ +}; + +/* PRIO section */ + +#define TCQ_PRIO_BANDS 16 +#define TCQ_MIN_PRIO_BANDS 2 + +struct tc_prio_qopt { + int bands; /* Number of bands */ + __u8 priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */ +}; + +/* MULTIQ section */ + +struct tc_multiq_qopt { + __u16 bands; /* Number of bands */ + __u16 max_bands; /* Maximum number of queues */ +}; + +/* PLUG section */ + +#define TCQ_PLUG_BUFFER 0 +#define TCQ_PLUG_RELEASE_ONE 1 +#define TCQ_PLUG_RELEASE_INDEFINITE 2 +#define TCQ_PLUG_LIMIT 3 + +struct tc_plug_qopt { + /* TCQ_PLUG_BUFFER: Inset a plug into the queue and + * buffer any incoming packets + * TCQ_PLUG_RELEASE_ONE: Dequeue packets from queue head + * to beginning of the next plug. + * TCQ_PLUG_RELEASE_INDEFINITE: Dequeue all packets from queue. + * Stop buffering packets until the next TCQ_PLUG_BUFFER + * command is received (just act as a pass-thru queue). + * TCQ_PLUG_LIMIT: Increase/decrease queue size + */ + int action; + __u32 limit; +}; + +/* TBF section */ + +struct tc_tbf_qopt { + struct tc_ratespec rate; + struct tc_ratespec peakrate; + __u32 limit; + __u32 buffer; + __u32 mtu; +}; + +enum { + TCA_TBF_UNSPEC, + TCA_TBF_PARMS, + TCA_TBF_RTAB, + TCA_TBF_PTAB, + TCA_TBF_RATE64, + TCA_TBF_PRATE64, + TCA_TBF_BURST, + TCA_TBF_PBURST, + __TCA_TBF_MAX, +}; + +#define TCA_TBF_MAX (__TCA_TBF_MAX - 1) + + +/* TEQL section */ + +/* TEQL does not require any parameters */ + +/* SFQ section */ + +struct tc_sfq_qopt { + unsigned quantum; /* Bytes per round allocated to flow */ + int perturb_period; /* Period of hash perturbation */ + __u32 limit; /* Maximal packets in queue */ + unsigned divisor; /* Hash divisor */ + unsigned flows; /* Maximal number of flows */ +}; + +struct tc_sfqred_stats { + __u32 prob_drop; /* Early drops, below max threshold */ + __u32 forced_drop; /* Early drops, after max threshold */ + __u32 prob_mark; /* Marked packets, below max threshold */ + __u32 forced_mark; /* Marked packets, after max threshold */ + __u32 prob_mark_head; /* Marked packets, below max threshold */ + __u32 forced_mark_head;/* Marked packets, after max threshold */ +}; + +struct tc_sfq_qopt_v1 { + struct tc_sfq_qopt v0; + unsigned int depth; /* max number of packets per flow */ + unsigned int headdrop; +/* SFQRED parameters */ + __u32 limit; /* HARD maximal flow queue length (bytes) */ + __u32 qth_min; /* Min average length threshold (bytes) */ + __u32 qth_max; /* Max average length threshold (bytes) */ + unsigned char Wlog; /* log(W) */ + unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */ + unsigned char Scell_log; /* cell size for idle damping */ + unsigned char flags; + __u32 max_P; /* probability, high resolution */ +/* SFQRED stats */ + struct tc_sfqred_stats stats; +}; + + +struct tc_sfq_xstats { + __s32 allot; +}; + +/* RED section */ + +enum { + TCA_RED_UNSPEC, + TCA_RED_PARMS, + TCA_RED_STAB, + TCA_RED_MAX_P, + __TCA_RED_MAX, +}; + +#define TCA_RED_MAX (__TCA_RED_MAX - 1) + +struct tc_red_qopt { + __u32 limit; /* HARD maximal queue length (bytes) */ + __u32 qth_min; /* Min average length threshold (bytes) */ + __u32 qth_max; /* Max average length threshold (bytes) */ + unsigned char Wlog; /* log(W) */ + unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */ + unsigned char Scell_log; /* cell size for idle damping */ + unsigned char flags; +#define TC_RED_ECN 1 +#define TC_RED_HARDDROP 2 +#define TC_RED_ADAPTATIVE 4 +}; + +struct tc_red_xstats { + __u32 early; /* Early drops */ + __u32 pdrop; /* Drops due to queue limits */ + __u32 other; /* Drops due to drop() calls */ + __u32 marked; /* Marked packets */ +}; + +/* GRED section */ + +#define MAX_DPs 16 + +enum { + TCA_GRED_UNSPEC, + TCA_GRED_PARMS, + TCA_GRED_STAB, + TCA_GRED_DPS, + TCA_GRED_MAX_P, + __TCA_GRED_MAX, +}; + +#define TCA_GRED_MAX (__TCA_GRED_MAX - 1) + +struct tc_gred_qopt { + __u32 limit; /* HARD maximal queue length (bytes) */ + __u32 qth_min; /* Min average length threshold (bytes) */ + __u32 qth_max; /* Max average length threshold (bytes) */ + __u32 DP; /* up to 2^32 DPs */ + __u32 backlog; + __u32 qave; + __u32 forced; + __u32 early; + __u32 other; + __u32 pdrop; + __u8 Wlog; /* log(W) */ + __u8 Plog; /* log(P_max/(qth_max-qth_min)) */ + __u8 Scell_log; /* cell size for idle damping */ + __u8 prio; /* prio of this VQ */ + __u32 packets; + __u32 bytesin; +}; + +/* gred setup */ +struct tc_gred_sopt { + __u32 DPs; + __u32 def_DP; + __u8 grio; + __u8 flags; + __u16 pad1; +}; + +/* CHOKe section */ + +enum { + TCA_CHOKE_UNSPEC, + TCA_CHOKE_PARMS, + TCA_CHOKE_STAB, + TCA_CHOKE_MAX_P, + __TCA_CHOKE_MAX, +}; + +#define TCA_CHOKE_MAX (__TCA_CHOKE_MAX - 1) + +struct tc_choke_qopt { + __u32 limit; /* Hard queue length (packets) */ + __u32 qth_min; /* Min average threshold (packets) */ + __u32 qth_max; /* Max average threshold (packets) */ + unsigned char Wlog; /* log(W) */ + unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */ + unsigned char Scell_log; /* cell size for idle damping */ + unsigned char flags; /* see RED flags */ +}; + +struct tc_choke_xstats { + __u32 early; /* Early drops */ + __u32 pdrop; /* Drops due to queue limits */ + __u32 other; /* Drops due to drop() calls */ + __u32 marked; /* Marked packets */ + __u32 matched; /* Drops due to flow match */ +}; + +/* HTB section */ +#define TC_HTB_NUMPRIO 8 +#define TC_HTB_MAXDEPTH 8 +#define TC_HTB_PROTOVER 3 /* the same as HTB and TC's major */ + +struct tc_htb_opt { + struct tc_ratespec rate; + struct tc_ratespec ceil; + __u32 buffer; + __u32 cbuffer; + __u32 quantum; + __u32 level; /* out only */ + __u32 prio; +}; +struct tc_htb_glob { + __u32 version; /* to match HTB/TC */ + __u32 rate2quantum; /* bps->quantum divisor */ + __u32 defcls; /* default class number */ + __u32 debug; /* debug flags */ + + /* stats */ + __u32 direct_pkts; /* count of non shaped packets */ +}; +enum { + TCA_HTB_UNSPEC, + TCA_HTB_PARMS, + TCA_HTB_INIT, + TCA_HTB_CTAB, + TCA_HTB_RTAB, + TCA_HTB_DIRECT_QLEN, + TCA_HTB_RATE64, + TCA_HTB_CEIL64, + __TCA_HTB_MAX, +}; + +#define TCA_HTB_MAX (__TCA_HTB_MAX - 1) + +struct tc_htb_xstats { + __u32 lends; + __u32 borrows; + __u32 giants; /* too big packets (rate will not be accurate) */ + __u32 tokens; + __u32 ctokens; +}; + +/* HFSC section */ + +struct tc_hfsc_qopt { + __u16 defcls; /* default class */ +}; + +struct tc_service_curve { + __u32 m1; /* slope of the first segment in bps */ + __u32 d; /* x-projection of the first segment in us */ + __u32 m2; /* slope of the second segment in bps */ +}; + +struct tc_hfsc_stats { + __u64 work; /* total work done */ + __u64 rtwork; /* work done by real-time criteria */ + __u32 period; /* current period */ + __u32 level; /* class level in hierarchy */ +}; + +enum { + TCA_HFSC_UNSPEC, + TCA_HFSC_RSC, + TCA_HFSC_FSC, + TCA_HFSC_USC, + __TCA_HFSC_MAX, +}; + +#define TCA_HFSC_MAX (__TCA_HFSC_MAX - 1) + + +/* CBQ section */ + +#define TC_CBQ_MAXPRIO 8 +#define TC_CBQ_MAXLEVEL 8 +#define TC_CBQ_DEF_EWMA 5 + +struct tc_cbq_lssopt { + unsigned char change; + unsigned char flags; +#define TCF_CBQ_LSS_BOUNDED 1 +#define TCF_CBQ_LSS_ISOLATED 2 + unsigned char ewma_log; + unsigned char level; +#define TCF_CBQ_LSS_FLAGS 1 +#define TCF_CBQ_LSS_EWMA 2 +#define TCF_CBQ_LSS_MAXIDLE 4 +#define TCF_CBQ_LSS_MINIDLE 8 +#define TCF_CBQ_LSS_OFFTIME 0x10 +#define TCF_CBQ_LSS_AVPKT 0x20 + __u32 maxidle; + __u32 minidle; + __u32 offtime; + __u32 avpkt; +}; + +struct tc_cbq_wrropt { + unsigned char flags; + unsigned char priority; + unsigned char cpriority; + unsigned char __reserved; + __u32 allot; + __u32 weight; +}; + +struct tc_cbq_ovl { + unsigned char strategy; +#define TC_CBQ_OVL_CLASSIC 0 +#define TC_CBQ_OVL_DELAY 1 +#define TC_CBQ_OVL_LOWPRIO 2 +#define TC_CBQ_OVL_DROP 3 +#define TC_CBQ_OVL_RCLASSIC 4 + unsigned char priority2; + __u16 pad; + __u32 penalty; +}; + +struct tc_cbq_police { + unsigned char police; + unsigned char __res1; + unsigned short __res2; +}; + +struct tc_cbq_fopt { + __u32 split; + __u32 defmap; + __u32 defchange; +}; + +struct tc_cbq_xstats { + __u32 borrows; + __u32 overactions; + __s32 avgidle; + __s32 undertime; +}; + +enum { + TCA_CBQ_UNSPEC, + TCA_CBQ_LSSOPT, + TCA_CBQ_WRROPT, + TCA_CBQ_FOPT, + TCA_CBQ_OVL_STRATEGY, + TCA_CBQ_RATE, + TCA_CBQ_RTAB, + TCA_CBQ_POLICE, + __TCA_CBQ_MAX, +}; + +#define TCA_CBQ_MAX (__TCA_CBQ_MAX - 1) + +/* dsmark section */ + +enum { + TCA_DSMARK_UNSPEC, + TCA_DSMARK_INDICES, + TCA_DSMARK_DEFAULT_INDEX, + TCA_DSMARK_SET_TC_INDEX, + TCA_DSMARK_MASK, + TCA_DSMARK_VALUE, + __TCA_DSMARK_MAX, +}; + +#define TCA_DSMARK_MAX (__TCA_DSMARK_MAX - 1) + +/* ATM section */ + +enum { + TCA_ATM_UNSPEC, + TCA_ATM_FD, /* file/socket descriptor */ + TCA_ATM_PTR, /* pointer to descriptor - later */ + TCA_ATM_HDR, /* LL header */ + TCA_ATM_EXCESS, /* excess traffic class (0 for CLP) */ + TCA_ATM_ADDR, /* PVC address (for output only) */ + TCA_ATM_STATE, /* VC state (ATM_VS_*; for output only) */ + __TCA_ATM_MAX, +}; + +#define TCA_ATM_MAX (__TCA_ATM_MAX - 1) + +/* Network emulator */ + +enum { + TCA_NETEM_UNSPEC, + TCA_NETEM_CORR, + TCA_NETEM_DELAY_DIST, + TCA_NETEM_REORDER, + TCA_NETEM_CORRUPT, + TCA_NETEM_LOSS, + TCA_NETEM_RATE, + TCA_NETEM_ECN, + TCA_NETEM_RATE64, + __TCA_NETEM_MAX, +}; + +#define TCA_NETEM_MAX (__TCA_NETEM_MAX - 1) + +struct tc_netem_qopt { + __u32 latency; /* added delay (us) */ + __u32 limit; /* fifo limit (packets) */ + __u32 loss; /* random packet loss (0=none ~0=100%) */ + __u32 gap; /* re-ordering gap (0 for none) */ + __u32 duplicate; /* random packet dup (0=none ~0=100%) */ + __u32 jitter; /* random jitter in latency (us) */ +}; + +struct tc_netem_corr { + __u32 delay_corr; /* delay correlation */ + __u32 loss_corr; /* packet loss correlation */ + __u32 dup_corr; /* duplicate correlation */ +}; + +struct tc_netem_reorder { + __u32 probability; + __u32 correlation; +}; + +struct tc_netem_corrupt { + __u32 probability; + __u32 correlation; +}; + +struct tc_netem_rate { + __u32 rate; /* byte/s */ + __s32 packet_overhead; + __u32 cell_size; + __s32 cell_overhead; +}; + +enum { + NETEM_LOSS_UNSPEC, + NETEM_LOSS_GI, /* General Intuitive - 4 state model */ + NETEM_LOSS_GE, /* Gilbert Elliot models */ + __NETEM_LOSS_MAX +}; +#define NETEM_LOSS_MAX (__NETEM_LOSS_MAX - 1) + +/* State transition probabilities for 4 state model */ +struct tc_netem_gimodel { + __u32 p13; + __u32 p31; + __u32 p32; + __u32 p14; + __u32 p23; +}; + +/* Gilbert-Elliot models */ +struct tc_netem_gemodel { + __u32 p; + __u32 r; + __u32 h; + __u32 k1; +}; + +#define NETEM_DIST_SCALE 8192 +#define NETEM_DIST_MAX 16384 + +/* DRR */ + +enum { + TCA_DRR_UNSPEC, + TCA_DRR_QUANTUM, + __TCA_DRR_MAX +}; + +#define TCA_DRR_MAX (__TCA_DRR_MAX - 1) + +struct tc_drr_stats { + __u32 deficit; +}; + +/* MQPRIO */ +#define TC_QOPT_BITMASK 15 +#define TC_QOPT_MAX_QUEUE 16 + +struct tc_mqprio_qopt { + __u8 num_tc; + __u8 prio_tc_map[TC_QOPT_BITMASK + 1]; + __u8 hw; + __u16 count[TC_QOPT_MAX_QUEUE]; + __u16 offset[TC_QOPT_MAX_QUEUE]; +}; + +/* SFB */ + +enum { + TCA_SFB_UNSPEC, + TCA_SFB_PARMS, + __TCA_SFB_MAX, +}; + +#define TCA_SFB_MAX (__TCA_SFB_MAX - 1) + +/* + * Note: increment, decrement are Q0.16 fixed-point values. + */ +struct tc_sfb_qopt { + __u32 rehash_interval; /* delay between hash move, in ms */ + __u32 warmup_time; /* double buffering warmup time in ms (warmup_time < rehash_interval) */ + __u32 max; /* max len of qlen_min */ + __u32 bin_size; /* maximum queue length per bin */ + __u32 increment; /* probability increment, (d1 in Blue) */ + __u32 decrement; /* probability decrement, (d2 in Blue) */ + __u32 limit; /* max SFB queue length */ + __u32 penalty_rate; /* inelastic flows are rate limited to 'rate' pps */ + __u32 penalty_burst; +}; + +struct tc_sfb_xstats { + __u32 earlydrop; + __u32 penaltydrop; + __u32 bucketdrop; + __u32 queuedrop; + __u32 childdrop; /* drops in child qdisc */ + __u32 marked; + __u32 maxqlen; + __u32 maxprob; + __u32 avgprob; +}; + +#define SFB_MAX_PROB 0xFFFF + +/* QFQ */ +enum { + TCA_QFQ_UNSPEC, + TCA_QFQ_WEIGHT, + TCA_QFQ_LMAX, + __TCA_QFQ_MAX +}; + +#define TCA_QFQ_MAX (__TCA_QFQ_MAX - 1) + +struct tc_qfq_stats { + __u32 weight; + __u32 lmax; +}; + +/* CODEL */ + +enum { + TCA_CODEL_UNSPEC, + TCA_CODEL_TARGET, + TCA_CODEL_LIMIT, + TCA_CODEL_INTERVAL, + TCA_CODEL_ECN, + __TCA_CODEL_MAX +}; + +#define TCA_CODEL_MAX (__TCA_CODEL_MAX - 1) + +struct tc_codel_xstats { + __u32 maxpacket; /* largest packet we've seen so far */ + __u32 count; /* how many drops we've done since the last time we + * entered dropping state + */ + __u32 lastcount; /* count at entry to dropping state */ + __u32 ldelay; /* in-queue delay seen by most recently dequeued packet */ + __s32 drop_next; /* time to drop next packet */ + __u32 drop_overlimit; /* number of time max qdisc packet limit was hit */ + __u32 ecn_mark; /* number of packets we ECN marked instead of dropped */ + __u32 dropping; /* are we in dropping state ? */ +}; + +/* FQ_CODEL */ + +enum { + TCA_FQ_CODEL_UNSPEC, + TCA_FQ_CODEL_TARGET, + TCA_FQ_CODEL_LIMIT, + TCA_FQ_CODEL_INTERVAL, + TCA_FQ_CODEL_ECN, + TCA_FQ_CODEL_FLOWS, + TCA_FQ_CODEL_QUANTUM, + __TCA_FQ_CODEL_MAX +}; + +#define TCA_FQ_CODEL_MAX (__TCA_FQ_CODEL_MAX - 1) + +enum { + TCA_FQ_CODEL_XSTATS_QDISC, + TCA_FQ_CODEL_XSTATS_CLASS, +}; + +struct tc_fq_codel_qd_stats { + __u32 maxpacket; /* largest packet we've seen so far */ + __u32 drop_overlimit; /* number of time max qdisc + * packet limit was hit + */ + __u32 ecn_mark; /* number of packets we ECN marked + * instead of being dropped + */ + __u32 new_flow_count; /* number of time packets + * created a 'new flow' + */ + __u32 new_flows_len; /* count of flows in new list */ + __u32 old_flows_len; /* count of flows in old list */ +}; + +struct tc_fq_codel_cl_stats { + __s32 deficit; + __u32 ldelay; /* in-queue delay seen by most recently + * dequeued packet + */ + __u32 count; + __u32 lastcount; + __u32 dropping; + __s32 drop_next; +}; + +struct tc_fq_codel_xstats { + __u32 type; + union { + struct tc_fq_codel_qd_stats qdisc_stats; + struct tc_fq_codel_cl_stats class_stats; + }; +}; + +/* FQ */ + +enum { + TCA_FQ_UNSPEC, + + TCA_FQ_PLIMIT, /* limit of total number of packets in queue */ + + TCA_FQ_FLOW_PLIMIT, /* limit of packets per flow */ + + TCA_FQ_QUANTUM, /* RR quantum */ + + TCA_FQ_INITIAL_QUANTUM, /* RR quantum for new flow */ + + TCA_FQ_RATE_ENABLE, /* enable/disable rate limiting */ + + TCA_FQ_FLOW_DEFAULT_RATE,/* obsolete, do not use */ + + TCA_FQ_FLOW_MAX_RATE, /* per flow max rate */ + + TCA_FQ_BUCKETS_LOG, /* log2(number of buckets) */ + + TCA_FQ_FLOW_REFILL_DELAY, /* flow credit refill delay in usec */ + + __TCA_FQ_MAX +}; + +#define TCA_FQ_MAX (__TCA_FQ_MAX - 1) + +struct tc_fq_qd_stats { + __u64 gc_flows; + __u64 highprio_packets; + __u64 tcp_retrans; + __u64 throttled; + __u64 flows_plimit; + __u64 pkts_too_long; + __u64 allocation_errors; + __s64 time_next_delayed_flow; + __u32 flows; + __u32 inactive_flows; + __u32 throttled_flows; + __u32 pad; +}; + +/* Heavy-Hitter Filter */ + +enum { + TCA_HHF_UNSPEC, + TCA_HHF_BACKLOG_LIMIT, + TCA_HHF_QUANTUM, + TCA_HHF_HH_FLOWS_LIMIT, + TCA_HHF_RESET_TIMEOUT, + TCA_HHF_ADMIT_BYTES, + TCA_HHF_EVICT_TIMEOUT, + TCA_HHF_NON_HH_WEIGHT, + __TCA_HHF_MAX +}; + +#define TCA_HHF_MAX (__TCA_HHF_MAX - 1) + +struct tc_hhf_xstats { + __u32 drop_overlimit; /* number of times max qdisc packet limit + * was hit + */ + __u32 hh_overlimit; /* number of times max heavy-hitters was hit */ + __u32 hh_tot_count; /* number of captured heavy-hitters so far */ + __u32 hh_cur_count; /* number of current heavy-hitters */ +}; + +/* PIE */ +enum { + TCA_PIE_UNSPEC, + TCA_PIE_TARGET, + TCA_PIE_LIMIT, + TCA_PIE_TUPDATE, + TCA_PIE_ALPHA, + TCA_PIE_BETA, + TCA_PIE_ECN, + TCA_PIE_BYTEMODE, + __TCA_PIE_MAX +}; +#define TCA_PIE_MAX (__TCA_PIE_MAX - 1) + +struct tc_pie_xstats { + __u32 prob; /* current probability */ + __u32 delay; /* current delay in ms */ + __u32 avg_dq_rate; /* current average dq_rate in bits/pie_time */ + __u32 packets_in; /* total number of packets enqueued */ + __u32 dropped; /* packets dropped due to pie_action */ + __u32 overlimit; /* dropped due to lack of space in queue */ + __u32 maxq; /* maximum queue size */ + __u32 ecn_mark; /* packets marked with ecn*/ +}; +#endif diff --git a/package/gluon-simple-tc/src/include/linux/rtnetlink.h b/package/gluon-simple-tc/src/include/linux/rtnetlink.h new file mode 100644 index 00000000..248fdd3f --- /dev/null +++ b/package/gluon-simple-tc/src/include/linux/rtnetlink.h @@ -0,0 +1,639 @@ +#ifndef __LINUX_RTNETLINK_H +#define __LINUX_RTNETLINK_H + +#include +#include +#include +#include +#include + +/* rtnetlink families. Values up to 127 are reserved for real address + * families, values above 128 may be used arbitrarily. + */ +#define RTNL_FAMILY_IPMR 128 +#define RTNL_FAMILY_IP6MR 129 +#define RTNL_FAMILY_MAX 129 + +/**** + * Routing/neighbour discovery messages. + ****/ + +/* Types of messages */ + +enum { + RTM_BASE = 16, +#define RTM_BASE RTM_BASE + + RTM_NEWLINK = 16, +#define RTM_NEWLINK RTM_NEWLINK + RTM_DELLINK, +#define RTM_DELLINK RTM_DELLINK + RTM_GETLINK, +#define RTM_GETLINK RTM_GETLINK + RTM_SETLINK, +#define RTM_SETLINK RTM_SETLINK + + RTM_NEWADDR = 20, +#define RTM_NEWADDR RTM_NEWADDR + RTM_DELADDR, +#define RTM_DELADDR RTM_DELADDR + RTM_GETADDR, +#define RTM_GETADDR RTM_GETADDR + + RTM_NEWROUTE = 24, +#define RTM_NEWROUTE RTM_NEWROUTE + RTM_DELROUTE, +#define RTM_DELROUTE RTM_DELROUTE + RTM_GETROUTE, +#define RTM_GETROUTE RTM_GETROUTE + + RTM_NEWNEIGH = 28, +#define RTM_NEWNEIGH RTM_NEWNEIGH + RTM_DELNEIGH, +#define RTM_DELNEIGH RTM_DELNEIGH + RTM_GETNEIGH, +#define RTM_GETNEIGH RTM_GETNEIGH + + RTM_NEWRULE = 32, +#define RTM_NEWRULE RTM_NEWRULE + RTM_DELRULE, +#define RTM_DELRULE RTM_DELRULE + RTM_GETRULE, +#define RTM_GETRULE RTM_GETRULE + + RTM_NEWQDISC = 36, +#define RTM_NEWQDISC RTM_NEWQDISC + RTM_DELQDISC, +#define RTM_DELQDISC RTM_DELQDISC + RTM_GETQDISC, +#define RTM_GETQDISC RTM_GETQDISC + + RTM_NEWTCLASS = 40, +#define RTM_NEWTCLASS RTM_NEWTCLASS + RTM_DELTCLASS, +#define RTM_DELTCLASS RTM_DELTCLASS + RTM_GETTCLASS, +#define RTM_GETTCLASS RTM_GETTCLASS + + RTM_NEWTFILTER = 44, +#define RTM_NEWTFILTER RTM_NEWTFILTER + RTM_DELTFILTER, +#define RTM_DELTFILTER RTM_DELTFILTER + RTM_GETTFILTER, +#define RTM_GETTFILTER RTM_GETTFILTER + + RTM_NEWACTION = 48, +#define RTM_NEWACTION RTM_NEWACTION + RTM_DELACTION, +#define RTM_DELACTION RTM_DELACTION + RTM_GETACTION, +#define RTM_GETACTION RTM_GETACTION + + RTM_NEWPREFIX = 52, +#define RTM_NEWPREFIX RTM_NEWPREFIX + + RTM_GETMULTICAST = 58, +#define RTM_GETMULTICAST RTM_GETMULTICAST + + RTM_GETANYCAST = 62, +#define RTM_GETANYCAST RTM_GETANYCAST + + RTM_NEWNEIGHTBL = 64, +#define RTM_NEWNEIGHTBL RTM_NEWNEIGHTBL + RTM_GETNEIGHTBL = 66, +#define RTM_GETNEIGHTBL RTM_GETNEIGHTBL + RTM_SETNEIGHTBL, +#define RTM_SETNEIGHTBL RTM_SETNEIGHTBL + + RTM_NEWNDUSEROPT = 68, +#define RTM_NEWNDUSEROPT RTM_NEWNDUSEROPT + + RTM_NEWADDRLABEL = 72, +#define RTM_NEWADDRLABEL RTM_NEWADDRLABEL + RTM_DELADDRLABEL, +#define RTM_DELADDRLABEL RTM_DELADDRLABEL + RTM_GETADDRLABEL, +#define RTM_GETADDRLABEL RTM_GETADDRLABEL + + RTM_GETDCB = 78, +#define RTM_GETDCB RTM_GETDCB + RTM_SETDCB, +#define RTM_SETDCB RTM_SETDCB + + RTM_NEWNETCONF = 80, +#define RTM_NEWNETCONF RTM_NEWNETCONF + RTM_GETNETCONF = 82, +#define RTM_GETNETCONF RTM_GETNETCONF + + RTM_NEWMDB = 84, +#define RTM_NEWMDB RTM_NEWMDB + RTM_DELMDB = 85, +#define RTM_DELMDB RTM_DELMDB + RTM_GETMDB = 86, +#define RTM_GETMDB RTM_GETMDB + + __RTM_MAX, +#define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) +}; + +#define RTM_NR_MSGTYPES (RTM_MAX + 1 - RTM_BASE) +#define RTM_NR_FAMILIES (RTM_NR_MSGTYPES >> 2) +#define RTM_FAM(cmd) (((cmd) - RTM_BASE) >> 2) + +/* + Generic structure for encapsulation of optional route information. + It is reminiscent of sockaddr, but with sa_family replaced + with attribute type. + */ + +struct rtattr { + unsigned short rta_len; + unsigned short rta_type; +}; + +/* Macros to handle rtattributes */ + +#define RTA_ALIGNTO 4 +#define RTA_ALIGN(len) ( ((len)+RTA_ALIGNTO-1) & ~(RTA_ALIGNTO-1) ) +#define RTA_OK(rta,len) ((len) >= (int)sizeof(struct rtattr) && \ + (rta)->rta_len >= sizeof(struct rtattr) && \ + (rta)->rta_len <= (len)) +#define RTA_NEXT(rta,attrlen) ((attrlen) -= RTA_ALIGN((rta)->rta_len), \ + (struct rtattr*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len))) +#define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len)) +#define RTA_SPACE(len) RTA_ALIGN(RTA_LENGTH(len)) +#define RTA_DATA(rta) ((void*)(((char*)(rta)) + RTA_LENGTH(0))) +#define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0)) + + + + +/****************************************************************************** + * Definitions used in routing table administration. + ****/ + +struct rtmsg { + unsigned char rtm_family; + unsigned char rtm_dst_len; + unsigned char rtm_src_len; + unsigned char rtm_tos; + + unsigned char rtm_table; /* Routing table id */ + unsigned char rtm_protocol; /* Routing protocol; see below */ + unsigned char rtm_scope; /* See below */ + unsigned char rtm_type; /* See below */ + + unsigned rtm_flags; +}; + +/* rtm_type */ + +enum { + RTN_UNSPEC, + RTN_UNICAST, /* Gateway or direct route */ + RTN_LOCAL, /* Accept locally */ + RTN_BROADCAST, /* Accept locally as broadcast, + send as broadcast */ + RTN_ANYCAST, /* Accept locally as broadcast, + but send as unicast */ + RTN_MULTICAST, /* Multicast route */ + RTN_BLACKHOLE, /* Drop */ + RTN_UNREACHABLE, /* Destination is unreachable */ + RTN_PROHIBIT, /* Administratively prohibited */ + RTN_THROW, /* Not in this table */ + RTN_NAT, /* Translate this address */ + RTN_XRESOLVE, /* Use external resolver */ + __RTN_MAX +}; + +#define RTN_MAX (__RTN_MAX - 1) + + +/* rtm_protocol */ + +#define RTPROT_UNSPEC 0 +#define RTPROT_REDIRECT 1 /* Route installed by ICMP redirects; + not used by current IPv4 */ +#define RTPROT_KERNEL 2 /* Route installed by kernel */ +#define RTPROT_BOOT 3 /* Route installed during boot */ +#define RTPROT_STATIC 4 /* Route installed by administrator */ + +/* Values of protocol >= RTPROT_STATIC are not interpreted by kernel; + they are just passed from user and back as is. + It will be used by hypothetical multiple routing daemons. + Note that protocol values should be standardized in order to + avoid conflicts. + */ + +#define RTPROT_GATED 8 /* Apparently, GateD */ +#define RTPROT_RA 9 /* RDISC/ND router advertisements */ +#define RTPROT_MRT 10 /* Merit MRT */ +#define RTPROT_ZEBRA 11 /* Zebra */ +#define RTPROT_BIRD 12 /* BIRD */ +#define RTPROT_DNROUTED 13 /* DECnet routing daemon */ +#define RTPROT_XORP 14 /* XORP */ +#define RTPROT_NTK 15 /* Netsukuku */ +#define RTPROT_DHCP 16 /* DHCP client */ +#define RTPROT_MROUTED 17 /* Multicast daemon */ + +/* rtm_scope + + Really it is not scope, but sort of distance to the destination. + NOWHERE are reserved for not existing destinations, HOST is our + local addresses, LINK are destinations, located on directly attached + link and UNIVERSE is everywhere in the Universe. + + Intermediate values are also possible f.e. interior routes + could be assigned a value between UNIVERSE and LINK. +*/ + +enum rt_scope_t { + RT_SCOPE_UNIVERSE=0, +/* User defined values */ + RT_SCOPE_SITE=200, + RT_SCOPE_LINK=253, + RT_SCOPE_HOST=254, + RT_SCOPE_NOWHERE=255 +}; + +/* rtm_flags */ + +#define RTM_F_NOTIFY 0x100 /* Notify user of route change */ +#define RTM_F_CLONED 0x200 /* This route is cloned */ +#define RTM_F_EQUALIZE 0x400 /* Multipath equalizer: NI */ +#define RTM_F_PREFIX 0x800 /* Prefix addresses */ + +/* Reserved table identifiers */ + +enum rt_class_t { + RT_TABLE_UNSPEC=0, +/* User defined values */ + RT_TABLE_COMPAT=252, + RT_TABLE_DEFAULT=253, + RT_TABLE_MAIN=254, + RT_TABLE_LOCAL=255, + RT_TABLE_MAX=0xFFFFFFFF +}; + + +/* Routing message attributes */ + +enum rtattr_type_t { + RTA_UNSPEC, + RTA_DST, + RTA_SRC, + RTA_IIF, + RTA_OIF, + RTA_GATEWAY, + RTA_PRIORITY, + RTA_PREFSRC, + RTA_METRICS, + RTA_MULTIPATH, + RTA_PROTOINFO, /* no longer used */ + RTA_FLOW, + RTA_CACHEINFO, + RTA_SESSION, /* no longer used */ + RTA_MP_ALGO, /* no longer used */ + RTA_TABLE, + RTA_MARK, + RTA_MFC_STATS, + __RTA_MAX +}; + +#define RTA_MAX (__RTA_MAX - 1) + +#define RTM_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct rtmsg)))) +#define RTM_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct rtmsg)) + +/* RTM_MULTIPATH --- array of struct rtnexthop. + * + * "struct rtnexthop" describes all necessary nexthop information, + * i.e. parameters of path to a destination via this nexthop. + * + * At the moment it is impossible to set different prefsrc, mtu, window + * and rtt for different paths from multipath. + */ + +struct rtnexthop { + unsigned short rtnh_len; + unsigned char rtnh_flags; + unsigned char rtnh_hops; + int rtnh_ifindex; +}; + +/* rtnh_flags */ + +#define RTNH_F_DEAD 1 /* Nexthop is dead (used by multipath) */ +#define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */ +#define RTNH_F_ONLINK 4 /* Gateway is forced on link */ + +/* Macros to handle hexthops */ + +#define RTNH_ALIGNTO 4 +#define RTNH_ALIGN(len) ( ((len)+RTNH_ALIGNTO-1) & ~(RTNH_ALIGNTO-1) ) +#define RTNH_OK(rtnh,len) ((rtnh)->rtnh_len >= sizeof(struct rtnexthop) && \ + ((int)(rtnh)->rtnh_len) <= (len)) +#define RTNH_NEXT(rtnh) ((struct rtnexthop*)(((char*)(rtnh)) + RTNH_ALIGN((rtnh)->rtnh_len))) +#define RTNH_LENGTH(len) (RTNH_ALIGN(sizeof(struct rtnexthop)) + (len)) +#define RTNH_SPACE(len) RTNH_ALIGN(RTNH_LENGTH(len)) +#define RTNH_DATA(rtnh) ((struct rtattr*)(((char*)(rtnh)) + RTNH_LENGTH(0))) + +/* RTM_CACHEINFO */ + +struct rta_cacheinfo { + __u32 rta_clntref; + __u32 rta_lastuse; + __s32 rta_expires; + __u32 rta_error; + __u32 rta_used; + +#define RTNETLINK_HAVE_PEERINFO 1 + __u32 rta_id; + __u32 rta_ts; + __u32 rta_tsage; +}; + +/* RTM_METRICS --- array of struct rtattr with types of RTAX_* */ + +enum { + RTAX_UNSPEC, +#define RTAX_UNSPEC RTAX_UNSPEC + RTAX_LOCK, +#define RTAX_LOCK RTAX_LOCK + RTAX_MTU, +#define RTAX_MTU RTAX_MTU + RTAX_WINDOW, +#define RTAX_WINDOW RTAX_WINDOW + RTAX_RTT, +#define RTAX_RTT RTAX_RTT + RTAX_RTTVAR, +#define RTAX_RTTVAR RTAX_RTTVAR + RTAX_SSTHRESH, +#define RTAX_SSTHRESH RTAX_SSTHRESH + RTAX_CWND, +#define RTAX_CWND RTAX_CWND + RTAX_ADVMSS, +#define RTAX_ADVMSS RTAX_ADVMSS + RTAX_REORDERING, +#define RTAX_REORDERING RTAX_REORDERING + RTAX_HOPLIMIT, +#define RTAX_HOPLIMIT RTAX_HOPLIMIT + RTAX_INITCWND, +#define RTAX_INITCWND RTAX_INITCWND + RTAX_FEATURES, +#define RTAX_FEATURES RTAX_FEATURES + RTAX_RTO_MIN, +#define RTAX_RTO_MIN RTAX_RTO_MIN + RTAX_INITRWND, +#define RTAX_INITRWND RTAX_INITRWND + RTAX_QUICKACK, +#define RTAX_QUICKACK RTAX_QUICKACK + __RTAX_MAX +}; + +#define RTAX_MAX (__RTAX_MAX - 1) + +#define RTAX_FEATURE_ECN 0x00000001 +#define RTAX_FEATURE_SACK 0x00000002 +#define RTAX_FEATURE_TIMESTAMP 0x00000004 +#define RTAX_FEATURE_ALLFRAG 0x00000008 + +struct rta_session { + __u8 proto; + __u8 pad1; + __u16 pad2; + + union { + struct { + __u16 sport; + __u16 dport; + } ports; + + struct { + __u8 type; + __u8 code; + __u16 ident; + } icmpt; + + __u32 spi; + } u; +}; + +struct rta_mfc_stats { + __u64 mfcs_packets; + __u64 mfcs_bytes; + __u64 mfcs_wrong_if; +}; + +/**** + * General form of address family dependent message. + ****/ + +struct rtgenmsg { + unsigned char rtgen_family; +}; + +/***************************************************************** + * Link layer specific messages. + ****/ + +/* struct ifinfomsg + * passes link level specific information, not dependent + * on network protocol. + */ + +struct ifinfomsg { + unsigned char ifi_family; + unsigned char __ifi_pad; + unsigned short ifi_type; /* ARPHRD_* */ + int ifi_index; /* Link index */ + unsigned ifi_flags; /* IFF_* flags */ + unsigned ifi_change; /* IFF_* change mask */ +}; + +/******************************************************************** + * prefix information + ****/ + +struct prefixmsg { + unsigned char prefix_family; + unsigned char prefix_pad1; + unsigned short prefix_pad2; + int prefix_ifindex; + unsigned char prefix_type; + unsigned char prefix_len; + unsigned char prefix_flags; + unsigned char prefix_pad3; +}; + +enum +{ + PREFIX_UNSPEC, + PREFIX_ADDRESS, + PREFIX_CACHEINFO, + __PREFIX_MAX +}; + +#define PREFIX_MAX (__PREFIX_MAX - 1) + +struct prefix_cacheinfo { + __u32 preferred_time; + __u32 valid_time; +}; + + +/***************************************************************** + * Traffic control messages. + ****/ + +struct tcmsg { + unsigned char tcm_family; + unsigned char tcm__pad1; + unsigned short tcm__pad2; + int tcm_ifindex; + __u32 tcm_handle; + __u32 tcm_parent; + __u32 tcm_info; +}; + +enum { + TCA_UNSPEC, + TCA_KIND, + TCA_OPTIONS, + TCA_STATS, + TCA_XSTATS, + TCA_RATE, + TCA_FCNT, + TCA_STATS2, + TCA_STAB, + __TCA_MAX +}; + +#define TCA_MAX (__TCA_MAX - 1) + +#define TCA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcmsg)))) +#define TCA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcmsg)) + +/******************************************************************** + * Neighbor Discovery userland options + ****/ + +struct nduseroptmsg { + unsigned char nduseropt_family; + unsigned char nduseropt_pad1; + unsigned short nduseropt_opts_len; /* Total length of options */ + int nduseropt_ifindex; + __u8 nduseropt_icmp_type; + __u8 nduseropt_icmp_code; + unsigned short nduseropt_pad2; + unsigned int nduseropt_pad3; + /* Followed by one or more ND options */ +}; + +enum { + NDUSEROPT_UNSPEC, + NDUSEROPT_SRCADDR, + __NDUSEROPT_MAX +}; + +#define NDUSEROPT_MAX (__NDUSEROPT_MAX - 1) + +/* RTnetlink multicast groups - backwards compatibility for userspace */ +#define RTMGRP_LINK 1 +#define RTMGRP_NOTIFY 2 +#define RTMGRP_NEIGH 4 +#define RTMGRP_TC 8 + +#define RTMGRP_IPV4_IFADDR 0x10 +#define RTMGRP_IPV4_MROUTE 0x20 +#define RTMGRP_IPV4_ROUTE 0x40 +#define RTMGRP_IPV4_RULE 0x80 + +#define RTMGRP_IPV6_IFADDR 0x100 +#define RTMGRP_IPV6_MROUTE 0x200 +#define RTMGRP_IPV6_ROUTE 0x400 +#define RTMGRP_IPV6_IFINFO 0x800 + +#define RTMGRP_DECnet_IFADDR 0x1000 +#define RTMGRP_DECnet_ROUTE 0x4000 + +#define RTMGRP_IPV6_PREFIX 0x20000 + +/* RTnetlink multicast groups */ +enum rtnetlink_groups { + RTNLGRP_NONE, +#define RTNLGRP_NONE RTNLGRP_NONE + RTNLGRP_LINK, +#define RTNLGRP_LINK RTNLGRP_LINK + RTNLGRP_NOTIFY, +#define RTNLGRP_NOTIFY RTNLGRP_NOTIFY + RTNLGRP_NEIGH, +#define RTNLGRP_NEIGH RTNLGRP_NEIGH + RTNLGRP_TC, +#define RTNLGRP_TC RTNLGRP_TC + RTNLGRP_IPV4_IFADDR, +#define RTNLGRP_IPV4_IFADDR RTNLGRP_IPV4_IFADDR + RTNLGRP_IPV4_MROUTE, +#define RTNLGRP_IPV4_MROUTE RTNLGRP_IPV4_MROUTE + RTNLGRP_IPV4_ROUTE, +#define RTNLGRP_IPV4_ROUTE RTNLGRP_IPV4_ROUTE + RTNLGRP_IPV4_RULE, +#define RTNLGRP_IPV4_RULE RTNLGRP_IPV4_RULE + RTNLGRP_IPV6_IFADDR, +#define RTNLGRP_IPV6_IFADDR RTNLGRP_IPV6_IFADDR + RTNLGRP_IPV6_MROUTE, +#define RTNLGRP_IPV6_MROUTE RTNLGRP_IPV6_MROUTE + RTNLGRP_IPV6_ROUTE, +#define RTNLGRP_IPV6_ROUTE RTNLGRP_IPV6_ROUTE + RTNLGRP_IPV6_IFINFO, +#define RTNLGRP_IPV6_IFINFO RTNLGRP_IPV6_IFINFO + RTNLGRP_DECnet_IFADDR, +#define RTNLGRP_DECnet_IFADDR RTNLGRP_DECnet_IFADDR + RTNLGRP_NOP2, + RTNLGRP_DECnet_ROUTE, +#define RTNLGRP_DECnet_ROUTE RTNLGRP_DECnet_ROUTE + RTNLGRP_DECnet_RULE, +#define RTNLGRP_DECnet_RULE RTNLGRP_DECnet_RULE + RTNLGRP_NOP4, + RTNLGRP_IPV6_PREFIX, +#define RTNLGRP_IPV6_PREFIX RTNLGRP_IPV6_PREFIX + RTNLGRP_IPV6_RULE, +#define RTNLGRP_IPV6_RULE RTNLGRP_IPV6_RULE + RTNLGRP_ND_USEROPT, +#define RTNLGRP_ND_USEROPT RTNLGRP_ND_USEROPT + RTNLGRP_PHONET_IFADDR, +#define RTNLGRP_PHONET_IFADDR RTNLGRP_PHONET_IFADDR + RTNLGRP_PHONET_ROUTE, +#define RTNLGRP_PHONET_ROUTE RTNLGRP_PHONET_ROUTE + RTNLGRP_DCB, +#define RTNLGRP_DCB RTNLGRP_DCB + RTNLGRP_IPV4_NETCONF, +#define RTNLGRP_IPV4_NETCONF RTNLGRP_IPV4_NETCONF + RTNLGRP_IPV6_NETCONF, +#define RTNLGRP_IPV6_NETCONF RTNLGRP_IPV6_NETCONF + RTNLGRP_MDB, +#define RTNLGRP_MDB RTNLGRP_MDB + __RTNLGRP_MAX +}; +#define RTNLGRP_MAX (__RTNLGRP_MAX - 1) + +/* TC action piece */ +struct tcamsg { + unsigned char tca_family; + unsigned char tca__pad1; + unsigned short tca__pad2; +}; +#define TA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcamsg)))) +#define TA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcamsg)) +#define TCA_ACT_TAB 1 /* attr type must be >=1 */ +#define TCAA_MAX 1 + +/* New extended info filters for IFLA_EXT_MASK */ +#define RTEXT_FILTER_VF (1 << 0) +#define RTEXT_FILTER_BRVLAN (1 << 1) + +/* End of information exported to user level */ + + + +#endif /* __LINUX_RTNETLINK_H */ diff --git a/package/gluon-site/Makefile b/package/gluon-site/Makefile new file mode 100644 index 00000000..fc9f58ce --- /dev/null +++ b/package/gluon-site/Makefile @@ -0,0 +1,42 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-site +PKG_VERSION:=$(if $(GLUON_SITE_CODE),$(GLUON_SITE_CODE),1) +PKG_RELEASE:=$(GLUON_RELEASE) + +PKG_FILE_DEPENDS := $(GLUON_SITEDIR)/ +PKG_BUILD_DEPENDS := luci + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) + + +define Package/gluon-site + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Site-specific files of Gluon +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile + $(call GluonBuildI18N,gluon-site,$(GLUON_SITEDIR)/i18n) +endef + +define Package/gluon-site/install + $(INSTALL_DIR) $(1)/lib/gluon + $(CP) $(GLUON_SITEDIR)/site.conf $(1)/lib/gluon/site.conf + echo "$(GLUON_RELEASE)" > $(1)/lib/gluon/release + + $(call GluonInstallI18N,gluon-site,$(1)) +endef + +$(eval $(call BuildPackage,gluon-site)) diff --git a/package/gluon-status-page/Makefile b/package/gluon-status-page/Makefile new file mode 100644 index 00000000..4e44e2b2 --- /dev/null +++ b/package/gluon-status-page/Makefile @@ -0,0 +1,37 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-status-page +PKG_VERSION:=1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + +define Package/gluon-status-page + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Adds a status page showing information about the node. + DEPENDS:=+gluon-core +gluon-neighbour-info +uhttpd +endef + +define Package/gluon-status-page/description + Adds a status page showing information about the node. + Especially useful in combination with the next-node feature. +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-status-page/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,gluon-status-page)) diff --git a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/status b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/status new file mode 100755 index 00000000..771bdaba --- /dev/null +++ b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/status @@ -0,0 +1,161 @@ +#!/usr/bin/lua + +local util = require("luci.util") +local fs = require("luci.fs") +local ltn12 = require 'luci.ltn12' +local sys = require("luci.sys") +local json = require("luci.json") +local nixio = require 'nixio' +local platform_info = require("platform_info") + +local hostname = sys.hostname() +local model = platform_info.get_model() +local release = util.trim(fs.readfile("/lib/gluon/release") or "") + +function escape_html(s) + return (s:gsub('&', '&'):gsub('<', '<'):gsub('>', '>'):gsub('"', '"')) +end + +function neighbours(ifname) + local info = util.exec("gluon-neighbour-info -d ff02::2:1001 -p 1001 -r nodeinfo -t 3 -i " .. ifname) + local macs = {} + for _, line in ipairs(util.split(info)) do + local data = json.decode(line) + if data then + local function add_macs(list) + if list then + for _, mac in ipairs(list) do + macs[mac] = data + end + end + end + + if data["network"] then + add_macs(data["network"]["mesh_interfaces"]) + + if data["network"]["mesh"] and data["network"]["mesh"]["bat0"] and + data["network"]["mesh"]["bat0"]["interfaces"] then + local interfaces = data["network"]["mesh"]["bat0"]["interfaces"] + add_macs(interfaces["other"]) + add_macs(interfaces["wireless"]) + add_macs(interfaces["tunnel"]) + end + end + end + end + + return macs +end + +io.write("Content-type: text/html\n\n") +io.write("\n") +io.write("") +io.write("") +io.write("") +io.write("" .. escape_html(hostname) .. "") +io.write("") +io.write("") + +io.write("

" .. escape_html(hostname) .. "

") +io.write("
")
+
+io.write("Model: " .. escape_html(model) .. "\n")
+io.write("Firmware release: " .. escape_html(release) .. "\n\n")
+
+io.write(escape_html(util.trim(sys.exec("uptime | sed 's/^ \+//'"))) .. "\n\n")
+io.write(escape_html(sys.exec("ip address show dev br-client")) .. "\n")
+io.write(escape_html(sys.exec("free -m")) .. "\n")
+io.write(escape_html(sys.exec("df /rom /overlay")))
+io.write("
") + +io.write("

Neighbours

") + +local interfaces = util.split(util.trim(util.exec("iw dev | grep IBSS -B 5 | grep Interface | cut -d' ' -f2"))) + +for _, ifname in ipairs(interfaces) do + io.write("

" .. escape_html(ifname) .. "

") + io.write("
")
+
+  io.write(escape_html(sys.exec("iw dev " .. ifname .. " link")) .. "\n")
+
+  for _, line in ipairs(util.split(util.exec("iw dev " .. ifname .. " station dump"))) do
+    local mac = line:match("^Station (.*) %(on ")
+    if mac then
+      io.write("Station " .. mac .. " (on " .. escape_html(ifname) .. ")\n")
+    else
+      io.write(escape_html(line) .. "\n")
+    end
+  end
+
+  io.write("
") +end + +local stat, fastd_status = pcall( + function() + local fastd_sock = nixio.socket('unix', 'stream') + assert(fastd_sock:connect('/var/run/fastd.mesh_vpn.socket')) + + decoder = json.Decoder() + ltn12.pump.all(ltn12.source.file(fastd_sock), decoder:sink()) + return decoder:get() + end +) + +io.write("

VPN status

") +io.write("
")
+
+if stat then
+  io.write(string.format("fastd running for %.3f seconds\n", fastd_status.uptime/1000))
+
+  local peers = 0
+  local connections = 0
+
+  for key, peer in pairs(fastd_status.peers) do
+    peers = peers+1
+
+    if peer.connection then
+      connections = connections+1
+    end
+  end
+
+  io.write(string.format("There are %i peers configured, of which %i are connected:\n\n", peers, connections))
+
+  for key, peer in pairs(fastd_status.peers) do
+    io.write(string.format("%s: ", escape_html(peer.name)))
+
+    if peer.connection then
+      io.write(string.format("connected for %.3f seconds\n", peer.connection.established/1000))
+    else
+      io.write("not connected\n")
+    end
+  end
+
+else
+  io.write("fastd not running")
+end
+
+io.write("
") + +io.write("") +io.write("") +io.write("") diff --git a/package/gluon-status-page/files/lib/gluon/status-page/www/index.html b/package/gluon-status-page/files/lib/gluon/status-page/www/index.html new file mode 100644 index 00000000..75700015 --- /dev/null +++ b/package/gluon-status-page/files/lib/gluon/status-page/www/index.html @@ -0,0 +1,12 @@ + + + + + + + + + + Redirecting... + + diff --git a/package/gluon-status-page/files/lib/gluon/status-page/www/status.js b/package/gluon-status-page/files/lib/gluon/status-page/www/status.js new file mode 100644 index 00000000..e17102d0 --- /dev/null +++ b/package/gluon-status-page/files/lib/gluon/status-page/www/status.js @@ -0,0 +1,9 @@ +function update_node(id, ip, hostname) { + var el = document.getElementById(id); + + if (!el) + return; + + el.href = "http://[" + ip + "]/"; + el.textContent += " (" + hostname + ")"; +} diff --git a/package/gluon-status-page/files/lib/gluon/upgrade/500-status-page b/package/gluon-status-page/files/lib/gluon/upgrade/500-status-page new file mode 100755 index 00000000..ee7a58c9 --- /dev/null +++ b/package/gluon-status-page/files/lib/gluon/upgrade/500-status-page @@ -0,0 +1,13 @@ +#!/bin/sh + +uci batch <<-EOF + delete uhttpd.main.listen_http + add_list uhttpd.main.listen_http=0.0.0.0:80 + add_list uhttpd.main.listen_http=[::]:80 + + delete uhttpd.main.listen_https + + set uhttpd.main.home=/lib/gluon/status-page/www + + commit uhttpd +EOF diff --git a/package/gluon-wan-dnsmasq/Makefile b/package/gluon-wan-dnsmasq/Makefile new file mode 100644 index 00000000..3722210f --- /dev/null +++ b/package/gluon-wan-dnsmasq/Makefile @@ -0,0 +1,35 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-wan-dnsmasq +PKG_VERSION:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + +define Package/gluon-wan-dnsmasq + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Support for a secondary DNS server using the WAN interface + DEPENDS:=+gluon-core +dnsmasq +libpacketmark +endef + +define Package/gluon-wan-dnsmasq/description + Gluon community wifi mesh firmware framework: Support for a secondary DNS server using the WAN interface +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-wan-dnsmasq/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,gluon-wan-dnsmasq)) diff --git a/package/gluon-wan-dnsmasq/files/etc/config/gluon-wan-dnsmasq b/package/gluon-wan-dnsmasq/files/etc/config/gluon-wan-dnsmasq new file mode 100644 index 00000000..9c7e9b4c --- /dev/null +++ b/package/gluon-wan-dnsmasq/files/etc/config/gluon-wan-dnsmasq @@ -0,0 +1,2 @@ +config 'static' + # list 'server' '192.168.0.1' # Example diff --git a/package/gluon-wan-dnsmasq/files/etc/hotplug.d/iface/50-gluon-wan-dnsmasq b/package/gluon-wan-dnsmasq/files/etc/hotplug.d/iface/50-gluon-wan-dnsmasq new file mode 100644 index 00000000..d559e9b1 --- /dev/null +++ b/package/gluon-wan-dnsmasq/files/etc/hotplug.d/iface/50-gluon-wan-dnsmasq @@ -0,0 +1,3 @@ +if [ "$INTERFACE" = 'wan' -o "$INTERFACE" = 'wan6' ]; then + /lib/gluon/wan-dnsmasq/update.lua +fi diff --git a/package/gluon-wan-dnsmasq/files/etc/init.d/gluon-wan-dnsmasq b/package/gluon-wan-dnsmasq/files/etc/init.d/gluon-wan-dnsmasq new file mode 100755 index 00000000..22bed039 --- /dev/null +++ b/package/gluon-wan-dnsmasq/files/etc/init.d/gluon-wan-dnsmasq @@ -0,0 +1,26 @@ +#!/bin/sh /etc/rc.common + +START=60 + +SERVICE_NAME=gluon-wan-dnsmasq +SERVICE_USE_PID=1 +SERVICE_PID_FILE=/var/run/gluon-wan-dnsmasq.pid + + +PORT=54 +PACKET_MARK=1 + +RESOLV_CONF_DIR=/var/gluon/wan-dnsmasq +RESOLV_CONF=$RESOLV_CONF_DIR/resolv.conf + + +start() { + mkdir -p $RESOLV_CONF_DIR + /lib/gluon/wan-dnsmasq/update.lua + + LD_PRELOAD=libpacketmark.so LIBPACKETMARK_MARK=$PACKET_MARK service_start /usr/sbin/dnsmasq -x $SERVICE_PID_FILE -u root -i lo -p $PORT -h -r $RESOLV_CONF +} + +stop() { + service_stop /usr/sbin/dnsmasq +} diff --git a/package/gluon-wan-dnsmasq/files/lib/gluon/wan-dnsmasq/update.lua b/package/gluon-wan-dnsmasq/files/lib/gluon/wan-dnsmasq/update.lua new file mode 100755 index 00000000..88a86507 --- /dev/null +++ b/package/gluon-wan-dnsmasq/files/lib/gluon/wan-dnsmasq/update.lua @@ -0,0 +1,46 @@ +#!/usr/bin/lua + +local RESOLV_CONF_DIR = '/var/gluon/wan-dnsmasq' +local RESOLV_CONF = RESOLV_CONF_DIR .. '/resolv.conf' + + +local ubus = require('ubus').connect() +local uci = require('luci.model.uci').cursor() +local fs = require 'nixio.fs' + + +local new_servers = '' + + +local function append_servers(servers) + for _, server in ipairs(servers) do + new_servers = new_servers .. 'nameserver ' .. server .. '\n' + end +end + +local function append_interface_servers(iface) + append_servers(ubus:call('network.interface.' .. iface, 'status', {}).inactive['dns-server']) +end + + +local static = uci:get_first('gluon-wan-dnsmasq', 'static', 'server') + +if type(static) == 'table' and #static > 0 then + append_servers(static) +else + pcall(append_interface_servers, 'wan6') + pcall(append_interface_servers, 'wan') +end + + +fs.mkdirr(RESOLV_CONF_DIR) + +local old_servers = fs.readfile(RESOLV_CONF) + +if new_servers ~= old_servers then + local f = io.open(RESOLV_CONF .. '.tmp', 'w') + f:write(new_servers) + f:close() + + fs.rename(RESOLV_CONF .. '.tmp', RESOLV_CONF) +end diff --git a/patches/openwrt/0027-ar71xx-fix-model-string-detection-on-NETGEAR-WNDR3700-3800-WNDRMAC.patch b/patches/openwrt/0027-ar71xx-fix-model-string-detection-on-NETGEAR-WNDR3700-3800-WNDRMAC.patch index a6868085..f4051a2d 100644 --- a/patches/openwrt/0027-ar71xx-fix-model-string-detection-on-NETGEAR-WNDR3700-3800-WNDRMAC.patch +++ b/patches/openwrt/0027-ar71xx-fix-model-string-detection-on-NETGEAR-WNDR3700-3800-WNDRMAC.patch @@ -1,51 +1,64 @@ From: Matthias Schiffer -Date: Sun, 15 Mar 2015 19:51:15 +0100 +Date: Sun, 29 Mar 2015 13:23:26 +0200 Subject: ar71xx: fix model string detection on NETGEAR WNDR3700/3800/WNDRMAC There were a few issues with the existing code to detect the model string: * Always using the string starting with byte 56 would cut off the W of WNDR when - the ID starts with 29763654+16+128 instead of 29763654+16+64 + the ID starts with 29763654+16+64 instead of 29763654+16+128 * The string contained garbage after the zero byte instead of cutting it off after the zero (which wasn't always visible using busybox tools, but could confuse other scripts) +Tested on a WNDR3700v1 and a WNDR3700v2 using the new 29763654+16+64 ID in the +ART. Furthermore, tested against ART dumps of a WNDR3700v2 using the old +$'\xff...' value and a WNDR3800. + +The [ -z "$model" ] check was dropped as there is no way to actually hit this +unless no ART partition is found at all. + +The awk command was carefully crafted to work both with gawk and the (horribly +broken) busybox awk. + +Fixes #18992. + +Signed-off-by: Matthias Schiffer + diff --git a/target/linux/ar71xx/base-files/lib/ar71xx.sh b/target/linux/ar71xx/base-files/lib/ar71xx.sh -index a698ce5..0f9be69 100755 +index a698ce5..1838cb4 100755 --- a/target/linux/ar71xx/base-files/lib/ar71xx.sh +++ b/target/linux/ar71xx/base-files/lib/ar71xx.sh -@@ -37,16 +37,28 @@ wndr3700_board_detect() { +@@ -37,16 +37,26 @@ wndr3700_board_detect() { machine="NETGEAR WNDR3700" ;; "33373031") - local model - model=$(ar71xx_get_mtd_offset_size_format art 56 10 %c) - if [ -z "$model" ] || [ "$model" = $'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' ]; then -+ case "$(ar71xx_get_mtd_offset_size_format art 56 10 %c)" in -+ $'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff') - machine="NETGEAR WNDR3700v2" +- machine="NETGEAR WNDR3700v2" - elif [ -z "$model" ] || [ "$model" = $'\xff\xff\xff\xff\xff\xff\xff\xff\xffN' ]; then -+ ;; -+ $'\xff\xff\xff\xff\xff\xff\xff\xff\xffN') - machine="NETGEAR WNDRMAC" +- machine="NETGEAR WNDRMAC" - else -- machine="NETGEAR $model" -- fi -- ;; ++ # Use awk to remove everything after the first zero byte ++ model="$(ar71xx_get_mtd_offset_size_format art 41 32 %c | awk 'BEGIN{FS="[[:cntrl:]]"} {print $1; exit}')" ++ case $model in ++ $'\xff'*) ++ if [ "${model:24:1}" = 'N' ]; then ++ machine="NETGEAR WNDRMAC" ++ else ++ machine="NETGEAR WNDR3700v2" ++ fi ++ ;; ++ '29763654+16+64'*) ++ machine="NETGEAR ${model:14}" ++ ;; ++ '29763654+16+128'*) ++ machine="NETGEAR ${model:15}" + ;; + *) -+ # Use awk to remove everything after the first zero byte -+ model="$(ar71xx_get_mtd_offset_size_format art 41 32 %c | awk 'BEGIN{FS="[[:cntrl:]]"} {print $1; exit}')" -+ case $model in -+ '29763654+16+64'*) -+ machine="NETGEAR ${model:14}" -+ ;; -+ '29763654+16+128'*) -+ machine="NETGEAR ${model:15}" -+ ;; -+ *) -+ # Unknown ID -+ machine="NETGEAR $model" -+ esac ++ # Unknown ID + machine="NETGEAR $model" +- fi +- ;; + esac esac diff --git a/patches/openwrt/0032-mpc85xx-move-newly-created-files-from-patch-files-to-files-directory.patch b/patches/openwrt/0032-mpc85xx-move-newly-created-files-from-patch-files-to-files-directory.patch new file mode 100644 index 00000000..656ffc27 --- /dev/null +++ b/patches/openwrt/0032-mpc85xx-move-newly-created-files-from-patch-files-to-files-directory.patch @@ -0,0 +1,1111 @@ +From: Matthias Schiffer +Date: Thu, 30 Apr 2015 03:21:01 +0200 +Subject: mpc85xx: move newly created files from patch files to files directory + +This will make these files much more maintainable. + +diff --git a/target/linux/mpc85xx/files/arch/powerpc/boot/cuboot-tl-wdr4900-v1.c b/target/linux/mpc85xx/files/arch/powerpc/boot/cuboot-tl-wdr4900-v1.c +new file mode 100644 +index 0000000..17459ef +--- /dev/null ++++ b/target/linux/mpc85xx/files/arch/powerpc/boot/cuboot-tl-wdr4900-v1.c +@@ -0,0 +1,168 @@ ++/* ++ * U-Boot compatibility wrapper for the TP-Link TL-WDR4900 v1 board ++ * ++ * Copyright (c) 2013 Gabor Juhos ++ * ++ * Based on: ++ * cuboot-85xx.c ++ * Author: Scott Wood ++ * Copyright (c) 2007 Freescale Semiconductor, Inc. ++ * ++ * simpleboot.c ++ * Authors: Scott Wood ++ * Grant Likely ++ * Copyright (c) 2007 Freescale Semiconductor, Inc. ++ * Copyright (c) 2008 Secret Lab Technologies Ltd. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ */ ++ ++#include "ops.h" ++#include "types.h" ++#include "io.h" ++#include "stdio.h" ++#include ++ ++BSS_STACK(4*1024); ++ ++static unsigned long bus_freq; ++static unsigned long int_freq; ++static u64 mem_size; ++static unsigned char enetaddr[6]; ++ ++static void process_boot_dtb(void *boot_dtb) ++{ ++ const u32 *na, *ns, *reg, *val32; ++ const char *path; ++ u64 memsize64; ++ int node, size, i; ++ ++ /* Make sure FDT blob is sane */ ++ if (fdt_check_header(boot_dtb) != 0) ++ fatal("Invalid device tree blob\n"); ++ ++ /* Find the #address-cells and #size-cells properties */ ++ node = fdt_path_offset(boot_dtb, "/"); ++ if (node < 0) ++ fatal("Cannot find root node\n"); ++ na = fdt_getprop(boot_dtb, node, "#address-cells", &size); ++ if (!na || (size != 4)) ++ fatal("Cannot find #address-cells property"); ++ ++ ns = fdt_getprop(boot_dtb, node, "#size-cells", &size); ++ if (!ns || (size != 4)) ++ fatal("Cannot find #size-cells property"); ++ ++ /* Find the memory range */ ++ node = fdt_node_offset_by_prop_value(boot_dtb, -1, "device_type", ++ "memory", sizeof("memory")); ++ if (node < 0) ++ fatal("Cannot find memory node\n"); ++ reg = fdt_getprop(boot_dtb, node, "reg", &size); ++ if (size < (*na+*ns) * sizeof(u32)) ++ fatal("cannot get memory range\n"); ++ ++ /* Only interested in memory based at 0 */ ++ for (i = 0; i < *na; i++) ++ if (*reg++ != 0) ++ fatal("Memory range is not based at address 0\n"); ++ ++ /* get the memsize and trucate it to under 4G on 32 bit machines */ ++ memsize64 = 0; ++ for (i = 0; i < *ns; i++) ++ memsize64 = (memsize64 << 32) | *reg++; ++ if (sizeof(void *) == 4 && memsize64 >= 0x100000000ULL) ++ memsize64 = 0xffffffff; ++ ++ mem_size = memsize64; ++ ++ /* get clock frequencies */ ++ node = fdt_node_offset_by_prop_value(boot_dtb, -1, "device_type", ++ "cpu", sizeof("cpu")); ++ if (!node) ++ fatal("Cannot find cpu node\n"); ++ ++ val32 = fdt_getprop(boot_dtb, node, "clock-frequency", &size); ++ if (!val32 || (size != 4)) ++ fatal("Cannot get clock frequency"); ++ ++ int_freq = *val32; ++ ++ val32 = fdt_getprop(boot_dtb, node, "bus-frequency", &size); ++ if (!val32 || (size != 4)) ++ fatal("Cannot get bus frequency"); ++ ++ bus_freq = *val32; ++ ++ path = fdt_get_alias(boot_dtb, "ethernet0"); ++ if (path) { ++ const void *p; ++ ++ node = fdt_path_offset(boot_dtb, path); ++ if (node < 0) ++ fatal("Cannot find ethernet0 node"); ++ ++ p = fdt_getprop(boot_dtb, node, "mac-address", &size); ++ if (!p || (size < 6)) { ++ printf("no mac-address property, finding local\n\r"); ++ p = fdt_getprop(boot_dtb, node, "local-mac-address", &size); ++ } ++ ++ if (!p || (size < 6)) ++ fatal("cannot get MAC addres"); ++ ++ memcpy(enetaddr, p, sizeof(enetaddr)); ++ } ++} ++ ++static void platform_fixups(void) ++{ ++ void *soc, *mpic; ++ ++ dt_fixup_memory(0, mem_size); ++ ++ dt_fixup_mac_address_by_alias("ethernet0", enetaddr); ++ dt_fixup_cpu_clocks(int_freq, bus_freq / 8, bus_freq); ++ ++ /* Unfortunately, the specific model number is encoded in the ++ * soc node name in existing dts files -- once that is fixed, ++ * this can do a simple path lookup. ++ */ ++ soc = find_node_by_devtype(NULL, "soc"); ++ if (soc) { ++ void *serial = NULL; ++ ++ setprop(soc, "bus-frequency", &bus_freq, sizeof(bus_freq)); ++ ++ while ((serial = find_node_by_devtype(serial, "serial"))) { ++ if (get_parent(serial) != soc) ++ continue; ++ ++ setprop(serial, "clock-frequency", &bus_freq, ++ sizeof(bus_freq)); ++ } ++ } ++ ++ mpic = find_node_by_compatible(NULL, "fsl,mpic"); ++ if (mpic) ++ setprop(mpic, "clock-frequency", &bus_freq, sizeof(bus_freq)); ++} ++ ++void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, ++ unsigned long r6, unsigned long r7) ++{ ++ mem_size = 64 * 1024 * 1024; ++ ++ simple_alloc_init(_end, mem_size - (u32)_end - 1024*1024, 32, 64); ++ ++ fdt_init(_dtb_start); ++ serial_console_init(); ++ ++ printf("\n\r-- TL-WDR4900 v1 boot wrapper --\n\r"); ++ ++ process_boot_dtb((void *) r3); ++ ++ platform_ops.fixups = platform_fixups; ++} +diff --git a/target/linux/mpc85xx/files/arch/powerpc/boot/dts/tl-wdr4900-v1.dts b/target/linux/mpc85xx/files/arch/powerpc/boot/dts/tl-wdr4900-v1.dts +new file mode 100644 +index 0000000..49e516c +--- /dev/null ++++ b/target/linux/mpc85xx/files/arch/powerpc/boot/dts/tl-wdr4900-v1.dts +@@ -0,0 +1,212 @@ ++/* ++ * TP-Link TL-WDR4900 v1 Device Tree Source ++ * ++ * Copyright 2013 Gabor Juhos ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++/include/ "fsl/p1010si-pre.dtsi" ++ ++/ { ++ model = "TP-Link TL-WDR4900 v1"; ++ compatible = "tp-link,TL-WDR4900v1"; ++ ++ chosen { ++ bootargs = "console=ttyS0,115200"; ++/* ++ linux,stdout-path = "/soc@ffe00000/serial@4500"; ++*/ ++ }; ++ ++ aliases { ++ spi0 = &spi0; ++ }; ++ ++ memory { ++ device_type = "memory"; ++ }; ++ ++ soc: soc@ffe00000 { ++ ranges = <0x0 0x0 0xffe00000 0x100000>; ++ ++ spi0: spi@7000 { ++ flash@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "spansion,s25fl129p1"; ++ reg = <0>; ++ spi-max-frequency = <25000000>; ++ ++ u-boot@0 { ++ reg = <0x0 0x0050000>; ++ label = "u-boot"; ++ read-only; ++ }; ++ ++ dtb@50000 { ++ reg = <0x00050000 0x00010000>; ++ label = "dtb"; ++ read-only; ++ }; ++ ++ kernel@60000 { ++ reg = <0x00060000 0x002a0000>; ++ label = "kernel"; ++ }; ++ ++ rootfs@300000 { ++ reg = <0x00300000 0x00ce0000>; ++ label = "rootfs"; ++ }; ++ ++ config@fe0000 { ++ reg = <0x00fe0000 0x00010000>; ++ label = "config"; ++ read-only; ++ }; ++ ++ caldata@ff0000 { ++ reg = <0x00ff0000 0x00010000>; ++ label = "caldata"; ++ read-only; ++ }; ++ ++ firmware@60000 { ++ reg = <0x00060000 0x00f80000>; ++ label = "firmware"; ++ }; ++ }; ++ }; ++ ++ gpio0: gpio-controller@f000 { ++ }; ++ ++ usb@22000 { ++ phy_type = "utmi"; ++ dr_mode = "host"; ++ }; ++ ++ mdio@24000 { ++ phy0: ethernet-phy@0 { ++ reg = <0x0>; ++ qca,ar8327-initvals = < ++ 0x00004 0x07600000 /* PAD0_MODE */ ++ 0x00008 0x00000000 /* PAD5_MODE */ ++ 0x0000c 0x01000000 /* PAD6_MODE */ ++ 0x00010 0x40000000 /* POWER_ON_STRIP */ ++ 0x00050 0xcf35cf35 /* LED_CTRL0 */ ++ 0x00054 0xcf35cf35 /* LED_CTRL1 */ ++ 0x00058 0xcf35cf35 /* LED_CTRL2 */ ++ 0x0005c 0x03ffff00 /* LED_CTRL3 */ ++ 0x0007c 0x0000007e /* PORT0_STATUS */ ++ >; ++ }; ++ }; ++ ++ mdio@25000 { ++ status = "disabled"; ++ }; ++ ++ mdio@26000 { ++ status = "disabled"; ++ }; ++ ++ enet0: ethernet@b0000 { ++ phy-handle = <&phy0>; ++ phy-connection-type = "rgmii-id"; ++ }; ++ ++ enet1: ethernet@b1000 { ++ status = "disabled"; ++ }; ++ ++ enet2: ethernet@b2000 { ++ status = "disabled"; ++ }; ++ ++ sdhc@2e000 { ++ status = "disabled"; ++ }; ++ ++ serial1: serial@4600 { ++ status = "disabled"; ++ }; ++ ++ can0: can@1c000 { ++ status = "disabled"; ++ }; ++ ++ can1: can@1d000 { ++ status = "disabled"; ++ }; ++ }; ++ ++ pci0: pcie@ffe09000 { ++ reg = <0 0xffe09000 0 0x1000>; ++ ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 ++ 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; ++ pcie@0 { ++ ranges = <0x2000000 0x0 0xa0000000 ++ 0x2000000 0x0 0xa0000000 ++ 0x0 0x20000000 ++ ++ 0x1000000 0x0 0x0 ++ 0x1000000 0x0 0x0 ++ 0x0 0x100000>; ++ }; ++ }; ++ ++ pci1: pcie@ffe0a000 { ++ reg = <0 0xffe0a000 0 0x1000>; ++ ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 ++ 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; ++ pcie@0 { ++ ranges = <0x2000000 0x0 0x80000000 ++ 0x2000000 0x0 0x80000000 ++ 0x0 0x20000000 ++ ++ 0x1000000 0x0 0x0 ++ 0x1000000 0x0 0x0 ++ 0x0 0x100000>; ++ }; ++ }; ++ ++ ifc: ifc@ffe1e000 { ++ status = "disabled"; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ system { ++ gpios = <&gpio0 2 1>; /* active low */ ++ label = "tp-link:blue:system"; ++ }; ++ ++ usb1 { ++ gpios = <&gpio0 3 1>; /* active low */ ++ label = "tp-link:green:usb1"; ++ }; ++ ++ usb2 { ++ gpios = <&gpio0 4 1>; /* active low */ ++ label = "tp-link:green:usb2"; ++ }; ++ }; ++ ++ buttons { ++ compatible = "gpio-keys"; ++ ++ reset { ++ label = "Reset button"; ++ gpios = <&gpio0 5 1>; /* active low */ ++ linux,code = <0x198>; /* KEY_RESTART */ ++ }; ++ }; ++}; ++ ++/include/ "fsl/p1010si-post.dtsi" +diff --git a/target/linux/mpc85xx/files/arch/powerpc/platforms/85xx/tl_wdr4900_v1.c b/target/linux/mpc85xx/files/arch/powerpc/platforms/85xx/tl_wdr4900_v1.c +new file mode 100644 +index 0000000..95afa4d +--- /dev/null ++++ b/target/linux/mpc85xx/files/arch/powerpc/platforms/85xx/tl_wdr4900_v1.c +@@ -0,0 +1,145 @@ ++/* ++ * TL-WDR4900 v1 board setup ++ * ++ * Copyright (c) 2013 Gabor Juhos ++ * ++ * Based on: ++ * p1010rdb.c: ++ * P1010RDB Board Setup ++ * Copyright 2011 Freescale Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "mpc85xx.h" ++ ++void __init tl_wdr4900_v1_pic_init(void) ++{ ++ struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | ++ MPIC_SINGLE_DEST_CPU, ++ 0, 256, " OpenPIC "); ++ ++ BUG_ON(mpic == NULL); ++ ++ mpic_init(mpic); ++} ++ ++#ifdef CONFIG_PCI ++static struct gpio_led tl_wdr4900_v1_wmac_leds_gpio[] = { ++ { ++ .name = "tp-link:blue:wps", ++ .gpio = 1, ++ .active_low = 1, ++ }, ++}; ++ ++static struct ath9k_platform_data tl_wdr4900_v1_wmac0_data = { ++ .led_pin = 0, ++ .eeprom_name = "pci_wmac0.eeprom", ++ .leds = tl_wdr4900_v1_wmac_leds_gpio, ++ .num_leds = ARRAY_SIZE(tl_wdr4900_v1_wmac_leds_gpio), ++}; ++ ++static struct ath9k_platform_data tl_wdr4900_v1_wmac1_data = { ++ .led_pin = 0, ++ .eeprom_name = "pci_wmac1.eeprom", ++}; ++ ++static void tl_wdr4900_v1_pci_wmac_fixup(struct pci_dev *dev) ++{ ++ if (!machine_is(tl_wdr4900_v1)) ++ return; ++ ++ if (dev->bus->number == 1 && ++ PCI_SLOT(dev->devfn) == 0) { ++ dev->dev.platform_data = &tl_wdr4900_v1_wmac0_data; ++ return; ++ } ++ ++ if (dev->bus->number == 3 && ++ PCI_SLOT(dev->devfn) == 0 && ++ dev->device == 0xabcd) { ++ dev->dev.platform_data = &tl_wdr4900_v1_wmac1_data; ++ ++ /* ++ * The PCI header of the AR9381 chip is not programmed ++ * correctly by the bootloader and the device uses wrong ++ * data due to that. Replace the broken values with the ++ * correct ones. ++ */ ++ dev->device = 0x30; ++ dev->class = 0x028000; ++ ++ pr_info("pci %s: AR9381 fixup applied\n", pci_name(dev)); ++ } ++} ++ ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATHEROS, PCI_ANY_ID, ++ tl_wdr4900_v1_pci_wmac_fixup); ++#endif /* CONFIG_PCI */ ++ ++/* ++ * Setup the architecture ++ */ ++static void __init tl_wdr4900_v1_setup_arch(void) ++{ ++ if (ppc_md.progress) ++ ppc_md.progress("tl_wdr4900_v1_setup_arch()", 0); ++ ++ fsl_pci_assign_primary(); ++ ++ printk(KERN_INFO "TL-WDR4900 v1 board from TP-Link\n"); ++} ++ ++machine_arch_initcall(tl_wdr4900_v1, mpc85xx_common_publish_devices); ++machine_arch_initcall(tl_wdr4900_v1, swiotlb_setup_bus_notifier); ++ ++/* ++ * Called very early, device-tree isn't unflattened ++ */ ++static int __init tl_wdr4900_v1_probe(void) ++{ ++ unsigned long root = of_get_flat_dt_root(); ++ ++ if (of_flat_dt_is_compatible(root, "tp-link,TL-WDR4900v1")) ++ return 1; ++ ++ return 0; ++} ++ ++define_machine(tl_wdr4900_v1) { ++ .name = "Freescale P1014", ++ .probe = tl_wdr4900_v1_probe, ++ .setup_arch = tl_wdr4900_v1_setup_arch, ++ .init_IRQ = tl_wdr4900_v1_pic_init, ++#ifdef CONFIG_PCI ++ .pcibios_fixup_bus = fsl_pcibios_fixup_bus, ++#endif ++ .get_irq = mpic_get_irq, ++ .restart = fsl_rstcr_restart, ++ .calibrate_decr = generic_calibrate_decr, ++ .progress = udbg_progress, ++}; +diff --git a/target/linux/mpc85xx/patches-3.10/140-powerpc-85xx-tl-wdr4900-v1-support.patch b/target/linux/mpc85xx/patches-3.10/140-powerpc-85xx-tl-wdr4900-v1-support.patch +index 8407176..dae2305 100644 +--- a/target/linux/mpc85xx/patches-3.10/140-powerpc-85xx-tl-wdr4900-v1-support.patch ++++ b/target/linux/mpc85xx/patches-3.10/140-powerpc-85xx-tl-wdr4900-v1-support.patch +@@ -11,16 +11,9 @@ the Freescale P1014 SoC. + Signed-off-by: Gabor Juhos + --- + arch/powerpc/boot/Makefile | 3 + +- arch/powerpc/boot/cuboot-tl-wdr4900-v1.c | 164 ++++++++++++++++++++++++++ +- arch/powerpc/boot/dts/tl-wdr4900-v1.dts | 166 +++++++++++++++++++++++++++ + arch/powerpc/boot/wrapper | 4 + + arch/powerpc/platforms/85xx/Kconfig | 11 ++ + arch/powerpc/platforms/85xx/Makefile | 1 + +- arch/powerpc/platforms/85xx/tl_wdr4900_v1.c | 145 +++++++++++++++++++++++ +- 7 files changed, 494 insertions(+) +- create mode 100644 arch/powerpc/boot/cuboot-tl-wdr4900-v1.c +- create mode 100644 arch/powerpc/boot/dts/tl-wdr4900-v1.dts +- create mode 100644 arch/powerpc/platforms/85xx/tl_wdr4900_v1.c + + --- a/arch/powerpc/boot/Makefile + +++ b/arch/powerpc/boot/Makefile +@@ -41,388 +34,6 @@ Signed-off-by: Gabor Juhos + + # Board ports in arch/powerpc/platform/embedded6xx/Kconfig + image-$(CONFIG_STORCENTER) += cuImage.storcenter +---- /dev/null +-+++ b/arch/powerpc/boot/cuboot-tl-wdr4900-v1.c +-@@ -0,0 +1,164 @@ +-+/* +-+ * U-Boot compatibility wrapper for the TP-Link TL-WDR4900 v1 board +-+ * +-+ * Copyright (c) 2013 Gabor Juhos +-+ * +-+ * Based on: +-+ * cuboot-85xx.c +-+ * Author: Scott Wood +-+ * Copyright (c) 2007 Freescale Semiconductor, Inc. +-+ * +-+ * simpleboot.c +-+ * Authors: Scott Wood +-+ * Grant Likely +-+ * Copyright (c) 2007 Freescale Semiconductor, Inc. +-+ * Copyright (c) 2008 Secret Lab Technologies Ltd. +-+ * +-+ * This program is free software; you can redistribute it and/or modify it +-+ * under the terms of the GNU General Public License version 2 as published +-+ * by the Free Software Foundation. +-+ */ +-+ +-+#include "ops.h" +-+#include "types.h" +-+#include "io.h" +-+#include "stdio.h" +-+#include +-+ +-+BSS_STACK(4*1024); +-+ +-+static unsigned long bus_freq; +-+static unsigned long int_freq; +-+static u64 mem_size; +-+static unsigned char enetaddr[6]; +-+ +-+static void process_boot_dtb(void *boot_dtb) +-+{ +-+ const u32 *na, *ns, *reg, *val32; +-+ const char *path; +-+ u64 memsize64; +-+ int node, size, i; +-+ +-+ /* Make sure FDT blob is sane */ +-+ if (fdt_check_header(boot_dtb) != 0) +-+ fatal("Invalid device tree blob\n"); +-+ +-+ /* Find the #address-cells and #size-cells properties */ +-+ node = fdt_path_offset(boot_dtb, "/"); +-+ if (node < 0) +-+ fatal("Cannot find root node\n"); +-+ na = fdt_getprop(boot_dtb, node, "#address-cells", &size); +-+ if (!na || (size != 4)) +-+ fatal("Cannot find #address-cells property"); +-+ +-+ ns = fdt_getprop(boot_dtb, node, "#size-cells", &size); +-+ if (!ns || (size != 4)) +-+ fatal("Cannot find #size-cells property"); +-+ +-+ /* Find the memory range */ +-+ node = fdt_node_offset_by_prop_value(boot_dtb, -1, "device_type", +-+ "memory", sizeof("memory")); +-+ if (node < 0) +-+ fatal("Cannot find memory node\n"); +-+ reg = fdt_getprop(boot_dtb, node, "reg", &size); +-+ if (size < (*na+*ns) * sizeof(u32)) +-+ fatal("cannot get memory range\n"); +-+ +-+ /* Only interested in memory based at 0 */ +-+ for (i = 0; i < *na; i++) +-+ if (*reg++ != 0) +-+ fatal("Memory range is not based at address 0\n"); +-+ +-+ /* get the memsize and trucate it to under 4G on 32 bit machines */ +-+ memsize64 = 0; +-+ for (i = 0; i < *ns; i++) +-+ memsize64 = (memsize64 << 32) | *reg++; +-+ if (sizeof(void *) == 4 && memsize64 >= 0x100000000ULL) +-+ memsize64 = 0xffffffff; +-+ +-+ mem_size = memsize64; +-+ +-+ /* get clock frequencies */ +-+ node = fdt_node_offset_by_prop_value(boot_dtb, -1, "device_type", +-+ "cpu", sizeof("cpu")); +-+ if (!node) +-+ fatal("Cannot find cpu node\n"); +-+ +-+ val32 = fdt_getprop(boot_dtb, node, "clock-frequency", &size); +-+ if (!val32 || (size != 4)) +-+ fatal("Cannot get clock frequency"); +-+ +-+ int_freq = *val32; +-+ +-+ val32 = fdt_getprop(boot_dtb, node, "bus-frequency", &size); +-+ if (!val32 || (size != 4)) +-+ fatal("Cannot get bus frequency"); +-+ +-+ bus_freq = *val32; +-+ +-+ path = fdt_get_alias(boot_dtb, "ethernet0"); +-+ if (path) { +-+ const void *p; +-+ +-+ node = fdt_path_offset(boot_dtb, path); +-+ if (node < 0) +-+ fatal("Cannot find ethernet0 node"); +-+ +-+ p = fdt_getprop(boot_dtb, node, "mac-address", &size); +-+ if (!p || (size < 6)) { +-+ printf("no mac-address property, finding local\n\r"); +-+ p = fdt_getprop(boot_dtb, node, "local-mac-address", &size); +-+ } +-+ +-+ if (!p || (size < 6)) +-+ fatal("cannot get MAC addres"); +-+ +-+ memcpy(enetaddr, p, sizeof(enetaddr)); +-+ } +-+} +-+ +-+static void platform_fixups(void) +-+{ +-+ void *soc; +-+ +-+ dt_fixup_memory(0, mem_size); +-+ +-+ dt_fixup_mac_address_by_alias("ethernet0", enetaddr); +-+ dt_fixup_cpu_clocks(int_freq, bus_freq / 8, bus_freq); +-+ +-+ /* Unfortunately, the specific model number is encoded in the +-+ * soc node name in existing dts files -- once that is fixed, +-+ * this can do a simple path lookup. +-+ */ +-+ soc = find_node_by_devtype(NULL, "soc"); +-+ if (soc) { +-+ void *serial = NULL; +-+ +-+ setprop(soc, "bus-frequency", &bus_freq, sizeof(bus_freq)); +-+ +-+ while ((serial = find_node_by_devtype(serial, "serial"))) { +-+ if (get_parent(serial) != soc) +-+ continue; +-+ +-+ setprop(serial, "clock-frequency", &bus_freq, +-+ sizeof(bus_freq)); +-+ } +-+ } +-+} +-+ +-+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, +-+ unsigned long r6, unsigned long r7) +-+{ +-+ mem_size = 64 * 1024 * 1024; +-+ +-+ simple_alloc_init(_end, mem_size - (u32)_end - 1024*1024, 32, 64); +-+ +-+ fdt_init(_dtb_start); +-+ serial_console_init(); +-+ +-+ printf("\n\r-- TL-WDR4900 v1 boot wrapper --\n\r"); +-+ +-+ process_boot_dtb((void *) r3); +-+ +-+ platform_ops.fixups = platform_fixups; +-+} +---- /dev/null +-+++ b/arch/powerpc/boot/dts/tl-wdr4900-v1.dts +-@@ -0,0 +1,212 @@ +-+/* +-+ * TP-Link TL-WDR4900 v1 Device Tree Source +-+ * +-+ * Copyright 2013 Gabor Juhos +-+ * +-+ * This program is free software; you can redistribute it and/or modify it +-+ * under the terms of the GNU General Public License as published by the +-+ * Free Software Foundation; either version 2 of the License, or (at your +-+ * option) any later version. +-+ */ +-+ +-+/include/ "fsl/p1010si-pre.dtsi" +-+ +-+/ { +-+ model = "TP-Link TL-WDR4900 v1"; +-+ compatible = "tp-link,TL-WDR4900v1"; +-+ +-+ chosen { +-+ bootargs = "console=ttyS0,115200"; +-+/* +-+ linux,stdout-path = "/soc@ffe00000/serial@4500"; +-+*/ +-+ }; +-+ +-+ aliases { +-+ spi0 = &spi0; +-+ }; +-+ +-+ memory { +-+ device_type = "memory"; +-+ }; +-+ +-+ soc: soc@ffe00000 { +-+ ranges = <0x0 0x0 0xffe00000 0x100000>; +-+ +-+ spi0: spi@7000 { +-+ flash@0 { +-+ #address-cells = <1>; +-+ #size-cells = <1>; +-+ compatible = "spansion,s25fl129p1"; +-+ reg = <0>; +-+ spi-max-frequency = <25000000>; +-+ +-+ u-boot@0 { +-+ reg = <0x0 0x0050000>; +-+ label = "u-boot"; +-+ read-only; +-+ }; +-+ +-+ dtb@50000 { +-+ reg = <0x00050000 0x00010000>; +-+ label = "dtb"; +-+ read-only; +-+ }; +-+ +-+ kernel@60000 { +-+ reg = <0x00060000 0x002a0000>; +-+ label = "kernel"; +-+ }; +-+ +-+ rootfs@300000 { +-+ reg = <0x00300000 0x00ce0000>; +-+ label = "rootfs"; +-+ }; +-+ +-+ config@fe0000 { +-+ reg = <0x00fe0000 0x00010000>; +-+ label = "config"; +-+ read-only; +-+ }; +-+ +-+ caldata@ff0000 { +-+ reg = <0x00ff0000 0x00010000>; +-+ label = "caldata"; +-+ read-only; +-+ }; +-+ +-+ firmware@60000 { +-+ reg = <0x00060000 0x00f80000>; +-+ label = "firmware"; +-+ }; +-+ }; +-+ }; +-+ +-+ gpio0: gpio-controller@f000 { +-+ }; +-+ +-+ usb@22000 { +-+ phy_type = "utmi"; +-+ dr_mode = "host"; +-+ }; +-+ +-+ mdio@24000 { +-+ phy0: ethernet-phy@0 { +-+ reg = <0x0>; +-+ qca,ar8327-initvals = < +-+ 0x00004 0x07600000 /* PAD0_MODE */ +-+ 0x00008 0x00000000 /* PAD5_MODE */ +-+ 0x0000c 0x01000000 /* PAD6_MODE */ +-+ 0x00010 0x40000000 /* POWER_ON_STRIP */ +-+ 0x00050 0xcf35cf35 /* LED_CTRL0 */ +-+ 0x00054 0xcf35cf35 /* LED_CTRL1 */ +-+ 0x00058 0xcf35cf35 /* LED_CTRL2 */ +-+ 0x0005c 0x03ffff00 /* LED_CTRL3 */ +-+ 0x0007c 0x0000007e /* PORT0_STATUS */ +-+ >; +-+ }; +-+ }; +-+ +-+ mdio@25000 { +-+ status = "disabled"; +-+ }; +-+ +-+ mdio@26000 { +-+ status = "disabled"; +-+ }; +-+ +-+ enet0: ethernet@b0000 { +-+ phy-handle = <&phy0>; +-+ phy-connection-type = "rgmii-id"; +-+ }; +-+ +-+ enet1: ethernet@b1000 { +-+ status = "disabled"; +-+ }; +-+ +-+ enet2: ethernet@b2000 { +-+ status = "disabled"; +-+ }; +-+ +-+ sdhc@2e000 { +-+ status = "disabled"; +-+ }; +-+ +-+ serial1: serial@4600 { +-+ status = "disabled"; +-+ }; +-+ +-+ can0: can@1c000 { +-+ status = "disabled"; +-+ }; +-+ +-+ can1: can@1d000 { +-+ status = "disabled"; +-+ }; +-+ }; +-+ +-+ pci0: pcie@ffe09000 { +-+ reg = <0 0xffe09000 0 0x1000>; +-+ ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 +-+ 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; +-+ pcie@0 { +-+ ranges = <0x2000000 0x0 0xa0000000 +-+ 0x2000000 0x0 0xa0000000 +-+ 0x0 0x20000000 +-+ +-+ 0x1000000 0x0 0x0 +-+ 0x1000000 0x0 0x0 +-+ 0x0 0x100000>; +-+ }; +-+ }; +-+ +-+ pci1: pcie@ffe0a000 { +-+ reg = <0 0xffe0a000 0 0x1000>; +-+ ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 +-+ 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; +-+ pcie@0 { +-+ ranges = <0x2000000 0x0 0x80000000 +-+ 0x2000000 0x0 0x80000000 +-+ 0x0 0x20000000 +-+ +-+ 0x1000000 0x0 0x0 +-+ 0x1000000 0x0 0x0 +-+ 0x0 0x100000>; +-+ }; +-+ }; +-+ +-+ ifc: ifc@ffe1e000 { +-+ status = "disabled"; +-+ }; +-+ +-+ leds { +-+ compatible = "gpio-leds"; +-+ +-+ system { +-+ gpios = <&gpio0 2 1>; /* active low */ +-+ label = "tp-link:blue:system"; +-+ }; +-+ +-+ usb1 { +-+ gpios = <&gpio0 3 1>; /* active low */ +-+ label = "tp-link:green:usb1"; +-+ }; +-+ +-+ usb2 { +-+ gpios = <&gpio0 4 1>; /* active low */ +-+ label = "tp-link:green:usb2"; +-+ }; +-+ }; +-+ +-+ buttons { +-+ compatible = "gpio-keys"; +-+ +-+ reset { +-+ label = "Reset button"; +-+ gpios = <&gpio0 5 1>; /* active low */ +-+ linux,code = <0x198>; /* KEY_RESTART */ +-+ }; +-+ }; +-+}; +-+ +-+/include/ "fsl/p1010si-post.dtsi" + --- a/arch/powerpc/boot/wrapper + +++ b/arch/powerpc/boot/wrapper + @@ -197,6 +197,10 @@ cuboot*) +@@ -466,151 +77,3 @@ Signed-off-by: Gabor Juhos + obj-$(CONFIG_SBC8548) += sbc8548.o + obj-$(CONFIG_PPA8548) += ppa8548.o + obj-$(CONFIG_SOCRATES) += socrates.o socrates_fpga_pic.o +---- /dev/null +-+++ b/arch/powerpc/platforms/85xx/tl_wdr4900_v1.c +-@@ -0,0 +1,145 @@ +-+/* +-+ * TL-WDR4900 v1 board setup +-+ * +-+ * Copyright (c) 2013 Gabor Juhos +-+ * +-+ * Based on: +-+ * p1010rdb.c: +-+ * P1010RDB Board Setup +-+ * Copyright 2011 Freescale Semiconductor Inc. +-+ * +-+ * This program is free software; you can redistribute it and/or modify it +-+ * under the terms of the GNU General Public License as published by the +-+ * Free Software Foundation; either version 2 of the License, or (at your +-+ * option) any later version. +-+ */ +-+ +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+ +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+ +-+#include +-+#include +-+ +-+#include "mpc85xx.h" +-+ +-+void __init tl_wdr4900_v1_pic_init(void) +-+{ +-+ struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | +-+ MPIC_SINGLE_DEST_CPU, +-+ 0, 256, " OpenPIC "); +-+ +-+ BUG_ON(mpic == NULL); +-+ +-+ mpic_init(mpic); +-+} +-+ +-+#ifdef CONFIG_PCI +-+static struct gpio_led tl_wdr4900_v1_wmac_leds_gpio[] = { +-+ { +-+ .name = "tp-link:blue:wps", +-+ .gpio = 1, +-+ .active_low = 1, +-+ }, +-+}; +-+ +-+static struct ath9k_platform_data tl_wdr4900_v1_wmac0_data = { +-+ .led_pin = 0, +-+ .eeprom_name = "pci_wmac0.eeprom", +-+ .leds = tl_wdr4900_v1_wmac_leds_gpio, +-+ .num_leds = ARRAY_SIZE(tl_wdr4900_v1_wmac_leds_gpio), +-+}; +-+ +-+static struct ath9k_platform_data tl_wdr4900_v1_wmac1_data = { +-+ .led_pin = 0, +-+ .eeprom_name = "pci_wmac1.eeprom", +-+}; +-+ +-+static void tl_wdr4900_v1_pci_wmac_fixup(struct pci_dev *dev) +-+{ +-+ if (!machine_is(tl_wdr4900_v1)) +-+ return; +-+ +-+ if (dev->bus->number == 1 && +-+ PCI_SLOT(dev->devfn) == 0) { +-+ dev->dev.platform_data = &tl_wdr4900_v1_wmac0_data; +-+ return; +-+ } +-+ +-+ if (dev->bus->number == 3 && +-+ PCI_SLOT(dev->devfn) == 0 && +-+ dev->device == 0xabcd) { +-+ dev->dev.platform_data = &tl_wdr4900_v1_wmac1_data; +-+ +-+ /* +-+ * The PCI header of the AR9381 chip is not programmed +-+ * correctly by the bootloader and the device uses wrong +-+ * data due to that. Replace the broken values with the +-+ * correct ones. +-+ */ +-+ dev->device = 0x30; +-+ dev->class = 0x028000; +-+ +-+ pr_info("pci %s: AR9381 fixup applied\n", pci_name(dev)); +-+ } +-+} +-+ +-+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATHEROS, PCI_ANY_ID, +-+ tl_wdr4900_v1_pci_wmac_fixup); +-+#endif /* CONFIG_PCI */ +-+ +-+/* +-+ * Setup the architecture +-+ */ +-+static void __init tl_wdr4900_v1_setup_arch(void) +-+{ +-+ if (ppc_md.progress) +-+ ppc_md.progress("tl_wdr4900_v1_setup_arch()", 0); +-+ +-+ fsl_pci_assign_primary(); +-+ +-+ printk(KERN_INFO "TL-WDR4900 v1 board from TP-Link\n"); +-+} +-+ +-+machine_arch_initcall(tl_wdr4900_v1, mpc85xx_common_publish_devices); +-+machine_arch_initcall(tl_wdr4900_v1, swiotlb_setup_bus_notifier); +-+ +-+/* +-+ * Called very early, device-tree isn't unflattened +-+ */ +-+static int __init tl_wdr4900_v1_probe(void) +-+{ +-+ unsigned long root = of_get_flat_dt_root(); +-+ +-+ if (of_flat_dt_is_compatible(root, "tp-link,TL-WDR4900v1")) +-+ return 1; +-+ +-+ return 0; +-+} +-+ +-+define_machine(tl_wdr4900_v1) { +-+ .name = "Freescale P1014", +-+ .probe = tl_wdr4900_v1_probe, +-+ .setup_arch = tl_wdr4900_v1_setup_arch, +-+ .init_IRQ = tl_wdr4900_v1_pic_init, +-+#ifdef CONFIG_PCI +-+ .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +-+#endif +-+ .get_irq = mpic_get_irq, +-+ .restart = fsl_rstcr_restart, +-+ .calibrate_decr = generic_calibrate_decr, +-+ .progress = udbg_progress, +-+}; diff --git a/patches/openwrt/0033-mpc85xx-gianfar-add-add-mtd-mac-address-support.patch b/patches/openwrt/0033-mpc85xx-gianfar-add-add-mtd-mac-address-support.patch new file mode 100644 index 00000000..461e7479 --- /dev/null +++ b/patches/openwrt/0033-mpc85xx-gianfar-add-add-mtd-mac-address-support.patch @@ -0,0 +1,168 @@ +From: Matthias Schiffer +Date: Thu, 30 Apr 2015 02:10:54 +0200 +Subject: mpc85xx: gianfar: add add mtd-mac-address support + +diff --git a/target/linux/mpc85xx/patches-3.10/101-NET-add-of_get_mac_address_mtd.patch b/target/linux/mpc85xx/patches-3.10/101-NET-add-of_get_mac_address_mtd.patch +new file mode 100644 +index 0000000..cd88d2b +--- /dev/null ++++ b/target/linux/mpc85xx/patches-3.10/101-NET-add-of_get_mac_address_mtd.patch +@@ -0,0 +1,76 @@ ++From 92f38460229a8816404408f036f0a374f1013d0e Mon Sep 17 00:00:00 2001 ++From: John Crispin ++Date: Sun, 27 Jul 2014 09:40:01 +0100 ++Subject: NET: add of_get_mac_address_mtd() ++ ++Many embedded devices have information such as mac addresses stored inside mtd ++devices. This patch allows us to add a property inside a node describing a ++network interface. The new property points at a mtd partition with an offset ++where the mac address can be found. ++ ++Signed-off-by: John Crispin ++--- ++ drivers/of/of_net.c | 37 +++++++++++++++++++++++++++++++++++++ ++ include/linux/of_net.h | 1 + ++ 2 files changed, 38 insertions(+) ++ ++--- a/drivers/of/of_net.c +++++ b/drivers/of/of_net.c ++@@ -10,6 +10,7 @@ ++ #include ++ #include ++ #include +++#include ++ ++ /** ++ * It maps 'enum phy_interface_t' found in include/linux/phy.h ++@@ -92,3 +93,39 @@ const void *of_get_mac_address(struct de ++ return NULL; ++ } ++ EXPORT_SYMBOL(of_get_mac_address); +++ +++int of_get_mac_address_mtd(struct device_node *np, void *mac) +++{ +++ struct device_node *mtd_np = NULL; +++ size_t retlen; +++ int size, ret; +++ struct mtd_info *mtd; +++ const char *part; +++ const __be32 *list; +++ phandle phandle; +++ +++ list = of_get_property(np, "mtd-mac-address", &size); +++ if (!list || (size != (2 * sizeof(*list)))) +++ return -ENOENT; +++ +++ phandle = be32_to_cpup(list++); +++ if (phandle) +++ mtd_np = of_find_node_by_phandle(phandle); +++ +++ if (!mtd_np) +++ return -ENOENT; +++ +++ part = of_get_property(mtd_np, "label", NULL); +++ if (!part) +++ part = mtd_np->name; +++ +++ mtd = get_mtd_device_nm(part); +++ if (IS_ERR(mtd)) +++ return PTR_ERR(mtd); +++ +++ ret = mtd_read(mtd, be32_to_cpup(list), 6, &retlen, (u_char *) mac); +++ put_mtd_device(mtd); +++ +++ return ret; +++} +++EXPORT_SYMBOL_GPL(of_get_mac_address_mtd); ++--- a/include/linux/of_net.h +++++ b/include/linux/of_net.h ++@@ -11,6 +11,7 @@ ++ #include ++ extern const int of_get_phy_mode(struct device_node *np); ++ extern const void *of_get_mac_address(struct device_node *np); +++extern int of_get_mac_address_mtd(struct device_node *np, void *mac); ++ #else ++ static inline const int of_get_phy_mode(struct device_node *np) ++ { +diff --git a/target/linux/mpc85xx/patches-3.10/201-net-gianfar-use-mtd-mac-address.patch b/target/linux/mpc85xx/patches-3.10/201-net-gianfar-use-mtd-mac-address.patch +new file mode 100644 +index 0000000..1de4418 +--- /dev/null ++++ b/target/linux/mpc85xx/patches-3.10/201-net-gianfar-use-mtd-mac-address.patch +@@ -0,0 +1,19 @@ ++--- a/drivers/net/ethernet/freescale/gianfar.c +++++ b/drivers/net/ethernet/freescale/gianfar.c ++@@ -741,10 +741,13 @@ static int gfar_of_init(struct platform_ ++ if (stash_len || stash_idx) ++ priv->device_flags |= FSL_GIANFAR_DEV_HAS_BUF_STASHING; ++ ++- mac_addr = of_get_mac_address(np); +++ err = of_get_mac_address_mtd(np, dev->dev_addr); +++ if (err) { +++ mac_addr = of_get_mac_address(np); ++ ++- if (mac_addr) ++- memcpy(dev->dev_addr, mac_addr, ETH_ALEN); +++ if (mac_addr) +++ memcpy(dev->dev_addr, mac_addr, ETH_ALEN); +++ } ++ ++ if (model && !strcasecmp(model, "TSEC")) ++ priv->device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT | +diff --git a/target/linux/mpc85xx/patches-3.10/220-fix_gianfar_reported_number_of_sent_bytes_to_BQL.patch b/target/linux/mpc85xx/patches-3.10/220-fix_gianfar_reported_number_of_sent_bytes_to_BQL.patch +index d0380ff..0d510bc 100644 +--- a/target/linux/mpc85xx/patches-3.10/220-fix_gianfar_reported_number_of_sent_bytes_to_BQL.patch ++++ b/target/linux/mpc85xx/patches-3.10/220-fix_gianfar_reported_number_of_sent_bytes_to_BQL.patch +@@ -1,6 +1,6 @@ + --- a/drivers/net/ethernet/freescale/gianfar.c + +++ b/drivers/net/ethernet/freescale/gianfar.c +-@@ -2064,7 +2064,7 @@ static int gfar_start_xmit(struct sk_buf ++@@ -2067,7 +2067,7 @@ static int gfar_start_xmit(struct sk_buf + int i, rq = 0, do_tstamp = 0; + u32 bufaddr; + unsigned long flags; +@@ -9,7 +9,7 @@ + + /* TOE=1 frames larger than 2500 bytes may see excess delays + * before start of transmission. +-@@ -2130,7 +2130,10 @@ static int gfar_start_xmit(struct sk_buf ++@@ -2133,7 +2133,10 @@ static int gfar_start_xmit(struct sk_buf + } + + /* Update transmit stats */ +@@ -21,7 +21,7 @@ + tx_queue->stats.tx_packets++; + + txbdp = txbdp_start = tx_queue->cur_tx; +-@@ -2150,12 +2153,13 @@ static int gfar_start_xmit(struct sk_buf ++@@ -2153,12 +2156,13 @@ static int gfar_start_xmit(struct sk_buf + } else { + /* Place the fragment addresses and lengths into the TxBDs */ + for (i = 0; i < nr_frags; i++) { +@@ -37,7 +37,7 @@ + BD_LFLAG(TXBD_READY); + + /* Handle the last BD specially */ +-@@ -2165,7 +2169,7 @@ static int gfar_start_xmit(struct sk_buf ++@@ -2168,7 +2172,7 @@ static int gfar_start_xmit(struct sk_buf + bufaddr = skb_frag_dma_map(priv->dev, + &skb_shinfo(skb)->frags[i], + 0, +@@ -46,7 +46,7 @@ + DMA_TO_DEVICE); + + /* set the TxBD length and buffer pointer */ +-@@ -2231,7 +2235,7 @@ static int gfar_start_xmit(struct sk_buf ++@@ -2234,7 +2238,7 @@ static int gfar_start_xmit(struct sk_buf + lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb); + } + +@@ -55,7 +55,7 @@ + + /* We can work in parallel with gfar_clean_tx_ring(), except + * when modifying num_txbdfree. Note that we didn't grab the lock +-@@ -2551,7 +2555,7 @@ static void gfar_clean_tx_ring(struct gf ++@@ -2554,7 +2558,7 @@ static void gfar_clean_tx_ring(struct gf + bdp = next_txbd(bdp, base, tx_ring_size); + } + diff --git a/patches/openwrt/0034-mpc85xx-replace-WDR4900-uci-defaults-ethernet-MAC-address-hack-with-DTS-entry.patch b/patches/openwrt/0034-mpc85xx-replace-WDR4900-uci-defaults-ethernet-MAC-address-hack-with-DTS-entry.patch new file mode 100644 index 00000000..d27b0f0d --- /dev/null +++ b/patches/openwrt/0034-mpc85xx-replace-WDR4900-uci-defaults-ethernet-MAC-address-hack-with-DTS-entry.patch @@ -0,0 +1,41 @@ +From: Matthias Schiffer +Date: Thu, 30 Apr 2015 02:12:18 +0200 +Subject: mpc85xx: replace WDR4900 uci-defaults ethernet MAC address hack with DTS entry + +This also changes the MAC address to one of the adresses actually used by the +stock firmware on one of the ethernet interfaces. + +diff --git a/target/linux/mpc85xx/base-files/etc/uci-defaults/02_network b/target/linux/mpc85xx/base-files/etc/uci-defaults/02_network +index e4e3566..525a552 100755 +--- a/target/linux/mpc85xx/base-files/etc/uci-defaults/02_network ++++ b/target/linux/mpc85xx/base-files/etc/uci-defaults/02_network +@@ -20,8 +20,6 @@ tl-wdr4900-v1) + ucidef_add_switch "switch0" "1" "1" + ucidef_add_switch_vlan "switch0" "1" "0t 2 3 4 5" + ucidef_add_switch_vlan "switch0" "2" "0t 1" +- ucidef_set_interface_macaddr lan "$(mtd_get_mac_binary config 338)" +- ucidef_set_interface_macaddr wan "$(mtd_get_mac_binary config 344)" + ;; + *) + ucidef_set_interfaces_lan_wan "eth0" "eth1" +diff --git a/target/linux/mpc85xx/files/arch/powerpc/boot/dts/tl-wdr4900-v1.dts b/target/linux/mpc85xx/files/arch/powerpc/boot/dts/tl-wdr4900-v1.dts +index 49e516c..7e48e23 100644 +--- a/target/linux/mpc85xx/files/arch/powerpc/boot/dts/tl-wdr4900-v1.dts ++++ b/target/linux/mpc85xx/files/arch/powerpc/boot/dts/tl-wdr4900-v1.dts +@@ -63,7 +63,7 @@ + label = "rootfs"; + }; + +- config@fe0000 { ++ config: config@fe0000 { + reg = <0x00fe0000 0x00010000>; + label = "config"; + read-only; +@@ -118,6 +118,7 @@ + enet0: ethernet@b0000 { + phy-handle = <&phy0>; + phy-connection-type = "rgmii-id"; ++ mtd-mac-address = <&config 0x14c>; + }; + + enet1: ethernet@b1000 { diff --git a/patches/openwrt/0035-iwinfo-update-NanoStation-Loco-txpower-offsets.patch b/patches/openwrt/0035-iwinfo-update-NanoStation-Loco-txpower-offsets.patch new file mode 100644 index 00000000..0b5e1861 --- /dev/null +++ b/patches/openwrt/0035-iwinfo-update-NanoStation-Loco-txpower-offsets.patch @@ -0,0 +1,20 @@ +From: Matthias Schiffer +Date: Mon, 4 May 2015 20:38:37 +0200 +Subject: iwinfo: update NanoStation (Loco) txpower offsets + +diff --git a/package/network/utils/iwinfo/src/hardware.txt b/package/network/utils/iwinfo/src/hardware.txt +index 153ffeb..b8dfc51 100644 +--- a/package/network/utils/iwinfo/src/hardware.txt ++++ b/package/network/utils/iwinfo/src/hardware.txt +@@ -42,8 +42,9 @@ + 0x168c 0x0027 0x0777 0x4082 7 0 "Ubiquiti" "SR71" + 0x168c 0x0029 0x0777 0x4005 7 0 "Ubiquiti" "SR71-15" + 0x168c 0x002a 0x0777 0xe302 12 0 "Ubiquiti" "PicoStation M2" /* ToDo: confirm offset */ +-0x168c 0x002a 0x0777 0xe012 12 0 "Ubiquiti" "NanoStation M2" /* ToDo: confirm offset */ +-0x168c 0x002a 0x0777 0xe005 5 0 "Ubiquiti" "NanoStation M5" /* ToDo: confirm offset */ ++0x168c 0x002a 0x0777 0xe012 11 0 "Ubiquiti" "NanoStation M2" ++0x168c 0x002e 0x0777 0xe0a2 8 0 "Ubiquiti" "NanoStation Loco M2" ++0x168c 0x002a 0x0777 0xe005 16 0 "Ubiquiti" "NanoStation M5" + 0x168c 0x002a 0x0777 0xe202 12 0 "Ubiquiti" "Bullet M2" + 0x168c 0x002a 0x0777 0xe805 5 0 "Ubiquiti" "Bullet M5" + 0x168c 0x002a 0x0777 0xe345 0 0 "Ubiquiti" "WispStation M5" /* ToDo: confirm offset */ diff --git a/patches/packages/routing/0003-batman-adv-introduce-no_rebroadcast-option.patch b/patches/packages/routing/0003-batman-adv-introduce-no_rebroadcast-option.patch index d310fa12..c0e90d66 100644 --- a/patches/packages/routing/0003-batman-adv-introduce-no_rebroadcast-option.patch +++ b/patches/packages/routing/0003-batman-adv-introduce-no_rebroadcast-option.patch @@ -1,7 +1,33 @@ From: Matthias Schiffer -Date: Wed, 7 Jan 2015 16:48:06 +0100 +Date: Thu, 2 Apr 2015 20:24:14 +0200 Subject: batman-adv: introduce 'no_rebroadcast' option +diff --git a/batman-adv/files/lib/netifd/proto/batadv.sh b/batman-adv/files/lib/netifd/proto/batadv.sh +index 632a209..01f567f 100644 +--- a/batman-adv/files/lib/netifd/proto/batadv.sh ++++ b/batman-adv/files/lib/netifd/proto/batadv.sh +@@ -6,16 +6,19 @@ init_proto "$@" + + proto_batadv_init_config() { + proto_config_add_string "mesh" ++ proto_config_add_string "mesh_no_rebroadcast" + } + + proto_batadv_setup() { + local config="$1" + local iface="$2" + +- local mesh +- json_get_vars mesh ++ local mesh mesh_no_rebroadcast ++ json_get_vars mesh mesh_no_rebroadcast + + echo "$mesh" > "/sys/class/net/$iface/batman_adv/mesh_iface" ++ [ -n "$mesh_no_rebroadcast" ] && echo "$mesh_no_rebroadcast" > "/sys/class/net/$iface/batman_adv/no_rebroadcast" ++ + proto_init_update "$iface" 1 + proto_send_update "$config" + } diff --git a/batman-adv/patches/0001-batman-adv-introduce-no_rebroadcast-option.patch b/batman-adv/patches/0001-batman-adv-introduce-no_rebroadcast-option.patch new file mode 100644 index 0000000..cd79917 diff --git a/scripts/check_site.sh b/scripts/check_site.sh index 17ee4b56..e0aa43e5 100755 --- a/scripts/check_site.sh +++ b/scripts/check_site.sh @@ -1,6 +1,6 @@ #!/bin/sh -SITE_CONFIG_LUA=packages/gluon/gluon/gluon-core/files/usr/lib/lua/gluon/site_config.lua +SITE_CONFIG_LUA=package/gluon-core/files/usr/lib/lua/gluon/site_config.lua CHECK_SITE_LIB=scripts/check_site_lib.lua "$GLUONDIR"/openwrt/staging_dir/host/bin/lua -e "site = dofile(os.getenv('GLUONDIR') .. '/${SITE_CONFIG_LUA}'); dofile(os.getenv('GLUONDIR') .. '/${CHECK_SITE_LIB}'); dofile()" diff --git a/scripts/site.sh b/scripts/site.sh index c523da20..82016cbe 100755 --- a/scripts/site.sh +++ b/scripts/site.sh @@ -1,5 +1,5 @@ #!/bin/sh -SITE_CONFIG_LUA=packages/gluon/gluon/gluon-core/files/usr/lib/lua/gluon/site_config.lua +SITE_CONFIG_LUA=package/gluon-core/files/usr/lib/lua/gluon/site_config.lua "$GLUONDIR"/openwrt/staging_dir/host/bin/lua -e "print(assert(dofile(os.getenv('GLUONDIR') .. '/${SITE_CONFIG_LUA}').$1))" 2>/dev/null diff --git a/targets/ar71xx-generic/profiles.mk b/targets/ar71xx-generic/profiles.mk index c3090287..1cc4ce40 100644 --- a/targets/ar71xx-generic/profiles.mk +++ b/targets/ar71xx-generic/profiles.mk @@ -111,9 +111,10 @@ $(eval $(call GluonProfile,TLMR3040)) $(eval $(call GluonModel,TLMR3040,tl-mr3040-v1,tp-link-tl-mr3040-v1)) $(eval $(call GluonModel,TLMR3040,tl-mr3040-v2,tp-link-tl-mr3040-v2)) -# TL-MR3220 v1 +# TL-MR3220 v1, v2 $(eval $(call GluonProfile,TLMR3220)) $(eval $(call GluonModel,TLMR3220,tl-mr3220-v1,tp-link-tl-mr3220-v1)) +$(eval $(call GluonModel,TLMR3220,tl-mr3220-v2,tp-link-tl-mr3220-v2)) # TL-MR3420 v1, v2 $(eval $(call GluonProfile,TLMR3420)) @@ -137,11 +138,11 @@ $(eval $(call GluonModel,UBNT,ubnt-bullet-m,ubiquiti-bullet-m)) $(eval $(call GluonModel,UBNT,ubnt-loco-m-xw,ubiquiti-loco-m-xw)) $(eval $(call GluonModel,UBNT,ubnt-nano-m,ubiquiti-nanostation-m)) $(eval $(call GluonModel,UBNT,ubnt-nano-m-xw,ubiquiti-nanostation-m-xw)) +$(eval $(call GluonModel,UBNT,ubnt-uap-pro,ubiquiti-unifi-ap-pro)) $(eval $(call GluonModel,UBNT,ubnt-unifi,ubiquiti-unifi)) $(eval $(call GluonModel,UBNT,ubnt-unifi-outdoor,ubiquiti-unifiap-outdoor)) ifeq ($(BROKEN),1) $(eval $(call GluonModel,UBNT,ubnt-ls-sr71,ubiquiti-ls-sr71)) # BROKEN: Untested -$(eval $(call GluonModel,UBNT,ubnt-uap-pro,ubiquiti-unifi-ap-pro)) # BROKEN: not properly tested; probably issues with WLAN adapter detection $(eval $(call GluonModel,UBNT,ubnt-unifi-outdoor-plus,ubiquiti-unifiap-outdoor+)) # BROKEN: WLAN doesn't work correctly (high packet loss) endif @@ -183,8 +184,8 @@ $(eval $(call GluonModel,WNDR3700,wndr3700v2,netgear-wndr3700v2)) $(eval $(call GluonModel,WNDR3700,wndr3800,netgear-wndr3800)) ifeq ($(BROKEN),1) $(eval $(call GluonModel,WNDR3700,wndrmac,netgear-wndrmac)) # BROKEN: untested -$(eval $(call GluonModel,WNDR3700,wndrmacv2,netgear-wndrmacv2)) # BROKEN: untested endif +$(eval $(call GluonModel,WNDR3700,wndrmacv2,netgear-wndrmacv2)) ## Allnet