diff --git a/.gitignore b/.gitignore index 7a4602a1..ab2b03cf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ *~ -/build -/images +/lede +/output /site -/openwrt +/tmp /packages -/modules.local diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..1c827fb2 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,53 @@ +Contribution Guidelines +======================= + +Because Gluon is such a universal software package that is used by several +different communities with different expectations and requirements, it is both +essential and difficult to have contributions from the communities. While they +are sometimes necessary to adapt Gluon to the needs of the communities, they +also have to be adaptable enough to fit as many needs as possible. On the other +hands, very special needs are better addressed in [packages] in community +repositories, because the Gluon maintainers would not use or test them and +thus couldn't do their "job" of maintaining them. + +To ease the work for the maintainers and to reduce the frustration of +contributors, please adhere to the following guidelines: + +Discuss first, build later +-------------------------- +If you have some non-trivial enhancement like a new package, some modification +of what is announced by a node, it is often best to first discuss the precise +solution first. The maintainers might have hints as to how a solution could be +implemented easiest, point out solutions how the same thing can already be done +using other parts or why the proposed change breaks other parts of the system. +They might even refuse the idea altogether - after all, they have to sleep well +after merging the changes, too. + +The preferred way to discuss in the IRC channel ([#gluon] on irc.hackint.org) +or on the [mailing list], however, you can also open a new issue on Github to +discuss there. We maintain a [list of rejected features] and we'd like to +kindly ask you to review it first. In general, looking for duplicates may save +you some time. + +Develop on top of master +------------------------ +If you are not developing something specific to a release (like for example a +security fix to a feature that got completely rewritten since the release), +develop it on top of the master branch. New features and even feature changes +aren't usually backported to old releases, but will be included in the upcoming +release, which will be built from master. + +Use descriptive commit messages +------------------------------- +If you modify a single package, start the first line of your commit message +with the package name followed by a colon. The first line should be enough to +identify the commit a week later and still know roughly what it did. If you +fix some bug, detail in the remaining commit message exactly how it could be +triggered and what you did to fix it. If in question, have a glance at the +existing commit messages to get the idea. + + +[packages]: http://gluon.readthedocs.org/en/latest/user/site.html#packages +[#gluon]: https://webirc.hackint.org/#gluon +[mailing list]: mailto:gluon@luebeck.freifunk.net +[list of rejected features]: https://github.com/freifunk-gluon/gluon/issues?q=label%3Arejected diff --git a/LICENSE b/LICENSE index adc32281..a9adc369 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ The code of Project Gluon may be distributed under the following terms, unless -noted otherwise in indiviual files or subtrees. +noted otherwise in individual files or subtrees. -Copyright (c) 2013, Project Gluon +Copyright (c) 2013-2017, Project Gluon All rights reserved. Redistribution and use in source and binary forms, with or without @@ -25,10 +25,10 @@ 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. -OpenWRT is licensed under the terms of the GNU General Public License Version 2, -which can be found under openwrt/LICENSE after the openwrt submodule has been -obtained. This applies to the following submodules: - * openwrt +LEDE and OpenWrt are licensed under the terms of the GNU General Public License +Version 2, which can be found at lede/LICENSE after the lede repository has been +obtained. This applies to the following repositories: + * lede * packages/openwrt * packages/routing * packages/luci diff --git a/Makefile b/Makefile index f8a4f85e..fab156c5 100644 --- a/Makefile +++ b/Makefile @@ -4,419 +4,155 @@ LC_ALL:=C LANG:=C export LC_ALL LANG -empty:= -space:= $(empty) $(empty) -GLUONMAKE_EARLY = $(SUBMAKE) -C $(GLUON_ORIGOPENWRTDIR) -f $(GLUONDIR)/Makefile GLUON_TOOLS=0 -GLUONMAKE = $(SUBMAKE) -C $(GLUON_OPENWRTDIR) -f $(GLUONDIR)/Makefile +GLUON_SITEDIR ?= $(CURDIR)/site +GLUON_TMPDIR ?= $(CURDIR)/tmp -ifneq ($(OPENWRT_BUILD),1) +GLUON_OUTPUTDIR ?= $(CURDIR)/output +GLUON_IMAGEDIR ?= $(GLUON_OUTPUTDIR)/images +GLUON_PACKAGEDIR ?= $(GLUON_OUTPUTDIR)/packages -GLUONDIR:=${CURDIR} +export GLUON_TMPDIR GLUON_IMAGEDIR GLUON_PACKAGEDIR DEVICES -include $(GLUONDIR)/include/gluon.mk -TOPDIR:=$(GLUON_ORIGOPENWRTDIR) -export TOPDIR +$(GLUON_SITEDIR)/site.mk: + $(error No site configuration was found. Please check out a site configuration to $(GLUON_SITEDIR)) + +include $(GLUON_SITEDIR)/site.mk + + +GLUON_RELEASE ?= $(error GLUON_RELEASE not set. GLUON_RELEASE can be set in site.mk or on the command line) + + +export GLUON_RELEASE GLUON_ATH10K_MESH GLUON_REGION GLUON_DEBUG update: FORCE - $(GLUONDIR)/scripts/update.sh - $(GLUONDIR)/scripts/patch.sh - -patch: FORCE - $(GLUONDIR)/scripts/patch.sh - -unpatch: FORCE - $(GLUONDIR)/scripts/unpatch.sh + @GLUON_SITEDIR='$(GLUON_SITEDIR)' scripts/update.sh + @GLUON_SITEDIR='$(GLUON_SITEDIR)' scripts/patch.sh + @GLUON_SITEDIR='$(GLUON_SITEDIR)' scripts/feeds.sh update-patches: FORCE - $(GLUONDIR)/scripts/update.sh - $(GLUONDIR)/scripts/update-patches.sh - $(GLUONDIR)/scripts/patch.sh + @GLUON_SITEDIR='$(GLUON_SITEDIR)' scripts/update.sh + @GLUON_SITEDIR='$(GLUON_SITEDIR)' scripts/update-patches.sh + @GLUON_SITEDIR='$(GLUON_SITEDIR)' scripts/patch.sh --include $(TOPDIR)/include/host.mk - -_SINGLE=export MAKEFLAGS=$(space); - -override OPENWRT_BUILD=1 -override GLUON_TOOLS=1 -GREP_OPTIONS= -export OPENWRT_BUILD GLUON_TOOLS GREP_OPTIONS - --include $(TOPDIR)/include/debug.mk --include $(TOPDIR)/include/depends.mk -include $(GLUONDIR)/include/toplevel.mk +update-feeds: FORCE + @GLUON_SITEDIR='$(GLUON_SITEDIR)' scripts/feeds.sh -include $(GLUONDIR)/targets/targets.mk +GLUON_TARGETS := + +define GluonTarget +gluon_target := $(1)$$(if $(2),-$(2)) +GLUON_TARGETS += $$(gluon_target) +GLUON_TARGET_$$(gluon_target)_BOARD := $(1) +GLUON_TARGET_$$(gluon_target)_SUBTARGET := $(if $(3),$(3),$(2)) +endef + +include targets/targets.mk -CheckTarget := [ -n '$(GLUON_TARGET)' -a -n '$(GLUON_TARGET_$(GLUON_TARGET)_BOARD)' -a -n '$(GLUON_TARGET_$(GLUON_TARGET)_SUBTARGET)' ] \ - || (echo -e 'Please set GLUON_TARGET to a valid target. Gluon supports the following targets:$(subst $(space),\n * ,$(GLUON_TARGETS))'; false) +LEDEMAKE = $(MAKE) -C lede + +BOARD := $(GLUON_TARGET_$(GLUON_TARGET)_BOARD) +SUBTARGET := $(GLUON_TARGET_$(GLUON_TARGET)_SUBTARGET) +LEDE_TARGET := $(BOARD)$(if $(SUBTARGET),-$(SUBTARGET)) + +export LEDE_TARGET -CheckExternal := test -d $(GLUON_ORIGOPENWRTDIR) || (echo 'You don'"'"'t seem to have obtained the external repositories needed by Gluon; please call `make update` first!'; false) +CheckTarget := [ '$(LEDE_TARGET)' ] \ + || (echo 'Please set GLUON_TARGET to a valid target. Gluon supports the following targets:'; $(foreach target,$(GLUON_TARGETS),echo ' * $(target)';) false) + +CheckExternal := test -d lede || (echo 'You don'"'"'t seem to have obtained the external repositories needed by Gluon; please call `make update` first!'; false) -prepare-target: FORCE +list-targets: FORCE + @$(foreach target,$(GLUON_TARGETS),echo '$(target)';) + + +GLUON_DEFAULT_PACKAGES := -odhcpd -ppp -ppp-mod-pppoe -wpad-mini gluon-core ip6tables hostapd-mini + +GLUON_PACKAGES := +define merge_packages + $(foreach pkg,$(1), + GLUON_PACKAGES := $$(strip $$(filter-out -$$(patsubst -%,%,$(pkg)) $$(patsubst -%,%,$(pkg)),$$(GLUON_PACKAGES)) $(pkg)) + ) +endef +$(eval $(call merge_packages,$(GLUON_DEFAULT_PACKAGES) $(GLUON_SITE_PACKAGES))) + +GLUON_PACKAGES_YES := $(filter-out -%,$(GLUON_PACKAGES)) +GLUON_PACKAGES_NO := $(patsubst -%,%,$(filter -%,$(GLUON_PACKAGES))) + + +config: FORCE @$(CheckExternal) @$(CheckTarget) - +@$(GLUONMAKE_EARLY) prepare-target + @( \ + echo 'CONFIG_TARGET_$(BOARD)=y' \ + $(if $(SUBTARGET),&& echo 'CONFIG_TARGET_$(BOARD)_$(SUBTARGET)=y') \ + $(foreach pkg,$(GLUON_PACKAGES_NO),&& echo '# CONFIG_PACKAGE_$(pkg) is not set') \ + && scripts/target_config.sh generic \ + && GLUON_SITEDIR='$(GLUON_SITEDIR)' scripts/target_config.sh '$(GLUON_TARGET)' \ + $(foreach pkg,$(GLUON_PACKAGES_YES),&& echo 'CONFIG_PACKAGE_$(pkg)=y') \ + $(foreach lang,$(GLUON_LANGS),&& echo 'CONFIG_GLUON_WEB_LANG_$(lang)=y') \ + && echo 'CONFIG_GLUON_RELEASE="$(GLUON_RELEASE)"' \ + && echo 'CONFIG_GLUON_SITEDIR="$(GLUON_SITEDIR)"' \ + && echo 'CONFIG_GLUON_BRANCH="$(GLUON_BRANCH)"' \ + ) > lede/.config + +@$(LEDEMAKE) defconfig + + @GLUON_SITEDIR='$(GLUON_SITEDIR)' scripts/target_config_check.sh '$(GLUON_TARGET)' '$(GLUON_PACKAGES_YES)' + + +LUA := lede/staging_dir/hostpkg/bin/lua + +$(LUA): + @$(CheckExternal) + + +@[ -e lede/.config ] || $(LEDEMAKE) defconfig + +@$(LEDEMAKE) tools/install + +@$(LEDEMAKE) package/lua/host/install + +prepare-target: config $(LUA) ; all: prepare-target - +@$(GLUONMAKE) prepare - +@$(GLUONMAKE) images + @GLUON_SITEDIR='$(GLUON_SITEDIR)' $(LUA) scripts/site_config.lua \ + || (echo 'Your site configuration did not pass validation.'; false) -prepare: prepare-target - +@$(GLUONMAKE) $@ + @scripts/clean_output.sh + +@$(LEDEMAKE) + @GLUON_SITEDIR='$(GLUON_SITEDIR)' scripts/copy_output.sh '$(GLUON_TARGET)' -clean download images: FORCE - @$(CheckExternal) - @$(CheckTarget) - +@$(GLUONMAKE_EARLY) maybe-prepare-target - +@$(GLUONMAKE) $@ +clean download: config + +@$(LEDEMAKE) $@ -toolchain/% package/% target/% image/%: FORCE - @$(CheckExternal) - @$(CheckTarget) - +@$(GLUONMAKE_EARLY) maybe-prepare-target - +@$(GLUONMAKE) $@ +dirclean: FORCE + +@[ -e lede/.config ] || $(LEDEMAKE) defconfig + +@$(LEDEMAKE) dirclean + @rm -rf $(GLUON_TMPDIR) $(GLUON_OUTPUTDIR) -manifest: FORCE - @[ -n '$(GLUON_BRANCH)' ] || (echo 'Please set GLUON_BRANCH to create a manifest.'; false) +manifest: $(LUA) FORCE + @[ '$(GLUON_BRANCH)' ] || (echo 'Please set GLUON_BRANCH to create a manifest.'; false) @echo '$(GLUON_PRIORITY)' | grep -qE '^([0-9]*\.)?[0-9]+$$' || (echo 'Please specify a numeric value for GLUON_PRIORITY to create a manifest.'; false) @$(CheckExternal) - ( \ + @( \ echo 'BRANCH=$(GLUON_BRANCH)' && \ - echo 'DATE=$(shell $(GLUON_ORIGOPENWRTDIR)/staging_dir/host/bin/lua $(GLUONDIR)/scripts/rfc3339date.lua)' && \ + echo "DATE=$$($(LUA) scripts/rfc3339date.lua)" && \ echo 'PRIORITY=$(GLUON_PRIORITY)' && \ - echo \ - ) > $(GLUON_BUILDDIR)/$(GLUON_BRANCH).manifest.tmp - - +($(foreach GLUON_TARGET,$(GLUON_TARGETS), \ - ( [ ! -e $(BOARD_BUILDDIR)/prepared ] || ( $(GLUONMAKE) manifest GLUON_TARGET='$(GLUON_TARGET)' V=s$(OPENWRT_VERBOSE) ) ) && \ - ) :) - - mkdir -p $(GLUON_IMAGEDIR)/sysupgrade - mv $(GLUON_BUILDDIR)/$(GLUON_BRANCH).manifest.tmp $(GLUON_IMAGEDIR)/sysupgrade/$(GLUON_BRANCH).manifest - -dirclean : FORCE - for dir in build_dir dl staging_dir tmp; do \ - rm -rf $(GLUON_ORIGOPENWRTDIR)/$$dir; \ - done - rm -rf $(GLUON_BUILDDIR) $(GLUON_IMAGEDIR) - -else - -TOPDIR=${CURDIR} -export TOPDIR - -include rules.mk - -include $(GLUONDIR)/include/gluon.mk - -include $(INCLUDE_DIR)/host.mk -include $(INCLUDE_DIR)/depends.mk -include $(INCLUDE_DIR)/subdir.mk - -include package/Makefile -include tools/Makefile -include toolchain/Makefile -include target/Makefile - - -PROFILES := -PROFILE_PACKAGES := - -define Profile - $(eval $(call Profile/Default)) - $(eval $(call Profile/$(1))) -endef - -define GluonProfile -PROFILES += $(1) -PROFILE_PACKAGES += $(filter-out -%,$(2) $(GLUON_$(1)_SITE_PACKAGES)) -GLUON_$(1)_DEFAULT_PACKAGES := $(2) -GLUON_$(1)_FACTORY_SUFFIX := -squashfs-factory -GLUON_$(1)_SYSUPGRADE_SUFFIX := -squashfs-sysupgrade -GLUON_$(1)_FACTORY_EXT := .bin -GLUON_$(1)_SYSUPGRADE_EXT := .bin -GLUON_$(1)_MODELS := -endef - -define GluonProfileFactorySuffix -GLUON_$(1)_FACTORY_SUFFIX := $(2) -GLUON_$(1)_FACTORY_EXT := $(3) -endef - -define GluonProfileSysupgradeSuffix -GLUON_$(1)_SYSUPGRADE_SUFFIX := $(2) -GLUON_$(1)_SYSUPGRADE_EXT := $(3) -endef - -define GluonModel -GLUON_$(1)_MODELS += $(3) -GLUON_$(1)_MODEL_$(3) := $(2) -endef - - -include $(GLUONDIR)/targets/targets.mk -include $(GLUONDIR)/targets/$(GLUON_TARGET)/profiles.mk - -BOARD := $(GLUON_TARGET_$(GLUON_TARGET)_BOARD) -override SUBTARGET := $(GLUON_TARGET_$(GLUON_TARGET)_SUBTARGET) - -target_prepared_stamp := $(BOARD_BUILDDIR)/target-prepared -gluon_prepared_stamp := $(BOARD_BUILDDIR)/prepared - - -include $(INCLUDE_DIR)/target.mk - - -prereq: FORCE - +$(NO_TRACE_MAKE) prereq - -prepare-tmpinfo: FORCE - @+$(MAKE) -r -s staging_dir/host/.prereq-build OPENWRT_BUILD= QUIET=0 - mkdir -p tmp/info - $(_SINGLE)$(NO_TRACE_MAKE) -j1 -r -s -f include/scan.mk SCAN_TARGET="packageinfo" SCAN_DIR="package" SCAN_NAME="package" SCAN_DEPS="$(TOPDIR)/include/package*.mk $(TOPDIR)/overlay/*/*.mk" SCAN_EXTRA="" - $(_SINGLE)$(NO_TRACE_MAKE) -j1 -r -s -f include/scan.mk SCAN_TARGET="targetinfo" SCAN_DIR="target/linux" SCAN_NAME="target" SCAN_DEPS="profiles/*.mk $(TOPDIR)/include/kernel*.mk $(TOPDIR)/include/target.mk" SCAN_DEPTH=2 SCAN_EXTRA="" SCAN_MAKEOPTS="TARGET_BUILD=1" - for type in package target; do \ - f=tmp/.$${type}info; t=tmp/.config-$${type}.in; \ - [ "$$t" -nt "$$f" ] || ./scripts/metadata.pl $${type}_config "$$f" > "$$t" || { rm -f "$$t"; echo "Failed to build $$t"; false; break; }; \ - done - [ tmp/.config-feeds.in -nt tmp/.packagefeeds ] || ./scripts/feeds feed_config > tmp/.config-feeds.in - ./scripts/metadata.pl package_mk tmp/.packageinfo > tmp/.packagedeps || { rm -f tmp/.packagedeps; false; } - ./scripts/metadata.pl package_feeds tmp/.packageinfo > tmp/.packagefeeds || { rm -f tmp/.packagefeeds; false; } - touch $(TOPDIR)/tmp/.build - -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 - 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 - -gluon-tools: FORCE - +$(GLUONMAKE_EARLY) tools/sed/install - +$(GLUONMAKE_EARLY) package/lua/host/install - -config: FORCE - +$(NO_TRACE_MAKE) scripts/config/conf OPENWRT_BUILD= QUIET=0 - +$(GLUONMAKE) prepare-tmpinfo - ( \ - cat $(GLUONDIR)/include/config $(GLUONDIR)/targets/$(GLUON_TARGET)/config; \ - echo 'CONFIG_BUILD_SUFFIX="gluon-$(GLUON_TARGET)"'; \ - echo '$(patsubst %,CONFIG_PACKAGE_%=m,$(sort $(filter-out -%,$(GLUON_DEFAULT_PACKAGES) $(GLUON_SITE_PACKAGES) $(PROFILE_PACKAGES))))' \ - | sed -e 's/ /\n/g'; \ - echo '$(patsubst %,CONFIG_LUCI_LANG_%=y,$(GLUON_LANGS))' \ - | sed -e 's/ /\n/g'; \ - ) > $(BOARD_BUILDDIR)/config.tmp - scripts/config/conf --defconfig=$(BOARD_BUILDDIR)/config.tmp Config.in - mv .config $(BOARD_BUILDDIR)/config - - echo 'CONFIG_ALL_KMODS=y' >> $(BOARD_BUILDDIR)/config.tmp - scripts/config/conf --defconfig=$(BOARD_BUILDDIR)/config.tmp Config.in - mv .config $(BOARD_BUILDDIR)/config-allmods - - cp $(BOARD_BUILDDIR)/config .config - -prepare-target: FORCE - rm $(GLUON_OPENWRTDIR)/tmp || true - mkdir -p $(GLUON_OPENWRTDIR)/tmp - - for dir in build_dir dl staging_dir; do \ - mkdir -p $(GLUON_ORIGOPENWRTDIR)/$$dir; \ - done - for link in build_dir config Config.in dl include Makefile package rules.mk scripts staging_dir target toolchain tools; do \ - ln -sf $(GLUON_ORIGOPENWRTDIR)/$$link $(GLUON_OPENWRTDIR); \ - done - - +$(GLUONMAKE_EARLY) feeds - +$(GLUONMAKE_EARLY) gluon-tools - +$(GLUONMAKE) config - touch $(target_prepared_stamp) - -$(target_prepared_stamp): - +$(GLUONMAKE_EARLY) prepare-target - -maybe-prepare-target: $(target_prepared_stamp) - -$(BUILD_DIR)/.prepared: Makefile - @mkdir -p $$(dirname $@) - @touch $@ - -$(toolchain/stamp-install): $(tools/stamp-install) -$(package/stamp-compile): $(package/stamp-cleanup) - - -clean: FORCE - +$(SUBMAKE) clean - rm -f $(gluon_prepared_stamp) - - -export SHA512SUM := $(GLUONDIR)/scripts/sha512sum.sh - - -download: FORCE - +$(SUBMAKE) tools/download - +$(SUBMAKE) toolchain/download - +$(SUBMAKE) package/download - +$(SUBMAKE) target/download - -toolchain: $(toolchain/stamp-install) $(tools/stamp-install) - -include $(INCLUDE_DIR)/kernel.mk - -kernel: FORCE - +$(NO_TRACE_MAKE) -C $(TOPDIR)/target/linux/$(BOARD) -f $(GLUONDIR)/include/Makefile.target $(LINUX_DIR)/.image TARGET_BUILD=1 - +$(NO_TRACE_MAKE) -C $(TOPDIR)/target/linux/$(BOARD) -f $(GLUONDIR)/include/Makefile.target $(LINUX_DIR)/.modules TARGET_BUILD=1 - -packages: $(package/stamp-compile) - $(_SINGLE)$(SUBMAKE) -r package/index - -prepare-image: FORCE - rm -rf $(BOARD_KDIR) - mkdir -p $(BOARD_KDIR) - $(foreach k, vmlinux vmlinux.elf \ - $(if $(KERNEL_IMAGES),$(KERNEL_IMAGES),$(filter-out dtbs,$(KERNELNAME))), \ - $(CP) $(KERNEL_BUILD_DIR)/$(k) $(BOARD_KDIR)/$(k); \ - ) - +$(SUBMAKE) -C $(TOPDIR)/target/linux/$(BOARD)/image image_prepare KDIR="$(BOARD_KDIR)" - -prepare: FORCE - @$(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) - echo 'src packages file:../openwrt/bin/$(BOARD)/packages' > $(BOARD_BUILDDIR)/opkg.conf - - +$(GLUONMAKE) toolchain - +$(GLUONMAKE) kernel - +$(GLUONMAKE) packages - +$(GLUONMAKE) prepare-image - - echo "$(GLUON_RELEASE)" > $(gluon_prepared_stamp) - -$(gluon_prepared_stamp): - +$(GLUONMAKE) prepare - - -include $(INCLUDE_DIR)/package-ipkg.mk - -# override variables from rules.mk -PACKAGE_DIR = $(GLUON_OPENWRTDIR)/bin/$(BOARD)/packages - -PROFILE_BUILDDIR = $(BOARD_BUILDDIR)/profiles/$(PROFILE) -PROFILE_KDIR = $(PROFILE_BUILDDIR)/kernel -BIN_DIR = $(PROFILE_BUILDDIR)/images - -TARGET_DIR = $(PROFILE_BUILDDIR)/root - -PREPARED_RELEASE = $$(cat $(gluon_prepared_stamp)) -IMAGE_PREFIX = gluon-$(GLUON_SITE_CODE)-$(PREPARED_RELEASE) - -OPKG:= \ - IPKG_TMP="$(TMP_DIR)/ipkgtmp" \ - IPKG_INSTROOT="$(TARGET_DIR)" \ - IPKG_CONF_DIR="$(TMP_DIR)" \ - IPKG_OFFLINE_ROOT="$(TARGET_DIR)" \ - $(STAGING_DIR_HOST)/bin/opkg \ - -f $(BOARD_BUILDDIR)/opkg.conf \ - --cache $(TMP_DIR)/dl \ - --offline-root $(TARGET_DIR) \ - --force-postinstall \ - --add-dest root:/ \ - --add-arch all:100 \ - --add-arch $(ARCH_PACKAGES):200 - -EnableInitscript = ! grep -q '\#!/bin/sh /etc/rc.common' $(1) || bash ./etc/rc.common $(1) enable - - -enable_initscripts: FORCE - cd $(TARGET_DIR) && ( export IPKG_INSTROOT=$(TARGET_DIR); \ - $(foreach script,$(wildcard $(TARGET_DIR)/etc/init.d/*), \ - $(call EnableInitscript,$(script)); \ + echo && \ + $(foreach GLUON_TARGET,$(GLUON_TARGETS), \ + GLUON_SITEDIR='$(GLUON_SITEDIR)' scripts/generate_manifest.sh '$(GLUON_TARGET)' && \ ) : \ - ) + ) > 'tmp/$(GLUON_BRANCH).manifest.tmp' + @mkdir -p '$(GLUON_IMAGEDIR)/sysupgrade' + @mv 'tmp/$(GLUON_BRANCH).manifest.tmp' '$(GLUON_IMAGEDIR)/sysupgrade/$(GLUON_BRANCH).manifest' -# Generate package list -$(eval $(call merge-lists,INSTALL_PACKAGES,DEFAULT_PACKAGES GLUON_DEFAULT_PACKAGES GLUON_SITE_PACKAGES GLUON_$(PROFILE)_DEFAULT_PACKAGES GLUON_$(PROFILE)_SITE_PACKAGES)) +FORCE: ; -package_install: FORCE - $(OPKG) update - $(OPKG) install $(PACKAGE_DIR)/base-files_*.ipk $(PACKAGE_DIR)/libc_*.ipk - $(OPKG) install $(PACKAGE_DIR)/kernel_*.ipk - - $(OPKG) install $(INSTALL_PACKAGES) - +$(GLUONMAKE) enable_initscripts - - rm -f $(TARGET_DIR)/usr/lib/opkg/lists/* $(TARGET_DIR)/tmp/opkg.lock - -# Remove opkg database when opkg is not intalled - if [ ! -x $(TARGET_DIR)/bin/opkg ]; then rm -rf $(TARGET_DIR)/usr/lib/opkg; fi - - -ifeq ($(GLUON_OPKG_CONFIG),1) -include $(INCLUDE_DIR)/version.mk -endif - -opkg_config: FORCE - cp $(GLUON_OPENWRTDIR)/package/system/opkg/files/opkg.conf $(TARGET_DIR)/etc/opkg.conf - for d in base luci packages routing telephony management oldpackages; do \ - echo "src/gz %n_$$d %U/$$d" >> $(TARGET_DIR)/etc/opkg.conf; \ - done - $(VERSION_SED) $(TARGET_DIR)/etc/opkg.conf - - -image: FORCE - rm -rf $(TARGET_DIR) $(BIN_DIR) $(PROFILE_KDIR) - mkdir -p $(TARGET_DIR) $(BIN_DIR) $(TARGET_DIR)/tmp $(GLUON_IMAGEDIR)/factory $(GLUON_IMAGEDIR)/sysupgrade - cp -r $(BOARD_KDIR) $(PROFILE_KDIR) - - +$(GLUONMAKE) package_install - +$(GLUONMAKE) opkg_config GLUON_OPKG_CONFIG=1 - - $(call Image/mkfs/prepare) - $(_SINGLE)$(NO_TRACE_MAKE) -C $(TOPDIR)/target/linux/$(BOARD)/image install TARGET_BUILD=1 IMG_PREFIX=gluon \ - PROFILE="$(PROFILE)" KDIR="$(PROFILE_KDIR)" TARGET_DIR="$(TARGET_DIR)" BIN_DIR="$(BIN_DIR)" TMP_DIR="$(TMP_DIR)" - - $(foreach model,$(GLUON_$(PROFILE)_MODELS), \ - $(if $(GLUON_$(PROFILE)_SYSUPGRADE_EXT), \ - rm -f $(GLUON_IMAGEDIR)/sysupgrade/gluon-*-$(model)-sysupgrade$(GLUON_$(PROFILE)_SYSUPGRADE_EXT) && \ - cp $(BIN_DIR)/gluon-$(GLUON_$(PROFILE)_MODEL_$(model))$(GLUON_$(PROFILE)_SYSUPGRADE_SUFFIX)$(GLUON_$(PROFILE)_SYSUPGRADE_EXT) $(GLUON_IMAGEDIR)/sysupgrade/$(IMAGE_PREFIX)-$(model)-sysupgrade$(GLUON_$(PROFILE)_SYSUPGRADE_EXT) && \ - ) \ - $(if $(GLUON_$(PROFILE)_FACTORY_EXT), \ - rm -f $(GLUON_IMAGEDIR)/factory/gluon-*-$(model)$(GLUON_$(PROFILE)_FACTORY_EXT) && \ - cp $(BIN_DIR)/gluon-$(GLUON_$(PROFILE)_MODEL_$(model))$(GLUON_$(PROFILE)_FACTORY_SUFFIX)$(GLUON_$(PROFILE)_FACTORY_EXT) $(GLUON_IMAGEDIR)/factory/$(IMAGE_PREFIX)-$(model)$(GLUON_$(PROFILE)_FACTORY_EXT) && \ - ) \ - ) : - -image/%: $(gluon_prepared_stamp) - +$(GLUONMAKE) image PROFILE="$(patsubst image/%,%,$@)" V=s$(OPENWRT_VERBOSE) - -call_image/%: FORCE - +$(GLUONMAKE) $(patsubst call_image/%,image/%,$@) - -images: $(patsubst %,call_image/%,$(PROFILES)) ; - -manifest: FORCE - ( \ - cd $(GLUON_IMAGEDIR)/sysupgrade; \ - $(foreach profile,$(PROFILES), \ - $(foreach model,$(GLUON_$(profile)_MODELS), \ - file="$(IMAGE_PREFIX)-$(model)-sysupgrade$(GLUON_$(profile)_SYSUPGRADE_EXT)"; \ - [ -e "$$file" ] && echo '$(model)' "$(PREPARED_RELEASE)" "$$($(SHA512SUM) "$$file")" "$$file"; \ - ) \ - ) : \ - ) >> $(GLUON_BUILDDIR)/$(GLUON_BRANCH).manifest.tmp - - -.PHONY: all images prepare clean gluon-tools manifest - -endif +.PHONY: FORCE +.NOTPARALLEL: diff --git a/README.md b/README.md index 87750136..151d06b8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ Documentation (incomplete at this time, contribute if you can!) may be found at -http://gluon.readthedocs.org/ +http://gluon.readthedocs.org/. If you're new to Gluon and ready to get your feet wet, have a look at the [Getting Started Guide](http://gluon.readthedocs.org/en/latest/user/getting_started.html). @@ -8,15 +8,18 @@ If you're new to Gluon and ready to get your feet wet, have a look at the ## Issues & Feature requests -Before opening an issue make sure to read check whether any existing issues +Before opening an issue, make sure to check whether any existing issues (open or closed) match. If you're suggesting a new feature, drop by on IRC or our mailinglist to discuss it first. +We maintain a [Roadmap](https://github.com/freifunk-gluon/gluon/wiki/Roadmap) for +the future development of Gluon. + ## Use a release! -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 v2015.1 && make update`. +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 tag` +and switch to one by running `git checkout v2017.1 && make update`. If you're using the autoupdater, do not autoupdate nodes with anything but releases. If you upgrade using random master commits the nodes *will break* eventually. @@ -25,11 +28,11 @@ If you upgrade using random master commits the nodes *will break* eventually. To subscribe to the list, send a message to: - gluon-subscribe@luebeck.freifunk.net + gluon+subscribe@luebeck.freifunk.net To remove your address from the list, just send a message to the address in the `List-Unsubscribe` header of any list message. If you haven't changed addresses since subscribing, you can also send a message to: - gluon-unsubscribe@luebeck.freifunk.net + gluon+unsubscribe@luebeck.freifunk.net diff --git a/contrib/depdot.sh b/contrib/depdot.sh new file mode 100755 index 00000000..c065ea57 --- /dev/null +++ b/contrib/depdot.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +# Script to output the dependency graph of Gluon's packages +# Limitations: +# * Works only if directory names and package names are the same (true for all Gluon packages) +# * Doesn't show dependencies through virtual packages correctly + + + +shopt -s nullglob + + +pushd "$(dirname "$0")/.." >/dev/null + + +escape_name() { + echo -n "_$1" | tr -c '[:alnum:]' _ +} + +print_node () { + echo "$(escape_name "$1") [label=\"$1\", shape=box];" +} + +print_dep() { + echo "$(escape_name "$1") -> $(escape_name "$2");" +} + +echo 'digraph G {' + +for makefile in ./package/*/Makefile; do + dir="$(dirname "$makefile")" + package="$(basename "$dir")" + + deps=$(grep -w DEPENDS "$makefile" | cut -d= -f2 | tr -d +) + + print_node "$package" + for dep in $deps; do + print_node "$dep" + print_dep "$package" "$dep" + done +done | sort -u + +popd >/dev/null + +echo '}' diff --git a/contrib/i18n-scan.pl b/contrib/i18n-scan.pl new file mode 100755 index 00000000..8e7d2597 --- /dev/null +++ b/contrib/i18n-scan.pl @@ -0,0 +1,128 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Text::Balanced qw(extract_bracketed extract_delimited extract_tagged); + +@ARGV >= 1 || die "Usage: $0 \n"; + + +my %stringtable; + +sub dec_lua_str +{ + my $s = shift; + $s =~ s/[\s\n]+/ /g; + $s =~ s/\\n/\n/g; + $s =~ s/\\t/\t/g; + $s =~ s/\\(.)/$1/g; + $s =~ s/^ //; + $s =~ s/ $//; + return $s; +} + +sub dec_tpl_str +{ + my $s = shift; + $s =~ s/-$//; + $s =~ s/[\s\n]+/ /g; + $s =~ s/^ //; + $s =~ s/ $//; + $s =~ s/\\/\\\\/g; + return $s; +} + + +if( open F, "find @ARGV -type f '(' -name '*.html' -o -name '*.lua' ')' |" ) +{ + while( defined( my $file = readline F ) ) + { + chomp $file; + + if( open S, "< $file" ) + { + local $/ = undef; + my $raw = ; + close S; + + + my $text = $raw; + + while( $text =~ s/ ^ .*? (?:translate|translatef|i18n|_) [\n\s]* \( /(/sgx ) + { + ( my $code, $text ) = extract_bracketed($text, q{('")}); + + $code =~ s/\\\n/ /g; + $code =~ s/^\([\n\s]*//; + $code =~ s/[\n\s]*\)$//; + + my $res = ""; + my $sub = ""; + + if( $code =~ /^['"]/ ) + { + while( defined $sub ) + { + ( $sub, $code ) = extract_delimited($code, q{'"}, q{\s*(?:\.\.\s*)?}); + + if( defined $sub && length($sub) > 2 ) + { + $res .= substr $sub, 1, length($sub) - 2; + } + else + { + undef $sub; + } + } + } + elsif( $code =~ /^(\[=*\[)/ ) + { + my $stag = quotemeta $1; + my $etag = $stag; + $etag =~ s/\[/]/g; + + ( $res ) = extract_tagged($code, $stag, $etag); + + $res =~ s/^$stag//; + $res =~ s/$etag$//; + } + + $res = dec_lua_str($res); + $stringtable{$res}++ if $res; + } + + + $text = $raw; + + while( $text =~ s/ ^ .*? <% -? [:_] /<%/sgx ) + { + ( my $code, $text ) = extract_tagged($text, '<%', '%>'); + + if( defined $code ) + { + $code = dec_tpl_str(substr $code, 2, length($code) - 4); + $stringtable{$code}++; + } + } + } + } + + close F; +} + + +if( open C, "| msgcat -" ) +{ + printf C "msgid \"\"\nmsgstr \"Content-Type: text/plain; charset=UTF-8\"\n\n"; + + foreach my $key ( sort keys %stringtable ) + { + if( length $key ) + { + $key =~ s/"/\\"/g; + printf C "msgid \"%s\"\nmsgstr \"\"\n\n", $key; + } + } + + close C; +} diff --git a/contrib/lsupgrade.sh b/contrib/lsupgrade.sh index 7fe11299..eca7a852 100755 --- a/contrib/lsupgrade.sh +++ b/contrib/lsupgrade.sh @@ -2,10 +2,11 @@ # Script to list all upgrade scripts in a clear manner # Limitations: -# * Does only show scripts of packages whose `files' directory represent the whole image filesystem (which are all Gluon packages) +# * Does only show scripts of packages whose `files'/`luasrc' directories represent the whole image filesystem (which are all Gluon packages) -SUFFIX=files/lib/gluon/upgrade +SUFFIX1=files/lib/gluon/upgrade +SUFFIX2=luasrc/lib/gluon/upgrade shopt -s nullglob @@ -35,8 +36,11 @@ find ./package packages -name Makefile | while read makefile; do dirname="$(dirname "$dir" | cut -d/ -f 3-)" package="$(basename "$dir")" - for file in "${SUFFIX}"/*; do - echo "${GREEN}$(basename "${file}")${RESET}" "(${BLUE}${repo}${RESET}/${dirname}${dirname:+/}${RED}${package}${RESET}/${SUFFIX})" + for file in "${SUFFIX1}"/*; do + echo "${GREEN}$(basename "${file}")${RESET}" "(${BLUE}${repo}${RESET}/${dirname}${dirname:+/}${RED}${package}${RESET}/${SUFFIX1})" + done + for file in "${SUFFIX2}"/*; do + echo "${GREEN}$(basename "${file}")${RESET}" "(${BLUE}${repo}${RESET}/${dirname}${dirname:+/}${RED}${package}${RESET}/${SUFFIX2})" done popd >/dev/null done | sort diff --git a/contrib/sign.sh b/contrib/sign.sh index 082e967e..0923b2dc 100755 --- a/contrib/sign.sh +++ b/contrib/sign.sh @@ -1,6 +1,8 @@ #!/bin/sh -if [ $# -eq 0 -o "-h" = "$1" -o "-help" = "$1" -o "--help" = "$1" ]; then +set -e + +if [ $# -ne 2 -o "-h" = "$1" -o "--help" = "$1" -o ! -r "$1" -o ! -r "$2" ]; then cat < @@ -25,16 +27,18 @@ manifest="$2" upper="$(mktemp)" lower="$(mktemp)" -awk "BEGIN { sep=0 } - /^---\$/ { sep=1; next } - { if(sep==0) print > \"$upper\"; - else print > \"$lower\"}" \ +trap 'rm -f "$upper" "$lower"' EXIT + +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" +( + cat "$upper" + echo --- + cat "$lower" +) > "$manifest" diff --git a/contrib/sigtest.sh b/contrib/sigtest.sh new file mode 100755 index 00000000..2ed06d0f --- /dev/null +++ b/contrib/sigtest.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +if [ $# -eq 0 -o "-h" = "$1" -o "-help" = "$1" -o "--help" = "$1" ]; then + cat < + +sigtest.sh checks if a manifest is signed by the public key . There is +no output, success or failure is indicated via the return code. + +See also: + * ecdsautils in https://github.com/tcatm/ecdsautils + * http://gluon.readthedocs.org/en/latest/features/autoupdater.html + +EOHELP + exit 1 +fi + +public="$1" +manifest="$2" +upper="$(mktemp)" +lower="$(mktemp)" +ret=1 + +awk "BEGIN { sep=0 } + /^---\$/ { sep=1; next } + { if(sep==0) print > \"$upper\"; + else print > \"$lower\"}" \ + "$manifest" + +while read line +do + if ecdsaverify -s "$line" -p "$public" "$upper"; then + ret=0 + break + fi +done < "$lower" + +rm -f "$upper" "$lower" +exit $ret diff --git a/docs/conf.py b/docs/conf.py index 090de523..c0a54260 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -47,16 +47,16 @@ master_doc = 'index' # General information about the project. project = 'Gluon' -copyright = '2015, Project Gluon' +copyright = '2015-2017, 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 # built documents. # # The short X.Y version. -version = '2015.1+' +version = '2017.1+' # The full version, including alpha/beta/rc tags. -release = '2015.1+' +release = '2017.1+' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/dev/basics.rst b/docs/dev/basics.rst index 7e7d9f58..2f4d1d89 100644 --- a/docs/dev/basics.rst +++ b/docs/dev/basics.rst @@ -34,21 +34,7 @@ rerun `patches`; the resulting branch will be called `patched`, while the commit specified in `modules` can be refered to by the branch `base`. -:: - - make unpatch - -sets the repositories to the `base` branch, - -:: - - make patch - -re-applies the patches by resetting the `patched` branch to `base` and calling `git am` -for the patch files. Calling `make` or a similar command after calling `make unpatch` -is generally not a good idea. - -After new patches have been commited on top of the patched branch (or existing commits +After new patches have been commited on top of the `patched` branch (or existing commits since the base commit have been edited or removed), the patch directories can be regenerated using @@ -61,3 +47,19 @@ and you can try rebasing it onto the new `base` branch yourself and after that c Always call `make update-patches` after making changes to a module repository as `make update` will overwrite your commits, making `git reflog` the only way to recover them! + +Development Guidelines +---------------------- +lua should be used instead of sh whenever sensible. The following criteria +should be considered: + +- Is the script doing more than just executing external commands? if so, use lua +- Is the script parsing/editing json-data? If so, use lua for speed +- When using sh, use jsonfilter instead of json_* functions for speed + +Code formatting may sound like a topic for the pedantic, however it helps if +the code in the project is formatted in the same way. The following rules +apply: + +- use tabs instead of spaces +- trailing whitespaces must be eliminated diff --git a/docs/dev/configmode.rst b/docs/dev/configmode.rst deleted file mode 100644 index 9a174d4c..00000000 --- a/docs/dev/configmode.rst +++ /dev/null @@ -1,92 +0,0 @@ -Config Mode -=========== - -As of 2014.4 `gluon-config-mode` consists of several modules. - -gluon-config-mode-core - This modules provides the core functionality for the config mode. - All modules must depend on it. - -gluon-config-mode-hostname - Provides a hostname field. - -gluon-config-mode-autoupdater - Informs whether the autoupdater is enabled. - -gluon-config-mode-mesh-vpn - Allows toggling of mesh-vpn-fastd and setting a bandwidth limit. - -gluon-config-mode-geo-location - Enables the user to set the geographical location of the node. - -gluon-config-mode-contact-info - Adds a field where the user can provide contact information. - -In order to get a config mode close to the one found in 2014.3.x you may add -these modules to your `site.mk`: -gluon-config-mode-hostname, -gluon-config-mode-autoupdater, -gluon-config-mode-mesh-vpn, -gluon-config-mode-geo-location, -gluon-config-mode-contact-info - -Writing Config Mode Modules -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Config mode modules are located at `/lib/gluon/config-mode/wizard` and -`/lib/gluon/config-mode/reboot`. Modules are named like `0000-name.lua` and -are executed in lexical order. If you take the standard set of modules, the -order is, for wizard modules: - - - 0050-autoupdater-info - - 0100-hostname - - 0300-mesh-vpn - - 0400-geo-location - - 0500-contact-info - -While for reboot modules it is: - - - 0100-mesh-vpn - - 0900-msg-reboot - -Wizards -------- - -Wizard modules return a UCI section. A simple module capable of changing the -hostname might look like this:: - - local cbi = require "luci.cbi" - 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", "Hostname") - 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 - -Reboot page ------------ - -Reboot modules return a function that will be called when the page is to be -rendered or nil (i.e. the module is skipped):: - - if no_hello_world_today then - return nil - else - return function () - luci.template.render_string("Hello World!") - end - end - diff --git a/docs/dev/hardware.rst b/docs/dev/hardware.rst index a1a7f31c..7c17bcc9 100644 --- a/docs/dev/hardware.rst +++ b/docs/dev/hardware.rst @@ -11,85 +11,132 @@ is a requirement. At the moment, Gluon's scripts can't handle devices without WLAN adapters (although such environments may also be interesting, e.g. for automated testing in virtual machines). + .. _hardware-adding-profiles: Adding profiles --------------- -The vast majority of devices with ath9k WLAN uses the ar71xx target of OpenWrt. +The vast majority of devices with ath9k WLAN uses the ar71xx target of LEDE. If the hardware you want to add support for is also ar71xx, adding a new profile is enough. -Profiles are defined in ``targets/-/profiles.mk``. There are two macros -used to define which images are generated: ``GluonProfile`` and ``GluonModel``. The following examples -are taken from ``profiles.mk`` of the ``ar71xx-generic`` target:: +Profiles are defined in ``targets/*`` in a shell-based DSL (so common shell +commands syntax like ``if`` can be used. - $(eval $(call GluonProfile,TLWR1043)) - $(eval $(call GluonModel,TLWR1043,tl-wr1043nd-v1-squashfs,tp-link-tl-wr1043n-nd-v1)) - $(eval $(call GluonModel,TLWR1043,tl-wr1043nd-v2-squashfs,tp-link-tl-wr1043n-nd-v2)) +The ``device`` command is used to define an image build for a device. It takes +two or three parameters. -The ``GluonProfile`` macro takes at least one parameter, the profile name as it is -defined in the Makefiles of OpenWrt (``openwrt/target/linux///profiles/*`` -and ``openwrt/target/linux//image/Makefile``). If the target you are on doesn't define -profiles (e.g. on x86), just add a single profile called ``Generic`` or similar. - -It may optionally take a second parameter which defines additional packages to include for the profile -(e.g. ath10k). The additional packages defined in ``openwrt/target/linux///profiles/*`` -aren't used. - -The ``GluonModel`` macro takes three parameters: The profile name, the suffix of the image file -generated by OpenWrt (without the file extension), and the final image name of the Gluon image. -The final image name must be the same that is returned by the following command. - -:: +The first parameter defines the Gluon profile name, which is used to refer to the +device and is part of the generated image name. The profile name must be same as +the output of the following command (on the target device), so the autoupdater +can work:: lua -e 'print(require("platform_info").get_image_name())' +The second parameter defines the name of the image files generated by LEDE. Usually, +it is also the LEDE profile name; for devices that still use the old image build +code, a third parameter with the LEDE profile name can be passed. The profile names +can be found in the image Makefiles in ``lede/target/linux//image/Makefile``. -This is just so the autoupdater can work. The command has to be executed _on_ the target (eg. the hardware router with a flashed image). So you'll first have to build an image with a guessed name, and afterwards build a new, correctly named image. On targets which aren't supported by the autoupdater, -``require("platform_info").get_image_name()`` will just return ``nil`` and the final image name -may be defined arbitrarily. +Examples:: + + device tp-link-tl-wr1043n-nd-v1 tl-wr1043nd-v1 + device alfa-network-hornet-ub hornet-ub HORNETUB + +Suffixes and extensions +''''''''''''''''''''''' + +By default, image files are expected to have the extension ``.bin``. In addition, +the images generated by LEDE have a suffix before the extension that defaults to +``-squashfs-factory`` and ``-squashfs-sysupgrade``. + +This can be changed using the ``factory`` and ``sysupgrade`` commands, either at +the top of the file to set the defaults for all images, or for a single image. There +are three forms with 0 to 2 arguments (all work with ``sysupgrade`` as well):: + + factory SUFFIX .EXT + factory .EXT + factory + +When only an extension is given, the default suffix is retained. When no arguments +are given, this signals that no factory (or sysupgrade) image exists. + +Aliases +''''''' + +Sometimes multiple models use the same LEDE images. In this case, the ``alias`` +command can be used to create symlinks and additional entries in the autoupdater +manifest for the alternative models. + +Standalone images +''''''''''''''''' + +On targets without *per-device rootfs* support in LEDE, the commands described above +can't be used. Instead, ``factory_image`` and ``sysupgrade_image`` are used:: + + factory_image PROFILE IMAGE .EXT + sysupgrade_image PROFILE IMAGE .EXT + +Again, the profile name must match the value printed by the aforementioned Lua +command. The image name must match the part between the target name and the extension +as generated by LEDE and is to be omitted when no such part exists. + +Packages +'''''''' + +The ``packages`` command takes an arbitrary number of arguments. Each argument +defines an additional package to include in the images in addition to the default +package sets defined by LEDE. When a package name is prefixed by a minus sign, the +packages are excluded instead. + +The ``packages`` command may be used at the top of a target definition to modify +the default package list for all images, or just for a single device (when the +target supports *per-default rootfs*). + + +Configuration +''''''''''''' + +The ``config`` command allows to add arbitary target-specific LEDE configuration +to be emitted to ``.config``. + +Notes +''''' On devices with multiple WLAN adapters, care must also be taken that the primary MAC address is configured correctly. ``/lib/gluon/core/sysconfig/primary_mac`` should contain the MAC address which -can be found on a label on most hardware; if it does not, ``/lib/gluon/upgrade/core/initial/001-sysconfig`` +can be found on a label on most hardware; if it does not, ``/lib/gluon/upgrade/010-primary-mac`` in ``gluon-core`` might need a fix. (There have also been cases in which the address was incorrect -even on devices with only one WLAN adapter, in these cases an OpenWrt bug was the cause). +even on devices with only one WLAN adapter, in these cases a LEDE bug was the cause). + Adding support for new hardware targets --------------------------------------- + Adding a new target is much more complex than adding a new profile. There are two basic steps required for adding a new target: -Adjust packages -''''''''''''''' -One package that definitely needs adjustments for every new target added is ``lua-platform-info``. Just -start with a copy of an existing platform info script, adjust it for the new target, and add the new target -to the list of supported targets in the package Makefile. +Package adjustments +''''''''''''''''''' -On many targets, Gluon's network setup scripts (mainly in the packages ``gluon-core`` and ``gluon-mesh-batman-adv-core``) +One package that may need adjustments for new targets is ``libplatforminfo`` (to be found in +`packages/gluon/libs/libplatforminfo `_). +If the new platform works fine with the definitions found in ``default.c``, nothing needs to be done. Otherwise, +create a definition for the added target or subtarget, either by symlinking one of the files in the ``templates`` +directory, or adding a new source file. + +On many targets, Gluon's network setup scripts (mainly in the package ``gluon-core``) won't run correctly without some adjustments, so better double check that everything is fine there (and the files ``primary_mac``, ``lan_ifname`` and ``wan_ifname`` in ``/lib/gluon/core/sysconfig/`` contain sensible values). -Add support to the build system -''''''''''''''''''''''''''''''' -A directory for the new target must be created under ``targets``, and it must be added -to ``targets/targets.mk``. In the new target directory, three files must be created: +Build system support +'''''''''''''''''''' -* config -* profiles.mk -* vermagic +A definition for the new target must be created under ``targets``, and it must be added +to ``targets/targets.mk``. The ``GluonTarget`` macro takes one to three arguments: +the target name, the Gluon subtarget name (if the target has subtargets), and the +LEDE subtarget name (if it differs from the Gluon subtarget). The third argument +can be used to define multiple Gluon targets with different configuration for the +same LEDE target, like it is done for the ``ar71xx-tiny`` target. -The file ``config`` can be used to add additional, target-specific options to the OpenWrt config. It -must at least select the correct target and subtarget. For ``profiles.mk``, see :ref:`hardware-adding-profiles`. - -The files ``vermagic`` must have the correct content so kernel modules from the upstream repositories -can be installed without dependency issues. The OpenWrt version a Gluon release is based on is defined by the upstream package repo URL in ``include/gluon.mk`` -(in the variable ``CONFIG_VERSION_REPO``); at the time this documentation was written, this was ``barrier_breaker/14.07``; whenever -the package repo is updated, all ``vermagic`` files must be updated as well. - -The content is a hash which is part of the version number of the kernel package. So in the case of ``ar71xx-generic`` on -``barrier_breaker``, we look for the kernel package in the directory ``https://downloads.openwrt.org/barrier_breaker/14.07/ar71xx/generic/packages/base/``. -As the kernel package is called ``kernel_3.10.49-1-0114c71ed85677c9c1e4911437af4743_ar71xx.ipk``, the correct ``vermagic`` string -is ``0114c71ed85677c9c1e4911437af4743``. - -After this, is should be sufficient to call ``make GLUON_TARGET=-`` to build the images for the new target. +After this, is should be sufficient to call ``make GLUON_TARGET=`` to build the images for the new target. diff --git a/docs/dev/i18n.rst b/docs/dev/i18n.rst deleted file mode 100644 index b51bfdee..00000000 --- a/docs/dev/i18n.rst +++ /dev/null @@ -1,88 +0,0 @@ -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 ``packages/luci/luci.mk`` file after -Gluon's dependencies have been downloaded using ``make update``. 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/dev/mac_addresses.rst b/docs/dev/mac_addresses.rst new file mode 100644 index 00000000..b221a302 --- /dev/null +++ b/docs/dev/mac_addresses.rst @@ -0,0 +1,18 @@ +MAC addresses +============= + +Many devices don't have enough unique MAC addresses assigned by the vendor +(in batman-adv, each mesh interface needs an own MAC address that must be unique +mesh-wide). + +Gluon tries to solve this issue by using a hash of the primary MAC address as a +45 bit MAC address prefix. The resulting 8 addresses are used as follows: + +* 0: client0; WAN +* 1: mesh0 +* 2: ibss0 +* 3: wan_radio0 (private WLAN); batman-adv primary address +* 4: client1; LAN +* 5: mesh1 +* 6: ibss1 +* 7: wan_radio1 (private WLAN); mesh VPN diff --git a/docs/dev/upgrade.rst b/docs/dev/upgrade.rst index 3cd57950..2c18604d 100644 --- a/docs/dev/upgrade.rst +++ b/docs/dev/upgrade.rst @@ -6,7 +6,7 @@ Basics After each sysupgrade (including the initial installation), Gluon will execute all scripts under ``/lib/gluon/upgrade``. These scripts' filenames usually begin with a 3-digit number -specifying the order of execution. +specifying the order of execution. Note that the script files need to be executable. To get an overview of the ordering of all scripts of all packages, the helper script ``contrib/lsupgrade.sh`` in the Gluon repository can be used, which will print all upgrade scripts' filenames and directories. If executed @@ -16,17 +16,15 @@ Best practices -------------- * Most upgrade scripts are written in Lua. This allows using lots of helper functions provided - by LuCi and Gluon, e.g. to access the site configuration or edit UCI configuration files. + by Gluon, e.g. to access the site configuration or edit UCI configuration files. * Whenever possible, scripts shouldn't check if they are running for the first time, but just edit configuration - files to achive a valid configuration (without overwriting configuration changes made by the user where desirable). + files to achieve a valid configuration (without overwriting configuration changes made by the user where desirable). This allows using the same code to create the initial configuration and upgrade configurations on upgrades. * If it is unavoidable to run different code during the initial installation, the ``sysconfig.gluon_version`` variable - can be checked. This variable in ``nil`` during the initial installation and contains the previously install Gluon - version otherwise. The package ``gluon-legacy`` (which is responsible for upgrades from the old firmwares of - Hamburg/Kiel/Lübeck) uses the special value ``legacy``; other packages should handle this value just as any other - string. + can be checked. This variable is ``nil`` during the initial installation and contains the previously install Gluon + version otherwise. Script ordering --------------- diff --git a/docs/dev/web/config-mode.rst b/docs/dev/web/config-mode.rst new file mode 100644 index 00000000..9c0c2430 --- /dev/null +++ b/docs/dev/web/config-mode.rst @@ -0,0 +1,82 @@ +Config Mode +=========== + +The `Config Mode` consists of several modules that provide a range of different +condiguration options: + +gluon-config-mode-core + This modules provides the core functionality for the config mode. + All modules must depend on it. + +gluon-config-mode-hostname + Provides a hostname field. + +gluon-config-mode-autoupdater + Informs whether the autoupdater is enabled. + +gluon-config-mode-mesh-vpn + Allows toggling of mesh-vpn-fastd and setting a bandwidth limit. + +gluon-config-mode-geo-location + Enables the user to set the geographical location of the node. + +gluon-config-mode-contact-info + Adds a field where the user can provide contact information. + + +Writing Config Mode modules +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Config mode modules are located at ``/lib/gluon/config-mode/wizard`` and +``/lib/gluon/config-mode/reboot``. Modules are named like ``0000-name.lua`` and +are executed in lexical order. In the standard package set, the +order is, for wizard modules: + + - 0050-autoupdater-info + - 0100-hostname + - 0300-mesh-vpn + - 0400-geo-location + - 0500-contact-info + +The reboot module order is: + + - 0100-mesh-vpn + - 0900-msg-reboot + +All modules are run in the gluon-web model context and have access to the same +variables as "full" gluon-web modules. + +Wizards +------- + +Wizard modules must return a function that is provided with the wizard form and an +UCI cursor. The function can create configuration sections in the form: + +.. code-block:: lua + + return function(form, uci) + local s = form:section(Section) + local o = s:option(Value, "hostname", "Hostname") + o.default = uci:get_first("system", "system", "hostname") + o.datatype = "hostname" + + function o:write(data) + uci:set("system", uci:get_first("system", "system"), "hostname", data) + end + + return {'system'} + end + +The function may return a table of UCI packages to commit after the individual +fields' `write` methods have been executed. This is done to avoid committing the +packages repeatedly when multiple wizard modules modify the same package. + +Reboot page +----------- + +Reboot modules are simply executed when the reboot page is +rendered: + +.. code-block:: lua + + renderer.render_string("Hello World!") diff --git a/docs/dev/web/controller.rst b/docs/dev/web/controller.rst new file mode 100644 index 00000000..cfec73d4 --- /dev/null +++ b/docs/dev/web/controller.rst @@ -0,0 +1,117 @@ +Controllers +=========== + +Controllers live in ``/lib/gluon/web/controller``. They define which pages ("routes") +exist under the ``/cgi-bin/gluon`` path, and what code is run when these pages are requested. + +Controller scripts mostly consist of calls of the `entry` function, which each define +one route: + +.. code-block:: lua + + entry({"admin"}, alias("admin", "info"), _("Advanced settings"), 10) + entry({"admin", "info"}, template("admin/info"), _("Information"), 1) + +The entry function expects 4 arguments: + + - `path`: Components of the path to define a route for. + + The above example defines routes for the paths ``admin`` and ``admin/info``. + + - `target`: Dispatcher for the route. See the following section for details. + - `title`: Page title (also used in navigation). The underscore function is used + + - `order`: Sort index in navigation (defaults to 100) + +Navigation indexes are automatically generated for each path level. Pages can be +hidden from the navigation by setting the `hidden` property of the node object +returned by `entry`: + +.. code-block:: lua + + entry({"hidden"}, alias("foo"), _("I'm hidden!")).hidden = true + + +Dispatchers +----------- + + - *alias* (*path*, ...): Redirects to a different page. The path components are + passed as individual arguments. + - *call* (*func*, ...): Runs a Lua function for custom request handling. The given + function is called with the HTTP object and the template renderer as first + two arguments, followed by all additional arguments passed to `call`. + - *template* (*view*): Renders the given view. See :doc:`view`. + - *model* (*name*): Displays and evaluates a form as defined by the given model. See the + :doc:`model` page for an explanation of gluon-web models. + + +.. _web-controller-http: + +The HTTP object +--------------- + +The HTTP object provides information about the HTTP requests and allows to add +data to the reply. Using it directly is rarely necessary when gluon-web +models and views are used. + +Useful functions: + + - *getenv* (*key*): Returns a value from the CGI environment passed by the webserver. + - *formvalue* (*key*): Returns a value passed in a query string or in the content + of a POST request. If multiple values with the same name have been passed, only + the first is returned. + - *formvaluetable* (*key*): Similar to *formvalue*, but returns a table of all + values for the given key. + - *status* (*code*, *message*): Writes the HTTP status to the reply. Has no effect + if a status has already been sent or non-header data has been written. + - *header* (*key*, *value*): Adds an HTTP header to the reply to be sent to to + the client. Has no effect when non-header data has already been written. + - *prepare_content* (*mime*): Sets the *Content-Type* header to the given MIME + type, potentially setting additional headers or modifying the MIME type to + accommodate browser quirks + - *write* (*data*, ...): Sends the given data to the client. If headers have not + been sent, it will be done before the data is written. + + +HTTP functions are called in method syntax, for example: + +.. code-block:: lua + + http:write('Output!') + + +.. _web-controller-template-renderer: + +The template renderer +--------------------- + +The template renderer allows to render templates (views). The most useful functions +are: + + - *render* (*view*, *scope*): Renders the given view, optionally passing a table + with additional variables to make available in the template. + - *render_string* (*str*, *scope*): Same as *render*, but the template is passed + directly instead of being loaded from the view directory. + +The renderer functions are called in property syntax, for example: + +.. code-block:: lua + + renderer.render('layout') + + +Differences from LuCI +--------------------- + + - Controllers must not use the *module* function to define a Lua module (*gluon-web* + will set up a proper environment for each controller itself) + - Entries are defined at top level, not inside an *index* function + - The *alias* dispatcher triggers an HTTP redirect instead of directly running + the dispatcher of the aliased route. + - The *call* dispatcher is passed a function instead of a string with a function + name. + - The *cbi* dispatcher of LuCI has been renamed to *model*. + - The HTTP POST handler support the multipart/form-data encoding only, so + ``enctype="multipart/form-data"`` must be included in all *
* HTML + elements. + - Other dispatchers like *form* are not provided. diff --git a/docs/dev/web/i18n.rst b/docs/dev/web/i18n.rst new file mode 100644 index 00000000..4ef03a34 --- /dev/null +++ b/docs/dev/web/i18n.rst @@ -0,0 +1,96 @@ +Internationalization support +============================ + +General guidelines +------------------ + +* All config mode packages must be fully translatable, with complete English and German texts. +* All new expert mode packages must be fully translatable. English texts are required. +* German translations are recommended. Other supported languages, especially French, are + nice-to-have, but not required. If you don't know a language well, rather leave the translation + blank, so it is obvious that there is no proper translation yet. +* 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 Gluon +--------------------- + +Internationalization support is available in all components (models, view and +controllers) of *gluon-web*-based packages. Strings are translated using the *translate*, +*_translate* and *translatef* functions (*translate* for static strings, *translatef* +for printf-like formatted string; *_translate* works the same as *translate*, but +will return *nil* instead of the original string when no translation is available) +. In views, the special tags ``<%:...%>`` can be used to translate the contained string. + +Example from the *gluon-config-mode-geo-location* package: + +.. code-block:: lua + + local share_location = s:option(Flag, "location", 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 in the ``contrib`` directory: + +.. code-block:: sh + + cd package/gluon-web-mesh-vpn-fastd + mkdir i18n + cd i18n + ../../../contrib/i18n-scan.pl ../files ../luasrc > gluon-web-mesh-vpn-fastd.pot + +The same command can be run again to update the template. + +In addition, some additions to the Makefile must be made. Instead of LEDE's default *package.mk*, +the Gluon version (``../gluon.mk`` for core packages) must be used. The i18n files must be installed +and PKG_CONFIG_DEPENDS must be added:: + + ... + include ../gluon.mk + + PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) + ... + define Build/Compile + $(call GluonBuildI18N,gluon-web-mesh-vpn-fastd,i18n) + endef + + define Package/gluon-web-mesh-vpn-fastd/install + ... + $(call GluonInstallI18N,gluon-web-mesh-vpn-fastd,$(1)) + endef + ... + + +Adding translations +------------------- + +A new translation file for a template can be added using the *msginit* command: + +.. code-block:: sh + + cd package/gluon-web-mesh-vpn-fastd/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: + +.. code-block:: sh + + msgmerge -U de.po gluon-web-mesh-vpn-fastd.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 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 *gluon-web* can be found in ``package/gluon.mk``. +New languages just need to be added to *GLUON_SUPPORTED_LANGS*, after a human-readable +language name has been defined in the same file. diff --git a/docs/dev/web/model.rst b/docs/dev/web/model.rst new file mode 100644 index 00000000..6026a71c --- /dev/null +++ b/docs/dev/web/model.rst @@ -0,0 +1,148 @@ +Models +====== + +Models are defined in ``/lib/gluon/web/model``. Each model defines one or more +forms to display on a page, and how the submitted form data is handled. + +Let's start with an example: + +.. code-block:: lua + + local f = Form(translate('Hostname')) + + local s = f:section(Section) + + local o = s:option(Value, 'hostname', translate('Hostname')) + o.default = uci:get_first('system', 'system', 'hostname') + function o:write(data) + uci:set('system', uci:get_first('system', 'system'), 'hostname', data) + uci:commit('system') + end + + return f + +The toplevel element of a model is always a *Form*, but it is also possible for +a model to return multiple forms, which are displayed one below the other. + +A *Form* has one or more *Sections*, and each *Section* has different types +of options. + +All of these elements have an *id*, which is used to identify them in the HTML +form and handlers. If no ID is given, numerical IDs will be assigned automatically, +but using explicitly named elements is often advisable (and it is required if a +form does not always include the same elements, i.e., some forms, sections or +options are added conditionally). IDs are hierarchical, so in the above example, +the *Value* would get the ID ``1.1.hostname`` (value *hostname* in first section +of first form). + +Classes and methods +------------------- + + - *Form* (*title*, *description*, *id*) + + - *Form:section* (*type*, *title*, *description*, *id*) + + Creates a new section of the given type (usually *Section*). + + - *Form:write* () + + Is called after the form has beed submitted (but only if the data is valid). It + is called last (after all options' *write* methods) and is usually used + to commit changed UCI packages. + + The default implementation of *write* doesn't to anything, but it can be + overridden. + + - *Section* (usually instanciated through *Form:section*) + + - *Section:option* (*type*, *id*, *title*, *description*) + + Creates a new option of the given type. Option types: + + - *Value*: simple text entry + - *TextValue*: multiline text field + - *ListValue*: radio buttons or dropdown selection + - *DynamicList*: variable number of text entry fields + - *Flag*: checkbox + +Most option types share the same properties and methods: + + - *default*: default value + - *optional*: value may be empty + - *datatype*: one of the types described in :ref:`web-model-datatypes` + + By default (when *datatype* is *nil*), all values are accepted. + + - *state*: has one of the values *FORM_NODATA*, *FORM_VALID* and *FORM_INVALID* + when read in a form handler + + An option that has not been submitted because of its dependencies will have + the state *FORM_NODATA*, *FORM_INVALID* if the submitted value is not valid + according to the set *datatype*, and *FORM_VALID* otherwise. + + - *data*: can be read in form handlers to get the submitted value + + - *depends* (*self*, *option*, *value*): adds a dependency on another option + + The option will only be shown when the passed option has the given value. This + is mainly useful when the other value is a *Flag* or *ListValue*. + + - *depends* (*self*, *deps*): adds a dependency on multiple other options + + *deps* must be a table with options as keys and values as values. The option + will only be shown when all passed options have the corresponding values. + + Multiple alternative dependencies can be added by calling *depends* repeatedly. + + - *value* (*self*, *value*, *text*): adds a choice to a *ListValue* + + - *write* (*self*, *data*): is called with the submitted value when all form data is valid. + + Does not do anything by default, but can be overridden. + +The *default* value, the *value* argument to *depends* and the output *data* always have +the same type, which is usually a string (or *nil* for optional values). Exceptions +are: + + - *Flag* uses boolean values + - *DynamicList* uses a table of strings + +Despite its name, the *datatype* setting does not affect the returned value type, +but only defines a validator the check the submitted value with. + +For a more complete example that actually makes use of most of these features, +have a look at the model of the *gluon-web-network* package. + +.. _web-model-datatypes: + +Data types +---------- + + - *integer*: an integral number + - *uinteger*: an integral number greater than or equal to zero + - *float*: a number + - *ufloat*: a number greater than or equal to zero + - *ipaddr*: an IPv4 or IPv6 address + - *ip4addr*: an IPv4 address + - *ip6addr*: an IPv6 address + - *wpakey*: a string usable as a WPA key (either between 8 and 63 characters, or 64 hex digits) + - *range* (*min*, *max*): a number in the given range (inclusive) + - *min* (*min*): a number greater than or equal to the given minimum + - *max* (*max*): a number less than or equal to the given maximum + - *irange* (*min*, *max*): an integral number in the given range (inclusive) + - *imin* (*min*): an integral number greater than or equal to the given minimum + - *imax* (*max*): an integral number less than or equal to the given maximum + - *minlength* (*min*): a string with the given minimum length + - *maxlength* (*max*): a string with the given maximum length + +Differences from LuCI +--------------------- + + - LuCI's *SimpleForm* and *SimpleSection* are called *Form* and *Section*, respectively + - Is it not possible to add options to a *Form* directly, a *Section* must always + be created explicitly + - Many of LuCI's CBI classes have been removed, most importantly the *Map* + - The *rmempty* option attribute does not exist, use *optional* instead + - Only the described data types are supported + - Form handlers work completely differently (in particular, a *Form*'s *handle* + method should usually not be overridden in *gluon-web*) diff --git a/docs/dev/web/view.rst b/docs/dev/web/view.rst new file mode 100644 index 00000000..30dc68a8 --- /dev/null +++ b/docs/dev/web/view.rst @@ -0,0 +1,55 @@ +Views +===== + +The template parser reads views from ``/lib/gluon/web/view``. Writing own view +should be avoided in favour of using :doc:`model` with their predefined views. + +Views are partial HTML pages, with additional template tags that allow +to embed Lua code and translation strings. The following tags are defined: + + - ``<%`` ... ``%>`` evaluates the enclosed Lua expression. + - ``<%=`` ... ``%>`` evaluates the enclosed Lua expression and prints its value. + - ``<%+`` ... ``%>`` includes another template. + - ``<%:`` ... ``%>`` translates the enclosed string using the loaded i18n catalog. + - ``<%_`` ... ``%>`` translates the enclosed string *without escaping HTML entities* + in the translation. This only makes sense when the i18n catalog contains HTML code. + - ``<%#`` ... ``%>`` is a comment. + +All of these also come in the whitespace-stripping variants ``<%-`` and ``-%>`` that +remove all whitespace before or after the tag. + +Complex combinations of HTML and Lua code are possible, for example: + +.. code-block:: text + +
+ <% if foo then %> + Content + <% end %> +
+ + +Variables and functions +----------------------- + +Many call sites define additional variables (for example, model templates can +access the model as *self* and a unique element ID as *id*), but the following +variables and functions should always be available for the embedded Lua code: + + - *renderer*: :ref:`web-controller-template-renderer` + - *http*: :ref:`web-controller-http` + - *request*: Table containing the path components of the current page + - *url* (*path*): returns the URL for the given path, which is passed as a table of path components. + - *attr* (*key*, *value*): Returns a string of the form ``key="value"`` + (with a leading space character before the key). + + *value* is converted to a string (tables are serialized as JSON) and HTML entities + are escaped. Returns an empty string when *value* is *nil* or *false*. + - *include* (*template*): Includes another template. + - *node* (*path*, ...): Returns the controller node for the given page (passed as + one argument per path component). + + Use ``node(unpack(request))`` to get the node for the current page. + - *pcdata* (*str*): Escapes HTML entities in the passed string. + - *urlencode* (*str*): Escapes the passed string for use in an URL. + - *translate*, *_translate* and *translatef*: see :doc:`i18n` diff --git a/docs/features/authorized-keys.rst b/docs/features/authorized-keys.rst index b3b0aaf6..2f23ded5 100644 --- a/docs/features/authorized-keys.rst +++ b/docs/features/authorized-keys.rst @@ -8,7 +8,7 @@ If you select this package, add a list of authorized keys to ``site.conf`` like { authorized_keys = { 'ssh-rsa AAA.... user1@host', - 'ssh-rsa AAA.... user2@host }, + 'ssh-rsa AAA.... user2@host' }, hostname_prefix = ... ... diff --git a/docs/features/autoupdater.rst b/docs/features/autoupdater.rst index fdc511d9..7b12b4b7 100644 --- a/docs/features/autoupdater.rst +++ b/docs/features/autoupdater.rst @@ -11,14 +11,19 @@ during development), but it can be enabled by setting the variable GLUON_BRANCH to override the default branch set in the set in the site configuration. A manifest file for the updater can be generated with `make manifest`. A signing script (using -ecdsautils) can by found in the `contrib` directory. When creating the manifest, ``GLUON_PRIORITY`` can -be set on the command line, or it can be taken from the ``site.mk``. +``ecdsautils``) can by found in the `contrib` directory. When creating the manifest, the +``PRIORITY`` value may be defined by setting ``GLUON_PRIORITY`` on the command line or in ``site.mk``. -The priority defines the maximum number of days that may pass between releasing an update and installation -of the images. The update probability with start at 0 after the release time mentioned in the manifest -and then slowly rise to 1 after the number of days given by the priority has passed. +``GLUON_PRIORITY`` defines the maximum number of days that may pass between releasing an update and installation +of the images. The update probability will start at 0 after the release time declared in the manifest file +by the variable DATE and then slowly rise up to 1 when ``GLUON_PRIORITY`` days have passed. The autoupdater checks +for updates hourly (at a random minute of the hour), but usually only updates during its run between +4am and 5am, except when the whole ``GLUON_PRIORITY`` days and another 24 hours have passed. -The priority may be an integer or a decimal fraction. +``GLUON_PRIORITY`` may be an integer or a decimal fraction. + +Automated nightly builds +------------------------ A fully automated nightly build could use the following commands: @@ -28,12 +33,13 @@ A fully automated nightly build could use the following commands: (cd site && git pull) make update make clean - make -j5 GLUON_TARGET=ar71xx-generic GLUON_BRANCH=experimental + NUM_CORES_PLUS_ONE=$(expr $(nproc) + 1) + make -j$NUM_CORES_PLUS_ONE GLUON_TARGET=ar71xx-generic GLUON_BRANCH=experimental make manifest GLUON_BRANCH=experimental - contrib/sign.sh $SECRETKEY images/sysupgrade/experimental.manifest + contrib/sign.sh $SECRETKEY output/images/sysupgrade/experimental.manifest rm -rf /where/to/put/this/experimental - cp -r images /where/to/put/this/experimental + cp -r output/images /where/to/put/this/experimental Infrastructure @@ -59,7 +65,7 @@ The server must be available via IPv6. Command Line ------------ -These commands can be used on a node. +These commands can be used on a node: :: @@ -71,4 +77,8 @@ These commands can be used on a node. # Force update check, even when the updater is disabled autoupdater -f +:: + # If fallback is true the updater will perform an update only if the timespan + # PRIORITY days (as defined in the manifest) and another 24h have passed + autoupdater --fallback diff --git a/docs/features/dns-cache.rst b/docs/features/dns-cache.rst new file mode 100644 index 00000000..92be66f6 --- /dev/null +++ b/docs/features/dns-cache.rst @@ -0,0 +1,41 @@ +DNS caching +=========== + +User experience may be greatly improved when dns is accelerated. Also, it +seems like a good idea to keep the number of packages being exchanged +between node and gateway as small as possible. In order to do this, a +DNS cache may be used on a node. The dnsmasq instance listening on port +53 on the node will be reconfigured to answer requests, use a list of +upstream servers and a specific cache size if the options listed below are +added to site.conf. Upstream servers are the DNS servers which are normally +used by the nodes to resolve hostnames (e.g. gateways/supernodes). + +There are the following settings: + servers + cacheentries + +If both options are set the node will cache as much DNS records as set with +'cacheentries' in RAM. The 'servers' list will be used to resolve the received +DNS queries if the request cannot be answered from cache. +If these settings do not exist, the cache is not intialized and RAM usage will not increase. + +When next_node.name is set, an A record and an AAAA record for the +next-node IP address are placed in the dnsmasq configuration. This means that the content +of next_node.name may be resolved even without upstream connectivity. + +:: + + dns = { + cacheentries = 5000, + servers = { '2001:db8::1', }, + }, + + next_node = { + name = 'nextnode', + ip6 = '2001:db8:8::1', + ip4 = '198.51.100.1', + } + + +The cache will be initialized during startup. +Each cache entry will occupy about 90 bytes of RAM. diff --git a/docs/features/mesh-on-wan.rst b/docs/features/mesh-on-wan.rst deleted file mode 100644 index 2f1a8a47..00000000 --- a/docs/features/mesh-on-wan.rst +++ /dev/null @@ -1,18 +0,0 @@ -Mesh on WAN -=========== - -It's possible to enable the mesh on the WAN port like this:: - - uci set network.mesh_wan.auto=1 - uci commit - -It may also be disabled again by running:: - - uci set network.mesh_wan.auto=0 - uci commit - -site.conf ---------- - -The optional option ``mesh_on_wan`` may be set to ``true`` (``false`` is the -default) to enable meshing on the WAN port without further configuration. diff --git a/docs/features/announce.rst b/docs/features/monitoring.rst similarity index 52% rename from docs/features/announce.rst rename to docs/features/monitoring.rst index 9e2bf020..ca4ae08d 100644 --- a/docs/features/announce.rst +++ b/docs/features/monitoring.rst @@ -1,5 +1,5 @@ -Announcing Node Information -=========================== +Node monitoring +=============== Gluon is capable of announcing information about each node to the mesh and to neighbouring nodes. This allows nodes to learn each others hostname, @@ -8,7 +8,7 @@ IP addresses, location, software versions and various other information. Format of collected data ------------------------ -Information to be announced is currently split into two categories: +Information to be announced is currently split into three categories: nodeinfo In this category (mostly) static information is collected. If @@ -19,15 +19,19 @@ Information to be announced is currently split into two categories: This category holds fast changing data, like traffic counters, uptime, system load or the selected gateway. -Both categories will have a ``node_id`` key by default. It should be used to -match data from *statistics* to *nodeinfo*. + neighbours + `neighbours` contains information about all neighbouring nodes of all + interfaces. This data can be used to determine the network topology. + +All categories will have a ``node_id`` key. It should be used to +relate data of different catagories. Accessing Node Information -------------------------- There are two packages responsible for distribution of the information. For one, information is distributed across the mesh using alfred_. Information -between neighbouring nodes is exchanged using `gluon-announced`. +between neighbouring nodes is exchanged using `gluon-respondd`. .. _alfred: http://www.open-mesh.org/projects/alfred @@ -41,10 +45,15 @@ retrieve the data you'll need both a local alfred daemon and alfred-json_ installed. Please note that at least one alfred daemon is required to run as `master`. -.. _alfred-json: https://github.com/tcatm/alfred-json +.. _alfred-json: https://github.com/ffnord/alfred-json -`nodeinfo` is distributed as alfred datatype `158`, while `statistics` uses -`159`. Both are compressed using GZip (alfred-json can handle the decompression). +The following datatypes are used: + +* `nodeinfo`: 158 +* `statistics`: 159 +* `neighbours`: 160 + +All data is compressed using GZip (alfred-json can handle the decompression). In order to retrieve statistics data you could run: @@ -88,20 +97,28 @@ In order to retrieve statistics data you could run: You can find more information about alfred in its README_. -.. _README: http://www.open-mesh.org/projects/alfred/repository/revisions/master/entry/README +.. _README: https://git.open-mesh.org/alfred.git/blob_plain/refs/heads/master:/README -gluon-announced -~~~~~~~~~~~~~~~ +gluon-respondd +~~~~~~~~~~~~~~ -`gluon-announced` allows querying neighbouring nodes for their `nodeinfo`. +`gluon-respondd` allows querying neighbouring nodes for their information. It is a daemon listening on the multicast address ``ff02::2:1001`` on -UDP port 1001 on the bare mesh interfaces. +UDP port 1001 on both the bare mesh interfaces and `br-client`. Unicast +requests are supported as well. + +The supported requests are: + +* ``nodeinfo``, ``statistics``, ``neighbours``: Returns the data of single category uncompressed. +* ``GET nodeinfo``, ...: Returns the data of one or multiple categories (separated by spaces) + compressed using the `deflate` algorithm (without a gzip header). The data may + be decompressed using zlib and many zlib bindings using -15 as the window size parameter. gluon-neighbour-info ~~~~~~~~~~~~~~~~~~~~ -A programm called `gluon-neighbour-info` has been developed to retrieve -information from neighbours. +The programm `gluon-neighbour-info` can be used to retrieve +information from other nodes. :: @@ -109,55 +126,13 @@ information from neighbours. -p 1001 -d ff02:0:0:0:0:0:2:1001 \ -r nodeinfo -On optional timeout may be specified, e.g. `-t 5` (default: 3 seconds). +An optional timeout may be specified, e.g. `-t 5` (default: 3 seconds). See +the usage information printed by ``gluon-neighbour-info -h`` for more information +about the supported arguments. -Adding a fact -------------- +Adding a data provider +---------------------- -To add a fact just add a file to either ``/lib/gluon/announce/nodeinfo.d/`` or -``/lib/gluon/announce/statistics.d/``. - -The file must contain a lua script and its name will become the key for the -resulting JSON object. A simple script adding a ``hostname`` field might look -like this: - -:: - - return uci:get_first('system', 'system', 'hostname') - -The directory structure will be converted to a JSON object, i.e. you may -create subdirectories. So, if the directories look like this - -:: - - . - ├── hardware - │   └── model - ├── hostname - ├── network - │   └── mac - ├── node_id - └── software - └── firmware - -the resulting JSON would become: - -:: - - # /lib/gluon/announce/announce.lua nodeinfo - { - "hardware" : { - "model" : "TP-Link TL-MR3420 v1" - }, - "hostname" : "mr3420-test", - "network" : { - "mac" : "90:f6:52:82:06:02" - }, - "node_id" : "90f652820602", - "software" : { - "firmware" : { - "base" : "gluon-v2014.2-32-ge831099", - "release" : "0.4.1+0-exp20140720" - } - } - } +To add a provider, you need to install a shared object into ``/lib/gluon/respondd``. +For more information, refer to the `respondd README `_ +and have a look the existing providers. diff --git a/docs/features/private-wlan.rst b/docs/features/private-wlan.rst index 343cd5c3..1c46ed76 100644 --- a/docs/features/private-wlan.rst +++ b/docs/features/private-wlan.rst @@ -4,7 +4,7 @@ Private WLAN It is possible to set up a private WLAN that bridges the WAN port and is seperated from the mesh network. Please note that you should not enable ``mesh_on_wan`` simultaneously. -The private WLAN can be enabled through the config mode if the package ``gluon-luci-private-wifi`` is installed. +The private WLAN can be enabled through the config mode if the package ``gluon-web-private-wifi`` is installed. You may also enable a private WLAN using the command line:: uci set wireless.wan_radio0=wifi-iface diff --git a/docs/features/roles.rst b/docs/features/roles.rst index 4cbf1f29..3af09c01 100644 --- a/docs/features/roles.rst +++ b/docs/features/roles.rst @@ -2,7 +2,7 @@ Roles ===== It is possible to define a set of roles you want to distinguish at backend side. One node can own one -role which it will announce via alfred inside the mesh. This will make it easier to differentiate +role which it will announce via alfred inside the mesh. This will make it easier to differentiate nodes when parsing alfred data. E.g to count only **normal** nodes and not the gateways or servers (nodemap). A lot of things are possible. @@ -11,18 +11,20 @@ For this the section ``roles`` in ``site.conf`` is needed:: roles = { default = 'node', list = { - node = 'Normal Node', - test = 'Test Node', - backbone = 'Backbone Node', - service = 'Service Node', + 'node', + 'test', + 'backbone', + 'service', }, }, +The strings to display in the web interface are configured per language in the +``i18n/en.po``, ``i18n/de.po``, etc. files of the site repository using message IDs like +``gluon-web-node-role:role:node`` and ``gluon-web-node-role:role:backbone``. + The value of ``default`` is the role every node will initially own. This value should be part of ``list`` as well. If you want node owners to change the defined roles via config-mode you can add the package -``gluon-luci-node-role`` to your ``site.mk``. Then, you can select one of the defined roles from a dropdown list -where the right-handed value is the one which is displayed and the left-handed key the one which is configured into -the system. +``gluon-web-node-role`` to your ``site.mk``. The role is saved in ``gluon-node-info.system.role``. To change the role using command line do:: diff --git a/docs/features/wired-mesh.rst b/docs/features/wired-mesh.rst new file mode 100644 index 00000000..1ea263a9 --- /dev/null +++ b/docs/features/wired-mesh.rst @@ -0,0 +1,65 @@ +Wired mesh (Mesh-on-WAN/LAN) +============================ + +In addition to meshing over WLAN and VPN, it is also possible to +configure wired meshing over the LAN or WAN ports. This allows +nodes to be connected directly or over wireless bridges. + +Mesh-on-WAN can be enabled in addition to the mesh VPN, so multiple nodes +in the same local network that is used as VPN uplink can also mesh directly. +Enabling Mesh-on-WAN should be avoided if the local network is also bridged with +a WLAN access point, as meshing over batman-adv causes large amounts of +multicast traffic, which will take up a lot of airtime. + +Enabling Mesh-on-LAN will replace the normal "client network" function +of the LAN ports, as client network ports may never be connected (so care must be taken to always +enable Mesh-on-LAN before connecting two nodes' LAN ports). + +Configuration +~~~~~~~~~~~~~ + +Both Mesh-on-WAN and Mesh-on-LAN can be configured on the "Network" page +of the *Advanced settings* (if the package ``gluon-web-network`` is installed). + +It is also possible to enable Mesh-on-WAN and Mesh-on-LAN by default by +adding ``mesh_on_wan = true`` and ``mesh_on_lan = true`` to ``site.conf``. + +Commandline configuration +------------------------- + +Mesh-on-WAN +........... + +It's possible to enable Mesh-on-WAN like this:: + + uci set network.mesh_wan.auto=1 + uci commit network + +It may be disabled by running:: + + uci set network.mesh_wan.auto=0 + uci commit network + + +Mesh-on-LAN +........... + +Configuring Mesh-on-LAN is a bit more complicated:: + + uci set network.mesh_lan.auto=1 + for ifname in $(cat /lib/gluon/core/sysconfig/lan_ifname); do + uci del_list network.client.ifname=$ifname + done + uci commit network + +It may be disabled by running:: + + uci set network.mesh_lan.auto=0 + for ifname in $(cat /lib/gluon/core/sysconfig/lan_ifname); do + uci add_list network.client.ifname=$ifname + done + uci commit network + +Please note that this configuration has changed in Gluon v2016.1. Using +the old commands on v2016.1 and later will break the corresponding options +in the *Advanced settings*. diff --git a/docs/features/wlan-configuration.rst b/docs/features/wlan-configuration.rst new file mode 100644 index 00000000..445b4bf1 --- /dev/null +++ b/docs/features/wlan-configuration.rst @@ -0,0 +1,34 @@ +WLAN configuration +================== + +Gluon allows to configure 2.4GHz and 5GHz radios independently. The configuration +may include any or all of the three networks "client" (AP mode), "mesh" (802.11s +mode) and "ibss" (adhoc mode), which can be used simultaneously (using "mesh" and +"ibss" at same time should be avoided though as weaker hardware usually can't handle the additional +load). See :doc:`../user/site` for details on the configuration. + +Upgrade behaviour +----------------- + +For each of these networks, the site configuration may define a `disabled` flag (by +default, all configured networks are enabled). This flag is merely a default setting, +on upgrades the existing setting is always retained (as this setting may have been changed +by the user). This means that it is not possible to enable or disable an existing network +configurations during upgrades. + +For the "mesh" and "ibss" networks, the default setting only has an effect if none +of the two has existed before. If a new configuration has been added for "mesh" or "ibss", +while the other of the two has already existed before, the enabled/disabled state of the +existing configuration will also be set for the new configuration. + +This allows upgrades to change from IBSS to 11s and vice-versa while retaining the +"wireless meshing is enabled/disabled" property configured by the user regardless +of the used mode. + +During upgrades the wifi channel of the 2.4GHz and 5GHz radio will be restored to the channel +configured in the site.conf. If you need to preserve a user defined wifi channel during upgrades +you can configure this via the uci section ``gluon-core.wireless``:: + + uci set gluon-core.@wireless[0].preserve_channels='1' + +Keep in mind that nodes running wifi interfaces on custom channels can't mesh with default nodes anymore! diff --git a/docs/index.rst b/docs/index.rst index 92fb58b7..e509a990 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -5,10 +5,8 @@ Gluon is a modular framework for creating OpenWrt-based firmwares for wireless m Several Freifunk communities in Germany use Gluon as the foundation of their Freifunk firmwares. -User Documentation ------------------- - .. toctree:: + :caption: User Documentation :maxdepth: 2 user/getting_started @@ -16,39 +14,73 @@ User Documentation user/x86 user/faq -Features --------- - .. toctree:: + :caption: Features :maxdepth: 2 features/configmode features/autoupdater + features/wlan-configuration features/private-wlan - features/mesh-on-wan - features/announce + features/wired-mesh + features/dns-cache + features/monitoring features/authorized-keys features/roles -Developer Documentation ------------------------ - .. toctree:: + :caption: Developer Documentation :maxdepth: 2 dev/basics dev/hardware dev/upgrade - dev/configmode dev/wan - dev/i18n - -Releases --------- + dev/mac_addresses .. toctree:: + :caption: gluon-web Reference :maxdepth: 1 + dev/web/controller + dev/web/model + dev/web/view + dev/web/i18n + dev/web/config-mode + +.. toctree:: + :caption: Packages + :maxdepth: 1 + + package/gluon-client-bridge + package/gluon-config-mode-contact-info + package/gluon-config-mode-geo-location + package/gluon-ebtables-filter-multicast + package/gluon-ebtables-filter-ra-dhcp + package/gluon-ebtables-segment-mld + package/gluon-ebtables-source-filter + +.. toctree:: + :caption: Releases + :maxdepth: 1 + + releases/v2017.1 + releases/v2016.2.6 + releases/v2016.2.5 + releases/v2016.2.4 + releases/v2016.2.3 + releases/v2016.2.2 + releases/v2016.2.1 + releases/v2016.2 + releases/v2016.1.6 + releases/v2016.1.5 + releases/v2016.1.4 + releases/v2016.1.3 + releases/v2016.1.2 + releases/v2016.1.1 + releases/v2016.1 + releases/v2015.1.2 + releases/v2015.1.1 releases/v2015.1 releases/v2014.4 releases/v2014.3.1 @@ -61,6 +93,19 @@ Supported Devices & Architectures ar71xx-generic ^^^^^^^^^^^^^^ +* 8devices + + - Carambola 2 + +* ALFA Network + + - AP121 + - AP121U + - Hornet-UB + - Tube2H + - N2 + - N5 + * Allnet - ALL0315N @@ -68,17 +113,21 @@ ar71xx-generic * Buffalo - WZR-HP-AG300H / WZR-600DHP + - WZR-HP-G300NH + - WZR-HP-G300NH2 - WZR-HP-G450H * D-Link - - DIR-825 (B1) + - DIR-505 (A1, A2) - DIR-615 (C1) + - DIR-825 (B1) -* GL-Inet +* GL Innovations - - 6408A (v1) - - 6416A (v1) + - GL-AR150 + - GL-iNet 6408A (v1) + - GL-iNet 6416A (v1) * Linksys @@ -90,47 +139,72 @@ ar71xx-generic - WNDR3800 - WNDRMAC (v2) +* Onion + + - Omega + +* OpenMesh + + - MR600 (v1, v2) + - MR900 (v1, v2) + - MR1750 (v1, v2) [#ath10k]_ + - OM2P (v1, v2) + - OM2P-HS (v1, v2, v3) + - OM2P-LC + - OM5P + - OM5P-AN + - OM5P-AC (v1, v2) [#ath10k]_ + * 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) + - Archer C5 (v1) [#ath10k]_ + - Archer C7 (v2) [#ath10k]_ + - CPE210 (v1.0, v1.1) + - CPE220 (v1.1) + - CPE510 (v1.0, v1.1) + - CPE520 (v1.1) + - RE450 - 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-WR710N (v1, v2.1) + - TL-WR842N/ND (v1, v2, v3) + - TL-WR1043N/ND (v1, v2, v3, v4) - TL-WR2543N/ND (v1) + - WBS210 (v1.20) + - WBS510 (v1.20) * Ubiquiti - - Bullet M2 - - Nanostation M2 - - Nanostation M XW - - Loco M XW - - Picostation M2 - - Rocket M2 + - Air Gateway + - Air Gateway LR + - Air Gateway PRO + - Air Router + - Bullet M2/M5 + - Loco M2/M5 + - Loco M2/M5 XW + - Nanostation M2/M5 + - Nanostation M2/M5 XW + - Picostation M2/M5 + - Rocket M2/M5 + - Rocket M2/M5 Ti + - Rocket M2/M5 XW - UniFi AP + - UniFi AP AC Lite [#ath10k]_ + - UniFi AP AC Pro [#ath10k]_ + - UniFi AP LR - UniFi AP Pro - UniFi AP Outdoor + - UniFi AP Outdoor+ + +* Western Digital + + - My Net N600 + - My Net N750 + +.. [#ath10k] + Device uses the ath10k WLAN driver; no image is built unless GLUON_ATH10K_MESH + is set as described in :ref:`getting-started-make-variables` ar71xx-nand ^^^^^^^^^^^ @@ -140,6 +214,50 @@ ar71xx-nand - WNDR3700 (v4) - WNDR4300 (v1) +ar71xx-tiny +^^^^^^^^^^^ + +* D-Link + + - DIR-615 (C1) + +* TP-Link + + - TL-MR13U (v1) + - TL-MR3020 (v1) + - TL-MR3040 (v1, v2) + - TL-MR3220 (v1, v2) + - TL-MR3420 (v1, v2) + - TL-WA701N/ND (v1, v2) + - TL-WA730RE (v1) + - TL-WA750RE (v1) + - TL-WA801N/ND (v1, v2, v3) + - TL-WA830RE (v1, v2) + - TL-WA850RE (v1) + - TL-WA860RE (v1) + - TL-WA901N/ND (v1, v2, v3, v4) + - TL-WA7210N (v2) + - TL-WA7510N (v1) + - TL-WR703N (v1) + - TL-WR710N (v1, v2, v2.1) + - TL-WR740N (v1, v3, v4, v5) + - TL-WR741N/ND (v1, v2, v4, v5) + - TL-WR743N/ND (v1, v2) + - TL-WR841N/ND (v3, v5, v7, v8, v9, v10, v11, v12) + - TL-WR843N/ND (v1) + - TL-WR940N (v1, v2, v3, v4) + - TL-WR941ND (v2, v3, v4, v5, v6) + +brcm2708-bcm2708 +^^^^^^^^^^^^^^^^ + +* RaspberryPi 1 + +brcm2708-bcm2709 +^^^^^^^^^^^^^^^^ + +* RaspberryPi 2 + mpc85xx-generic ^^^^^^^^^^^^^^^ @@ -149,15 +267,26 @@ mpc85xx-generic x86-generic ^^^^^^^^^^^ + * x86-generic * x86-virtualbox * x86-vmware See also: :doc:`user/x86` -x86-kvm_guest -^^^^^^^^^^^^^ -* x86-kvm +x86-geode +^^^^^^^^^ + +* x86-geode + +See also: :doc:`user/x86` + +x86-64 +^^^^^^ + +* x86-64-generic +* x86-64-virtualbox +* x86-64-vmware See also: :doc:`user/x86` diff --git a/docs/package/gluon-client-bridge.rst b/docs/package/gluon-client-bridge.rst new file mode 100644 index 00000000..131072f6 --- /dev/null +++ b/docs/package/gluon-client-bridge.rst @@ -0,0 +1,11 @@ +gluon-client-bridge +=================== + +This package provides a bridge (*br-client*) for connecting clients. It will +also setup a wireless interface, provided it is configured in *site.conf*. + +site.conf +--------- + +wifi24.ap.ssid / wifi5.ap.ssid + SSID for the client network diff --git a/docs/package/gluon-config-mode-contact-info.rst b/docs/package/gluon-config-mode-contact-info.rst new file mode 100644 index 00000000..6072aa5a --- /dev/null +++ b/docs/package/gluon-config-mode-contact-info.rst @@ -0,0 +1,21 @@ +gluon-config-mode-contact-info +============================== + +This package allows the user to provide contact information within config mode to be +distributed in the mesh. You can define whether the owner contact field is +obligatory or not in your site.conf. + +site.conf +--------- + +config_mode.owner.obligatory \: optional (defaults to false) + If ``obligatory`` is set to ``true``, the contact info field must be supplied + and may not be left empty. + +Example:: + + config_mode = { + owner = { + obligatory = true + } + } diff --git a/docs/package/gluon-config-mode-geo-location.rst b/docs/package/gluon-config-mode-geo-location.rst new file mode 100644 index 00000000..83ca238b --- /dev/null +++ b/docs/package/gluon-config-mode-geo-location.rst @@ -0,0 +1,14 @@ +gluon-config-mode-geo-location +============================== + +This package enables the user to set latitude, longitude and altitude of their +node within config mode. As the usage of the altitude is not well defined the +corresponding field can be disabled. + +site.conf +--------- + +config_mode.geo_location.show_altitude : optional + - ``true`` enables the altitude field + - ``false`` disables the altitude field if altitude has not yet been set + - defaults to ``true`` diff --git a/docs/package/gluon-ebtables-filter-multicast.rst b/docs/package/gluon-ebtables-filter-multicast.rst new file mode 100644 index 00000000..eca9c6c7 --- /dev/null +++ b/docs/package/gluon-ebtables-filter-multicast.rst @@ -0,0 +1,30 @@ +gluon-ebtables-filter-multicast +=============================== + +The *gluon-ebtables-filter-multicast* package filters out various kinds of +non-essential multicast traffic, as this traffic often constitutes a +disproportionate burden on the mesh network. Unfortunately, this breaks many useful services +(Avahi, Bonjour chat, ...), but this seems unavoidable, as the current Avahi implementation is +optimized for small local networks and causes too much traffic in large mesh networks. + +The multicast packets are filtered between the nodes' client bridge (*br-client*) and mesh +interface (*bat0*) on output. + + +The following packet types are considered essential and aren't filtered: + +* ARP (except requests for/replies from 0.0.0.0) +* DHCP, DHCPv6 +* ICMPv6 (except Echo Requests (ping) and Node Information Queries (RFC4620) +* IGMP + +In addition, the following packet types are allowed to allow experimentation with +layer 3 routing protocols. + +* Babel +* OSPF +* RIPng + +The following packet types are also allowed: + +* BitTorrent Local Peer Discovery (it seems better to have local peers for BitTorrent than sending everything through the internet) diff --git a/docs/package/gluon-ebtables-filter-ra-dhcp.rst b/docs/package/gluon-ebtables-filter-ra-dhcp.rst new file mode 100644 index 00000000..539fbc0d --- /dev/null +++ b/docs/package/gluon-ebtables-filter-ra-dhcp.rst @@ -0,0 +1,13 @@ +gluon-ebtables-filter-ra-dhcp +============================= + +The *gluon-ebtables-filter-ra-dhcp* package tries to prevent common +misconfigurations (i.e. connecting the client interface of a Gluon +node to a private network) from causing issues for either of the +networks. + +The rules are the following: + +* DHCP requests, DHCPv6 requests and Router Solicitations may only be sent from clients to the mesh, but aren't forwarded + from the mesh to clients +* DHCP replies, DHCPv6 replies and Router Advertisements from clients aren't forwarded to the mesh diff --git a/docs/package/gluon-ebtables-segment-mld.rst b/docs/package/gluon-ebtables-segment-mld.rst new file mode 100644 index 00000000..7e197ece --- /dev/null +++ b/docs/package/gluon-ebtables-segment-mld.rst @@ -0,0 +1,16 @@ +gluon-ebtables-segment-mld +========================== + +These filters drop IGMP/MLD packets before they enter the mesh and +filter any IGMP/MLD packets coming from the mesh. + +IGMP/MLD have the concept of a local, elected Querier. For more +decentralization and increased robustness, the idea of this package is +to split the IGMP/MLD domain a querier is responsible for, allowing to +have a querier per node. The split IGMP/MLD domain will also reduce +overhead for this packet type, increasing scalability. + +Beware of the consequences of using this package though: You might need +to explicitly, manually mark ports on snooping switches leading towards +your mesh node as multicast router ports for now (Multicast Router +Discovery, MRD, not implemented yet). diff --git a/docs/package/gluon-ebtables-source-filter.rst b/docs/package/gluon-ebtables-source-filter.rst new file mode 100644 index 00000000..99ed2137 --- /dev/null +++ b/docs/package/gluon-ebtables-source-filter.rst @@ -0,0 +1,30 @@ +gluon-ebtables-source-filter +============================ + +The *gluon-ebtables-source-filter* package adds an additional layer-2 filter +ruleset to prevent unreasonable traffic entering the network via the nodes. +Unreasonable means traffic entering the mesh via a node which source IP does +not belong to the configured IP space. + +One may first check if there is a certain proportion of unreasonable traffic, +before adding this package to the firmware image. Additional one should not +use this package if some kind of gateway or upstream network is provided by +a device connected to the client port. + +site.conf +--------- + +prefix4 : optional + - IPv4 subnet + +prefix6 : + - IPv6 subnet + +extra_prefixes6 : optional + - list of additional IPv6 subnets + +Example:: + + prefix4 = '198.51.100.0/21', + prefix6 = '2001:db8:8::/64', + extra_prefixes6 = { '2001:db8:9::/64', '2001:db8:100::/60' }, diff --git a/docs/releases/v2015.1.1.rst b/docs/releases/v2015.1.1.rst new file mode 100644 index 00000000..4800dc19 --- /dev/null +++ b/docs/releases/v2015.1.1.rst @@ -0,0 +1,27 @@ +Gluon 2015.1.1 +============== + +Added hardware support +~~~~~~~~~~~~~~~~~~~~~~ +ar71xx-generic +^^^^^^^^^^^^^^ + +* TP-Link + + - TL-WA830RE (v1) + +New features +~~~~~~~~~~~~ +The `x86-generic` and `x86-kvm_guest` images now support two ethernet interfaces by default. If two interfaces exist during +the first boot, `eth0` will be used as LAN and `eth1` as WAN. + +Bugfixes +~~~~~~~~ + +* Fix German "Expert Mode" label (was "Export Mode") +* Fix download of OpenSSL during build (because of broken OpenSSL download servers...) +* Fix ABI break causing kernel panics when trying to use network-related modules from the official OpenWrt repository (like `kmod-pppoe`) +* Fix race conditions breaking parallel build occasionally +* A broken network configuration would be generated when an older Gluon version was updated to 2015.1 with + ``mesh_on_lan`` enabled in `site.conf` +* Minor announced/alfred JSON format fixes (don't output empty lists where empty objects would be expected) diff --git a/docs/releases/v2015.1.2.rst b/docs/releases/v2015.1.2.rst new file mode 100644 index 00000000..97b97b35 --- /dev/null +++ b/docs/releases/v2015.1.2.rst @@ -0,0 +1,41 @@ +Gluon 2015.1.2 +============== + +Added hardware support +~~~~~~~~~~~~~~~~~~~~~~ +ar71xx-generic +^^^^^^^^^^^^^^ + +* TP-Link + + - TL-WA701N/ND (v2) + - TL-WA801N/ND (v1) + - TL-WA830RE (v2) + - TL-WR740N / TL-WR741ND (v5) + +New features +~~~~~~~~~~~~ + +* Ubiquiti Loco M, Picostation M and Rocket M now get their own images (which are just copies of the Bullet M image) + so it's more obvious for users which image to use +* The x86-generic images now contain the e1000e ethernet driver by default + +Bugfixes +~~~~~~~~ + +* Fix download of OpenSSL during build because of broken OpenSSL download servers (again...) +* Fix another ABI incompatiblity with the upstream kernel modules which prevented loading some filesystem-related modules +* Fix potential MAC address conflicts on x86 target when using mesh-on-wan/lan +* Fix signal strength indicators on TP-LINK CPE210/510 +* Fix the model name string on some NETGEAR WNDR3700v2 +* Fix 5GHz WLAN switching channels and losing connectivity when other WLANs using the same channel are detected (including other Gluon nodes...); see https://github.com/freifunk-gluon/gluon/issues/386 +* Fix DNS resolution for mesh VPN on IPv6-only WAN; see https://github.com/freifunk-gluon/gluon/issues/397 +* gluon-mesh-batman-adv-15: update batman-adv to 2015.0 with additional bugfixes (fixes various minor bugs) +* gluon-mesh-batman-adv-15: fix forwarding of fragmented frames over multiple links with different MTUs + + batman-adv compat 15 doesn't re-fragment frames that are fragmented already. In particular, + this breaks transmission of large packets which are first fragmented for mesh-on-lan/wan and are then sent + over the mesh VPN, which has an even smaller MTU. Work around this limitation by decreasing the maximum fragment + size to 1280, so they can always be forwarded as long there's no link with a MTU smaller than 1280. + + See https://github.com/freifunk-gluon/gluon/issues/435 diff --git a/docs/releases/v2016.1.1.rst b/docs/releases/v2016.1.1.rst new file mode 100644 index 00000000..59ca2504 --- /dev/null +++ b/docs/releases/v2016.1.1.rst @@ -0,0 +1,64 @@ +Gluon 2016.1.1 +============== + +Added hardware support +~~~~~~~~~~~~~~~~~~~~~~ + +ar71xx-generic +^^^^^^^^^^^^^^ + +* Onion Omega +* TP-Link TL-MR13U v1 + + +Bugfixes +~~~~~~~~ + +Build +^^^^^ + +Don't overwrite the opkg repository key on each build. + +AirOS 5.6.x compatiblity +^^^^^^^^^^^^^^^^^^^^^^^^ + +Downgrading to AirOS 5.5.x before flashing Gluon on Airmax M XM/XW devices +(NanoStation, Bullet, ...) is not necessary anymore. + +Status page +^^^^^^^^^^^ + +* Fix purging of disappered neighbours from the list +* Don't clear the signal graphs when scrolling in mobile browsers +* Improve browser compability (don't assume the Internationalization API is available, + fixes the display of numbers in Firefox for Android) + +Config mode +^^^^^^^^^^^ + +* Strip trailing whitespace from number input fields (LuCI's validator doesn't catch this) +* Don't allow negative bandwidth limits + +Failsafe mode +^^^^^^^^^^^^^ + +* Fix entering the failsafe mode on the TL-WDR4900. + +Known Issues +~~~~~~~~~~~~ + +* Default TX power on many Ubiquiti devices is too high, correct offsets are unknown (`#94 `_) + + Reducing the TX power in the Expert Mode is recommended. + +* The MAC address of the WAN interface is modified even when Mesh-on-WAN is disabled (`#496 `_) + + This may lead to issues in environments where a fixed MAC address is expected (like VMware when promicious mode is disallowed). + +* Inconsistent respondd/announced API (`#522 `_) + + The current API is inconsistent and will be replaced eventually. The old API will still be supported for a while. + +* Nondeterministic production of broken images for some (very old) hardware (`#669 `_) + + At the moment it seems like only the TL-WR841N v5 is affected. diff --git a/docs/releases/v2016.1.2.rst b/docs/releases/v2016.1.2.rst new file mode 100644 index 00000000..77f7efb8 --- /dev/null +++ b/docs/releases/v2016.1.2.rst @@ -0,0 +1,29 @@ +Gluon 2016.1.2 +============== + +Added hardware support +~~~~~~~~~~~~~~~~~~~~~~ + +The *x86-generic* images now contain the ATIIXP PATA driver, adding support for +FUTRO Thin Clients. + +Bugfixes +~~~~~~~~ + +A nondeterministic boot hang (`#669 `_) has been fixed. +The TL-WR841N v5 seems to be affected in particular, but the kernel bug is not hardware-specific per se. + +Known Issues +~~~~~~~~~~~~ + +* Default TX power on many Ubiquiti devices is too high, correct offsets are unknown (`#94 `_) + + Reducing the TX power in the Expert Mode is recommended. + +* The MAC address of the WAN interface is modified even when Mesh-on-WAN is disabled (`#496 `_) + + This may lead to issues in environments where a fixed MAC address is expected (like VMware when promicious mode is disallowed). + +* Inconsistent respondd API (`#522 `_) + + The current API is inconsistent and will be replaced eventually. The old API will still be supported for a while. diff --git a/docs/releases/v2016.1.3.rst b/docs/releases/v2016.1.3.rst new file mode 100644 index 00000000..ba5b9672 --- /dev/null +++ b/docs/releases/v2016.1.3.rst @@ -0,0 +1,43 @@ +Gluon 2016.1.3 +============== + +Added hardware support +~~~~~~~~~~~~~~~~~~~~~~ + +ar71xx-generic +^^^^^^^^^^^^^^ + +* ALFA Hornet UB / AP121 / AP121U +* TP-Link TL-WA7510N + +Bugfixes +~~~~~~~~ + +* The nondeterministic boot hang (`#669 `_) that was thought to + be fixed in Gluon v2016.1.2 has resurfaced on other hardware. We believe it is now fixed properly. +* Sysupgrades on the Xen DomU have been fixed. +* Gluon can now be built on systems that use LibreSSL instead of OpenSSL. + +Known Issues +~~~~~~~~~~~~ + +* Default TX power on many Ubiquiti devices is too high, correct offsets are unknown (`#94 `_) + + Reducing the TX power in the Expert Mode is recommended. + +* The MAC address of the WAN interface is modified even when Mesh-on-WAN is disabled (`#496 `_) + + This may lead to issues in environments where a fixed MAC address is expected (like VMware when promicious mode is disallowed). + +* Inconsistent respondd API (`#522 `_) + + The current API is inconsistent and will be replaced eventually. The old API will still be supported for a while. + +* Unwritable flash on some Ubiquiti PicoStations (`#687 `_) + + Gluon v2016.1.1 added support for Ubiquiti AirMAX devices with AirOS 5.6.x without downgrading AirOS first before + flashing Gluon. It was discovered that on Ubiquiti PicoStations, this downgrade is still necessary, as the + flash is not correctly unlocked, leaving the device unable to leave Config Mode and making regular sysupgrades + impossible. + + TFTP recovery can be used in this state to flash a new firmware. diff --git a/docs/releases/v2016.1.4.rst b/docs/releases/v2016.1.4.rst new file mode 100644 index 00000000..0d8d2019 --- /dev/null +++ b/docs/releases/v2016.1.4.rst @@ -0,0 +1,46 @@ +Gluon 2016.1.4 +============== + +Added hardware support +~~~~~~~~~~~~~~~~~~~~~~ + +ar71xx-generic +^^^^^^^^^^^^^^ + +* 8devices Carambola 2 +* Meraki MR12/MR62/MR16/MR66 + +Bugfixes +~~~~~~~~ + +* Major update of all WLAN drivers + + We've taken the unusual step of updating the WLAN drivers ("wireless-backports") to a much newer version, as + it was reported that the new version fixes unstable WLAN seen in many setups +* Build fix: a race condition causing parallel builds to fail has been fixed +* Build fix: the Gluon tree could get into a state in which all commands fail with "Too many levels of symbolic links" +* Build fix: allow building Gluon on systems with certain versions of *dash* as */bin/sh* + +Known Issues +~~~~~~~~~~~~ + +* Default TX power on many Ubiquiti devices is too high, correct offsets are unknown (`#94 `_) + + Reducing the TX power in the Expert Mode is recommended. + +* The MAC address of the WAN interface is modified even when Mesh-on-WAN is disabled (`#496 `_) + + This may lead to issues in environments where a fixed MAC address is expected (like VMware when promicious mode is disallowed). + +* Inconsistent respondd API (`#522 `_) + + The current API is inconsistent and will be replaced eventually. The old API will still be supported for a while. + +* Unwritable flash on some Ubiquiti PicoStations (`#687 `_) + + Gluon v2016.1.1 added support for Ubiquiti AirMAX devices with AirOS 5.6.x without downgrading AirOS first before + flashing Gluon. It was discovered that on Ubiquiti PicoStations, this downgrade is still necessary, as the + flash is not correctly unlocked, leaving the device unable to leave Config Mode and making regular sysupgrades + impossible. + + TFTP recovery can be used in this state to flash a new firmware. diff --git a/docs/releases/v2016.1.5.rst b/docs/releases/v2016.1.5.rst new file mode 100644 index 00000000..e5ee1a00 --- /dev/null +++ b/docs/releases/v2016.1.5.rst @@ -0,0 +1,66 @@ +Gluon 2016.1.5 +============== + +Added hardware support +~~~~~~~~~~~~~~~~~~~~~~ + +ar71xx-generic +^^^^^^^^^^^^^^ + +* OpenMesh + + - MR600 (v1, v2) + - MR900 (v1, v2) + - OM2P (v1, v2) + - OM2P-HS (v1, v2) + - OM2P-LC + - OM5P + - OM5P-AN + +* Ubiquiti + + - Rocket M XW + +* TP-LINK + + - TL-WR841N/ND v11 + +Bugfixes +~~~~~~~~ + +* build: fix race condition caused by using certain make targets (like *clean*, *images* or *package/\**) + with parallel build options without doing a full build before +* build: fix package dependency issue causing "recursive dependency" warning + + This dependency issue could lead to broken configurations and reportedly caused failed builds in some cases + when additional (site-specific) packages were used. +* build: Gluon will now build correctly with GCC 6 as host compiler +* Fix configuration of batman-adv when VLANs are used on top of IBSS interfaces (regression due to netifd update in :doc:`v2016.1.4`) +* Add back missing ath10k firmware (regression due to mac80211 update in :doc:`v2016.1.4`) +* Gluon can now be used on all supported Ubiquiti AirMAX devices without downgrading to AirOS 5.5.x before + + :doc:`v2016.1.1` added support for most Ubiquiti AirMAX devices with AirOS 5.6.x without downgrading AirOS, + but left some devices (at least some PicoStations and Bullets) with unwritable flash. This issue has been + resolved (`#687 `_). +* Add upgrade script to automatically remove whitespace from configured geolocation + + The new respondd implementation included in :doc:`v2016.1` is stricter about the number format than the + old one and doesn't accept trailing whitespace (so one or both coordinates are missing from the output). + + The Config Mode has been fixed to strip whitespace from numeric fields in new configurations since :doc:`v2016.1.1`. + This still left old configurations, which are now fixed by this script. + +Known Issues +~~~~~~~~~~~~ + +* Default TX power on many Ubiquiti devices is too high, correct offsets are unknown (`#94 `_) + + Reducing the TX power in the Expert Mode is recommended. + +* The MAC address of the WAN interface is modified even when Mesh-on-WAN is disabled (`#496 `_) + + This may lead to issues in environments where a fixed MAC address is expected (like VMware when promicious mode is disallowed). + +* Inconsistent respondd API (`#522 `_) + + The current API is inconsistent and will be replaced eventually. The old API will still be supported for a while. diff --git a/docs/releases/v2016.1.6.rst b/docs/releases/v2016.1.6.rst new file mode 100644 index 00000000..e9f97838 --- /dev/null +++ b/docs/releases/v2016.1.6.rst @@ -0,0 +1,55 @@ +Gluon 2016.1.6 +============== + +Bugfixes +~~~~~~~~ + +* build: fix nodejs host build on Debian Wheezy (`#776 `_) +* build: fix parallel builds with Make 4.2+ + + Trying to use ``-j N`` with Make 4.2 would spawn an unlimited number of processes, + eventually leading to memory exhaustion. + +* build: fix occasional build failure in libpcap package +* build: don't require hexdump for x86 builds (`#811 `_) + + Trying to build Gluon for x86 on systems without hexdump would silently generate + broken images. + +* Add support for DNS servers given by their link-local IPv6 address in Router Advertisements + (`#854 `_) + +* ar71xx-generic: correctly setup LNA GPIOs on CPE210/510 (`#796 `_) + + Improves the reception by about 20dB. + +* ar71xx-generic: switch default WAN/LAN assignment on Ubiquiti UAP Pro + (`#764 `_) + + Switch to the usual "PoE is WAN/setup mode, secondary is LAN" scheme. This only affects + new installations; the assignment won't be changed on updates unless the configuration is + reset. + +* ar71xx-generic: fix ath10k memory leak (`#690 `_) +* ar71xx-generic: add support for new TP-Link region codes + (`#860 `_) + + TP-Link has started providing US- and EU-specific firmwares for the Archer C7 v2. To generate + Gluon images installable from these new firmwares, the ``GLUON_REGION`` variable must be set + to ``eu`` or ``us`` in ``site.mk`` or on the ``make`` command line (the images will still be + installable from all old firmwares without region codes). + +Known Issues +~~~~~~~~~~~~ + +* Default TX power on many Ubiquiti devices is too high, correct offsets are unknown (`#94 `_) + + Reducing the TX power in the Expert Mode is recommended. + +* The MAC address of the WAN interface is modified even when Mesh-on-WAN is disabled (`#496 `_) + + This may lead to issues in environments where a fixed MAC address is expected (like VMware when promicious mode is disallowed). + +* Inconsistent respondd API (`#522 `_) + + The current API is inconsistent and will be replaced eventually. The old API will still be supported for a while. diff --git a/docs/releases/v2016.1.rst b/docs/releases/v2016.1.rst new file mode 100644 index 00000000..94229c5a --- /dev/null +++ b/docs/releases/v2016.1.rst @@ -0,0 +1,276 @@ +Gluon 2016.1 +============ + +Added hardware support +~~~~~~~~~~~~~~~~~~~~~~ + +ar71xx-generic +^^^^^^^^^^^^^^ + +* Buffalo + + - WZR-HP-G300NH + +* D-Link + + - DIR-505 (A1) + +* TP-Link + + - CPE210/220/510/520 v1.1 + - TL-WA901N/ND v1 + - TL-WR710N v2 + - TL-WR801N/ND v1, v2 + - TL-WR841N/ND v10 + - TL-WR843N/ND v1 + - TL-WR940N v1, v2, v3 + - TL-WR941ND v6 + - TL-WR1043N/ND v3 + +* Ubiquiti + + - airGateway + - airRouter + - UniFi AP Outdoor+ + +* Western Digital + + - My Net N600 + - My Net N750 + +x86-xen_domu +^^^^^^^^^^^^ + +New target containing the necessary drivers for use in Xen. + +x86-64 +^^^^^^ + +64bit version of `x86-generic`. The generic image can also be used in KVM with VirtIO. + +New features +~~~~~~~~~~~~ + +Kernel module opkg repository +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +We've not been able to keep ABI compatiblity with the kernel of the official OpenWrt images. +Therefore, Gluon now generates an opkg repository with modules itself. + +The repository can be found at `output/modules/` by default, the image output directory has +been moved from `images/` to `output/images/`. See the updated :doc:`../user/getting_started` guide +for information on the handling of the signing keys for this repository. + +The `opkg_repo` site.conf option has been replaced to allow specifying this and other additional repositories. + +New status page +^^^^^^^^^^^^^^^ + +The new status page provides a visually pleasing experience, and displays all important information +on a node in a clear manner. It also contains a real-time signal strength graph for all neighbouring +nodes to aid with the alignment of antennas. + +802.11s mesh support +^^^^^^^^^^^^^^^^^^^^ + +Gluon now supports using 802.11s for its mesh links instead of IBSS (Adhoc). This will allow supporting +more WLAN hardware in the future (like Ralink/Mediatek, which don't support AP and IBSS mode simultaneously). + +Note that batman-adv is still used on top of 802.11s (and 802.11s forwarding is disabled), the mesh routing protocol +provided by 802.11s is not used. + +Multicast filter extension +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The `gluon-ebtables-filter-multicast` package has been extended to filter out multicast +ICMP and ICMPv6 Echo Requests (ping) and Node Information Queries (RFC4620). This prevents +pings to multicast addresses like ff02::1 to cause traffic peaks +(as all nodes and clients would answer such a ping). + +French translation +^^^^^^^^^^^^^^^^^^ + +A French translation for the Config Mode/Expert Mode has been added. + +Bugfixes +~~~~~~~~ + +* Update kernel code for the QCA953x + + Might improve stability of the TP-Link TL-WR841N/ND v9. +* Fix model detection on some Netgear WNDR3700v2 + + The broken devices will identify as "NETGEAR ". + This also breaks the autoupdater, making a manual upgrade necessary. +* Ensure that `odhcp6c` doesn't spawn multiple instances of ``dhcpv6.script`` +* Fix support for Buffalo WZR-600DHP + + A flashable factory image is generated now. The sysupgrade image is still shared + with the WZR-HP-AG300H. + +Site changes +~~~~~~~~~~~~ + +* ``site.conf`` + + - New WLAN configuration + + ``wifi24`` and ``wifi5`` need to be updated to a new more flexible format. + A configuration using the old format + + :: + + { + channel = 1, + htmode = 'HT20' + ssid = 'entenhausen.freifunk.net', + mesh_ssid = 'xe:xx:xx:xx:xx:xx', + mesh_bssid = 'xe:xx:xx:xx:xx:xx', + mesh_mcast_rate = 12000, + } + + would look like this in the new format:: + + { + channel = 1, + ap = { + ssid = 'entenhausen.freifunk.net', + }, + ibss = { + ssid = 'xe:xx:xx:xx:xx:xx', + bssid = 'xe:xx:xx:xx:xx:xx', + mcast_rate = 12000, + }, + } + + The ``htmode`` option has been dropped, the channel width is now always set to 20MHz + (see https://github.com/freifunk-gluon/gluon/issues/487 for a discussion of this change). + + In addition to the old IBSS (Adhoc) based meshing, 802.11s-based meshing can be configured + using the ``mesh`` section. Example:: + + { + channel = 1, + ap = { + ssid = 'entenhausen.freifunk.net', + }, + mesh = { + id = 'mesh.entenhausen.freifunk.net', -- can by any string, human-readable or random + mcast_rate = 12000, + }, + } + + While using ``ibss`` and ``mesh`` at the same time is possible, is causes high load in + very active meshes, so it is advisable to avoid such configurations. + + - Bandwidth limitation defaults + + The old section ``simple_tc.mesh_vpn`` has been moved to ``fastd_mesh_vpn.bandwidth_limit`` and the ``ifname`` + field isn't used anymore. What looked like this + before + + :: + + simple_tc = { + mesh_vpn = { + ifname = 'mesh-vpn', + enabled = false, + limit_egress = 200, + limit_ingress = 3000, + }, + } + + needs to be changed to + + :: + + fastd_mesh_vpn = { + -- ... + + bandwidth_limit = { + enabled = false, + egress = 200, + ingress = 3000, + }, + } + + - opkg repository configuration + + The opkg configuration has been changed to be more flexible and allow specifying custom repositories. + Example:: + + opkg = { + openwrt = 'http://opkg.services.ffeh/openwrt/%n/%v/%S/packages', + extra = { + modules = 'http://opkg.services.ffeh/modules/gluon-%GS-%GR/%S', + }, + } + + The keys of the ``extra`` table (like ``modules`` in this example) can be chosen arbitrarily. + + Instead of explicitly specifying the whole URL, using patterns is recommended. The following + patterns are understood: + + - ``%n`` is replaced by the OpenWrt version codename (e.g. "chaos_calmer") + - ``%v`` is replaced by the OpenWrt version number (e.g. "15.05") + - ``%S`` is replaced by the target architecture (e.g. "ar71xx/generic") + - ``%GS`` is replaced by the Gluon site code (as specified in ``site.conf``) + - ``%GV`` is replaced by the Gluon version + - ``%GR`` is replaced by the Gluon release (as specified in ``site.mk``) + + +* ``site.mk`` + + - The packages `gluon-announce` and `gluon-announced` were merged into + the package `gluon-respondd`. If you had any of them (probably + `gluon-announced`) in your package list, you have to replace them. + + +* ``i18n/`` + + - The translations of ``gluon-config-mode:pubkey`` now have to show the fastd + public key themselves if desired, making the formatting of the key and whether it is shown at + all configurable. To retain the old format, add ``

`` to the beginning of + your translations and append:: + + "

" + "
" + " # <%= hostname %>" + "
" + "<%= pubkey %>" + "
" + +Internals +~~~~~~~~~ + +* OpenWrt has been updated to Chaos Calmer +* mac80211 has been backported from OpenWrt trunk r47249 (wireless-testing 2015-07-21) + + This allows us to support the TL-WR940N v3/TL-WR941ND v6, which uses a TP9343 (QCA956x) SoC. +* Several packages have been moved from the Gluon repo to the packages repo, removing references to Gluon: + + - gluon-cron -> micrond (the crontabs are now read from ``/usr/lib/micron.d`` instead of ``/lib/gluon/cron``) + - gluon-radvd -> uradvd + - gluon-simple-tc -> simple-tc (the config file has been renamed as well) + +* Some of the Gluon-specific i18n support code in the build system has been removed, as LuCI now provides + similar facilities +* The C-based `luci-lib-jsonc` library is now used for JSON encoding/decoding instead of the pure Lua `luci-lib-json` +* The site config is now stored as JSON on the node. The Lua interface ``gluon.site_config`` is still available, and a C interface was added as part of the new package `libgluonutil`. +* The `respondd` daemon now uses C modules instead of Lua snippets, which greatly enhances response speed and reduces memory usage. The Gluon integration package has + been renamed from `gluon-announced` to `gluon-respondd`. + +Known Issues +~~~~~~~~~~~~ + +* Default TX power on many Ubiquiti devices is too high, correct offsets are unknown (`#94 `_) + + Reducing the TX power in the Expert Mode is recommended. +* batman-adv causes stability issues for both alfred and respondd/announced (`#177 `_) +* The MAC address of the WAN interface is modified even when Mesh-on-WAN is disabled (`#496 `_) + + This may lead to issues in environments where a fixed MAC address is expected (like VMware when promicious mode is disallowed). + +* Inconsistent respondd/announced API (`#522 `_) + + The current API is inconsistent and will be replaced in the next release. The old API will still be supported for a while. diff --git a/docs/releases/v2016.2.1.rst b/docs/releases/v2016.2.1.rst new file mode 100644 index 00000000..2f71205c --- /dev/null +++ b/docs/releases/v2016.2.1.rst @@ -0,0 +1,59 @@ +Gluon 2016.2.1 +============== + +Added hardware support +~~~~~~~~~~~~~~~~~~~~~~ + +ar71xx-generic +^^^^^^^^^^^^^^ + +* TP-Link + + - TL-WA901ND v4 + +Bugfixes +~~~~~~~~ + +* Make status page work with disabled cookies/local storage + (`#912 `_) + +* Update kernel to 3.18.44 + + Fixes CVE-2016-5195 and CVE-2016-7117. It is unlikely that these issues pose + a threat to usual Gluon setups, but installing additional packages may make a + system vulnerable. In any case, updating is highly recommended. + +* Downgrade mac80211 to an earlier state + + Unfortunately, a mac80211 update that was done shortly before the release of + Gluon v2016.2 (that seemed necessary to properly support ath10k devices) had + again caused severe ath9k stability issues that remained unreported until v2016.2 + was out. + + We have now reverted mac80211 to an earlier state that was reported to be very + stable (while keeping the ath10k-specific changes); in addition, some patches + that were reported to cause connection or performance issues with certain clients + have been reverted. While is it still not perfectly stable, is should be at least + as good as (and probably better than) the v2016.1.x release series. + +Known Issues +~~~~~~~~~~~~ + +* Default TX power on many Ubiquiti devices is too high, correct offsets are unknown (`#94 `_) + + Reducing the TX power in the Advanced Settings is recommended. + +* The MAC address of the WAN interface is modified even when Mesh-on-WAN is disabled (`#496 `_) + + This may lead to issues in environments where a fixed MAC address is expected (like VMware when promicious mode is disallowed). + +* Inconsistent respondd API (`#522 `_) + + The current API is inconsistent and will be replaced eventually. The old API will still be supported for a while. + +* Git HTTPS downloads from git.kernel.org fail on Debian Wheezy (`#919 `_) + + The GnuTLS version on Debian Wheezy is too old and can't establish a connection with + git.kernel.org anymore. A newer GnuTLS version is available in wheezy-backports, but + as there is no libcurl3-gnutls package linked against the new version, installing the + new version has no effect. diff --git a/docs/releases/v2016.2.2.rst b/docs/releases/v2016.2.2.rst new file mode 100644 index 00000000..fe054f54 --- /dev/null +++ b/docs/releases/v2016.2.2.rst @@ -0,0 +1,78 @@ +Gluon 2016.2.2 +============== + +Added hardware support +~~~~~~~~~~~~~~~~~~~~~~ + +ar71xx-generic +^^^^^^^^^^^^^^ + +* TP-Link + + - CPE210/510 EU/US versions + - TL-WA801N/ND v3 + - TL-WR841ND v11 EU/US versions + +Bugfixes +~~~~~~~~ + +* Fix boot on certain QCA955x-based devices (e.g. OpenMesh OM5P AC v2) (`#965 `_) + + This issue was a regression in Gluon v2016.2.1. + +* Build: Fix git downloads from git.kernel.org on Debian Wheezy (`#919 `_) + + We've switched back from HTTPS to the git protocol for now to avoid using + the old GnuTLS version of Debian Wheezy which can't establish a HTTPS connection + with git.kernel.org anymore. + + This issue was a regression in Gluon v2016.2. + +* Fix RX filter of Ubiquiti UAP Outdoor+ (`d43147a8e03d `_) + + This issue was a regression in Gluon v2016.2. + +* Fix switched WAN/LAN interface assignment on CPE210 (`59deb2064d54 `_) + + This issue was a regression in Gluon v2016.2. + +* Significantly reduce CPU load used by signal strength LEDs (`#897 `_) + +* Fix ethernet port of the Ubiquiti UAP AC Lite (`#911 `_) + +* Build: Don't use host ``/tmp`` directory (`f9072a36411b `_) + + Fixes build when ``/tmp`` is mounted with *noexec*. + +* Fix mesh interface type respondd/alfred announcements when using VLANs over IBSS (`#941 `_) + +* Fix next-node ebtables rules without *next_node.ip4* (`9dbe9f785d2b `_) + + Gluon v2016.2 added support for using the next-node feature without specifying an IPv4 + address. Some scripts had not been adjusted, making the next-node unreliable when + no IPv4 address was specified. + +Other changes +~~~~~~~~~~~~~ + +* x86-generic and x86-64 images now have PATA and MMC support to allow using them + on various devices that were previously unsupported. + +* Clean up opkg postinst scripts up on image generation + + OpenWrt does this by default to save a little space. + +Known Issues +~~~~~~~~~~~~ + +* Default TX power on many Ubiquiti devices is too high, correct offsets are unknown (`#94 `_) + + Reducing the TX power in the Advanced Settings is recommended. + +* The MAC address of the WAN interface is modified even when Mesh-on-WAN is disabled (`#496 `_) + + This may lead to issues in environments where a fixed MAC address is expected (like VMware when promicious mode is disallowed). + +* Inconsistent respondd API (`#522 `_) + + The current API is inconsistent and will be replaced eventually. The old API will still be supported for a while. diff --git a/docs/releases/v2016.2.3.rst b/docs/releases/v2016.2.3.rst new file mode 100644 index 00000000..dacd5cd2 --- /dev/null +++ b/docs/releases/v2016.2.3.rst @@ -0,0 +1,62 @@ +Gluon 2016.2.3 +============== + +Added hardware support +~~~~~~~~~~~~~~~~~~~~~~ + +ar71xx-generic +^^^^^^^^^^^^^^ + +* TP-Link TL-WR940N v4 +* TP-Link TL-WR1043ND v4 + +Removed hardware support +~~~~~~~~~~~~~~~~~~~~~~~~ + +Support for Meraki devices (MR12/16/62/66) has been removed for now because of +severe problems (all devices were using the same MAC addresses). Support will return +when the issues have been fixed. + +Bugfixes +~~~~~~~~ + +* Automatically restart respondd on failure (`#863 `_) + + There have been many reports of respondd processes disappearing; the exact cause is unclear, + but might be related to the batman-adv debugfs interface and/or out-of-memory conditions. + + A new respondd initscript uses procd to automatically restart respondd when it dies. + +* Make autoupdater timeouts more robust (`#987 `_) + + It was reported that wget processes sometimes hang indefinitely during the autoupdater manifest + download. The autoupdater has been improved to ensure that wget can always be interrupted after + a timeout. + + This issue, together with the recent addition of lock files to ensure that only one instance + of the autoupdater can run at a time, had caused the autoupdater to blocked completely + by hanging processes in some cases (till a node was rebooted). + +* Fix regulation domain switching in ath10k (`#1001 `_) + + Prevents use of too high transmission power in some cases. + +* Ensure that *prefix6* in site.conf is always a /64 prefix (`6b62e2f `_) + + Other prefix lengths were never supported and don't make sense in many places the prefix is used. Ensure + that such configurations will not pass validation. + +Known Issues +~~~~~~~~~~~~ + +* Default TX power on many Ubiquiti devices is too high, correct offsets are unknown (`#94 `_) + + Reducing the TX power in the Advanced Settings is recommended. + +* The MAC address of the WAN interface is modified even when Mesh-on-WAN is disabled (`#496 `_) + + This may lead to issues in environments where a fixed MAC address is expected (like VMware when promicious mode is disallowed). + +* Inconsistent respondd API (`#522 `_) + + The current API is inconsistent and will be replaced eventually. The old API will still be supported for a while. diff --git a/docs/releases/v2016.2.4.rst b/docs/releases/v2016.2.4.rst new file mode 100644 index 00000000..4fb06026 --- /dev/null +++ b/docs/releases/v2016.2.4.rst @@ -0,0 +1,55 @@ +Gluon 2016.2.4 +============== + +Bugfixes +~~~~~~~~ + +* Fix batman-adv (compat 15) not being able to transmit packages of specific sizes (`b7eeef9 `_) + + We suspect that this issue was also the reason for the autoupdater/wget hangs observed by many communities. + Non-Gluon nodes like gateways should be updated to batman-adv 2017.0.1 to get the fix. + +* Fix build after ftp.all.kernel.org discontinuation (`#1059 `_) + +* Fix high load because of frequent calls of the respondd initscript (`9a0aeb9 `_) + + The respondd restart triggers added in v2016.2.3 ran a significant portion of the respondd initscript for each router advertisement + received. This was fixed by a backport of a netifd patch. + +* x86 sysupgrade fixes (`41fd50d `_, + `ad37e2b `_) + + This fixes sysupgrade on mmcblk and similar devices. + +Other changes +~~~~~~~~~~~~~ + +* The manifest generator has been extended to generate SHA256 checksums in addition to SHA512 ones + (`f9d59be `_) + + We have recently switched the autoupdater to SHA256 in the Gluon master to avoid mixing two different + lengths of hashes for no good reason. This makes the manifests of Gluon v2016.2.x compatible with the + new autoupdater so it doesn't prevent backports or downgrades. + + **Note:** Downgrades of major Gluon versions are generally unsupported and will often lead to + broken configurations. + +Known Issues +~~~~~~~~~~~~ + +* x86 sysupgrade (sometimes) loses config when kernel partition grows (`#1010 `_) + + This issue affects upgrades from v2016.2.x and older to the Gluon master only, we hope to fix it before the next + major release. + +* Default TX power on many Ubiquiti devices is too high, correct offsets are unknown (`#94 `_) + + Reducing the TX power in the Advanced Settings is recommended. + +* The MAC address of the WAN interface is modified even when Mesh-on-WAN is disabled (`#496 `_) + + This may lead to issues in environments where a fixed MAC address is expected (like VMware when promicious mode is disallowed). + +* Inconsistent respondd API (`#522 `_) + + The current API is inconsistent and will be replaced eventually. The old API will still be supported for a while. diff --git a/docs/releases/v2016.2.5.rst b/docs/releases/v2016.2.5.rst new file mode 100644 index 00000000..07a27f0c --- /dev/null +++ b/docs/releases/v2016.2.5.rst @@ -0,0 +1,36 @@ +Gluon 2016.2.5 +============== + +This version contains only a single bugfix for a regression introduced in Gluon v2016.2.4. +As the regression affects batman-adv compat 15 only, firmwares using the compat 14 legacy +version don't need to be updated. + +Bugfixes +~~~~~~~~ + +* Fix kernel crash with batman-adv compat 15 (`d452a7c `_) + + An incorrect backport of a fix for a very improbable kernel crash caused a much more + frequent kernel crash. The backport has been fixed. + + This bug a regression in Gluon v2016.2.4. + +Known Issues +~~~~~~~~~~~~ + +* x86 sysupgrade (sometimes) loses config when kernel partition grows (`#1010 `_) + + This issue affects upgrades from v2016.2.x and older to the Gluon master only, we hope to fix it before the next + major release. + +* Default TX power on many Ubiquiti devices is too high, correct offsets are unknown (`#94 `_) + + Reducing the TX power in the Advanced Settings is recommended. + +* The MAC address of the WAN interface is modified even when Mesh-on-WAN is disabled (`#496 `_) + + This may lead to issues in environments where a fixed MAC address is expected (like VMware when promicious mode is disallowed). + +* Inconsistent respondd API (`#522 `_) + + The current API is inconsistent and will be replaced eventually. The old API will still be supported for a while. diff --git a/docs/releases/v2016.2.6.rst b/docs/releases/v2016.2.6.rst new file mode 100644 index 00000000..fac3f13d --- /dev/null +++ b/docs/releases/v2016.2.6.rst @@ -0,0 +1,57 @@ +Gluon 2016.2.6 +============== + +Added hardware support +~~~~~~~~~~~~~~~~~~~~~~ + +ar71xx-generic +^^^^^^^^^^^^^^ + +* TP-Link TL-WR841N/ND v12 + +Bugfixes +~~~~~~~~ + +* Fix `CVE-2016-10229 `_ + (`#1097 `_) + + Fortunately, the standard Gluon setup is not vulnerable, as the issue only affects + applications that use MSG_PEEK on UDP sockets. dnsmasq does use MSG_PEEK, but + only in the DHCP component, which is not enabled during normal node operation. + +* Fix roaming issue affecting communication between clients + (`#1121 `_) + + This issue affects all previous releases of Gluon v2016.2.x. + +* Fix build against OpenSSL 1.1 (`b6a22ce `_) + +* Fix build with long path names (`#1120 `_) + +* Use new staged sysupgrade procedure (`d4a69c0 `_) + + The new sysupgrade fixes an issue affecting x86, causing nodes to lose their + configuration on upgrade when the size of the kernel partition grows. This is + the case when upgrading from Gluon v2016.2.x to newer (LEDE-based) Gluon + versions. **This means that a Gluon node running an older version must be + upgraded to Gluon v2016.2.6 first before switching to a LEDE-based version!** + + One downside of the staged sysupgrade is that all processes, including the SSH + server, will be terminated at the start of the sysupgrade to allow unmounting + the root filesystem. This makes it impossible to get any feedback from the + upgrade process without a serial console. + +Known Issues +~~~~~~~~~~~~ + +* Default TX power on many Ubiquiti devices is too high, correct offsets are unknown (`#94 `_) + + Reducing the TX power in the Advanced Settings is recommended. + +* The MAC address of the WAN interface is modified even when Mesh-on-WAN is disabled (`#496 `_) + + This may lead to issues in environments where a fixed MAC address is expected (like VMware when promicious mode is disallowed). + +* Inconsistent respondd API (`#522 `_) + + The current API is inconsistent and will be replaced eventually. The old API will still be supported for a while. diff --git a/docs/releases/v2016.2.rst b/docs/releases/v2016.2.rst new file mode 100644 index 00000000..7693e447 --- /dev/null +++ b/docs/releases/v2016.2.rst @@ -0,0 +1,179 @@ +Gluon 2016.2 +============ + +Added hardware support +~~~~~~~~~~~~~~~~~~~~~~ + +ar71xx-generic +^^^^^^^^^^^^^^ + +* ALFA Network + + - Tube2H + - N2 + - N5 + +* Buffalo + + - WZR-HP-G300NH2 + +* GL Innovations + + - GL-AR150 + +* OpenMesh + + - MR1750 v1, v2 [#ath10k]_ + - OM2P-HS v3 + - OM5P-AC v1, v2 [#ath10k]_ + +* TP-Link + + - Archer C5 v1 [#ath10k]_ + - Archer C7 v2 [#ath10k]_ + - TL-WR710N v2.1 + - TL-WR842N/ND v3 + +* Ubiquiti + + - UniFi AP AC Lite [#ath10k]_ + - UniFi AP AC Pro [#ath10k]_ + +.. [#ath10k] + Device uses the ath10k WLAN driver; no image is built unless GLUON_ATH10K_MESH + is set as described in :ref:`getting-started-make-variables` + +brcm2708-bcm2708 +^^^^^^^^^^^^^^^^ + +* RaspberryPi 1 + +brcm2708-bcm2709 +^^^^^^^^^^^^^^^^ + +* RaspberryPi 2 + +New features +~~~~~~~~~~~~ + +* Many UBNT Airmax XM model names are detected correctly now (e.g., the Loco + is no longer displayed as Bullet) (`#632 `_) + + Also, various new image aliases have been added for these devices. + +* batman-adv: mesh_no_rebroadcast is now enabled for Mesh-on-WAN/LAN (`#652 `_) + +* The new UCI option ``gluon-core.@wireless[0].preserve_channels`` can be used to + prevent a changed WLAN channel from being reset on firmware upgrades (`#640 `_) + +* PoE passthrough can now be configured from site.conf and the Advanced Settings + on TP-Link CPE 210/510 and Ubiquiti NanoStations (`#328 `_) + +* The config mode *altitude* field can now be hidden using the ``config_mode.geo_location.show_altitude`` + site.conf setting (`#693 `_) + +* The contact information field in the config mode can be made obligatory using + the ``config_mode.owner.obligatory`` site.conf option + +* The *node name* setting in the config mode is no longer restricted to valid DNS + hostnames, but allows any UTF-8 string (`#414 `_) + +* Besides the hostname, public key, site config and primary MAC address, the contact + information can now be accessed from config mode site texts + +* The functions ``escape`` and ``urlescape`` for HTML and URL escaping are now available from config mode + site texts. They should always be used when including user-provided information like + hostnames and contact information in HTML code or URLs. + +* Dropbear has been updated to a newer version, enabling new SSH crypto methods and removing + some old ones like DSA. This reduces the time needed for the first boot and makes + SSH logins faster (`#223 `_) + +* WLAN basic and supported rate sets have been made configurable, to allow disabling + 802.11b rates (`#810 `_) + +* ath10k-based devices are now supported officially; it's possible to choose between + IBSS- and 11s-capable firmwares in site.mk (`#864 `_) + +* The ``prefix4`` and ``next_node.ip4`` site.conf options are optional now. + +Bugfixes +~~~~~~~~ + +* The stability of the ath9k WLAN driver has been improved significantly + (`#605 `_) + + mac80211, hostapd and other related drivers and services have been backported from LEDE ``42f559e``. + +* Extremely slow downloads could lead to multiple instances of the autoupdater + running concurrently (`#582 `_) + + A lockfile is used to prevent this and timeouts have been added to download processes. + +* Usage of static DNS servers on the WAN port has been fixed + (`#886 `_) + + This is a regression introduced in Gluon v2016.1.6. + +Other changes +~~~~~~~~~~~~~ + +* The "Expert Mode" has been renamed to "Advanced Settings" + +Site changes +~~~~~~~~~~~~ + +site.mk +^^^^^^^ + +If you want to support ath10k-based devices, you should set GLUON_ATH10K_MESH +and GLUON_REGION as described in :ref:`getting-started-make-variables`. + +i18n +^^^^ + +As the hostname field may now contain an arbitrary UTF-8 string, escaping must +be added. + +Change + +:: + + <%=hostname%> + +to + +:: + + <%=escape(hostname)%> + +Inside of URLs, ``urlescape`` must be used instead of ``escape``. + +Internals +~~~~~~~~~ + +* Mesh interfaces are now configured in a protocol-independent way in UCI (`#870 `_) + + The MAC address assignment of all mesh and WLAN interfaces has been modified to prepare for support of + Ralink/Mediatek-based WLAN chips. + +* Preparations for supporting the new batman-adv multicast optimizations have been made + (`#674 `_, `#675 `_, + `#679 `_) + +* All Lua code is minified now to save some space + +Known Issues +~~~~~~~~~~~~ + +* Default TX power on many Ubiquiti devices is too high, correct offsets are unknown (`#94 `_) + + Reducing the TX power in the Advanced Settings is recommended. + +* The MAC address of the WAN interface is modified even when Mesh-on-WAN is disabled (`#496 `_) + + This may lead to issues in environments where a fixed MAC address is expected (like VMware when promicious mode is disallowed). + +* Inconsistent respondd API (`#522 `_) + + The current API is inconsistent and will be replaced eventually. The old API will still be supported for a while. diff --git a/docs/releases/v2017.1.rst b/docs/releases/v2017.1.rst new file mode 100644 index 00000000..52a1bae1 --- /dev/null +++ b/docs/releases/v2017.1.rst @@ -0,0 +1,229 @@ +Gluon 2017.1 +============ + +General changes +~~~~~~~~~~~~~~~ + +Gluon 2017.1 is the first release of Gluon based on the LEDE 17.01 branch. The +kernel has been updated from 3.18.x to 4.4.x. + +We've used the opportunity to greatly simplify the Gluon build system, removing +many hacks that were required to make the build work with older OpenWrt releases. + +The *output/modules* directory is now called *output/packages* and provides a +replacement for the whole repository with target-specific packages of LEDE (in +contrast to packages that are common for all targets of the same architecture). + +**Note: There is an issue in all Gluon versions before 2016.2.6 that will +lead to x86 systems losing their configuration when upgrading to Gluon 2017.1!** +Older Gluon versions should be upgraded to 2016.2.6 first before switching to +2017.1. + +Another potential issue mostly affects virtual machines: Gluon 2017.1 images are +bigger than 2016.2.x images on x86. If your virtual harddisk is based on a +2016.2.x image, it must be resized to 273MB or bigger before upgrading to Gluon +2017.1. Using qemu, the command + +:: + + qemu-img resize $IMAGE 273MB + +can be used to do this. + +Added hardware support +~~~~~~~~~~~~~~~~~~~~~~ + +ar71xx-generic +^^^^^^^^^^^^^^ + +* TP-Link + + - RE450 + - WBS210 v1.20 + - WBS510 v1.20 + +* Ubiquiti + + - AirGateway LR + - AirGateway PRO + - Rocket M2/M5 Ti + - UniFi AP LR + +ar71xx-tiny +^^^^^^^^^^^ + +The new *ar71xx-tiny* target has split out of *ar71xx-generic*; all +*ar71xx-generic* devices with only 4MB of flash have been moved to this target. + +In contrast to *ar71xx-generic*, *ar71xx-tiny* **does not support opkg anymore** +to save some space. + +* TP-Link + + - TL-WA730RE v1 + - TL-WA7210N v2 + +x86-generic +^^^^^^^^^^^ + +The *x86-kvm* and *x86-xen_domu* targets have been removed; the *x86-generic* +images now support these usecases as well, so no separate targets are needed +anymore. + +x86-geode +^^^^^^^^^ + +The new *x86-geode* target for hardware based on Geode CPUs has been added. + +New features +~~~~~~~~~~~~ + +* Localization support has been added to the status page. In addition to German, + there are English and Russian translations now (`#1044 `_) + +* Add support for making nodes a DNS cache for clients + (`#1000 `_) + + See also: :doc:`../features/dns-cache` + +* Add L2TP via tunneldigger as an alternative VPN system + (`#978 `_) + + L2TP will usually give better performance than fastd as it runs in kernel + space, but it does not provide encryption. Also, tunneling over IPv6 is + currently unsupported by tunneldigger. + + It is not possible to include both fastd and tunneldigger in the same + firmware. + +* Add source filter package (`#1015 `_) + + The new package *gluon-ebtables-source-filter* can be used to prevent traffic + using unexpected IP addresses or packet types from entering the mesh. + + See also: :doc:`../package/gluon-ebtables-source-filter` + +Bugfixes +~~~~~~~~ + +* Disabling batman-adv on an interface (for example when an Ethernet link is lost + or before sysupgrades) could lead to a kernel crash in certain configurations + (`#680 `_) + +* A race condition in the network setup scripts could lead to incomplete setup + during boot or when interfaces were added or removed from batman-adv after + Ethernet link changes (`#905 `_) + + The fix also solved the long-standing issue of Ethernet-only nodes (i.e. no + WLAN or VPN mesh) not booting up correctly without an Ethernet mesh link. + +* Some fixes in the WLAN stack of LEDE have improved the stability of the ath9k + driver (`#605 `_) + +Site changes +~~~~~~~~~~~~ + +site.mk +^^^^^^^ + +* The *gluon-legacy* package does not exist anymore +* All *gluon-luci-* packages have been renamed to *gluon-web-* +* The *gluon-next-node* package has been merged into the Gluon core and must not + be specified in *site.mk* anymore + +site.conf +^^^^^^^^^ + +* The *fastd_mesh_vpn* configuration section has been restructured to allow + sharing more options with tunneldigger. Instead of + + .. code-block:: lua + + fastd_mesh_vpn = { + mtu = 1280, + configurable = true, + methods = {'salsa2012+umac'}, + groups = { ... }, + bandwidth_limit = { ... }, + } + + the configuration must look like this now: + + .. code-block:: lua + + mesh_vpn = { + mtu = 1280, + fastd = { + configurable = true, + methods = {'salsa2012+umac'}, + groups = { ... }, + } + bandwidth_limit = { ... }, + } + +* The *opkg.openwrt* option has been renamed to *opkg.lede* + +i18n +^^^^ + +* The *escape* function has been removed as it was duplicating the existing + *pcdata* function. All uses of *escape* in i18n templates must be changed to + use *pcdata* instead. + +* The *gluon-config-mode:altitude-label* and *gluon-config-mode:altitude-help* + translation IDs have been added to allow adjusting the texts for different + kinds of altitudes that might be expected. + +* The optional *gluon-config-mode:novpn* label has been added, which will be + shown in place of *gluon-config-mode:pubkey* when mesh VPN is disabled. + +Internals +~~~~~~~~~ + +* The LuCI base libraries have been replaced by a stripped-down + version called "gluon-web" (`#1007 `_) + + Custom packages will need to be adjusted; in particular, all uses of *luci.model.uci* + need to be replaced with *simple-uci*. The Gluon documentation explains the most important + changes required to migrate from LuCI to gluon-web. + +* respondd now listens on ``ff05::2:1001`` in addition to ``ff02::2:1001`` for mesh-wide + operation (`#984 `_) + + Eventually, ``ff02::2:1001`` will be available for exchanging information + between neighbouring nodes only; map servers should be moved to ``ff05::2:1001``. + +* batman-adv has been updated to version 2017.1 + +* Directly running make commands in the *lede* directory is supported now. Consequently, + build targets like ``target/linux/clean`` and ``package/NAME/compile`` can't be used + in the Gluon repository root anymore. + + The command ``make config`` will set up the LEDE *.config* in the way a normal + Gluon build would, so it's possible to build individual packages for testing + and development afterwards. + +* Target definitions have been migrated from a Make-based format to a simpler + shell-based DSL + +* Gluon does not pass any custom variables into the LEDE build anymore, so things + like *GLUONDIR*, *GLUON_VERSION*, or *GLUON_SITEDIR* aren't available + to package Makefiles in Gluon 2017.1. + + Instead of ``$(GLUONDIR)/package.mk``, ``$(TOPDIR)/../package/gluon.mk`` must + be included in custom packages now. + +Known issues +~~~~~~~~~~~~ + +* Default TX power on many Ubiquiti devices is too high, correct offsets are unknown (`#94 `_) + + Reducing the TX power in the Advanced Settings is recommended. + +* The MAC address of the WAN interface is modified even when Mesh-on-WAN is disabled (`#496 `_) + + This may lead to issues in environments where a fixed MAC address is expected (like VMware when promicious mode is disallowed). + +* Inconsistent respondd API (`#522 `_) + + The current API is inconsistent and will be replaced eventually. The old API will still be supported for a while. diff --git a/docs/site-example/i18n/de.po b/docs/site-example/i18n/de.po index ce27c813..70f00a71 100644 --- a/docs/site-example/i18n/de.po +++ b/docs/site-example/i18n/de.po @@ -12,27 +12,49 @@ msgstr "" msgid "gluon-config-mode:welcome" msgstr "" -"Willkommen zum Einrichtungsassistenten für deinen neuen Entenhausener " +"Willkommen zum Einrichtungsassistenten für deinen neuen Alpha Centauri " "Freifunk-Knoten. Fülle das folgende Formular deinen Vorstellungen " "entsprechend aus und sende es ab." msgid "gluon-config-mode:pubkey" msgstr "" -"Dies ist der öffentliche Schlüssel deines Freifunk-Knotens. Erst nachdem " -"er auf den Servern des Entenhausener Freifunk-Projektes eingetragen wurde, " -"kann sich dein Knoten mit dem Entenhausener Mesh-VPN zu verbinden. Bitte " +"

Dies ist der öffentliche Schlüssel deines Freifunk-Knotens. Erst nachdem " +"er auf den Servern des Freifunk-Projektes auf Alpha Centauri eingetragen wurde, " +"kann sich dein Knoten mit dem Mesh-VPN dort verbinden. Bitte " "schicke dazu diesen Schlüssel und den Namen deines Knotens " -"(<%=hostname%>) an " -"keys@entenhausen.freifunk.net." +"(<%=pcdata(hostname)%>) an " +"&" +"body=<%= urlencode('# ' .. hostname .. '\n' .. pubkey) %>\">keys@alpha-centauri.freifunk.net." +"

" +"
" +" # <%= pcdata(hostname) %>" +"
" +"<%= pubkey %>" +"
" + +msgid "gluon-config-mode:novpn" +msgstr "" +"

Du hast ausgewählt, kein Mesh-VPN " +"zu nutzen. Dein Knoten kann also nur dann eine Verbindung zum Freifunk-Netz " +"aufbauen, wenn andere Freifunk-Router in WLAN-Reichweite sind." +"

" msgid "gluon-config-mode:reboot" msgstr "" -"

Dein Knoten startet gerade neu und wird anschließend versuchen, " -"sich mit anderen Freifunkknoten in seiner Nähe zu " +"

Dein Knoten <%= pcdata(hostname) %> startet gerade neu und wird " +"anschließend versuchen, sich mit anderen Freifunkknoten in seiner Nähe zu " "verbinden. Weitere Informationen zur " -"Entenhausener Freifunk-Community findest du auf " -"unserer Webseite.

" +"Alpha Centauri Freifunk-Community findest du auf " +"unserer Webseite.

" "

Um zu dieser Konfigurationsseite zurückzugelangen, drücke im normalen " "Betrieb für drei Sekunden den Reset-Button. Das Gerät wird dann im Config " "Mode neustarten.

" "

Viel Spaß mit deinem Knoten und der Erkundung von Freifunk!

" + +msgid "gluon-config-mode:altitude-label" +msgstr "Höhe" + +msgid "gluon-config-mode:altitude-help" +msgstr "" +"Die Höhenangabe ist optional und sollte nur gesetzt werden, wenn ein " +"exakter Wert bekannt ist." diff --git a/docs/site-example/i18n/en.po b/docs/site-example/i18n/en.po index dedc06e1..181ebce1 100644 --- a/docs/site-example/i18n/en.po +++ b/docs/site-example/i18n/en.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Project-Id-Version: PACKAGE VERSION\n" -"PO-Revision-Date: 2015-03-19 20:28+0100\n" -"Last-Translator: Matthias Schiffer \n" +"PO-Revision-Date: 2016-02-04 14:28+0100\n" +"Last-Translator: David Lutz \n" "Language-Team: English\n" "Language: en\n" "MIME-Version: 1.0\n" @@ -12,25 +12,44 @@ msgstr "" msgid "gluon-config-mode:welcome" msgstr "" -"Welcome the the setup wizard of your new Freifunk Duckburg node. " -"Please fill out the following form and transmit it." +"Welcome to the setup wizard of your new Freifunk Alpha Centauri node. " +"Please fill out the following form and submit it." msgid "gluon-config-mode:pubkey" msgstr "" -"This is your Freifunk node's public key. The node won't be able to " -"connect to the mesh VPN until the key has been registered on the Freifunk " -"Duckburg servers. " -"To register the key send it together with your node's name (<%=hostname%>) to " -"keys@entenhausen.freifunk.net." +"

This is your Freifunk node's public key. The node won't be able to " +"connect to the mesh VPN until the key has been registered on the Freifunk servers. " +"To register, send the key together with your node's name (<%=pcdata(hostname)%>) to " +"&" +"body=<%= urlencode('# ' .. hostname .. '\n' .. pubkey) %>\">keys@alpha-centauri.freifunk.net." +"

" +"
" +" # <%= pcdata(hostname) %>" +"
" +"<%= pubkey %>" +"
" +msgid "gluon-config-mode:novpn" +msgstr "" +"

You have selected not to use the mesh VPN. " +"Your node will only be able to connect to the Freifunk network if other nodes in reach " +"already have a connection.

" msgid "gluon-config-mode:reboot" msgstr "" -"

The node is currently rebooting and will try to connect to other " -"nearby Freifunk nodes after that. " -"Your can find lots of information on the Freifunk Duckburg community on " -"our homepage.

" +"

Your node <%= pcdata(hostname) %> is currently rebooting and will " +"try to connect to other nearby Freifunk nodes after that. For more " +"information about the Freifunk community on Alpha Centauri, have a look at " +"our homepage.

" "

To get back to this configuration interface, press the reset button for " "3 seconds during normal operation. The device will then reboot into config " "mode.

" -"

Have fun with your node and exploring the Freifunk network!

" +"

Have fun with your node and exploring of the Freifunk network!

" + +msgid "gluon-config-mode:altitude-label" +msgstr "Altitude" + +msgid "gluon-config-mode:altitude-help" +msgstr "" +"Specifying the altitude is optional and should only be done if a proper " +"value is known." diff --git a/docs/site-example/i18n/fr.po b/docs/site-example/i18n/fr.po new file mode 100644 index 00000000..bd4aef44 --- /dev/null +++ b/docs/site-example/i18n/fr.po @@ -0,0 +1,58 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2015-08-06 20:28+0100\n" +"Last-Translator: Tobias Bernot \n" +"Language-Team: French\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "gluon-config-mode:welcome" +msgstr "" +"Bienvenue dans l'assistant de configuration pour votre nouveau nœud " +"Freifunk. Remplissez le formulaire suivant en fonction de vos besoins " +"et enregistrez le" + +msgid "gluon-config-mode:pubkey" +msgstr "" +"

Ceci est la clé publique de votre nœud Freifunk. Seulment après que la clé soit " +"entrée sur les serveurs de votre groupe de Freifunk votre nœud pourra se connecter " +"sur les serveur Mesh-VPN de votre groupe Freifunk. Veuillez envoyer la clé avec le " +"nom de votre nœud " +"(<%=pcdata(hostname)%>) à " +"&" +"body=<%= urlencode('# ' .. hostname .. '\n' .. pubkey) %>\">keys@alpha-centauri.freifunk.net." +"

" +"
" +" # <%= pcdata(hostname) %>" +"
" +"<%= pubkey %>" +"
" + +msgid "gluon-config-mode:novpn" +msgstr "" +"

Vous avez choisi de ne pas utiliser " +"le réseau VPN. Votre nœud ne pourra se connecter au réseau Freifunk que si " +"d'autres nœuds à portée ont déjà une connexion.

" + +msgid "gluon-config-mode:reboot" +msgstr "" +"

Votre nœud <%= pcdata(hostname) %> es en train de redémarrer et " +"va ensuite éssayer de se connecter avec les autres nœuds du réseau Freifunk " +"Vous pourrez trouver plus d'informations sur votre groupe Freifunk sur la page " +" de ton groupe .

" +"

Pour retrouver cette page de configuration veuillier appuyez pendant le " +"fonctionement normal pendant 3 Secondes sur le bouton reset. L'appareil va ensuite " +"redémarer en mode configuration.

" +"

Profitez votre de nœud et amusez vous à découvrir le réseau Freifunk!

" + +msgid "gluon-config-mode:altitude-label" +msgstr "Hauteur" + +msgid "gluon-config-mode:altitude-help" +msgstr "" +"La altitude est optionelle et ne devrait que être ajoutée si la valeur " +"exacte est connue." diff --git a/docs/site-example/i18n/gluon-site.pot b/docs/site-example/i18n/gluon-site.pot index 670de410..7fe3293c 100644 --- a/docs/site-example/i18n/gluon-site.pot +++ b/docs/site-example/i18n/gluon-site.pot @@ -7,5 +7,14 @@ msgstr "" msgid "gluon-config-mode:pubkey" msgstr "" +msgid "gluon-config-mode:novpn" +msgstr "" + msgid "gluon-config-mode:reboot" msgstr "" + +msgid "gluon-config-mode:altitude-label" +msgstr "" + +msgid "gluon-config-mode:altitude-help" +msgstr "" diff --git a/docs/site-example/site.conf b/docs/site-example/site.conf index 6cffded8..4fa426ee 100644 --- a/docs/site-example/site.conf +++ b/docs/site-example/site.conf @@ -1,4 +1,4 @@ --- This is an example site configuration for Gluon v2015.1+ +-- This is an example site configuration for Gluon v2017.1+ -- -- Take a look at the documentation located at -- http://gluon.readthedocs.org/ for details. @@ -10,12 +10,14 @@ -- hostname_prefix = 'freifunk-', -- Name of the community. - site_name = 'Freifunk Entenhausen', + site_name = 'Freifunk Alpha Centauri', -- Shorthand of the community. site_code = 'ffxx', - -- Prefixes used within the mesh. Both are required. + -- Prefixes used within the mesh. + -- prefix6 is required, prefix4 can be omitted if next_node.ip4 + -- is not set. prefix4 = '10.xxx.0.0/20', prefix6 = 'fdxx:xxxx:xxxx::/64', @@ -35,42 +37,40 @@ -- Wireless channel. channel = 1, + -- List of supported wifi rates (optional) + -- Example removes 802.11b compatibility for better performance + supported_rates = {6000, 9000, 12000, 18000, 24000, 36000, 48000, 54000}, + + -- List of basic wifi rates (optional, required if supported_rates is set) + -- Example removes 802.11b compatibility for better performance + basic_rate = {6000, 9000, 18000, 36000, 54000}, + -- ESSID used for client network. - ssid = 'entenhausen.freifunk.net', + ap = { + ssid = 'alpha-centauri.freifunk.net', + -- disabled = true, (optional) + }, - -- Specifies the channel width in 802.11n and 802.11ac mode. - -- Possible values are: - -- HT20 (single 20MHz channel), - -- HT40- (2x 20MHz channels, secondary below) - -- HT40+ (2x 20MHz channels, secondary above) - htmode = 'HT20', - - -- Adjust these values! - mesh_ssid = 'xe:xx:xx:xx:xx:xx', -- ESSID used for mesh - mesh_bssid = 'xe:xx:xx:xx:xx:xx', -- BSSID used for mesh - - -- Bitrate used for multicast/broadcast packets. - mesh_mcast_rate = 12000, - - -- (optional) mesh VLAN on 802.11 ad-hoc interface (1-4095) - -- mesh_vlan = 14, - -- client_disabled = true, - -- mesh_disabled = false, + mesh = { + -- Adjust these values! + id = 'ffxx-mesh', + mcast_rate = 12000, + -- disabled = true, (optional) + }, }, -- Wireless configuration for 5 GHz interfaces. -- This should be equal to the 2.4 GHz variant, except - -- for channel and htmode. + -- for channel. wifi5 = { - ssid = 'entenhausen.freifunk.net', channel = 44, - htmode = 'HT20', - mesh_ssid = 'xx:xx:xx:xx:xx:xx', - mesh_bssid = 'xx:xx:xx:xx:xx:xx', - mesh_mcast_rate = 12000, - -- mesh_vlan = 14, - -- client_disabled = true, - -- mesh_disabled = false, + ap = { + ssid = 'alpha-centauri.freifunk.net', + }, + mesh = { + id = 'ffxx-mesh', + mcast_rate = 12000, + }, }, -- The next node feature allows clients to always reach the node it is @@ -84,47 +84,74 @@ mac = 'xe:xx:xx:xx:xx:xx', }, - -- Refer to http://fastd.readthedocs.org/en/latest/ to better understand - -- what these options do. - fastd_mesh_vpn = { - -- List of crypto-methods to use. - methods = {'salsa2012+umac'}, + -- Options specific to routing protocols (optional) + -- mesh = { + -- Options specific to the batman-adv routing protocol (optional) + -- batman_adv = { + -- Gateway selection class (optional) + -- The default class 20 is based on the link quality (TQ) only, + -- class 1 is calculated from both the TQ and the announced bandwidth + -- gw_sel_class = 1, + -- }, + -- }, + + mesh_vpn = { -- enabled = true, - -- configurable = true, + mtu = 1280, - mtu = 1426, - groups = { - backbone = { - -- Limit number of connected peers to reduce bandwidth. - limit = 2, + fastd = { + -- Refer to http://fastd.readthedocs.org/en/latest/ to better understand + -- what these options do. - -- List of peers. - peers = { - peer1 = { - key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', + -- List of crypto-methods to use. + methods = {'salsa2012+umac'}, + -- configurable = true, + -- syslog_level = 'warn', - -- 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'}, + groups = { + backbone = { + -- Limit number of connected peers to reduce bandwidth. + limit = 1, + + -- 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'}, + }, }, + + -- Optional: nested peer groups + -- groups = { + -- backbone_sub = { + -- ... + -- }, + -- ... + -- }, }, - - -- Optional: nested peer groups - -- groups = { - -- backbone_sub = { - -- ... - -- }, + -- Optional: additional peer groups, possibly with other limits + -- backbone2 = { -- ... -- }, }, - -- Optional: additional peer groups, possibly with other limits - -- backbone2 = { - -- ... - -- }, + }, + + bandwidth_limit = { + -- The bandwidth limit can be enabled by default here. + enabled = false, + + -- Default upload limit (kbit/s). + egress = 200, + + -- Default download limit (kbit/s). + ingress = 3000, }, }, @@ -167,24 +194,20 @@ -- }, -- }, - -- Bandwidth limiting - simple_tc = { - mesh_vpn = { - ifname = 'mesh-vpn', - - -- You may enable it by default here. - enabled = false, - - -- Default upload limit (kbit/s). - limit_egress = 200, - - -- Default download limit (kbit/s). - limit_ingress = 3000, - }, - }, - -- Skip setup mode (config mode) on first boot -- setup_mode = { -- skip = true, -- }, + + -- config_mode = { + -- Show/hide the altitude field + -- geo_location = { + -- show_altitude = false, + -- }, + -- define if the contact field is obligatory (optional) + -- owner = { + -- obligatory = true + -- }, + -- }, + } diff --git a/docs/site-example/site.mk b/docs/site-example/site.mk index 6a16eb53..6ec1172a 100644 --- a/docs/site-example/site.mk +++ b/docs/site-example/site.mk @@ -1,13 +1,11 @@ ## gluon site.mk makefile example ## GLUON_SITE_PACKAGES -# specify gluon/openwrt packages to include here -# The gluon-mesh-batman-adv-* package must come first because of the dependency resolution +# specify Gluon/LEDE packages to include here GLUON_SITE_PACKAGES := \ - gluon-mesh-batman-adv-15 \ gluon-alfred \ - gluon-announced \ + gluon-respondd \ gluon-autoupdater \ gluon-config-mode-autoupdater \ gluon-config-mode-contact-info \ @@ -17,17 +15,16 @@ GLUON_SITE_PACKAGES := \ gluon-config-mode-mesh-vpn \ gluon-ebtables-filter-multicast \ gluon-ebtables-filter-ra-dhcp \ - gluon-luci-admin \ - gluon-luci-autoupdater \ - gluon-luci-portconfig \ - gluon-luci-wifi-config \ - gluon-next-node \ + gluon-web-admin \ + gluon-web-autoupdater \ + gluon-web-network \ + gluon-web-wifi-config \ + gluon-mesh-batman-adv-15 \ gluon-mesh-vpn-fastd \ gluon-radvd \ gluon-setup-mode \ gluon-status-page \ haveged \ - iptables \ iwinfo ## DEFAULT_GLUON_RELEASE @@ -38,6 +35,7 @@ GLUON_SITE_PACKAGES := \ DEFAULT_GLUON_RELEASE := 0.6+exp$(shell date '+%Y%m%d') +# Variables set with ?= can be overwritten from the command line ## GLUON_RELEASE # call make with custom GLUON_RELEASE flag, to use your own release version scheme. @@ -46,11 +44,13 @@ DEFAULT_GLUON_RELEASE := 0.6+exp$(shell date '+%Y%m%d') # would generate images named like this: # gluon-ff%site_code%-23.42+5-%router_model%.bin -# Allow overriding the release number from the command line GLUON_RELEASE ?= $(DEFAULT_GLUON_RELEASE) # Default priority for updates. GLUON_PRIORITY ?= 0 +# Region code required for some images; supported values: us eu +GLUON_REGION ?= eu + # Languages to include GLUON_LANGS ?= en de diff --git a/docs/user/faq.rst b/docs/user/faq.rst index 9da15270..40a4e521 100644 --- a/docs/user/faq.rst +++ b/docs/user/faq.rst @@ -1,3 +1,17 @@ Frequently Asked Questions ========================== +.. _faq-dns: + +DNS does not work on the nodes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Gluon nodes will ignore the DNS server on the WAN port for everything except +the mesh VPN, which can lead to confusion. + +All normal services on the nodes exclusively use the DNS server on the mesh +interface. This DNS server must be announced in router advertisements (using +*radvd* or a similar software) from one or more central servers in meshes based +on *batman-adv*. If your mesh does not have global IPv6 connectivity, you can setup +your *radvd* not to announce a default route by setting the *default lifetime* to 0; +in this case, the *radvd* is only used to announce the DNS server. diff --git a/docs/user/getting_started.rst b/docs/user/getting_started.rst index 885a3887..1330bd91 100644 --- a/docs/user/getting_started.rst +++ b/docs/user/getting_started.rst @@ -4,18 +4,20 @@ Getting Started Selecting the right version --------------------------- -Gluon's releases are managed using `Git tags`_. If you're a community getting +Gluon's releases are managed using `Git tags`_. If you are just getting started with Gluon we recommend to use the latest stable release of Gluon. Take a look at the `list of gluon releases`_ and notice the latest release, -e.g. *v2014.3*. +e.g. *v2017.1*. Always get Gluon using git and don't try to download it +as a Zip archive as the archive will be missing version information. -Please keep in mind that a matching site configuration for your community -is required. Due to new features being added (or sometimes being removed) -the format of the site configuration changes slightly between releases. +Please keep in mind that there is no "default Gluon" build; a site configuration +is required to adjust Gluon to your needs. Due to new features being added (or +sometimes being removed) the format of the site configuration changes slightly +between releases. Please refer to our release notes for instructions to update +an old site configuration to a newer release of Gluon. -Recent releases (starting with *v2014.3.1*) will come with an example -configuration located in *docs/site-example/*. +An example configuration can be found in the Gluon repository at *docs/site-example/*. .. _Git tags: http://git-scm.com/book/en/Git-Basics-Tagging .. _list of gluon releases: https://github.com/freifunk-gluon/gluon/releases @@ -27,18 +29,21 @@ freshly installed Debian Wheezy system the following packages are required: * `git` (to get Gluon and other dependencies) * `subversion` +* `python` (Python 3 doesn't work) * `build-essential` * `gawk` * `unzip` * `libncurses-dev` (actually `libncurses5-dev`) * `libz-dev` (actually `zlib1g-dev`) +* `libssl-dev` +* `wget` Building the images ------------------- To build Gluon, first check out the repository. Replace *RELEASE* with the -version you'd like to checkout, e.g. *v2015.1*. +version you'd like to checkout, e.g. *v2017.1*. :: @@ -47,88 +52,157 @@ version you'd like to checkout, e.g. *v2015.1*. This command will create a directory named *gluon/*. It might also tell a scary message about being in a *detached state*. **Don't panic!** Everything's fine. -Now, enter the freshly created directory: - -:: +Now, enter the freshly created directory:: cd gluon -It's time to add (or create) your site configuration. -So let's create the directory *site/*: +It's time to add (or create) your site configuration. If you already +have a site repository, just clone it:: -:: + git clone https://github.com/freifunk-alpha-centauri/site-ffac.git site + +If you want to build a new site, create a new git repository *site/*:: mkdir site cd site + git init -Copy *site.conf*, *site.mk* and *i18n* from *docs/site-example*: - -:: +Copy *site.conf*, *site.mk* and *i18n* from *docs/site-example*:: cp ../docs/site-example/site.conf . cp ../docs/site-example/site.mk . cp -r ../docs/site-example/i18n . -Edit these files to match your community, then go back to the top-level Gluon -directory and build Gluon: +Edit these files as you see fit and commit them into the site repository. +Extensive documentation about the site configuration can be found at: +:doc:`site`. The +site directory should always be a git repository by itself; committing site-specific files +to the Gluon main repository should be avoided, as it will make updates more complicated. -:: +Next go back to the top-level Gluon directory and build Gluon:: cd .. make update # Get other repositories used by Gluon make GLUON_TARGET=ar71xx-generic # Build Gluon -When calling make, the OpenWrt build environment is prepared/updated. In case of errors read the messages carefully and try to fix the stated issues (e.g. install tools not available yet). -``ar71xx-generic`` is the most common target and will generated images for most of the supported hardware. +``ar71xx-generic`` is the most common target and will generate images for most of the supported hardware. To see a complete list of supported targets, call ``make`` without setting ``GLUON_TARGET``. -The built images can be found in the directory `images`. Of these, the factory -images are to be used when flashing from the original firmware a device came with, -and sysupgrade is to upgrade from other versions of Gluon or any other OpenWRT-based -system. - You should reserve about 10GB of disk space for each `GLUON_TARGET`. -There are two levels of `make clean`: +The built images can be found in the directory `output/images`. Of these, the `factory` +images are to be used when flashing from the original firmware a device came with, +and `sysupgrade` is to upgrade from other versions of Gluon or any other OpenWrt/LEDE-based +system. -:: +**Note:** The images for some models are identical; to save disk space, symlinks are generated instead +of multiple copies of the same image. If your webserver's configuration prohibits following +symlinks, you can use the following command to resolve these links while copying the images:: + + cp -rL output/images /var/www + +Cleaning the build tree +....................... + +There are two levels of `make clean`:: make clean GLUON_TARGET=ar71xx-generic -will ensure all packages are rebuilt for a single target; this is what you normally want to do after an update. +will ensure all packages are rebuilt for a single target. This normally not +necessary, but may fix certain kinds of build failures. :: make dirclean -will clean the entire tree, so the toolchain will be rebuilt as well, which is -not necessary in most cases, and will take a while. +will clean the entire tree, so the toolchain will be rebuilt as well, which will take a while. +opkg repositories +----------------- -Environment variables ---------------------- +Gluon is mostly compatible with LEDE, so the normal LEDE package repositories +can be used for Gluon as well. -Gluon's build process can be controlled by various environment variables. +This is not true for kernel modules; the Gluon kernel is incompatible with the +kernel of the default LEDE images. Therefore, Gluon will not only generate images, +but also an opkg repository containing all core packages provided by LEDE, +including modules for the kernel of the generated images. -GLUON_SITEDIR - Path to the site configuration. Defaults to ``site/``. +Signing keys +............ -GLUON_IMAGEDIR - Path where images will be stored. Defaults to ``images/``. +Gluon does not support HTTPS for downloading packages; fortunately, opkg deploys +public-key cryptography to ensure package integrity. + +The Gluon images will contain public keys from two sources: the official LEDE keyring +(to allow installing userspace packages) and a Gluon-specific key (which is used +to sign the generated package repository). + +LEDE will handle the generation and handling of the keys itself. +When making firmware releases based on Gluon, it might make sense to store +the keypair, so updating the module repository later is possible. + +.. _getting-started-make-variables: + +Make variables +-------------- + +Gluon's build process can be controlled by various variables. They can +usually be set on the command line or in ``site.mk``. + +Common variables +................ + +GLUON_ATH10K_MESH + While Gluon does support some hardware with ath10k-based 5GHz WLAN, these WLAN adapters don't work + well for meshing at the moment, so building images for these models is disabled by default. In addition, + ath10k can't support IBSS and 11s meshing in the same image due to WLAN firmware restrictions. + + Setting GLUON_ATH10K_MESH to ``11s`` or ``ibss`` will enable generation of images for ath10k devices + and install the firmware for the corresponding WLAN mode. + +GLUON_BRANCH + Sets the default branch of the autoupdater. If unset, the autoupdater is disabled + by default. For the ``make manifest`` command, GLUON_BRANCH defines the branch to + generate a manifest for. + +GLUON_LANGS + Space-separated list of languages to include for the config mode/advanced settings. Defaults to ``en``. + ``en`` should always be included, other supported languages are ``de`` and ``fr``. + +GLUON_PRIORITY + Defines the priority of an automatic update in ``make manifest``. See :doc:`../features/autoupdater` for + a detailed description of this value. + +GLUON_REGION + Some devices (at the moment the TP-Link Archer C7) contain a region code that restricts + firmware installations. Set GLUON_REGION to ``eu`` or ``us`` to make the resulting + images installable from the respective stock firmwares. + +GLUON_RELEASE + Firmware release number: This string is displayed in the config mode, announced + via respondd/alfred and used by the autoupdater to decide if a newer version + is available. + +GLUON_TARGET + Target architecture to build. + +Special variables +................. GLUON_BUILDDIR - Working directory during build. Defaults to ``build/``. + Working directory during build. Defaults to ``build``. +GLUON_IMAGEDIR + Path where images will be stored. Defaults to ``$(GLUON_OUTPUTDIR)/images``. -So all in all, to update and rebuild a Gluon build tree, the following commands should be used (repeat the -``make clean`` and ``make`` for all targets you want to build): +GLUON_PACKAGEDIR + Path where the opkg package repository will be stored. Defaults to ``$(GLUON_OUTPUTDIR)/packages``. -:: +GLUON_OUTPUTDIR + Path where output files will be stored. Defaults to ``output``. - git pull - (cd site && git pull) - make update - make clean GLUON_TARGET=ar71xx-generic - make GLUON_TARGET=ar71xx-generic +GLUON_SITEDIR + Path to the site configuration. Defaults to ``site``. diff --git a/docs/user/site.rst b/docs/user/site.rst index bf6c1650..011f25d9 100644 --- a/docs/user/site.rst +++ b/docs/user/site.rst @@ -1,5 +1,5 @@ -Site -==== +Site configuration +================== The ``site`` consists of the files ``site.conf`` and ``site.mk``. In the first community based values are defined, which both are processed @@ -21,12 +21,14 @@ site_code The code of your community. It is good practice to use the TLD of your community here. -prefix4 +prefix4 \: optional The IPv4 Subnet of your community mesh network in CIDR notation, e.g. :: prefix4 = '10.111.111.0/18' + Required if ``next_node.ip4`` is set. + prefix6 The IPv6 subnet of your community mesh network, e.g. :: @@ -44,48 +46,105 @@ ntp_server List of NTP servers available in your community or used by your community, e.g.: :: - ntp_servers = {'1.ntp.services.ffeh','2.tnp.services.ffeh'} + ntp_servers = {'1.ntp.services.ffac','2.ntp.services.ffac'} + + This NTP servers must be reachable via IPv6 from the nodes. If you don't want to set an IPv6 address + explicitly, but use a hostname (which is recommended), see also the :ref:`FAQ `. + +opkg \: optional + ``opkg`` package manager configuration. + + There are two optional fields in the ``opkg`` section: + + - ``lede`` overrides the default LEDE repository URL. The default URL would + correspond to ``http://downloads.lede-project.org/snapshots/packages/%A`` + and usually doesn't need to be changed when nodes are expected to have IPv6 + internet connectivity. + - ``extra`` specifies a table of additional repositories (with arbitrary keys) -opkg_repo : optional - Overwrite the default ``opkg`` repository server, e.g.: :: - opkg_repo = 'http://opkg.services.ffeh/attitude_adjustment/12.09/%S/packages' + opkg = { + lede = 'http://opkg.services.ffac/lede/snapshots/packages/%A', + extra = { + gluon = 'http://opkg.services.ffac/modules/gluon-%GS-%GR/%S', + }, + } - The `%S` is a variable, which is replaced with the platform of an device - during the build process. + There are various patterns which can be used in the URLs: -regdom + - ``%n`` is replaced by the LEDE version codename + - ``%v`` is replaced by the LEDE version number (e.g. "17.01") + - ``%S`` is replaced by the target board (e.g. "ar71xx/generic") + - ``%A`` is replaced by the target architecture (e.g. "mips_24kc") + - ``%GS`` is replaced by the Gluon site code (as specified in ``site.conf``) + - ``%GV`` is replaced by the Gluon version + - ``%GR`` is replaced by the Gluon release (as specified in ``site.mk``) + +regdom \: optional The wireless regulatory domain responsible for your area, e.g.: :: regdom = 'DE' -wifi24 - WLAN Configuration of your community in the 2.4Ghz radio. Consisting - of ``ssid`` of your client network, the ``channel`` your community is using, - ``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. 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.: + Setting ``regdom`` is mandatory if ``wifi24`` or ``wifi5`` is defined. + +wifi24 \: optional + WLAN configuration for 2.4 GHz devices. + ``channel`` must be set to a valid wireless channel for your radio. + + There are currently three interface types available. You many choose to + configure any subset of them: + + - ``ap`` creates a master interface where clients may connect + - ``mesh`` creates an 802.11s mesh interface with forwarding disabled + - ``ibss`` creates an ad-hoc interface + + Each interface may be disabled by setting ``disabled`` to ``true``. + This will only affect new installations. + Upgrades will not change the disabled state. + + Additionally it is possible to configure the ``supported_rates`` and ``basic_rate`` + of each radio. Both are optional, by default hostapd/driver dictate the rates. + If ``supported_rates`` is set, ``basic_rate`` is required, because ``basic_rate`` + has to be a subset of ``supported_rates``. + The example below disables 802.11b rates. + + ``ap`` requires a single parameter, a string, named ``ssid`` which sets the + interface's ESSID. + + ``mesh`` requires a single parameter, a string, named ``id`` which sets the mesh id. + + ``ibss`` requires two parametersr: ``ssid`` (a string) and ``bssid`` (a MAC). + An optional parameter ``vlan`` (integer) is supported. + + Both ``mesh`` and ``ibss`` accept an optional ``mcast_rate`` (kbit/s) parameter for + setting the multicast bitrate. Increasing the default value of 1000 to something + like 12000 is recommended. :: wifi24 = { - ssid = 'entenhausen.freifunk.net', channel = 11, - htmode = 'HT40-', - mesh_ssid = 'ff:ff:ff:ee:ba:be', - mesh_bssid = 'ff:ff:ff:ee:ba:be', - mesh_mcast_rate = 12000, + supported_rates = {6000, 9000, 12000, 18000, 24000, 36000, 48000, 54000}, + basic_rate = {6000, 9000, 18000, 36000, 54000}, + ap = { + ssid = 'alpha-centauri.freifunk.net', + }, + mesh = { + id = 'alpha-centauri-mesh', + mcast_rate = 12000, + }, + ibss = { + ssid = 'ff:ff:ff:ee:ba:be', + bssid = 'ff:ff:ff:ee:ba:be', + mcast_rate = 12000, + }, }, -wifi5 +wifi5 \: optional Same as `wifi24` but for the 5Ghz radio. -next_node : package +next_node \: package Configuration of the local node feature of Gluon :: @@ -95,61 +154,156 @@ next_node : package mac = 'ca:ff:ee:ba:be:00' } + The IPv4 next-node address is optional. -fastd_mesh_vpn - Remote server setup for the fastd-based mesh VPN. +mesh \: optional + Options specific to routing protocols. - The `enabled` option can be set to true to enable the VPN by default. + At the moment, only the ``batman_adv`` routing protocol has such options: - 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. + The optional value ``gw_sel_class`` sets the gateway selection class. The default + class 20 is based on the link quality (TQ) only, class 1 is calculated from + both the TQ and the announced bandwidth. + :: + + mesh = { + batman_adv = { + gw_sel_class = 1, + }, + } + + +mesh_vpn + Remote server setup for the mesh VPN. + + The `enabled` option can be set to true to enable the VPN by default. `mtu` + defines the MTU of the VPN interface. + + The `fastd` section configures settings specific to the *fastd* VPN + implementation. + + If `configurable` is set to `false` or unset, the method list will be replaced on updates + with the list from the site configuration. Setting `configurable` to `true` will allow the user to + add the method ``null`` to the beginning of the method list or remove ``null`` from it, + and make this change survive updates. Setting `configurable` is necessary for the + package `gluon-web-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. + + You can set syslog_level from verbose (default) to warn to reduce syslog output. + + The `tunneldigger` section is used to define the *tunneldigger* broker list. + + **Note:** It doesn't make sense to include both `fastd` and `tunneldigger` + sections in the same configuration file, as only one of the packages *gluon-mesh-vpn-fastd* + and *gluon-mesh-vpn-tunneldigger* should be installed with the current + implementation. + :: - fastd_mesh_vpn = { - methods = {'salsa2012+umac'}, - -- enabled = true, - -- configurable = true, - mtu = 1426, - groups = { - backbone = { - limit = 2, - peers = { - peer1 = { - key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', - remotes = {'ipv4 "vpn1.entenhausen.freifunk.net" port 10000'}, + mesh_vpn = { + -- enabled = true, + mtu = 1280, + + fastd = { + methods = {'salsa2012+umac'}, + -- configurable = true, + -- syslog_level = 'warn', + groups = { + backbone = { + -- Limit number of connected peers from this group + limit = 1, + peers = { + peer1 = { + key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', + -- Having multiple domains prevents SPOF in freifunk.net + remotes = { + 'ipv4 "vpn1.alpha-centauri.freifunk.net" port 10000', + 'ipv4 "vpn1.alpha-centauri-freifunk.de" port 10000', + }, + }, + peer2 = { + key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', + -- You can also omit the ipv4 to allow both connection via ipv4 and ipv6 + remotes = {'"vpn2.alpha-centauri.freifunk.net" port 10000'}, + }, + peer3 = { + key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', + -- In addition to domains you can also add ip addresses, which provides + -- resilience in case of dns outages + remotes = { + '"vpn3.alpha-centauri.freifunk.net" port 10000', + '[2001:db8::3:1]:10000', + '192.0.2.3:10000', + }, + }, }, - } - } - } + -- Optional: nested peer groups + -- groups = { + -- lowend_backbone = { + -- limit = 1, + -- peers = ... + -- }, + -- }, + }, + -- Optional: additional peer groups, possibly with other limits + -- peertopeer = { + -- limit = 10, + -- peers = { ... }, + -- }, + }, + }, + + tunneldigger = { + brokers = {'vpn1.alpha-centauri.freifunk.net'} + }, + + bandwidth_limit = { + -- The bandwidth limit can be enabled by default here. + enabled = false, + + -- Default upload limit (kbit/s). + egress = 200, + + -- Default download limit (kbit/s). + ingress = 3000, + }, } -mesh_on_wan : optional +mesh_on_wan \: optional Enables the mesh on the WAN port (``true`` or ``false``). + :: -mesh_on_lan : optional + mesh_on_wan = true, + +mesh_on_lan \: optional Enables the mesh on the LAN port (``true`` or ``false``). + :: + + mesh_on_lan = true, -autoupdater : package +poe_passthrough \: optional + Enable PoE passthrough by default on hardware with such a feature. + +autoupdater \: package Configuration for the autoupdater feature of Gluon. + + The mirrors are checked in random order until the manifest could be downloaded + successfully or all mirrors have been tried. :: autoupdater = { - branch = 'experimental', + branch = 'stable', branches = { stable = { name = 'stable', mirrors = { 'http://[fdca:ffee:babe:1::fec1]/firmware/stable/sysupgrade/', - 'http://[fdca:ffee:babe:1::fec2]/firmware/stable/sysupgrade/', + 'http://autoupdate.alpha-centauri.freifunk.net/firmware/stable/sysupgrade/', }, - probability = 0.08, + -- Number of good signatures required good_signatures = 2, pubkeys = { 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', -- someguy @@ -159,18 +313,21 @@ autoupdater : package } } -roles : optional - Optional role definitions. With this nodes will announce their role inside the mesh. - In the backend this adds the facility to distinguish between normal, backbone and - service nodes or even gateways (if they advertise the role, also). It is up to + All configured mirrors must be reachable from the nodes via IPv6. If you don't want to set an IPv6 address + explicitly, but use a hostname (which is recommended), see also the :ref:`FAQ `. + +roles \: optional + Optional role definitions. Nodes will announce their role inside the mesh. + This will allow in the backend to distinguish between normal, backbone and + service nodes or even gateways (if they advertise that role). It is up to the community which roles to define. See the section below as an example. ``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 package ``gluon-web-node-role`` to ``site.mk``. - The strings to display in the LuCI interface can be configured per language in the + The strings to display in the web interface are 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``. + ``gluon-web-node-role:role:node`` and ``gluon-web-node-role:role:backbone``. :: roles = { @@ -183,20 +340,7 @@ roles : optional }, }, -simple_tc : package - Uplink traffic control, ingress and egress values are specified in kbit/s. - :: - - simple_tc = { - mesh_vpn = { - ifname = 'mesh-vpn', - enabled = false, - limit_egress = 200, - limit_ingress = 3000, - }, - }, - -setup_mode : package +setup_mode \: package Allows skipping setup mode (config mode) at first boot when attribute ``skip`` is set to ``true``. This is optional and may be left out. :: @@ -205,16 +349,16 @@ setup_mode : package skip = true, }, -legacy : package +legacy \: package Configuration for the legacy upgrade path. This is only required in communities upgrading from Lübeck's LFF-0.3.x. :: legacy = { version_files = {'/etc/.freifunk_version_keep', '/etc/.eff_version_keep'}, - old_files = {'/etc/config/config_mode', '/etc/config/ffeh', '/etc/config/freifunk'}, - config_mode_configs = {'config_mode', 'ffeh', 'freifunk'}, - fastd_configs = {'ffeh_mesh_vpn', 'mesh_vpn'}, + old_files = {'/etc/config/config_mode', '/etc/config/ffac', '/etc/config/freifunk'}, + config_mode_configs = {'config_mode', 'ffac', 'freifunk'}, + fastd_configs = {'ffac_mesh_vpn', 'mesh_vpn'}, mesh_ifname = 'freifunk', tc_configs = {'ffki', 'freifunk'}, wifi_names = {'wifi_freifunk', 'wifi_freifunk5', 'wifi_mesh', 'wifi_mesh5'}, @@ -227,8 +371,8 @@ The ``site.mk`` is a Makefile which should define constants involved in the build process of Gluon. GLUON_SITE_PACKAGES - Defines a list of packages which should installed additional - to the ``gluon_core`` package. + Defines a list of packages which should be installed additionally + to the ``gluon-core`` package. GLUON_RELEASE The current release version Gluon should use. @@ -237,8 +381,12 @@ GLUON_PRIORITY The default priority for the generated manifests (see the autoupdater documentation for more information). +GLUON_REGION + Region code to build into images where necessary. Valid values are the empty string, + ``us`` and ``eu``. + GLUON_LANGS - List of languages (as two-letter-codes) to include for the web interface. Should always contain + List of languages (as two-letter-codes) to be included in the web interface. Should always contain ``en``. .. _site-config-mode-texts: @@ -255,14 +403,67 @@ gluon-config-mode:welcome gluon-config-mode:pubkey Information about the public VPN key on the reboot page. +gluon-config-mode:novpn + Information shown on the reboot page, if the mesh VPN was not selected. + +gluon-config-mode:altitude-label + Label for the ``altitude`` field + +gluon-config-mode:altitude-help + Description for the usage of the ``altitude`` field + gluon-config-mode:reboot - General information about the reboot page. + General information shown on the reboot page. There is a POT file in the site example directory which can be used to create templates for the language files. The command ``msginit -l en -i ../../docs/site-example/i18n/gluon-site.pot`` can be used from the ``i18n`` directory to create an initial PO file called ``en.po`` if the ``gettext`` utilities are installed. +.. note:: + + An empty ``msgstr``, as is the default after running ``msginit``, leads to + the ``msgid`` being printed as-is. It does *not* hide the whole text, as + might be expected. + + Depending on the context, you might be able to use comments like + ```` as translations to effectively hide the text. + +Site modules +------------ + +The file ``modules`` in the site repository is completely optional and can be used +to supply additional package feeds from which packages are built. The git repositories +specified here are retrieved in addition to the default feeds when ``make update`` +it called. + +This file's format is very similar to the toplevel ``modules`` file of the Gluon +tree, with the important different that the list of feeds must be assigned to +the variable ``GLUON_SITE_FEEDS``. Multiple feed names must be separated by spaces, +for example:: + + GLUON_SITE_FEEDS='foo bar' + +The feed names may only contain alphanumerical characters, underscores and slashes. +For each of the feeds, the following variables are used to specify how to update +the feed: + +PACKAGES_${feed}_REPO + The URL of the git repository to clone (usually ``git://`` or ``http(s)://``) + +PACKAGES_${feed}_COMMIT + The commit ID of the repository to use + +PACKAGES_${feed}_BRANCH + Optional: The branch of the repository the given commit ID can be found in. + Defaults to the default branch of the repository (usually ``master``) + +These variables are always all uppercase, so for an entry ``foo`` in GLUON_SITE_FEEDS, +the corresponding configuration variables would be ``PACKAGES_FOO_REPO``, +``PACKAGES_FOO_COMMIT`` and ``PACKAGES_FOO_BRANCH``. Slashes in feed names are +replaced by underscores to get valid shell variable identifiers. + + Examples -------- @@ -301,22 +502,37 @@ site-repos in the wild This is a non-exhaustive list of site-repos from various communities: +* `site-ffa `_ (Altdorf, Landshut & Umgebung) +* `site-ffac `_ (Regio Aachen) * `site-ffbs `_ (Braunschweig) * `site-ffhb `_ (Bremen) * `site-ffda `_ (Darmstadt) +* `site-ffeh `_ (Ehingen) +* `site-fffl `_ (Flensburg) * `site-ffgoe `_ (Göttingen) +* `site-ffgt-rhw `_ (Guetersloh) * `site-ffhh `_ (Hamburg) +* `site-ffho `_ (Hochstift) * `site-ffhgw `_ (Greifswald) -* `site-ffhl `_ (Lübeck) -* `site-ffmd `_ (Magdeburg) -* `site-ffmwu `_ (Mainz, Wiesbaden & Umgebung) -* `site-ffmyk `_ (Mayen-Koblenz) -* `site-ffm `_ (München) -* `site-ffms `_ (Münster) -* `site-ffnw `_ (Nordwest) -* `site-ffpb `_ (Paderborn) * `site-ffka `_ (Karlsruhe) -* `site-ffrl `_ (Rheinland) -* `site-ffrg `_ (Ruhrgebiet) +* `site-ffki `_ (Kiel) +* `site-fflz `_ (Lausitz) +* `site-ffl `_ (Leipzig) +* `site-ffhl `_ (Lübeck) +* `site-fflg `_ (Lüneburg) +* `site-ffmd `_ (Magdeburg) +* `site-ffmwu `_ (Mainz, Wiesbaden & Umgebung) +* `site-ffmyk `_ (Mayen-Koblenz) +* `site-ffmo `_ (Moers) +* `site-ffmg `_ (Mönchengladbach) +* `site-ffm `_ (München) +* `site-ffhmue `_ (Münden) +* `site-ffms `_ (Münsterland) +* `site-neuss `_ (Neuss) +* `site-ffniers `_ (Niersufer) +* `site-ffnw `_ (Nordwest) +* `site-ffrgb `_ (Regensburg) +* `site-ffrn `_ (Rhein-Neckar) +* `site-ffruhr `_ (Ruhrgebiet, Multi-Communities) * `site-ffs `_ (Stuttgart) * `site-fftr `_ (Trier) diff --git a/docs/user/x86.rst b/docs/user/x86.rst index b985d6fc..a65edfcc 100644 --- a/docs/user/x86.rst +++ b/docs/user/x86.rst @@ -2,12 +2,12 @@ x86 support =========== Gluon can run on normal x86 systems, for example virtual machines -and VPN boxes. There is no WLAN support on x86 though. +and VPN boxes. By default, there is no WLAN support on x86 though. Targets ^^^^^^^ -There are two targets for x86 images: +The following targets for x86 images exist: `x86-generic` Generic x86 support with many different ethernet drivers; should run on @@ -22,8 +22,8 @@ There are two targets for x86 images: These images only differ in the image file format, the content is the same. Therefore there is only a single `x86-generic` sysupgrade image instead of three. - Please note that the `x86-generic` image doesn't include VirtIO support, so another virtual NIC - like `pcnet32` must be chosen when using VirtualBox. +`x86-geode` + x86 image for Geode CPUs. -`x86-kvm` - The `x86-kvm` image uses VirtIO as its harddisk and network driver. +`x86-64` + 64bit version of `x86-generic`. diff --git a/include/Makefile.target b/include/Makefile.target deleted file mode 100644 index a78a4044..00000000 --- a/include/Makefile.target +++ /dev/null @@ -1,19 +0,0 @@ -# code adjusted from openwrt/include/kernel-defaults.mk - -override define Kernel/Configure - $(LINUX_CONF_CMD) > $(LINUX_DIR)/.config.target -# copy CONFIG_KERNEL_* settings over to .config.target - awk '/^(#[[:space:]]+)?CONFIG_KERNEL/{sub("CONFIG_KERNEL_","CONFIG_");print}' $(BOARD_BUILDDIR)/config-allmods >> $(LINUX_DIR)/.config.target - echo "# CONFIG_KALLSYMS_EXTRA_PASS is not set" >> $(LINUX_DIR)/.config.target - echo "# CONFIG_KALLSYMS_ALL is not set" >> $(LINUX_DIR)/.config.target - echo "# CONFIG_KALLSYMS_UNCOMPRESSED is not set" >> $(LINUX_DIR)/.config.target - $(SCRIPT_DIR)/metadata.pl kconfig $(TMP_DIR)/.packageinfo $(BOARD_BUILDDIR)/config-allmods $(KERNEL_PATCHVER) > $(LINUX_DIR)/.config.override - $(SCRIPT_DIR)/kconfig.pl 'm+' '+' $(LINUX_DIR)/.config.target /dev/null $(LINUX_DIR)/.config.override > $(LINUX_DIR)/.config - $(call Kernel/SetNoInitramfs) - rm -rf $(KERNEL_BUILD_DIR)/modules - $(_SINGLE) [ -d $(LINUX_DIR)/user_headers ] || $(MAKE) $(KERNEL_MAKEOPTS) INSTALL_HDR_PATH=$(LINUX_DIR)/user_headers headers_install - cp $(GLUONDIR)/targets/$(GLUON_TARGET)/vermagic $(LINUX_DIR)/.vermagic -endef - -# The Makefile included here is $(TOPDIR)/target/linux/$(BOARD)/Makefile -include Makefile diff --git a/include/config b/include/config deleted file mode 100644 index ac1a4f8d..00000000 --- a/include/config +++ /dev/null @@ -1,22 +0,0 @@ -CONFIG_IMAGEOPT=y -# CONFIG_PER_FEED_REPO is not set - -CONFIG_DEVEL=y - -CONFIG_BUSYBOX_CUSTOM=y -CONFIG_BUSYBOX_CONFIG_SHA512SUM=y -# CONFIG_BUSYBOX_CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set -CONFIG_BUSYBOX_CONFIG_IP=y -CONFIG_BUSYBOX_CONFIG_FEATURE_IP_ADDRESS=y -CONFIG_BUSYBOX_CONFIG_FEATURE_IP_LINK=y -CONFIG_BUSYBOX_CONFIG_FEATURE_IP_ROUTE=y -CONFIG_BUSYBOX_CONFIG_FEATURE_IP_TUNNEL=y -CONFIG_BUSYBOX_CONFIG_FEATURE_IP_RULE=y -CONFIG_BUSYBOX_CONFIG_FEATURE_IP_SHORT_FORMS=y -CONFIG_BUSYBOX_CONFIG_FEATURE_WGET_TIMEOUT=y - -CONFIG_ATH_USER_REGD=y -CONFIG_PACKAGE_ATH_DEBUG=y -CONFIG_ATH10K_CT_COMMUNITY_FW=y - -CONFIG_LUCI_SRCDIET=y diff --git a/include/gluon.mk b/include/gluon.mk deleted file mode 100644 index fdccef20..00000000 --- a/include/gluon.mk +++ /dev/null @@ -1,72 +0,0 @@ -ifneq ($(__gluon_inc),1) -__gluon_inc=1 - -GLUON_SITEDIR ?= $(GLUONDIR)/site -GLUON_IMAGEDIR ?= $(GLUONDIR)/images -GLUON_BUILDDIR ?= $(GLUONDIR)/build - -GLUON_ORIGOPENWRTDIR := $(GLUONDIR)/openwrt -GLUON_SITE_CONFIG := $(GLUON_SITEDIR)/site.conf - -export GLUONDIR GLUON_SITEDIR GLUON_SITE_CONFIG GLUON_IMAGEDIR GLUON_BUILDDIR - - -BOARD_BUILDDIR = $(GLUON_BUILDDIR)/$(GLUON_TARGET) -BOARD_KDIR = $(BOARD_BUILDDIR)/kernel - -export BOARD_BUILDDIR - -GLUON_OPENWRTDIR = $(BOARD_BUILDDIR)/openwrt - - -$(GLUON_SITEDIR)/site.mk: - $(error There was no site configuration found. Please check out a site configuration to $(GLUON_SITEDIR)) - --include $(GLUON_SITEDIR)/site.mk - - -GLUON_VERSION := $(shell cd $(GLUONDIR) && git describe --always 2>/dev/null || echo unknown) -export GLUON_VERSION - -GLUON_LANGS ?= en -export GLUON_LANGS - - -ifeq ($(OPENWRT_BUILD),1) -ifeq ($(GLUON_TOOLS),1) - -CONFIG_VERSION_REPO := $(shell $(GLUONDIR)/scripts/site.sh opkg_repo || echo http://downloads.openwrt.org/chaos_calmer/15.05-rc1/%S/packages) -export CONFIG_VERSION_REPO - -GLUON_SITE_CODE := $(shell $(GLUONDIR)/scripts/site.sh site_code) -export GLUON_SITE_CODE - -ifeq ($(GLUON_RELEASE),) -$(error GLUON_RELEASE not set. GLUON_RELEASE can be set in site.mk or on the command line.) -endif -export GLUON_RELEASE - -endif -endif - - -define merge-lists -$(1) := -$(foreach var,$(2),$(1) := $$(filter-out -% $$(patsubst -%,%,$$(filter -%,$$($(var)))),$$($(1)) $$($(var))) -) -endef - -GLUON_TARGETS := - -define GluonTarget -gluon_target := $(1)$$(if $(2),-$(2)) -GLUON_TARGETS += $$(gluon_target) -GLUON_TARGET_$$(gluon_target)_BOARD := $(1) -GLUON_TARGET_$$(gluon_target)_SUBTARGET := $(2) -endef - -GLUON_DEFAULT_PACKAGES := gluon-core kmod-ipv6 firewall ip6tables -uboot-envtools -wpad-mini hostapd-mini - -override DEFAULT_PACKAGES.router := - -endif #__gluon_inc diff --git a/include/package.mk b/include/package.mk deleted file mode 100644 index 76e109e2..00000000 --- a/include/package.mk +++ /dev/null @@ -1,35 +0,0 @@ -include $(INCLUDE_DIR)/package.mk - -# Annoyingly, make's shell function replaces all newlines with spaces, so we have to do some escaping work. Yuck. -define GluonCheckSite -[ -z "$$GLUONDIR" ] || sed -e 's/-@/\n/g' -e 's/+@/@/g' <<'END__GLUON__CHECK__SITE' | "$$GLUONDIR"/scripts/check_site.sh -$(shell cat $(1) | sed -ne '1h; 1!H; $$ {g; s/@/+@/g; s/\n/-@/g; p}') -END__GLUON__CHECK__SITE -endef - -# Languages supported by LuCi -GLUON_SUPPORTED_LANGS := ca zh_cn en fr de el he hu it ja ms no pl pt_br pt ro ru es sv uk vi - -GLUON_I18N_PACKAGES := $(foreach lang,$(GLUON_SUPPORTED_LANGS),+LUCI_LANG_$(lang):luci-i18n-base-$(lang)) -GLUON_I18N_CONFIG := $(foreach lang,$(GLUON_SUPPORTED_LANGS),CONFIG_LUCI_LANG_$(lang)) -GLUON_ENABLED_LANGS := $(foreach lang,$(GLUON_SUPPORTED_LANGS),$(if $(CONFIG_LUCI_LANG_$(lang)),$(lang))) - - -define GluonBuildI18N - mkdir -p $$(PKG_BUILD_DIR)/i18n - for lang in $$(GLUON_ENABLED_LANGS); do \ - if [ -e $(2)/$$$$lang.po ]; then \ - rm -f $$(PKG_BUILD_DIR)/i18n/$(1).$$$$lang.lmo; \ - po2lmo $(2)/$$$$lang.po $$(PKG_BUILD_DIR)/i18n/$(1).$$$$lang.lmo; \ - fi; \ - done -endef - -define GluonInstallI18N - $$(INSTALL_DIR) $(2)/usr/lib/lua/luci/i18n - for lang in $$(GLUON_ENABLED_LANGS); do \ - if [ -e $$(PKG_BUILD_DIR)/i18n/$(1).$$$$lang.lmo ]; then \ - $$(INSTALL_DATA) $$(PKG_BUILD_DIR)/i18n/$(1).$$$$lang.lmo $(2)/usr/lib/lua/luci/i18n/$(1).$$$$lang.lmo; \ - fi; \ - done -endef diff --git a/include/toplevel.mk b/include/toplevel.mk deleted file mode 100644 index 72522da5..00000000 --- a/include/toplevel.mk +++ /dev/null @@ -1,62 +0,0 @@ -# Makefile for OpenWrt -# -# Copyright (C) 2007-2012 OpenWrt.org -# Copyright (C) 2013-2014 Project Gluon -# -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# - -RELEASE:=Barrier Breaker -PREP_MK= OPENWRT_BUILD= QUIET=0 - -export IS_TTY=$(shell tty -s && echo 1 || echo 0) - -include $(GLUONDIR)/include/verbose.mk - -REVISION:=$(shell [ -d $(TOPDIR) ] && cd $(TOPDIR) && ./scripts/getver.sh 2>/dev/null) - -HOSTCC ?= gcc -OPENWRTVERSION:=$(RELEASE)$(if $(REVISION), ($(REVISION))) -export RELEASE -export REVISION -export OPENWRTVERSION -export IS_TTY=$(shell tty -s && echo 1 || echo 0) -export LD_LIBRARY_PATH:=$(subst ::,:,$(if $(LD_LIBRARY_PATH),$(LD_LIBRARY_PATH):)$(STAGING_DIR_HOST)/lib) -export DYLD_LIBRARY_PATH:=$(subst ::,:,$(if $(DYLD_LIBRARY_PATH),$(DYLD_LIBRARY_PATH):)$(STAGING_DIR_HOST)/lib) -export GIT_CONFIG_PARAMETERS='core.autocrlf=false' -export MAKE_JOBSERVER=$(filter --jobserver%,$(MAKEFLAGS)) - -# prevent perforce from messing with the patch utility -unexport P4PORT P4USER P4CONFIG P4CLIENT - -# prevent user defaults for quilt from interfering -unexport QUILT_PATCHES QUILT_PATCH_OPTS - -unexport C_INCLUDE_PATH CROSS_COMPILE ARCH - -# prevent distro default LPATH from interfering -unexport LPATH - -# make sure that a predefined CFLAGS variable does not disturb packages -export CFLAGS= - -ifneq ($(shell $(HOSTCC) 2>&1 | grep clang),) - export HOSTCC_REAL?=$(HOSTCC) - export HOSTCC_WRAPPER:=$(TOPDIR)/scripts/clang-gcc-wrapper -else - export HOSTCC_WRAPPER:=$(HOSTCC) -endif - -SCAN_COOKIE?=$(shell echo $$$$) -export SCAN_COOKIE - -SUBMAKE:=umask 022; $(SUBMAKE) - -ULIMIT_FIX=_limit=`ulimit -n`; [ "$$_limit" = "unlimited" -o "$$_limit" -ge 1024 ] || ulimit -n 1024; - -FORCE: ; - -.PHONY: FORCE -.NOTPARALLEL: - diff --git a/include/verbose.mk b/include/verbose.mk deleted file mode 100644 index d34f55fc..00000000 --- a/include/verbose.mk +++ /dev/null @@ -1,67 +0,0 @@ -# -# Copyright (C) 2006 OpenWrt.org -# -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# - -ifndef OPENWRT_VERBOSE - OPENWRT_VERBOSE:= -endif -ifeq ("$(origin V)", "command line") - OPENWRT_VERBOSE:=$(V) -endif - -ifeq ($(OPENWRT_VERBOSE),1) - OPENWRT_VERBOSE:=w -endif -ifeq ($(OPENWRT_VERBOSE),99) - OPENWRT_VERBOSE:=s -endif - -ifeq ($(NO_TRACE_MAKE),) -NO_TRACE_MAKE := $(MAKE) V=s$(OPENWRT_VERBOSE) -export NO_TRACE_MAKE -endif - -ifeq ($(IS_TTY),1) - ifneq ($(strip $(NO_COLOR)),1) - _Y:=\\033[33m - _R:=\\033[31m - _N:=\\033[m - endif -endif - -ifeq ($(findstring s,$(OPENWRT_VERBOSE)),) - define MESSAGE - printf "$(_Y)%s$(_N)\n" "$(1)" >&8 - endef - - define ERROR_MESSAGE - printf "$(_R)%s$(_N)\n" "$(1)" >&8 - endef - - ifeq ($(QUIET),1) - ifneq ($(CURDIR),$(TOPDIR)) - _DIR:=$(patsubst $(TOPDIR)/%,%,${CURDIR}) - else - _DIR:= - endif - _NULL:=$(if $(MAKECMDGOALS),$(shell \ - $(call MESSAGE, make[$(MAKELEVEL)]$(if $(_DIR), -C $(_DIR)) $(MAKECMDGOALS)); \ - )) - SUBMAKE=$(MAKE) - else - SILENT:=>/dev/null $(if $(findstring w,$(OPENWRT_VERBOSE)),,2>&1) - export QUIET:=1 - SUBMAKE=cmd() { $(SILENT) $(MAKE) -s $$* < /dev/null || { echo "make $$*: build failed. Please re-run make with V=s to see what's going on"; false; } } 8>&1 9>&2; cmd - endif - - .SILENT: $(MAKECMDGOALS) -else - SUBMAKE=$(MAKE) -w - define MESSAGE - printf "%s\n" "$(1)" - endef - ERROR_MESSAGE=$(MESSAGE) -endif diff --git a/modules b/modules index 783113be..c3a0802d 100644 --- a/modules +++ b/modules @@ -1,19 +1,19 @@ GLUON_FEEDS='openwrt gluon routing luci' -OPENWRT_REPO=git://git.openwrt.org/openwrt.git -OPENWRT_COMMIT=08ac77da771204772119aeecf6826a5da4a0a45f +LEDE_REPO=https://git.lede-project.org/source.git +LEDE_BRANCH=lede-17.01 +LEDE_COMMIT=65eec8bd5f6337956b972d07fde49eb5db9cb4a0 -PACKAGES_OPENWRT_REPO=git://github.com/openwrt/packages.git -PACKAGES_OPENWRT_COMMIT=4c4c2dbdae02b38eff4a6abd95cfd54f61702246 -PACKAGES_OPENWRT_BRANCH=for-15.05 +PACKAGES_OPENWRT_REPO=https://github.com/openwrt/packages.git +PACKAGES_OPENWRT_BRANCH=lede-17.01 +PACKAGES_OPENWRT_COMMIT=8844d7e2d4f717898c55c6345ad3b43fca52c440 -PACKAGES_GLUON_REPO=git://github.com/freifunk-gluon/packages.git -PACKAGES_GLUON_COMMIT=dcc5a5ab74822492877eadcba5fc3ad845ee65db +PACKAGES_GLUON_REPO=https://github.com/freifunk-gluon/packages.git +PACKAGES_GLUON_COMMIT=71823713c0e9451d1cd459cb10309f468188eb6e -PACKAGES_ROUTING_REPO=git://github.com/openwrt-routing/packages.git -PACKAGES_ROUTING_COMMIT=2bca6fb55f898c08e4227d35533fda2486c8983c -PACKAGES_ROUTING_BRANCH=for-15.05 +PACKAGES_ROUTING_REPO=https://github.com/openwrt-routing/packages.git +PACKAGES_ROUTING_COMMIT=8d9d70510b2c86f7503962308846ec874f0eb39f -PACKAGES_LUCI_REPO=git://github.com/openwrt/luci.git -PACKAGES_LUCI_COMMIT=a497fbab4c4d7e3228c67a93e107000f7e70fd1f -PACKAGES_LUCI_BRANCH=for-15.05 +PACKAGES_LUCI_REPO=https://github.com/openwrt/luci.git +PACKAGES_LUCI_BRANCH=lede-17.01 +PACKAGES_LUCI_COMMIT=1f014bd2180b364bec4c3f6457f72a0621884f9a diff --git a/overlay/opkg.mk b/overlay/opkg.mk new file mode 100644 index 00000000..ccbd2573 --- /dev/null +++ b/overlay/opkg.mk @@ -0,0 +1,10 @@ +# LEDE doesn't have a nice way to set the list of feeds in +# /etc/opkg/distfeeds.conf, so we use this overlay file (which is included by +# the opkg package Makefile though LEDE's IncludeOverlay mechanism). + +# The following definitions make /etc/opkg/distfeeds.conf match the one included +# in official LEDE builds (by default, FEEDS_DISABLED contains the original list +# of feeds (which are unused by Gluon), and FEEDS_ENABLED our own feed list). + +FEEDS_ENABLED := $(FEEDS_DISABLED) +FEEDS_DISABLED := diff --git a/package/gluon-alfred/Makefile b/package/gluon-alfred/Makefile index bb6926a5..be0ff0da 100644 --- a/package/gluon-alfred/Makefile +++ b/package/gluon-alfred/Makefile @@ -6,12 +6,13 @@ PKG_RELEASE:=1 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) -include $(INCLUDE_DIR)/package.mk +include ../gluon.mk + define Package/gluon-alfred SECTION:=gluon CATEGORY:=Gluon - DEPENDS:=+gluon-core +gluon-announce +gluon-cron +alfred + DEPENDS:=+gluon-core +gluon-respondd +gluon-neighbour-info gluon-mesh-batman-adv +micrond +alfred TITLE:=Configure alfred endef @@ -23,10 +24,12 @@ define Build/Configure endef define Build/Compile + $(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/) endef define Package/gluon-alfred/install $(CP) ./files/* $(1)/ + $(CP) $(PKG_BUILD_DIR)/luadest/* $(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 deleted file mode 100644 index 9f79bc64..00000000 --- a/package/gluon-alfred/files/lib/gluon/cron/alfred +++ /dev/null @@ -1 +0,0 @@ -* * * * * /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 deleted file mode 100755 index 8c52d8a6..00000000 --- a/package/gluon-alfred/files/lib/gluon/upgrade/500-enable-alfred +++ /dev/null @@ -1,19 +0,0 @@ -#!/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-alfred/files/usr/lib/autoupdater/abort.d/60gluon-alfred b/package/gluon-alfred/files/usr/lib/autoupdater/abort.d/60gluon-alfred new file mode 100755 index 00000000..621c09a0 --- /dev/null +++ b/package/gluon-alfred/files/usr/lib/autoupdater/abort.d/60gluon-alfred @@ -0,0 +1,6 @@ +#!/bin/sh + +. /lib/gluon/autoupdater/lib.sh + + +start_enabled alfred diff --git a/package/gluon-alfred/files/usr/lib/autoupdater/download.d/40gluon-alfred b/package/gluon-alfred/files/usr/lib/autoupdater/download.d/40gluon-alfred new file mode 100755 index 00000000..19427620 --- /dev/null +++ b/package/gluon-alfred/files/usr/lib/autoupdater/download.d/40gluon-alfred @@ -0,0 +1,6 @@ +#!/bin/sh + +. /lib/gluon/autoupdater/lib.sh + + +stop alfred diff --git a/package/gluon-alfred/files/usr/lib/micron.d/alfred b/package/gluon-alfred/files/usr/lib/micron.d/alfred new file mode 100644 index 00000000..87c052b2 --- /dev/null +++ b/package/gluon-alfred/files/usr/lib/micron.d/alfred @@ -0,0 +1 @@ +* * * * * gluon-neighbour-info -d ::1 -p 1001 -t 1 -c 1 -r nodeinfo | gzip | alfred -s 158; gluon-neighbour-info -d ::1 -p 1001 -t 1 -c 1 -r statistics | gzip | alfred -s 159; gluon-neighbour-info -d ::1 -p 1001 -t 1 -c 1 -r neighbours | gzip | alfred -s 160 diff --git a/package/gluon-alfred/luasrc/lib/gluon/upgrade/500-enable-alfred b/package/gluon-alfred/luasrc/lib/gluon/upgrade/500-enable-alfred new file mode 100755 index 00000000..e1a28080 --- /dev/null +++ b/package/gluon-alfred/luasrc/lib/gluon/upgrade/500-enable-alfred @@ -0,0 +1,14 @@ +#!/usr/bin/lua + +local uci = require('simple-uci').cursor() + +uci:delete('alfred', 'alfred') +uci:section('alfred', 'alfred', 'alfred', { + interface = 'br-client', + mode = 'slave', + batmanif = 'bat0', + start_vis = true, + run_facters = false, +}) + +uci:save('alfred') diff --git a/package/gluon-announce/Makefile b/package/gluon-announce/Makefile deleted file mode 100644 index 3f62c889..00000000 --- a/package/gluon-announce/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -include $(TOPDIR)/rules.mk - -PKG_NAME:=gluon-announce -PKG_VERSION:=1 -PKG_RELEASE:=1 - -PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) - -include $(INCLUDE_DIR)/package.mk - -define Package/gluon-announce - SECTION:=gluon - CATEGORY:=Gluon - DEPENDS:=+gluon-core +luci-lib-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 deleted file mode 100755 index e2974b49..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/collect.lua +++ /dev/null @@ -1,10 +0,0 @@ -#!/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 deleted file mode 100644 index 66303f4c..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/neighbours.d/node_id +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100644 index aee3cd81..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hardware/model +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100644 index 3072f8f8..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hardware/nproc +++ /dev/null @@ -1,14 +0,0 @@ -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 deleted file mode 100644 index 7d4f0521..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hostname +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100644 index 049eea58..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/network/mac +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100644 index 66303f4c..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/node_id +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100644 index cf50f79f..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/software/firmware +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index 876fb6d8..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/system/site_code +++ /dev/null @@ -1,3 +0,0 @@ -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 deleted file mode 100644 index 845de268..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/statistics.d/idletime +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100644 index d79973aa..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/statistics.d/loadavg +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100644 index 7b07a107..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/statistics.d/memory +++ /dev/null @@ -1,13 +0,0 @@ -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 deleted file mode 100644 index 66303f4c..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/statistics.d/node_id +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100644 index 33ecff66..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/statistics.d/processes +++ /dev/null @@ -1,3 +0,0 @@ -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 deleted file mode 100644 index 8426e9e1..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/statistics.d/rootfs_usage +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index 0bc45bea..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/statistics.d/uptime +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100644 index 17109785..00000000 --- a/package/gluon-announce/files/usr/lib/lua/gluon/announce.lua +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/lua - -module('gluon.announce', package.seeall) - -fs = require 'nixio.fs' -uci = require('luci.model.uci').cursor() -util = require 'luci.util' - -local function collect_entry(entry) - if fs.stat(entry, 'type') == 'dir' then - return collect_dir(entry) - else - return setfenv(loadfile(entry), _M)() - end -end - -function collect_dir(dir) - local ret = {} - - for entry in 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 deleted file mode 100644 index d5b06dce..00000000 --- a/package/gluon-announced/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -include $(TOPDIR)/rules.mk - -PKG_NAME:=gluon-announced -PKG_VERSION:=2 -PKG_RELEASE:=1 - -PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) - -include $(INCLUDE_DIR)/package.mk - -define Package/gluon-announced - SECTION:=gluon - CATEGORY:=Gluon - TITLE:=Provides node information to the network - DEPENDS:=+gluon-announce +respondd +lua-deflate -endef - -define Build/Prepare - mkdir -p $(PKG_BUILD_DIR) -endef - -define Build/Configure -endef - -define Build/Compile -endef - -define Package/gluon-announced/install - $(CP) ./files/* $(1)/ -endef - -$(eval $(call BuildPackage,gluon-announced)) 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 deleted file mode 100644 index a1e2c45f..00000000 --- a/package/gluon-announced/files/etc/hotplug.d/iface/10-gluon-announced +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh - -. /usr/share/libubox/jshn.sh -. /lib/functions/service.sh - -DEVLIST=/var/run/gluon-announced.devs -DAEMON=/usr/bin/respondd - -ifname_to_dev () { - json_load "$(ubus call network.interface.$1 status)" - json_get_var dev device - - echo "$dev" -} - -restart_announced () { - SERVICE_USE_PID=1 - SERVICE_WRITE_PID=1 - SERVICE_DAEMONIZE=1 - - DEVS=$(cat $DEVLIST | while read dev iface; do echo -n " -i $dev"; done) - - service_stop $DAEMON - service_start $DAEMON -g ff02::2:1001 -p 1001 -c 'return require("gluon.announced").handle_request' $DEVS -} - -case "$ACTION" in - ifdown) - sed -i "/$INTERFACE/d" $DEVLIST - ;; - ifup) - DEVICE="$(ifname_to_dev "$INTERFACE")" - MESH="$(cat "/sys/class/net/$DEVICE/batman_adv/mesh_iface" 2>/dev/null)" - - [ "$MESH" = "bat0" -o "$INTERFACE" = "client" ] || exit 0 - - DEVS=$(cat $DEVLIST; echo $DEVICE $INTERFACE) - - echo "$DEVS" | sort -u > $DEVLIST - - restart_announced - - ;; -esac - diff --git a/package/gluon-announced/files/lib/gluon/upgrade/400-announced-firewall b/package/gluon-announced/files/lib/gluon/upgrade/400-announced-firewall deleted file mode 100755 index 77acb1b9..00000000 --- a/package/gluon-announced/files/lib/gluon/upgrade/400-announced-firewall +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/lua - -local uci = require('luci.model.uci').cursor() - --- Allow announced port on WAN to allow resolving neighbours over mesh-on-wan -uci:section('firewall', 'rule', 'wan_announced', - { - name = 'wan_announced', - src = 'wan', - src_ip = 'fe80::/64', - dest_port = '1001', - proto = 'udp', - target = 'ACCEPT', - } -) - -uci:save('firewall') -uci:commit('firewall') diff --git a/package/gluon-announced/files/usr/lib/lua/gluon/announced.lua b/package/gluon-announced/files/usr/lib/lua/gluon/announced.lua deleted file mode 100644 index 99116b81..00000000 --- a/package/gluon-announced/files/usr/lib/lua/gluon/announced.lua +++ /dev/null @@ -1,33 +0,0 @@ -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 index 6ef90da3..7d010dc9 100644 --- a/package/gluon-authorized-keys/Makefile +++ b/package/gluon-authorized-keys/Makefile @@ -5,7 +5,8 @@ PKG_VERSION:=2 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) -include $(GLUONDIR)/include/package.mk +include ../gluon.mk + define Package/gluon-authorized-keys SECTION:=gluon @@ -22,10 +23,11 @@ define Build/Configure endef define Build/Compile + $(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/) endef define Package/gluon-authorized-keys/install - $(CP) ./files/* $(1)/ + $(CP) $(PKG_BUILD_DIR)/luadest/* $(1)/ endef define Package/gluon-authorized-keys/postinst diff --git a/package/gluon-authorized-keys/files/lib/gluon/upgrade/100-authorized-keys b/package/gluon-authorized-keys/luasrc/lib/gluon/upgrade/100-authorized-keys similarity index 100% rename from package/gluon-authorized-keys/files/lib/gluon/upgrade/100-authorized-keys rename to package/gluon-authorized-keys/luasrc/lib/gluon/upgrade/100-authorized-keys diff --git a/package/gluon-autoupdater/Makefile b/package/gluon-autoupdater/Makefile index b33bada9..eacf80c1 100644 --- a/package/gluon-autoupdater/Makefile +++ b/package/gluon-autoupdater/Makefile @@ -2,36 +2,51 @@ 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 +PKG_CONFIG_DEPENDS := CONFIG_GLUON_BRANCH +PKG_BUILD_DEPENDS := respondd + + +include ../gluon.mk + define Package/gluon-autoupdater SECTION:=gluon CATEGORY:=Gluon - DEPENDS:=+gluon-core +gluon-cron +autoupdater + DEPENDS:=+gluon-core +libgluonutil +micrond +autoupdater TITLE:=Automatically update firmware endef +define Package/gluon-autoupdater/config +config GLUON_BRANCH + string "Gluon autoupdater branch" + depends on PACKAGE_gluon-autoupdater + default "" +endef + define Build/Prepare mkdir -p $(PKG_BUILD_DIR) -endef - -define Build/Configure + $(CP) ./src/* $(PKG_BUILD_DIR)/ endef define Build/Compile + $(call Build/Compile/Default) + $(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/) endef define Package/gluon-autoupdater/install $(CP) ./files/* $(1)/ + $(CP) $(PKG_BUILD_DIR)/luadest/* $(1)/ - if [ '$(GLUON_BRANCH)' ]; then \ - $(INSTALL_DIR) $(1)/lib/gluon/autoupdater; \ - echo '$(GLUON_BRANCH)' > $(1)/lib/gluon/autoupdater/default_branch; \ - fi + $(INSTALL_DIR) $(1)/lib/gluon/respondd + $(CP) $(PKG_BUILD_DIR)/respondd.so $(1)/lib/gluon/respondd/autoupdater.so + +ifneq ($(CONFIG_GLUON_BRANCH),"") + $(INSTALL_DIR) $(1)/lib/gluon/autoupdater + echo '$(call qstrip,$(CONFIG_GLUON_BRANCH))' > $(1)/lib/gluon/autoupdater/default_branch +endif endef define Package/gluon-autoupdater/postinst diff --git a/package/gluon-autoupdater/check_site.lua b/package/gluon-autoupdater/check_site.lua index 1d8996f0..3eb2e721 100644 --- a/package/gluon-autoupdater/check_site.lua +++ b/package/gluon-autoupdater/check_site.lua @@ -1,12 +1,14 @@ need_string 'autoupdater.branch' local function check_branch(k, _) + assert_uci_name(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') + need_string_array_match(prefix .. 'pubkeys', '^%x+$') 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 deleted file mode 100644 index 75a67578..00000000 --- a/package/gluon-autoupdater/files/lib/gluon/announce/nodeinfo.d/software/autoupdater +++ /dev/null @@ -1,7 +0,0 @@ -local autoupdater = uci:get_all('autoupdater', 'settings') -if autoupdater then - return { - branch = autoupdater['branch'], - enabled = uci:get_bool('autoupdater', 'settings', 'enabled'), - } -end diff --git a/package/gluon-autoupdater/files/lib/gluon/autoupdater/lib.sh b/package/gluon-autoupdater/files/lib/gluon/autoupdater/lib.sh new file mode 100644 index 00000000..24ef2f90 --- /dev/null +++ b/package/gluon-autoupdater/files/lib/gluon/autoupdater/lib.sh @@ -0,0 +1,16 @@ +# Library to be sourced by download.d/abort.d scripts + + +stop() { + if [ -x /etc/init.d/"$1" ]; then + echo "Stopping $1..." + /etc/init.d/"$1" stop + fi +} + +start_enabled() { + if [ -x /etc/init.d/"$1" ] && /etc/init.d/"$1" enabled; then + echo "Starting $1..." + /etc/init.d/"$1" start + fi +} diff --git a/package/gluon-autoupdater/files/lib/gluon/upgrade/500-autoupdater b/package/gluon-autoupdater/files/lib/gluon/upgrade/500-autoupdater deleted file mode 100755 index fec313b3..00000000 --- a/package/gluon-autoupdater/files/lib/gluon/upgrade/500-autoupdater +++ /dev/null @@ -1,57 +0,0 @@ -#!/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-autoupdater/files/usr/lib/autoupdater/abort.d/90gluon-autoupdater b/package/gluon-autoupdater/files/usr/lib/autoupdater/abort.d/90gluon-autoupdater new file mode 100755 index 00000000..19def950 --- /dev/null +++ b/package/gluon-autoupdater/files/usr/lib/autoupdater/abort.d/90gluon-autoupdater @@ -0,0 +1,9 @@ +#!/bin/sh + +. /lib/gluon/autoupdater/lib.sh + + +start_enabled cron +start_enabled haveged +start_enabled micrond +start_enabled sysntpd diff --git a/package/gluon-autoupdater/files/usr/lib/autoupdater/download.d/10gluon-autoupdater b/package/gluon-autoupdater/files/usr/lib/autoupdater/download.d/10gluon-autoupdater new file mode 100755 index 00000000..6f2268fe --- /dev/null +++ b/package/gluon-autoupdater/files/usr/lib/autoupdater/download.d/10gluon-autoupdater @@ -0,0 +1,9 @@ +#!/bin/sh + +. /lib/gluon/autoupdater/lib.sh + + +stop cron +stop haveged +stop micrond +stop sysntpd diff --git a/package/gluon-autoupdater/luasrc/lib/gluon/upgrade/500-autoupdater b/package/gluon-autoupdater/luasrc/lib/gluon/upgrade/500-autoupdater new file mode 100755 index 00000000..6f3070bf --- /dev/null +++ b/package/gluon-autoupdater/luasrc/lib/gluon/upgrade/500-autoupdater @@ -0,0 +1,52 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local uci = require('simple-uci').cursor() + + +for name, config in pairs(site.autoupdater.branches) do + uci:delete('autoupdater', name) + uci:section('autoupdater', 'branch', name, { + name = config.name, + mirror = config.mirrors, + good_signatures = config.good_signatures, + pubkey = config.pubkeys, + }) +end + +if not uci:get('autoupdater', 'settings') then + local enabled = false + local branch = site.autoupdater.branch + + local f = io.open('/lib/gluon/autoupdater/default_branch') + if f then + enabled = true + branch = f:read('*line') + f:close() + end + + uci:section('autoupdater', 'autoupdater', 'settings', { + enabled = enabled, + branch = branch, + }) +end + +uci:set('autoupdater', 'settings', 'version_file', '/lib/gluon/release') + +uci:save('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 worked for +-- (priority+1) days after a firmware release, for example because the node +-- is always offline at night) +local minute = math.random(0, 59) + +local f = io.open('/usr/lib/micron.d/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-autoupdater/src/Makefile b/package/gluon-autoupdater/src/Makefile new file mode 100644 index 00000000..3ddc8a58 --- /dev/null +++ b/package/gluon-autoupdater/src/Makefile @@ -0,0 +1,6 @@ +all: respondd.so + +CFLAGS += -Wall + +respondd.so: respondd.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -o $@ $^ $(LDLIBS) -lgluonutil -luci diff --git a/package/gluon-autoupdater/src/respondd.c b/package/gluon-autoupdater/src/respondd.c new file mode 100644 index 00000000..66b7a928 --- /dev/null +++ b/package/gluon-autoupdater/src/respondd.c @@ -0,0 +1,79 @@ +/* + Copyright (c) 2016, 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 + + +static struct json_object * get_autoupdater(void) { + struct uci_context *ctx = uci_alloc_context(); + ctx->flags &= ~UCI_FLAG_STRICT; + + struct uci_package *p; + if (uci_load(ctx, "autoupdater", &p)) + goto error; + + struct uci_section *s = uci_lookup_section(ctx, p, "settings"); + if (!s) + goto error; + + struct json_object *ret = json_object_new_object(); + + json_object_object_add(ret, "branch", gluonutil_wrap_string(uci_lookup_option_string(ctx, s, "branch"))); + + const char *enabled = uci_lookup_option_string(ctx, s, "enabled"); + json_object_object_add(ret, "enabled", json_object_new_boolean(enabled && !strcmp(enabled, "1"))); + + uci_free_context(ctx); + + return ret; + + error: + uci_free_context(ctx); + return NULL; +} + +static struct json_object * respondd_provider_nodeinfo(void) { + struct json_object *ret = json_object_new_object(); + + struct json_object *software = json_object_new_object(); + json_object_object_add(software, "autoupdater", get_autoupdater()); + json_object_object_add(ret, "software", software); + + return ret; +} + + +const struct respondd_provider_info respondd_providers[] = { + {"nodeinfo", respondd_provider_nodeinfo}, + {} +}; diff --git a/package/gluon-client-bridge/Makefile b/package/gluon-client-bridge/Makefile new file mode 100644 index 00000000..b88b0291 --- /dev/null +++ b/package/gluon-client-bridge/Makefile @@ -0,0 +1,38 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-client-bridge +PKG_VERSION:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include ../gluon.mk + + +define Package/gluon-client-bridge + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Provides a bridge and a wireless interface for clients to connect to + DEPENDS:=+gluon-core +kmod-veth +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile + $(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/) +endef + +define Package/gluon-client-bridge/install + $(CP) $(PKG_BUILD_DIR)/luadest/* $(1)/ +endef + +define Package/gluon-client-bridge/postinst +#!/bin/sh +$(call GluonCheckSite,check_site.lua) +endef + +$(eval $(call BuildPackage,gluon-client-bridge)) diff --git a/package/gluon-client-bridge/check_site.lua b/package/gluon-client-bridge/check_site.lua new file mode 100644 index 00000000..c71f11c0 --- /dev/null +++ b/package/gluon-client-bridge/check_site.lua @@ -0,0 +1,15 @@ +need_string_match('next_node.mac', '^%x[02468aAcCeE]:%x%x:%x%x:%x%x:%x%x:%x%x$') + +if need_string_match('next_node.ip4', '^%d+.%d+.%d+.%d+$', false) then + need_string_match('prefix4', '^%d+.%d+.%d+.%d+/%d+$') +end + +need_string_match('next_node.ip6', '^[%x:]+$', false) + + +for _, config in ipairs({'wifi24', 'wifi5'}) do + if need_table(config .. '.ap', nil, false) then + need_string(config .. '.ap.ssid') + need_boolean(config .. '.ap.disabled', false) + end +end diff --git a/package/gluon-client-bridge/luasrc/lib/gluon/upgrade/300-gluon-client-bridge-network b/package/gluon-client-bridge/luasrc/lib/gluon/upgrade/300-gluon-client-bridge-network new file mode 100755 index 00000000..2f34c9fd --- /dev/null +++ b/package/gluon-client-bridge/luasrc/lib/gluon/upgrade/300-gluon-client-bridge-network @@ -0,0 +1,70 @@ +#!/usr/bin/lua + +local sysconfig = require 'gluon.sysconfig' +local sysctl = require 'gluon.sysctl' +local util = require 'gluon.util' + +local uci = require('simple-uci').cursor() + + +local interfaces = uci:get('network', 'client', 'ifname') or {} + +if type(interfaces) == 'string' then + local ifname = interfaces + interfaces = {} + for iface in ifname:gmatch('%S+') do + util.add_to_set(interfaces, iface) + end +end + +if sysconfig.lan_ifname and not ifname and not uci:get_bool('network', 'mesh_lan', 'auto') then + for lanif in sysconfig.lan_ifname:gmatch('%S+') do + util.add_to_set(interfaces, lanif) + end +end + +util.add_to_set(interfaces, 'local-port') + + +uci:delete('network', 'client') +uci:section('network', 'interface', 'client', { + type = 'bridge', + ifname = interfaces, + proto = 'none', + auto = true, + ipv6 = false, + macaddr = sysconfig.primary_mac, + igmp_snooping = true, + multicast_querier = true, +}) + +uci:save('network') + + +uci:delete('firewall', 'client') +uci:section('firewall', 'zone', 'client', { + name = 'client', + network = {'client'}, + input = 'DROP', + output = 'DROP', + forward = 'DROP', +}) + +uci:save('firewall') + + +local dnsmasq = uci:get_first('dhcp', 'dnsmasq') +uci:set('dhcp', dnsmasq, 'boguspriv', false) +uci:set('dhcp', dnsmasq, 'localise_queries', false) +uci:set('dhcp', dnsmasq, 'rebind_protection', false) + +uci:delete('dhcp', 'client') +uci:section('dhcp', 'dhcp', 'client', { + interface = 'client', + ignore = true, +}) + +uci:save('dhcp') + + +sysctl.set('net.ipv6.conf.br-client.forwarding', 0) diff --git a/package/gluon-client-bridge/luasrc/lib/gluon/upgrade/310-gluon-client-bridge-local-node b/package/gluon-client-bridge/luasrc/lib/gluon/upgrade/310-gluon-client-bridge-local-node new file mode 100755 index 00000000..43e54145 --- /dev/null +++ b/package/gluon-client-bridge/luasrc/lib/gluon/upgrade/310-gluon-client-bridge-local-node @@ -0,0 +1,48 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local sysconfig = require 'gluon.sysconfig' + +local uci = require('simple-uci').cursor() + + +uci:delete('network', 'local_node_dev') +uci:section('network', 'device', 'local_node_dev', { + type = 'veth', + name = 'local-node', + macaddr = site.next_node.mac, + peer_name = 'local-port', + peer_macaddr = sysconfig.primary_mac, +}) + + +local ip4, ip6 + +if site.next_node.ip4 then + local plen = site.prefix4:match('/%d+$') + ip4 = site.next_node.ip4 .. plen +end + +if site.next_node.ip6 then + ip6 = site.next_node.ip6 .. '/128' +end + +uci:delete('network', 'local_node') +uci:section('network', 'interface', 'local_node', { + ifname = 'local-node', + proto = 'static', + ipaddr = ip4, + ip6addr = ip6, + ip6deprecated = true, +}) + +uci:save('network') + + +uci:delete('dhcp', 'local_node') +uci:section('dhcp', 'dhcp', 'local_node', { + interface = 'local_node', + ignore = true, +}) + +uci:save('dhcp') diff --git a/package/gluon-client-bridge/luasrc/lib/gluon/upgrade/320-gluon-client-bridge-wireless b/package/gluon-client-bridge/luasrc/lib/gluon/upgrade/320-gluon-client-bridge-wireless new file mode 100755 index 00000000..058dc351 --- /dev/null +++ b/package/gluon-client-bridge/luasrc/lib/gluon/upgrade/320-gluon-client-bridge-wireless @@ -0,0 +1,56 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local util = require 'gluon.util' + +local uci = require('simple-uci').cursor() + + +local function is_disabled(config, name) + local disabled + if uci:get('wireless', name) then + disabled = uci:get_bool('wireless', name, 'disabled') + else + disabled = config and config.disabled + end + + return disabled +end + +local function configure_client(config, radio, index, suffix) + local name = 'client_' .. radio + local disabled = is_disabled(config, name) + + uci:delete('wireless', name) + + if not config then + return + end + + local macaddr = util.get_wlan_mac(uci, radio, index, 1) + if not macaddr then + return + end + + uci:section('wireless', 'wifi-iface', name, + { + device = radio, + network = 'client', + mode = 'ap', + ssid = config.ssid, + macaddr = macaddr, + ifname = suffix and 'client' .. suffix, + disabled = disabled or false, + } + ) +end + +local function configure_radio(radio, index, config) + local suffix = radio:match('^radio(%d+)$') + + configure_client(config.ap, radio, index, suffix) +end + +util.iterate_radios(uci, configure_radio) + +uci:save('wireless') diff --git a/package/gluon-config-mode-autoupdater/Makefile b/package/gluon-config-mode-autoupdater/Makefile index 4303940b..a77c07de 100644 --- a/package/gluon-config-mode-autoupdater/Makefile +++ b/package/gluon-config-mode-autoupdater/Makefile @@ -5,7 +5,7 @@ PKG_VERSION:=1 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) -include $(GLUONDIR)/include/package.mk +include ../gluon.mk PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) @@ -13,14 +13,10 @@ 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. + TITLE:=Config Mode: 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 @@ -30,10 +26,11 @@ endef define Build/Compile $(call GluonBuildI18N,gluon-config-mode-autoupdater,i18n) + $(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/) endef define Package/gluon-config-mode-autoupdater/install - $(CP) ./files/* $(1)/ + $(CP) $(PKG_BUILD_DIR)/luadest/* $(1)/ $(call GluonInstallI18N,gluon-config-mode-autoupdater,$(1)) endef 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 deleted file mode 100644 index 3bbe0390..00000000 --- a/package/gluon-config-mode-autoupdater/files/lib/gluon/config-mode/wizard/0050-autoupdater-info.lua +++ /dev/null @@ -1,19 +0,0 @@ -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/fr.po b/package/gluon-config-mode-autoupdater/i18n/fr.po new file mode 100644 index 00000000..7ee64f46 --- /dev/null +++ b/package/gluon-config-mode-autoupdater/i18n/fr.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-08-04 20:20+0100\n" +"Last-Translator: Bernot Tobias \n" +"Language-Team: French\n" +"Language: fr\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 "Ce nœud s'actualisera automatiquement quand une nouvelle " +"version sera disponible." diff --git a/package/gluon-config-mode-autoupdater/luasrc/lib/gluon/config-mode/wizard/0050-autoupdater-info.lua b/package/gluon-config-mode-autoupdater/luasrc/lib/gluon/config-mode/wizard/0050-autoupdater-info.lua new file mode 100644 index 00000000..6d52744e --- /dev/null +++ b/package/gluon-config-mode-autoupdater/luasrc/lib/gluon/config-mode/wizard/0050-autoupdater-info.lua @@ -0,0 +1,8 @@ +return function(form, uci) + if uci:get_bool("autoupdater", "settings", "enabled") then + local s = form:section( + Section, nil, + translate('This node will automatically update its firmware when a new version is available.') + ) + end +end diff --git a/package/gluon-config-mode-contact-info/Makefile b/package/gluon-config-mode-contact-info/Makefile index ff9cb57f..7a3780a6 100644 --- a/package/gluon-config-mode-contact-info/Makefile +++ b/package/gluon-config-mode-contact-info/Makefile @@ -5,7 +5,7 @@ PKG_VERSION:=1 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) -include $(GLUONDIR)/include/package.mk +include ../gluon.mk PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) @@ -13,10 +13,15 @@ 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. + TITLE:=Allows the user to provide contact information to be distributed in the mesh DEPENDS:=gluon-config-mode-core-virtual +gluon-node-info endef +define Package/gluon-config-mode-contact-info/description + Allows the user to provide contact information to be distributed in the mesh. + Can be made obligatory in site.conf +endef + define Build/Prepare mkdir -p $(PKG_BUILD_DIR) endef @@ -26,11 +31,17 @@ endef define Build/Compile $(call GluonBuildI18N,gluon-config-mode-contact-info,i18n) + $(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/) endef define Package/gluon-config-mode-contact-info/install - $(CP) ./files/* $(1)/ + $(CP) $(PKG_BUILD_DIR)/luadest/* $(1)/ $(call GluonInstallI18N,gluon-config-mode-contact-info,$(1)) endef +define Package/gluon-config-mode-contact-info/postinst +#!/bin/sh +$(call GluonCheckSite,check_site.lua) +endef + $(eval $(call BuildPackage,gluon-config-mode-contact-info)) diff --git a/package/gluon-config-mode-contact-info/check_site.lua b/package/gluon-config-mode-contact-info/check_site.lua new file mode 100644 index 00000000..fe818616 --- /dev/null +++ b/package/gluon-config-mode-contact-info/check_site.lua @@ -0,0 +1,3 @@ +if need_table('config_mode', nil, false) and need_table('config_mode.owner', nil, false) then + need_boolean('config_mode.owner.obligatory', false) +end 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 deleted file mode 100644 index a2182f95..00000000 --- a/package/gluon-config-mode-contact-info/files/lib/gluon/config-mode/wizard/0500-contact-info.lua +++ /dev/null @@ -1,34 +0,0 @@ -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 index 719246f4..35f0ee95 100644 --- a/package/gluon-config-mode-contact-info/i18n/de.po +++ b/package/gluon-config-mode-contact-info/i18n/de.po @@ -14,13 +14,13 @@ 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 " +"Please provide your contact information here to allow others to contact " +"you. 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 " +"Bitte hinterlege hier einen Hinweis, um anderen zu ermöglichen, " +"Kontakt mit dir aufzunehmen. 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" diff --git a/package/gluon-config-mode-contact-info/i18n/fr.po b/package/gluon-config-mode-contact-info/i18n/fr.po new file mode 100644 index 00000000..624b1864 --- /dev/null +++ b/package/gluon-config-mode-contact-info/i18n/fr.po @@ -0,0 +1,26 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2015-08-12 23:30+0100\n" +"Last-Translator:Tobias Bernot \n" +"Language-Team: French\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "Contact info" +msgstr "Informations de Contact" + +msgid "" +"Please provide your contact information here to allow others to contact " +"you. Note that this information will be visible publicly on " +"the internet together with your node's coordinates." +msgstr "" +"S'il vous plaît entrez ici des informations publiques pour " +"permettre aux autres de vous contacter. " +"Ces informations seront affichées en ligne, avec les coordonnées du nœud." + +msgid "e.g. E-mail or phone number" +msgstr "Ex : E-mail ou numéro de téléphone" 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 index 63939a83..9dcaf9ec 100644 --- 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 @@ -5,8 +5,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 " +"Please provide your contact information here to allow others to contact " +"you. Note that this information will be visible publicly on " "the internet together with your node's coordinates." msgstr "" diff --git a/package/gluon-config-mode-contact-info/luasrc/lib/gluon/config-mode/wizard/0500-contact-info.lua b/package/gluon-config-mode-contact-info/luasrc/lib/gluon/config-mode/wizard/0500-contact-info.lua new file mode 100644 index 00000000..1ef5deaf --- /dev/null +++ b/package/gluon-config-mode-contact-info/luasrc/lib/gluon/config-mode/wizard/0500-contact-info.lua @@ -0,0 +1,27 @@ +return function(form, uci) + local site = require 'gluon.site_config' + + local owner = uci:get_first("gluon-node-info", "owner") + + local s = form:section(Section, nil, translate( + 'Please provide your contact information here to ' + .. 'allow others to contact you. Note that ' + .. 'this information will be visible publicly ' + .. 'on the internet together with your node\'s coordinates.' + )) + + local o = s:option(Value, "contact", translate("Contact info"), translate("e.g. E-mail or phone number")) + o.default = uci:get("gluon-node-info", owner, "contact") + o.optional = not ((site.config_mode or {}).owner or {}).obligatory + -- without a minimal length, an empty string will be accepted even with "optional = false" + o.datatype = "minlength(1)" + function o:write(data) + if data then + uci:set("gluon-node-info", owner, "contact", data) + else + uci:delete("gluon-node-info", owner, "contact") + end + end + + return {'gluon-node-info'} +end diff --git a/package/gluon-config-mode-core/Makefile b/package/gluon-config-mode-core/Makefile index 5d700f7f..91b2e51f 100644 --- a/package/gluon-config-mode-core/Makefile +++ b/package/gluon-config-mode-core/Makefile @@ -8,7 +8,7 @@ PKG_VERSION:=2 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) -include $(GLUONDIR)/include/package.mk +include ../gluon.mk PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) @@ -16,8 +16,8 @@ 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) + TITLE:=Configuration wizard for user friendly setup of new mesh nodes + DEPENDS:=gluon-setup-mode-virtual +gluon-web-theme +gluon-lock-password +pretty-hostname PROVIDES:=gluon-config-mode-core-virtual endef @@ -30,10 +30,12 @@ endef define Build/Compile $(call GluonBuildI18N,gluon-config-mode-core,i18n) + $(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/) endef define Package/gluon-config-mode-core/install $(CP) ./files/* $(1)/ + $(CP) $(PKG_BUILD_DIR)/luadest/* $(1)/ $(call GluonInstallI18N,gluon-config-mode-core,$(1)) endef 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 deleted file mode 100644 index bf27c07f..00000000 --- a/package/gluon-config-mode-core/files/lib/gluon/config-mode/reboot/0900-msg-reboot.lua +++ /dev/null @@ -1,3 +0,0 @@ -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/lib/gluon/web/view/gluon/config-mode/reboot.html b/package/gluon-config-mode-core/files/lib/gluon/web/view/gluon/config-mode/reboot.html new file mode 100644 index 00000000..6c65010b --- /dev/null +++ b/package/gluon-config-mode-core/files/lib/gluon/web/view/gluon/config-mode/reboot.html @@ -0,0 +1,22 @@ +

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

+<% + local fs = require "nixio.fs" + local util = require "nixio.util" + + local parts_dir = "/lib/gluon/config-mode/reboot/" + local files = util.consume(fs.dir(parts_dir) or function() end) + table.sort(files) + + local parts = {} + for _, entry in ipairs(files) do + if entry:sub(1, 1) ~= '.' then + local p = assert(loadfile(parts_dir .. entry)) + setfenv(p, getfenv()) + table.insert(parts, p) + end + end + + for _, p in ipairs(parts) do + p() + end +%> diff --git a/package/gluon-config-mode-core/files/lib/gluon/web/view/gluon/config-mode/welcome.html b/package/gluon-config-mode-core/files/lib/gluon/web/view/gluon/config-mode/welcome.html new file mode 100644 index 00000000..22305131 --- /dev/null +++ b/package/gluon-config-mode-core/files/lib/gluon/web/view/gluon/config-mode/welcome.html @@ -0,0 +1,14 @@ +<%- + local sysconfig = require 'gluon.sysconfig' + + local msg = _translate('gluon-config-mode:welcome') + if not msg then return end +-%> +

+ <% + renderer.render_string(msg, { + hostname = hostname, + sysconfig = sysconfig, + }) + %> +

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 deleted file mode 100644 index 39ba00a9..00000000 --- a/package/gluon-config-mode-core/files/usr/lib/lua/luci/controller/gluon-config-mode/index.lua +++ /dev/null @@ -1,90 +0,0 @@ ---[[ -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 "nixio.fs" - local util = require "nixio.util" - - local parts_dir = "/lib/gluon/config-mode/reboot/" - local files = util.consume(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 deleted file mode 100644 index dda5e58c..00000000 --- a/package/gluon-config-mode-core/files/usr/lib/lua/luci/model/cbi/gluon-config-mode/wizard.lua +++ /dev/null @@ -1,39 +0,0 @@ -local wizard_dir = "/lib/gluon/config-mode/wizard/" -local i18n = luci.i18n -local uci = luci.model.uci.cursor() -local fs = require "nixio.fs" -local util = require "nixio.util" -local f, s - -local wizard = {} -local files = util.consume(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 deleted file mode 100644 index d2210eca..00000000 --- a/package/gluon-config-mode-core/files/usr/lib/lua/luci/view/gluon/cbi/config-mode.htm +++ /dev/null @@ -1,46 +0,0 @@ -<%- - 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 deleted file mode 100644 index e8f32d99..00000000 --- a/package/gluon-config-mode-core/files/usr/lib/lua/luci/view/gluon/config-mode/reboot.htm +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - <%=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 index 58d23894..dd335a47 100644 --- a/package/gluon-config-mode-core/i18n/de.po +++ b/package/gluon-config-mode-core/i18n/de.po @@ -10,7 +10,6 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#, fuzzy msgid "Save & restart" msgstr "Speichern & Neustarten" diff --git a/package/gluon-config-mode-core/i18n/fr.po b/package/gluon-config-mode-core/i18n/fr.po new file mode 100644 index 00000000..4988e251 --- /dev/null +++ b/package/gluon-config-mode-core/i18n/fr.po @@ -0,0 +1,23 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2015-08-12 23:30+0100\n" +"Last-Translator:Tobias Bernot \n" +"Language-Team: French\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "Save & restart" +msgstr "Enregistrer & Redémarer" + +msgid "Welcome!" +msgstr "Bienvenue!" + +msgid "Wizard" +msgstr "Assistant" + +msgid "Your node's setup is now complete." +msgstr "La configuration de votre nœud est terminée." diff --git a/package/gluon-config-mode-core/luasrc/lib/gluon/config-mode/reboot/0900-msg-reboot.lua b/package/gluon-config-mode-core/luasrc/lib/gluon/config-mode/reboot/0900-msg-reboot.lua new file mode 100644 index 00000000..36f8ff3b --- /dev/null +++ b/package/gluon-config-mode-core/luasrc/lib/gluon/config-mode/reboot/0900-msg-reboot.lua @@ -0,0 +1,18 @@ +local site = require 'gluon.site_config' +local sysconfig = require 'gluon.sysconfig' +local pretty_hostname = require 'pretty_hostname' + +local uci = require("simple-uci").cursor() + +local hostname = pretty_hostname.get(uci) +local contact = uci:get_first('gluon-node-info', 'owner', 'contact') + +local msg = _translate('gluon-config-mode:reboot') +if not msg then return end + +renderer.render_string(msg, { + hostname = hostname, + site = site, + sysconfig = sysconfig, + contact = contact, +}) diff --git a/package/gluon-config-mode-core/luasrc/lib/gluon/web/controller/gluon-config-mode/index.lua b/package/gluon-config-mode-core/luasrc/lib/gluon/web/controller/gluon-config-mode/index.lua new file mode 100644 index 00000000..52117ac8 --- /dev/null +++ b/package/gluon-config-mode-core/luasrc/lib/gluon/web/controller/gluon-config-mode/index.lua @@ -0,0 +1,2 @@ +entry({}, alias("wizard")) +entry({"wizard"}, model("gluon-config-mode/wizard"), _("Wizard"), 5) diff --git a/package/gluon-config-mode-core/luasrc/lib/gluon/web/model/gluon-config-mode/wizard.lua b/package/gluon-config-mode-core/luasrc/lib/gluon/web/model/gluon-config-mode/wizard.lua new file mode 100644 index 00000000..6cafb0e2 --- /dev/null +++ b/package/gluon-config-mode-core/luasrc/lib/gluon/web/model/gluon-config-mode/wizard.lua @@ -0,0 +1,64 @@ +local disp = require 'gluon.web.dispatcher' +local fs = require "nixio.fs" +local util = require "gluon.web.util" +local nixio_util = require "nixio.util" + +local uci = require("simple-uci").cursor() + +local wizard_dir = "/lib/gluon/config-mode/wizard/" + +local files = nixio_util.consume(fs.dir(wizard_dir) or function() end) +table.sort(files) + +local wizard = {} +for _, entry in ipairs(files) do + if entry:sub(1, 1) ~= '.' then + local f = assert(loadfile(wizard_dir .. entry)) + setfenv(f, getfenv()) + local w = f() + table.insert(wizard, w) + end +end + +local f = Form(translate("Welcome!")) +f.submit = translate('Save & restart') +f.reset = false + +local s = f:section(Section) +s.template = "gluon/config-mode/welcome" + +local commit = {'gluon-setup-mode'} + +for _, w in ipairs(wizard) do + for _, c in ipairs(w(f, uci) or {}) do + if not util.contains(commit, c) then + table.insert(commit, c) + end + end +end + +function f:write() + local nixio = require "nixio" + + uci:set("gluon-setup-mode", uci:get_first("gluon-setup-mode", "setup_mode"), "configured", true) + + for _, c in ipairs(commit) do + uci:commit(c) + end + + f.template = "gluon/config-mode/reboot" + f.hidenav = true + + if nixio.fork() == 0 then + -- Replace stdout with /dev/null + nixio.dup(nixio.open('/dev/null', 'w'), nixio.stdout) + + -- Sleep a little so the browser can fetch everything required to + -- display the reboot page, then reboot the device. + nixio.nanosleep(1) + + nixio.execp("reboot") + end +end + +return f diff --git a/package/gluon-config-mode-geo-location/Makefile b/package/gluon-config-mode-geo-location/Makefile index 28d34764..af523f09 100644 --- a/package/gluon-config-mode-geo-location/Makefile +++ b/package/gluon-config-mode-geo-location/Makefile @@ -5,7 +5,7 @@ PKG_VERSION:=1 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) -include $(GLUONDIR)/include/package.mk +include ../gluon.mk PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) @@ -26,11 +26,17 @@ endef define Build/Compile $(call GluonBuildI18N,gluon-config-mode-geo-location,i18n) + $(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/) endef define Package/gluon-config-mode-geo-location/install - $(CP) ./files/* $(1)/ + $(CP) $(PKG_BUILD_DIR)/luadest/* $(1)/ $(call GluonInstallI18N,gluon-config-mode-geo-location,$(1)) endef +define Package/gluon-config-mode-geo-location/postinst +#!/bin/sh +$(call GluonCheckSite,check_site.lua) +endef + $(eval $(call BuildPackage,gluon-config-mode-geo-location)) diff --git a/package/gluon-config-mode-geo-location/check_site.lua b/package/gluon-config-mode-geo-location/check_site.lua new file mode 100644 index 00000000..509226fe --- /dev/null +++ b/package/gluon-config-mode-geo-location/check_site.lua @@ -0,0 +1,3 @@ +if need_table('config_mode', nil, false) and need_table('config_mode.geo_location', nil, false) then + need_boolean('config_mode.geo_location.show_altitude', false) +end 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 deleted file mode 100644 index a3ac089d..00000000 --- a/package/gluon-config-mode-geo-location/files/lib/gluon/config-mode/wizard/0400-geo-location.lua +++ /dev/null @@ -1,60 +0,0 @@ -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 index e83443dd..c8bc906a 100644 --- a/package/gluon-config-mode-geo-location/i18n/de.po +++ b/package/gluon-config-mode-geo-location/i18n/de.po @@ -12,13 +12,10 @@ msgstr "" 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." +"enter its coordinates here." 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." +"Koordinaten. Hier hast du die Möglichkeit, diese zu hinterlegen." msgid "Latitude" msgstr "Breitengrad" @@ -26,9 +23,6 @@ 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" diff --git a/package/gluon-config-mode-geo-location/i18n/fr.po b/package/gluon-config-mode-geo-location/i18n/fr.po new file mode 100644 index 00000000..d3d7c6e8 --- /dev/null +++ b/package/gluon-config-mode-geo-location/i18n/fr.po @@ -0,0 +1,30 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2015-08-12 23:30+0100\n" +"Last-Translator:Tobias Bernot \n" +"Language-Team: French\n" +"Language: fr\n" +"MIME-Version: 1.0\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." +msgstr "" +"Pour Afficher votre nœud sur la Carte nous avons besoin de ses coordonnées. " +"Ici vous pouvez entrer sa position." + +msgid "Latitude" +msgstr "Latitude" + +msgid "Longitude" +msgstr "Longitude" + +msgid "Show node on the map" +msgstr "Afficher le nœud sur la carte" + +msgid "e.g. %s" +msgstr "Ex: %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 index a2be4fdf..7acf7f28 100644 --- 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 @@ -3,8 +3,7 @@ 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." +"enter its coordinates here." msgstr "" msgid "Latitude" @@ -13,9 +12,6 @@ msgstr "" msgid "Longitude" msgstr "" -msgid "Altitude" -msgstr "" - msgid "Show node on the map" msgstr "" diff --git a/package/gluon-config-mode-geo-location/luasrc/lib/gluon/config-mode/wizard/0400-geo-location.lua b/package/gluon-config-mode-geo-location/luasrc/lib/gluon/config-mode/wizard/0400-geo-location.lua new file mode 100644 index 00000000..4d7fec01 --- /dev/null +++ b/package/gluon-config-mode-geo-location/luasrc/lib/gluon/config-mode/wizard/0400-geo-location.lua @@ -0,0 +1,64 @@ +return function(form, uci) + local site = require 'gluon.site_config' + + local location = uci:get_first("gluon-node-info", "location") + + local function show_altitude() + if ((site.config_mode or {}).geo_location or {}).show_altitude ~= false then + return true + end + + return uci:get_bool("gluon-node-info", location, "altitude") + end + + local text = translate( + 'If you want the location of your node to ' .. + 'be displayed on the map, you can enter its coordinates here.' + ) + if show_altitude() then + text = text .. ' ' .. translate("gluon-config-mode:altitude-help") + end + + local s = form:section(Section, nil, text) + + local o + + local share_location = s:option(Flag, "location", translate("Show node on the map")) + share_location.default = uci:get_bool("gluon-node-info", location, "share_location") + function share_location:write(data) + uci:set("gluon-node-info", location, "share_location", data) + end + + o = s:option(Value, "latitude", translate("Latitude"), translatef("e.g. %s", "53.873621")) + o.default = uci:get("gluon-node-info", location, "latitude") + o:depends(share_location, true) + o.datatype = "float" + function o:write(data) + uci:set("gluon-node-info", location, "latitude", data) + end + + o = s:option(Value, "longitude", translate("Longitude"), translatef("e.g. %s", "10.689901")) + o.default = uci:get("gluon-node-info", location, "longitude") + o:depends(share_location, true) + o.datatype = "float" + function o:write(data) + uci:set("gluon-node-info", location, "longitude", data) + end + + if show_altitude() then + o = s:option(Value, "altitude", translate("gluon-config-mode:altitude-label"), translatef("e.g. %s", "11.51")) + o.default = uci:get("gluon-node-info", location, "altitude") + o:depends(share_location, true) + o.datatype = "float" + o.optional = true + function o:write(data) + if data then + uci:set("gluon-node-info", location, "altitude", data) + else + uci:delete("gluon-node-info", location, "altitude") + end + end + end + + return {'gluon-node-info'} +end diff --git a/package/gluon-config-mode-hostname/Makefile b/package/gluon-config-mode-hostname/Makefile index 803f018f..2b24a640 100644 --- a/package/gluon-config-mode-hostname/Makefile +++ b/package/gluon-config-mode-hostname/Makefile @@ -5,7 +5,7 @@ PKG_VERSION:=1 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) -include $(GLUONDIR)/include/package.mk +include ../gluon.mk PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) @@ -26,10 +26,11 @@ endef define Build/Compile $(call GluonBuildI18N,gluon-config-mode-hostname,i18n) + $(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/) endef define Package/gluon-config-mode-hostname/install - $(CP) ./files/* $(1)/ + $(CP) $(PKG_BUILD_DIR)/luadest/* $(1)/ $(call GluonInstallI18N,gluon-config-mode-hostname,$(1)) endef 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 deleted file mode 100644 index cf8bbf89..00000000 --- a/package/gluon-config-mode-hostname/files/lib/gluon/config-mode/wizard/0100-hostname.lua +++ /dev/null @@ -1,21 +0,0 @@ -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/fr.po b/package/gluon-config-mode-hostname/i18n/fr.po new file mode 100644 index 00000000..79702c06 --- /dev/null +++ b/package/gluon-config-mode-hostname/i18n/fr.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-08-12 23:30+0100\n" +"Last-Translator:Tobias Bernot \n" +"Language-Team: French\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "Node name" +msgstr "Nom du nœud" diff --git a/package/gluon-config-mode-hostname/luasrc/lib/gluon/config-mode/wizard/0100-hostname.lua b/package/gluon-config-mode-hostname/luasrc/lib/gluon/config-mode/wizard/0100-hostname.lua new file mode 100644 index 00000000..8661d4bd --- /dev/null +++ b/package/gluon-config-mode-hostname/luasrc/lib/gluon/config-mode/wizard/0100-hostname.lua @@ -0,0 +1,13 @@ +return function(form, uci) + local pretty_hostname = require "pretty_hostname" + + local s = form:section(Section) + local o = s:option(Value, "hostname", translate("Node name")) + o.default = pretty_hostname.get(uci) + + function o:write(data) + pretty_hostname.set(uci, data) + end + + return {'system'} +end diff --git a/package/gluon-config-mode-mesh-vpn/Makefile b/package/gluon-config-mode-mesh-vpn/Makefile index 6a8a3f2c..20e5c016 100644 --- a/package/gluon-config-mode-mesh-vpn/Makefile +++ b/package/gluon-config-mode-mesh-vpn/Makefile @@ -5,7 +5,7 @@ PKG_VERSION:=2 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) -include $(GLUONDIR)/include/package.mk +include ../gluon.mk PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) @@ -14,7 +14,7 @@ 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 + DEPENDS:=gluon-config-mode-core-virtual +gluon-mesh-vpn-core endef define Build/Prepare @@ -26,10 +26,11 @@ endef define Build/Compile $(call GluonBuildI18N,gluon-config-mode-mesh-vpn,i18n) + $(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/) endef define Package/gluon-config-mode-mesh-vpn/install - $(CP) ./files/* $(1)/ + $(CP) $(PKG_BUILD_DIR)/luadest/* $(1)/ $(call GluonInstallI18N,gluon-config-mode-mesh-vpn,$(1)) endef 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 deleted file mode 100644 index 1b32c731..00000000 --- a/package/gluon-config-mode-mesh-vpn/files/lib/gluon/config-mode/reboot/0100-mesh-vpn.lua +++ /dev/null @@ -1,29 +0,0 @@ -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 deleted file mode 100644 index 669a7bc3..00000000 --- a/package/gluon-config-mode-mesh-vpn/files/lib/gluon/config-mode/wizard/0300-mesh-vpn.lua +++ /dev/null @@ -1,64 +0,0 @@ -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 index 8c613aa0..06d44b8c 100644 --- a/package/gluon-config-mode-mesh-vpn/i18n/de.po +++ b/package/gluon-config-mode-mesh-vpn/i18n/de.po @@ -1,8 +1,8 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"PO-Revision-Date: 2015-03-19 22:05+0100\n" -"Last-Translator: Matthias Schiffer \n" +"PO-Revision-Date: 2015-10-07 00:32+0100\n" +"Last-Translator: Cyrus Fox \n" "Language-Team: German\n" "Language: de\n" "MIME-Version: 1.0\n" @@ -23,14 +23,14 @@ msgid "Use internet connection (mesh VPN)" msgstr "Internetverbindung nutzen (Mesh-VPN)" msgid "" -"Your internet connection can be used to establish an encrypted connection " +"Your internet connection can be used to establish a VPN 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 " +"VPN-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/fr.po b/package/gluon-config-mode-mesh-vpn/i18n/fr.po new file mode 100644 index 00000000..0c324f32 --- /dev/null +++ b/package/gluon-config-mode-mesh-vpn/i18n/fr.po @@ -0,0 +1,31 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2015-08-12 23:30+0100\n" +"Last-Translator:Tobias Bernot \n" +"Language-Team: French\n" +"Language: fr\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 "Débit déscendant (kbit/s)" + +msgid "Limit bandwidth" +msgstr "Limiter la bande passante" + +msgid "Upstream (kbit/s)" +msgstr "Débit ascendant (kbit/s)" + +msgid "Use internet connection (mesh VPN)" +msgstr "Utiliser la connection internet (Mesh-VPN)" + +msgid "" +"Your internet connection can be used to establish a VPN 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-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 index 52e2eef8..b6722919 100644 --- 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 @@ -14,7 +14,7 @@ msgid "Use internet connection (mesh VPN)" msgstr "" msgid "" -"Your internet connection can be used to establish an encrypted connection " +"Your internet connection can be used to establish a VPN 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 " diff --git a/package/gluon-config-mode-mesh-vpn/luasrc/lib/gluon/config-mode/reboot/0100-mesh-vpn.lua b/package/gluon-config-mode-mesh-vpn/luasrc/lib/gluon/config-mode/reboot/0100-mesh-vpn.lua new file mode 100644 index 00000000..4901aa5d --- /dev/null +++ b/package/gluon-config-mode-mesh-vpn/luasrc/lib/gluon/config-mode/reboot/0100-mesh-vpn.lua @@ -0,0 +1,34 @@ +local uci = require("simple-uci").cursor() +local lutil = require "gluon.web.util" + +local site = require 'gluon.site_config' +local sysconfig = require 'gluon.sysconfig' +local util = require "gluon.util" + +local pretty_hostname = require 'pretty_hostname' + + +local meshvpn_enabled = uci:get_bool("fastd", "mesh_vpn", "enabled") + +local hostname = pretty_hostname.get(uci) +local contact = uci:get_first("gluon-node-info", "owner", "contact") + +local pubkey +local msg + +if meshvpn_enabled then + pubkey = util.trim(lutil.exec("/etc/init.d/fastd show_key mesh_vpn")) + msg = _translate('gluon-config-mode:pubkey') +else + msg = _translate('gluon-config-mode:novpn') +end + +if not msg then return end + +renderer.render_string(msg, { + pubkey = pubkey, + hostname = hostname, + site = site, + sysconfig = sysconfig, + contact = contact, +}) diff --git a/package/gluon-config-mode-mesh-vpn/luasrc/lib/gluon/config-mode/wizard/0300-mesh-vpn.lua b/package/gluon-config-mode-mesh-vpn/luasrc/lib/gluon/config-mode/wizard/0300-mesh-vpn.lua new file mode 100644 index 00000000..69a64bd0 --- /dev/null +++ b/package/gluon-config-mode-mesh-vpn/luasrc/lib/gluon/config-mode/wizard/0300-mesh-vpn.lua @@ -0,0 +1,61 @@ +local fs = require "nixio.fs" + +local has_fastd = fs.access('/lib/gluon/mesh-vpn/fastd') +local has_tunneldigger = fs.access('/lib/gluon/mesh-vpn/tunneldigger') + +return function(form, uci) + if not (has_fastd or has_tunneldigger) then + return + end + + local msg = translate( + 'Your internet connection can be used to establish a ' .. + 'VPN 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(Section, nil, msg) + + local o + + local meshvpn = s:option(Flag, "meshvpn", translate("Use internet connection (mesh VPN)")) + meshvpn.default = uci:get_bool("fastd", "mesh_vpn", "enabled") or uci:get_bool("tunneldigger", "mesh_vpn", "enabled") + function meshvpn:write(data) + if has_fastd then + uci:set("fastd", "mesh_vpn", "enabled", data) + end + if has_tunneldigger then + uci:set("tunneldigger", "mesh_vpn", "enabled", data) + end + end + + local limit = s:option(Flag, "limit_enabled", translate("Limit bandwidth")) + limit:depends(meshvpn, true) + limit.default = uci:get_bool("simple-tc", "mesh_vpn", "enabled") + function limit:write(data) + uci:set("simple-tc", "mesh_vpn", "interface") + uci:set("simple-tc", "mesh_vpn", "enabled", data) + uci:set("simple-tc", "mesh_vpn", "ifname", "mesh-vpn") + end + + o = s:option(Value, "limit_ingress", translate("Downstream (kbit/s)")) + o:depends(limit, true) + o.default = uci:get("simple-tc", "mesh_vpn", "limit_ingress") + o.datatype = "uinteger" + function o:write(data) + uci:set("simple-tc", "mesh_vpn", "limit_ingress", data) + end + + o = s:option(Value, "limit_egress", translate("Upstream (kbit/s)")) + o:depends(limit, true) + o.default = uci:get("simple-tc", "mesh_vpn", "limit_egress") + o.datatype = "uinteger" + function o:write(data) + uci:set("simple-tc", "mesh_vpn", "limit_egress", data) + end + + return {'fastd', 'tunneldigger', 'simple-tc'} +end diff --git a/package/gluon-core/Makefile b/package/gluon-core/Makefile index bf9768e2..b4a2692e 100644 --- a/package/gluon-core/Makefile +++ b/package/gluon-core/Makefile @@ -1,40 +1,40 @@ include $(TOPDIR)/rules.mk PKG_NAME:=gluon-core -PKG_VERSION:=3 -PKG_RELEASE:=$(GLUON_VERSION) + +GLUON_VERSION = $(shell git describe --always --dirty=+ 2>/dev/null || echo unknown) +PKG_VERSION:=$(if $(DUMP),x,$(GLUON_VERSION)) + PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) -include $(GLUONDIR)/include/package.mk +include ../gluon.mk + define Package/gluon-core SECTION:=gluon CATEGORY:=Gluon TITLE:=Base files of Gluon - DEPENDS:=+gluon-site +lua-platform-info +luci-base +odhcp6c +firewall + DEPENDS:=+gluon-site +libgluonutil +lua-platform-info +lua-simple-uci +lua-hash +luci-lib-jsonc +luci-lib-nixio +odhcp6c +firewall +pretty-hostname 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 + $(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/) endef define Package/gluon-core/install $(CP) ./files/* $(1)/ + $(CP) $(PKG_BUILD_DIR)/luadest/* $(1)/ $(INSTALL_DIR) $(1)/lib/gluon - echo "$(GLUON_VERSION)" > $(1)/lib/gluon/gluon-version + echo '$(GLUON_VERSION)' > $(1)/lib/gluon/gluon-version endef define Package/gluon-core/postinst diff --git a/package/gluon-core/check_site.lua b/package/gluon-core/check_site.lua index 1a6987a0..d26b1671 100644 --- a/package/gluon-core/check_site.lua +++ b/package/gluon-core/check_site.lua @@ -1,10 +1,73 @@ need_string 'site_code' need_string 'site_name' +if need_table('opkg', nil, false) then + need_string('opkg.lede', false) + + function check_repo(k, _) + -- this is not actually a uci name, but using the same naming rules here is fine + assert_uci_name(k) + + need_string(string.format('opkg.extra[%q]', k)) + end + + need_table('opkg.extra', check_repo, false) +end + 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+$') +need_string_match('prefix6', '^[%x:]+/64$') + + +for _, config in ipairs({'wifi24', 'wifi5'}) do + if need_table(config, nil, false) then + need_string('regdom') -- regdom is only required when wifi24 or wifi5 is configured + + need_number(config .. '.channel') + + local rates = {1000, 2000, 5500, 6000, 9000, 11000, 12000, 18000, 24000, 36000, 48000, 54000} + local supported_rates = need_array_of(config .. '.supported_rates', rates, false) + if supported_rates then + need_array_of(config .. '.basic_rate', supported_rates, true) + else + need_array_of(config .. '.basic_rate', rates, false) + end + end +end + +need_boolean('poe_passthrough', false) +if need_table('dns', nil, false) then + need_number('dns.cacheentries', false) + need_string_array_match('dns.servers', '^[%x:]+$', false) +end + +if need_table('next_node', nil, false) then + need_string_match('next_node.ip6', '^[%x:]+$', false) + need_string_match('next_node.ip4', '^%d+.%d+.%d+.%d+$', false) +end + +for _, config in ipairs({'wifi24', 'wifi5'}) do + local rates = {1000, 2000, 5500, 6000, 9000, 11000, 12000, 18000, 24000, 36000, 48000, 54000} + rates = need_array_of(config .. '.supported_rates', rates, false) or rates + + if need_table(config .. '.ibss', nil, false) then + need_string(config .. '.ibss.ssid') + need_string_match(config .. '.ibss.bssid', '^%x[02468aAcCeE]:%x%x:%x%x:%x%x:%x%x:%x%x$') + need_one_of(config .. '.ibss.mcast_rate', rates, false) + need_number(config .. '.ibss.vlan', false) + need_boolean(config .. '.ibss.disabled', false) + end + + if need_table(config .. '.mesh', nil, false) then + need_string(config .. '.mesh.id') + need_one_of(config .. '.mesh.mcast_rate', rates, false) + need_boolean(config .. '.mesh.disabled', false) + end +end + +need_boolean('mesh_on_wan', false) +need_boolean('mesh_on_lan', false) +need_boolean('single_as_lan', false) diff --git a/package/gluon-core/files/etc/config/gluon-core b/package/gluon-core/files/etc/config/gluon-core new file mode 100644 index 00000000..9787ccc9 --- /dev/null +++ b/package/gluon-core/files/etc/config/gluon-core @@ -0,0 +1 @@ +config wireless diff --git a/package/gluon-core/files/etc/hotplug.d/ieee80211/01-gluon-core-codel-memusage b/package/gluon-core/files/etc/hotplug.d/ieee80211/01-gluon-core-codel-memusage new file mode 100755 index 00000000..cf0f1740 --- /dev/null +++ b/package/gluon-core/files/etc/hotplug.d/ieee80211/01-gluon-core-codel-memusage @@ -0,0 +1,8 @@ +#!/bin/sh +if [ "${ACTION}" = "add" ]; then + + RAM=$(awk '/MemTotal/ {print $2}' /proc/meminfo) + if [ "$RAM" -lt $((48*1024)) ]; then + echo "fq_memory_limit 1048576" > "/sys/kernel/debug/ieee80211/$DEVICENAME/aqm" + fi +fi diff --git a/package/gluon-cron/files/lib/gluon/cron/.keep b/package/gluon-core/files/lib/gluon/core/mesh/setup.d/.keep similarity index 100% rename from package/gluon-cron/files/lib/gluon/cron/.keep rename to package/gluon-core/files/lib/gluon/core/mesh/setup.d/.keep diff --git a/package/gluon-core/files/lib/gluon/core/mesh/teardown.d/.keep b/package/gluon-core/files/lib/gluon/core/mesh/teardown.d/.keep new file mode 100644 index 00000000..e69de29b diff --git a/package/gluon-core/files/lib/gluon/upgrade/010-primary-mac b/package/gluon-core/files/lib/gluon/upgrade/010-primary-mac deleted file mode 100755 index d7c6e968..00000000 --- a/package/gluon-core/files/lib/gluon/upgrade/010-primary-mac +++ /dev/null @@ -1,42 +0,0 @@ -#!/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 'nixio.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 deleted file mode 100755 index a051c738..00000000 --- a/package/gluon-core/files/lib/gluon/upgrade/020-interfaces +++ /dev/null @@ -1,36 +0,0 @@ -#!/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/140-firewall-rules b/package/gluon-core/files/lib/gluon/upgrade/140-firewall-rules deleted file mode 100755 index 792e06a2..00000000 --- a/package/gluon-core/files/lib/gluon/upgrade/140-firewall-rules +++ /dev/null @@ -1,30 +0,0 @@ -#!/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 deleted file mode 100755 index 219e505d..00000000 --- a/package/gluon-core/files/lib/gluon/upgrade/200-wireless +++ /dev/null @@ -1,12 +0,0 @@ -#!/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/998-commit b/package/gluon-core/files/lib/gluon/upgrade/998-commit new file mode 100755 index 00000000..db578a78 --- /dev/null +++ b/package/gluon-core/files/lib/gluon/upgrade/998-commit @@ -0,0 +1,3 @@ +#!/bin/sh + +exec uci commit diff --git a/package/gluon-core/files/lib/netifd/proto/gluon_mesh.sh b/package/gluon-core/files/lib/netifd/proto/gluon_mesh.sh new file mode 100755 index 00000000..e84e057c --- /dev/null +++ b/package/gluon-core/files/lib/netifd/proto/gluon_mesh.sh @@ -0,0 +1,49 @@ +#!/bin/sh + +. /lib/functions.sh +. ../netifd-proto.sh +init_proto "$@" + +proto_gluon_mesh_init_config() { + proto_config_add_boolean fixed_mtu + proto_config_add_boolean transitive +} + +proto_gluon_mesh_setup() { + export CONFIG="$1" + export IFNAME="$2" + + local fixed_mtu transitive + json_get_vars fixed_mtu transitive + + export FIXED_MTU="${fixed_mtu:-0}" + export TRANSITIVE="${transitive:-0}" + + for script in /lib/gluon/core/mesh/setup.d/*; do + [ ! -x "$script" ] || "$script" + done + + proto_init_update "$IFNAME" 1 + + proto_add_data + json_add_boolean fixed_mtu "$FIXED_MTU" + json_add_boolean transitive "$TRANSITIVE" + proto_close_data + + proto_send_update "$CONFIG" + + for script in /lib/gluon/core/mesh/post-setup.d/*; do + [ ! -x "$script" ] || "$script" + done +} + +proto_gluon_mesh_teardown() { + export CONFIG="$1" + export IFNAME="$2" + + for script in /lib/gluon/core/mesh/teardown.d/*; do + [ ! -x "$script" ] || "$script" + done +} + +add_protocol gluon_mesh 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 deleted file mode 100644 index cf151483..00000000 --- a/package/gluon-core/files/usr/lib/lua/gluon/site_config.lua +++ /dev/null @@ -1,21 +0,0 @@ -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/sysctl.lua b/package/gluon-core/files/usr/lib/lua/gluon/sysctl.lua deleted file mode 100644 index 44b0c217..00000000 --- a/package/gluon-core/files/usr/lib/lua/gluon/sysctl.lua +++ /dev/null @@ -1,8 +0,0 @@ -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/util.lua b/package/gluon-core/files/usr/lib/lua/gluon/util.lua deleted file mode 100644 index cf3677cb..00000000 --- a/package/gluon-core/files/usr/lib/lua/gluon/util.lua +++ /dev/null @@ -1,79 +0,0 @@ --- 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-core/files/lib/gluon/upgrade/001-upgrade b/package/gluon-core/luasrc/lib/gluon/upgrade/001-upgrade similarity index 100% rename from package/gluon-core/files/lib/gluon/upgrade/001-upgrade rename to package/gluon-core/luasrc/lib/gluon/upgrade/001-upgrade diff --git a/package/gluon-core/luasrc/lib/gluon/upgrade/010-primary-mac b/package/gluon-core/luasrc/lib/gluon/upgrade/010-primary-mac new file mode 100755 index 00000000..ba6c3c4c --- /dev/null +++ b/package/gluon-core/luasrc/lib/gluon/upgrade/010-primary-mac @@ -0,0 +1,54 @@ +#!/usr/bin/lua + +local sysconfig = require 'gluon.sysconfig' + + +if sysconfig.primary_mac then + os.exit(0) +end + + +local util = require 'gluon.util' +local platform = require 'gluon.platform' + +local fs = require 'nixio.fs' + + +local try_files = { + '/sys/class/net/eth0/address' +} + +if not ( + util.contains({'x86', 'brcm2708'}, platform.get_target()) or + platform.match('ar71xx', 'mikrotik') +) then + table.insert(try_files, 1, '/sys/class/ieee80211/phy0/macaddress') +end + +if platform.match('ar71xx', 'generic', {'tl-wdr3600', 'tl-wdr4300'}) then + table.insert(try_files, 1, '/sys/class/ieee80211/phy1/macaddress') +elseif platform.match('ramips', 'mt7621', {'dir-860l-b1'}) then + table.insert(try_files, 1, '/sys/class/ieee80211/phy1/macaddress') +elseif platform.match('ar71xx', 'generic', {'unifi-outdoor-plus', 'carambola2', + 'mr600', 'mr600v2', + 'mr900', 'mr900v2', + 'mr1750', 'mr1750v2', + 'om2p', 'om2pv2', + 'om2p-hs', 'om2p-hsv2', 'om2p-hsv3', + 'om2p-lc', + 'om5p', 'om5p-an', + 'om5p-ac', 'om5p-acv2'}) then + table.insert(try_files, 1, '/sys/class/net/eth0/address') +elseif 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/luasrc/lib/gluon/upgrade/020-interfaces b/package/gluon-core/luasrc/lib/gluon/upgrade/020-interfaces new file mode 100755 index 00000000..d1b6cee2 --- /dev/null +++ b/package/gluon-core/luasrc/lib/gluon/upgrade/020-interfaces @@ -0,0 +1,64 @@ +#!/usr/bin/lua + +local sysconfig = require 'gluon.sysconfig' + +-- Are we already set up? +if sysconfig.lan_ifname or sysconfig.wan_ifname then + os.exit(0) +end + + +local util = require 'gluon.util' +local platform = require 'gluon.platform' +local site = require 'gluon.site_config' + +local fs = require 'nixio.fs' +local uci = require('simple-uci').cursor() + + +local function iface_exists(ifaces) + if not ifaces then return nil end + + for iface in ifaces:gmatch('%S+') do + if fs.access('/sys/class/net/' .. iface:gsub('%..*$', '')) then + return ifaces + end + end +end + + +local lan_ifname = iface_exists(uci:get('network', 'lan', 'ifname')) +local wan_ifname = iface_exists(uci:get('network', 'wan', 'ifname')) + +if platform.match('ar71xx', 'generic', { + 'cpe210', + 'cpe510', + 'wbs210', + 'wbs510', + 'airgateway', + 'nanostation-m', + 'nanostation-m-xw', + 'unifi-outdoor-plus', + 'uap-pro', + 'unifiac-pro', +}) then + lan_ifname, wan_ifname = wan_ifname, lan_ifname +end + +if wan_ifname and lan_ifname then + sysconfig.wan_ifname = wan_ifname + sysconfig.lan_ifname = lan_ifname +else + local single_ifname = lan_ifname or wan_ifname + if site.single_as_lan then + sysconfig.lan_ifname = single_ifname + else + sysconfig.wan_ifname = single_ifname + end +end + + +uci:delete('network', 'lan') +uci:delete('network', 'wan') + +uci:save('network') diff --git a/package/gluon-core/files/lib/gluon/upgrade/030-system b/package/gluon-core/luasrc/lib/gluon/upgrade/030-system similarity index 65% rename from package/gluon-core/files/lib/gluon/upgrade/030-system rename to package/gluon-core/luasrc/lib/gluon/upgrade/030-system index d7a66605..e51d9f73 100755 --- a/package/gluon-core/files/lib/gluon/upgrade/030-system +++ b/package/gluon-core/luasrc/lib/gluon/upgrade/030-system @@ -1,18 +1,18 @@ #!/usr/bin/lua +local pretty_hostname = require 'pretty_hostname' 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 uci = require('simple-uci').cursor() local system = uci:get_first('system', 'system') - uci:set('system', system, 'hostname', (site.hostname_prefix or '') .. util.node_id()) + pretty_hostname.set(uci, (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/110-network b/package/gluon-core/luasrc/lib/gluon/upgrade/110-network similarity index 58% rename from package/gluon-core/files/lib/gluon/upgrade/110-network rename to package/gluon-core/luasrc/lib/gluon/upgrade/110-network index 07961788..6ca0dc84 100755 --- a/package/gluon-core/files/lib/gluon/upgrade/110-network +++ b/package/gluon-core/luasrc/lib/gluon/upgrade/110-network @@ -1,6 +1,6 @@ #!/usr/bin/lua -local uci = require('luci.model.uci').cursor() +local uci = require('simple-uci').cursor() local sysctl = require 'gluon.sysctl' local sysconfig = require 'gluon.sysconfig' @@ -9,9 +9,10 @@ uci:section('network', 'interface', 'wan', { ifname = sysconfig.wan_ifname, type = 'bridge', - igmp_snooping = 0, - peerdns = 0, - auto = 1, + igmp_snooping = true, + multicast_querier = false, + peerdns = false, + auto = true, } ) @@ -23,8 +24,9 @@ end uci:section('network', 'interface', 'wan6', { ifname = 'br-wan', - peerdns = 0, + peerdns = false, ip6table = 1, + sourcefilter = false, } ) @@ -52,7 +54,31 @@ uci:section('network', 'route6', 'wan6_unreachable', ) uci:save('network') -uci:commit('network') + + +uci:section('firewall', 'rule', 'wan_igmp', + { + name = 'Allow-IGMP', + src = 'wan', + proto = 'igmp', + family = 'ipv4', + target = 'ACCEPT', + } +) + +uci:section('firewall', 'rule', 'wan_mld', + { + name = 'Allow-MLD', + src = 'wan', + proto = 'icmp', + src_ip = 'fe80::/10', + icmp_type = { '130/0', '131/0', '132/0', '143/0', }, + family = 'ipv6', + target = 'ACCEPT', + } +) + +uci:save('firewall') sysctl.set('net.ipv6.conf.all.accept_ra', 0) diff --git a/package/gluon-core/files/lib/gluon/upgrade/120-ntp-servers b/package/gluon-core/luasrc/lib/gluon/upgrade/120-ntp-servers similarity index 82% rename from package/gluon-core/files/lib/gluon/upgrade/120-ntp-servers rename to package/gluon-core/luasrc/lib/gluon/upgrade/120-ntp-servers index 2b3a2df6..2afe3a2a 100755 --- a/package/gluon-core/files/lib/gluon/upgrade/120-ntp-servers +++ b/package/gluon-core/luasrc/lib/gluon/upgrade/120-ntp-servers @@ -1,7 +1,7 @@ #!/usr/bin/lua local site = require 'gluon.site_config' -local uci = require 'luci.model.uci' +local uci = require 'simple-uci' if not site.ntp_servers or #site.ntp_servers == 0 then os.exit(0) @@ -11,4 +11,3 @@ 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/luasrc/lib/gluon/upgrade/130-reboot-on-oom similarity index 100% rename from package/gluon-core/files/lib/gluon/upgrade/130-reboot-on-oom rename to package/gluon-core/luasrc/lib/gluon/upgrade/130-reboot-on-oom diff --git a/package/gluon-core/luasrc/lib/gluon/upgrade/140-firewall-rules b/package/gluon-core/luasrc/lib/gluon/upgrade/140-firewall-rules new file mode 100755 index 00000000..9af4e515 --- /dev/null +++ b/package/gluon-core/luasrc/lib/gluon/upgrade/140-firewall-rules @@ -0,0 +1,25 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local uci = require('simple-uci').cursor() + + +local function reject_input_on_wan(zone) + if zone.name == 'wan' then + uci:set('firewall', zone['.name'], 'input', 'REJECT') + uci:set('firewall', zone['.name'], 'conntrack', true) + end + + return true +end +uci:foreach('firewall', 'zone', reject_input_on_wan) + +uci:section('firewall', 'rule', 'wan_ssh', { + name = 'wan_ssh', + src = 'wan', + dest_port = '22', + proto = 'tcp', + target = 'ACCEPT', +}) + +uci:save('firewall') diff --git a/package/gluon-core/luasrc/lib/gluon/upgrade/150-poe-passthrough b/package/gluon-core/luasrc/lib/gluon/upgrade/150-poe-passthrough new file mode 100755 index 00000000..1ee362b8 --- /dev/null +++ b/package/gluon-core/luasrc/lib/gluon/upgrade/150-poe-passthrough @@ -0,0 +1,13 @@ +#!/usr/bin/lua + +local sysconfig = require 'gluon.sysconfig' +local site = require 'gluon.site_config' + +if (not sysconfig.gluon_version) and site.poe_passthrough then + local uci = require('simple-uci').cursor() + + if uci:get('system', 'gpio_switch_poe_passthrough') then + uci:set('system', 'gpio_switch_poe_passthrough', 'value', true) + uci:save('system') + end +end diff --git a/package/gluon-core/luasrc/lib/gluon/upgrade/200-wireless b/package/gluon-core/luasrc/lib/gluon/upgrade/200-wireless new file mode 100755 index 00000000..ba844950 --- /dev/null +++ b/package/gluon-core/luasrc/lib/gluon/upgrade/200-wireless @@ -0,0 +1,216 @@ +#!/usr/bin/lua + +local util = require 'gluon.util' +local site = require 'gluon.site_config' +local sysconfig = require 'gluon.sysconfig' + +local uci = require('simple-uci').cursor() + +-- Initial +if not sysconfig.gluon_version then + uci:delete_all('wireless', 'wifi-iface') +end + +local function get_channel(radio, config) + if uci:get_first('gluon-core', 'wireless', 'preserve_channels') then + return uci:get('wireless', radio, 'channel') or config.channel + else + return config.channel + end +end + +local function is_disabled(name) + if uci:get('wireless', name) then + return uci:get_bool('wireless', name, 'disabled') + else + return false + end +end + +-- Returns the first argument that is not nil; don't call without any non-nil arguments! +local function first_non_nil(first, ...) + if first ~= nil then + return first + else + return first_non_nil(...) + end +end + + +local function configure_ibss(config, radio, index, suffix, disabled) + local name = 'ibss_' .. radio + + uci:delete('network', name) + uci:delete('network', name .. '_vlan') + uci:delete('wireless', name) + + if not config then + return + end + + local macaddr = util.get_wlan_mac(uci, radio, index, 3) + if not macaddr then + return + end + + if config.vlan then + uci:section('network', 'interface', name, + { + proto = 'none', + } + ) + + uci:section('network', 'interface', name .. '_vlan', + { + ifname = '@' .. name .. '.' .. config.vlan, + proto = 'gluon_mesh', + } + ) + else + uci:section('network', 'interface', name, + { + proto = 'gluon_mesh', + } + ) + end + + uci:section('wireless', 'wifi-iface', name, + { + device = radio, + network = name, + mode = 'adhoc', + ssid = config.ssid, + bssid = config.bssid, + macaddr = macaddr, + mcast_rate = config.mcast_rate, + ifname = suffix and 'ibss' .. suffix, + disabled = disabled, + } + ) +end + +local function configure_mesh(config, radio, index, suffix, disabled) + local name = 'mesh_' .. radio + local macfilter = uci:get('wireless', name, 'macfilter') + local maclist = uci:get('wireless', name, 'maclist') + + uci:delete('network', name) + uci:delete('network', name .. '_vlan') + uci:delete('wireless', name) + + if not config then + return + end + + local macaddr = util.get_wlan_mac(uci, radio, index, 2) + if not macaddr then + return + end + + uci:section('network', 'interface', name, + { + proto = 'gluon_mesh', + } + ) + + uci:section('wireless', 'wifi-iface', name, + { + device = radio, + network = name, + mode = 'mesh', + mesh_id = config.id, + mesh_fwding = false, + macaddr = macaddr, + mcast_rate = config.mcast_rate, + ifname = suffix and 'mesh' .. suffix, + disabled = disabled, + macfilter = macfilter, + maclist = maclist, + } + ) +end + +local function fixup_wan(radio, index) + local name = 'wan_' .. radio + + if not uci:get('wireless', name) then + return + end + + local macaddr = util.get_wlan_mac(uci, radio, index, 4) + if not macaddr then + return + end + + uci:set('wireless', name, 'macaddr', macaddr) +end + +local function configure_radio(radio, index, config) + if not config then + return + end + + local suffix = radio:match('^radio(%d+)$') + if not suffix then + return + end + + local channel = get_channel(radio, config) + + uci:delete('wireless', radio, 'disabled') + + uci:set('wireless', radio, 'channel', channel) + uci:set('wireless', radio, 'htmode', 'HT20') + uci:set('wireless', radio, 'country', site.regdom) + + if config.supported_rates then + uci:set_list('wireless', radio, 'supported_rates', config.supported_rates) + else + uci:delete('wireless', radio, 'supported_rates') + end + + if config.basic_rate then + uci:set_list('wireless', radio, 'basic_rate', config.basic_rate) + else + uci:delete('wireless', radio, 'basic_rate') + end + + + local ibss_disabled = is_disabled('ibss_' .. radio) + local mesh_disabled = is_disabled('mesh_' .. radio) + + configure_ibss(config.ibss, radio, index, suffix, + first_non_nil( + ibss_disabled, + mesh_disabled, + (config.ibss or {}).disabled, -- will be nil if config.ibss or config.ibss.disabled is unset + false + ) + ) + configure_mesh(config.mesh, radio, index, suffix, + first_non_nil( + mesh_disabled, + ibss_disabled, + (config.mesh or {}).disabled, -- will be nil if config.mesh or config.mesh.disabled is unset + false + ) + ) + + fixup_wan(radio, index) +end + +util.iterate_radios(uci, configure_radio) + + +if uci:get('system', 'rssid_wlan0') then + if uci:get('wireless', 'mesh_radio0') then + uci:set('system', 'rssid_wlan0', 'dev', 'mesh0') + else + uci:set('system', 'rssid_wlan0', 'dev', 'ibss0') + end + + uci:save('system') +end + +uci:save('wireless') +uci:save('network') diff --git a/package/gluon-core/luasrc/lib/gluon/upgrade/210-interface-wan b/package/gluon-core/luasrc/lib/gluon/upgrade/210-interface-wan new file mode 100755 index 00000000..c5bb11ad --- /dev/null +++ b/package/gluon-core/luasrc/lib/gluon/upgrade/210-interface-wan @@ -0,0 +1,16 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local uci = require('simple-uci').cursor() + +if not uci:get('network', 'mesh_wan') then + uci:section('network', 'interface', 'mesh_wan', { + ifname = 'br-wan', + proto = 'gluon_mesh', + transitive = true, + fixed_mtu = true, + auto = site.mesh_on_wan or false, + }) +end + +uci:save('network') diff --git a/package/gluon-core/luasrc/lib/gluon/upgrade/220-interface-lan b/package/gluon-core/luasrc/lib/gluon/upgrade/220-interface-lan new file mode 100755 index 00000000..0a093133 --- /dev/null +++ b/package/gluon-core/luasrc/lib/gluon/upgrade/220-interface-lan @@ -0,0 +1,41 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local util = require 'gluon.util' +local sysconfig = require 'gluon.sysconfig' + +local uci = require('simple-uci').cursor() + +if not sysconfig.lan_ifname then + os.exit(0) +end + +uci:section('network', 'interface', 'mesh_lan', { + ifname = sysconfig.lan_ifname, + type = 'bridge', + igmp_snooping = false, + proto = 'gluon_mesh', + transitive = true, + fixed_mtu = true, +}) + +if uci:get('network', 'mesh_lan', 'auto') == nil then + local enable = site.mesh_on_lan + + if enable then + local interfaces = uci:get_list('network', 'client', 'ifname') + + if interfaces then + for lanif in sysconfig.lan_ifname:gmatch('%S+') do + if util.contains(interfaces, lanif) then + enable = false + break + end + end + end + end + + uci:set('network', 'mesh_lan', 'auto', enable or false) +end + +uci:save('network') diff --git a/package/gluon-core/luasrc/lib/gluon/upgrade/500-opkg b/package/gluon-core/luasrc/lib/gluon/upgrade/500-opkg new file mode 100755 index 00000000..52742798 --- /dev/null +++ b/package/gluon-core/luasrc/lib/gluon/upgrade/500-opkg @@ -0,0 +1,66 @@ +#!/usr/bin/lua + +local fs = require 'nixio.fs' +local site = require 'gluon.site_config' +local util = require 'gluon.util' + + +local subst = {} + + +local f = io.popen('. /etc/openwrt_release; echo "$DISTRIB_CODENAME"; echo "$DISTRIB_RELEASE"; echo "$DISTRIB_TARGET"; echo "$DISTRIB_ARCH"') +subst['%%n'] = f:read() +subst['%%v'] = f:read():gsub('-SNAPSHOT', '') +subst['%%S'] = f:read() +subst['%%A'] = f:read() +f:close() + +subst['%%GS'] = site.site_code +subst['%%GV'] = util.trim(fs.readfile('/lib/gluon/gluon-version')) +subst['%%GR'] = util.trim(fs.readfile('/lib/gluon/release')) + +function replace_patterns(url) + for k, v in pairs(subst) do + url = url:gsub(k, v) + end + + return url +end + + +local prefix = subst['%%n'] .. '_' + +if fs.access('/etc/opkg/distfeeds.conf') then + local distfeeds = {} + for line in io.lines('/etc/opkg/distfeeds.conf') do + table.insert(distfeeds, line) + end + + local f = io.open('/etc/opkg/distfeeds.conf', 'w') + + for _, line in ipairs(distfeeds) do + local name = line:match('^src/gz%s' .. prefix .. '(%S+)%s') + if name == 'core' then + f:write('# ' .. line .. '\n') + elseif name and site.opkg and site.opkg.lede then + f:write(string.format('src/gz %s %s/%s\n', prefix .. name, replace_patterns(site.opkg.lede), name)) + else + f:write(line .. '\n') + end + end + + f:close() + + if site.opkg and site.opkg.extra and next(site.opkg.extra) then + local f = io.open('/etc/opkg/gluon.conf', 'w') + + for k, v in pairs(site.opkg.extra) do + f:write(string.format('src/gz %s %s\n', k, replace_patterns(v))) + end + + f:close() + + else + os.remove('/etc/opkg/gluon.conf') + end +end diff --git a/package/gluon-core/luasrc/lib/gluon/upgrade/800-migrate-batadv b/package/gluon-core/luasrc/lib/gluon/upgrade/800-migrate-batadv new file mode 100755 index 00000000..ddd03c0a --- /dev/null +++ b/package/gluon-core/luasrc/lib/gluon/upgrade/800-migrate-batadv @@ -0,0 +1,24 @@ +#!/usr/bin/lua + +local uci = require('simple-uci').cursor() + +local function migrate_iface(iface) + if iface.proto ~= 'batadv' or iface.mesh ~= 'bat0' then + return + end + + local s = iface['.name'] + + uci:set('network', s, 'proto', 'gluon_mesh') + uci:set('network', s, 'fixed_mtu', true) + + if iface.mesh_no_rebroadcast then + uci:set('network', s, 'transitive', iface.mesh_no_rebroadcast) + end + + uci:delete('network', s, 'mesh') + uci:delete('network', s, 'mesh_no_rebroadcast') +end + +uci:foreach('network', 'interface', migrate_iface) +uci:save('network') diff --git a/package/gluon-core/luasrc/lib/gluon/upgrade/820-dns-config b/package/gluon-core/luasrc/lib/gluon/upgrade/820-dns-config new file mode 100755 index 00000000..5b64b413 --- /dev/null +++ b/package/gluon-core/luasrc/lib/gluon/upgrade/820-dns-config @@ -0,0 +1,40 @@ +#!/usr/bin/lua +local site = require 'gluon.site_config' +local uci = require('simple-uci').cursor() + +dnsmasq=uci:get_first("dhcp", "dnsmasq") + +uci:set('dhcp', dnsmasq, 'localise_queries', true) +uci:set('dhcp', dnsmasq, 'localservice', false) + +if site.dns and site.dns.servers then + uci:set('dhcp', dnsmasq, 'server', site.dns.servers) +else + uci:delete('dhcp', dnsmasq, 'server') +end + +if site.dns and site.dns.cacheentries then + uci:set('dhcp', dnsmasq, 'cachesize', site.dns.cacheentries) +else + uci:delete('dhcp', dnsmasq, 'cachesize') +end + +if site.next_node and site.next_node.name and site.next_node.ip4 then + uci:section('dhcp','domain','nextnode4',{ + name=site.next_node.name, + ip=site.next_node.ip4, + }) +else + uci:delete('dhcp', 'domain', 'nextnode4') +end + +if site.next_node and site.next_node.name and site.next_node.ip6 then + uci:section('dhcp','domain','nextnode6',{ + name=site.next_node.name, + ip=site.next_node.ip6, + }) +else + uci:delete('dhcp', 'domain', 'nextnode6') +end +uci:save('dhcp') + diff --git a/package/gluon-core/files/lib/gluon/upgrade/999-version b/package/gluon-core/luasrc/lib/gluon/upgrade/999-version similarity index 89% rename from package/gluon-core/files/lib/gluon/upgrade/999-version rename to package/gluon-core/luasrc/lib/gluon/upgrade/999-version index 9731692e..608545b7 100755 --- a/package/gluon-core/files/lib/gluon/upgrade/999-version +++ b/package/gluon-core/luasrc/lib/gluon/upgrade/999-version @@ -3,7 +3,7 @@ local sysconfig = require 'gluon.sysconfig' local fs = require 'nixio.fs' -local util = require 'luci.util' +local util = require 'gluon.util' -- Save the Gluon version in the sysconfig so we know which version we diff --git a/package/gluon-core/files/usr/lib/lua/gluon/platform.lua b/package/gluon-core/luasrc/usr/lib/lua/gluon/platform.lua similarity index 79% rename from package/gluon-core/files/usr/lib/lua/gluon/platform.lua rename to package/gluon-core/luasrc/usr/lib/lua/gluon/platform.lua index 3d56f081..5b4f559a 100644 --- a/package/gluon-core/files/usr/lib/lua/gluon/platform.lua +++ b/package/gluon-core/luasrc/usr/lib/lua/gluon/platform.lua @@ -1,5 +1,5 @@ local platform_info = require 'platform_info' -local util = require 'luci.util' +local util = require 'gluon.util' local setmetatable = setmetatable @@ -21,11 +21,9 @@ function match(target, subtarget, boards) return false end - if not util.contains(boards, get_board_name()) then + if boards and not util.contains(boards, get_board_name()) then return false end return true end - - diff --git a/package/gluon-core/luasrc/usr/lib/lua/gluon/site_config.lua b/package/gluon-core/luasrc/usr/lib/lua/gluon/site_config.lua new file mode 100644 index 00000000..7e27525d --- /dev/null +++ b/package/gluon-core/luasrc/usr/lib/lua/gluon/site_config.lua @@ -0,0 +1,29 @@ +local function get_site_config() + local config = '/lib/gluon/site.json' + + local json = require 'luci.jsonc' + local decoder = json.new() + local sink = decoder:sink() + + local file = assert(io.open(config)) + + while true do + local chunk = file:read(2048) + if not chunk or chunk:len() == 0 then break end + sink(chunk) + end + + file:close() + + return assert(decoder:get()) +end + +local setmetatable = setmetatable + +module 'gluon.site_config' + +setmetatable(_M, { + __index = get_site_config(), +}) + +return _M diff --git a/package/gluon-core/files/usr/lib/lua/gluon/sysconfig.lua b/package/gluon-core/luasrc/usr/lib/lua/gluon/sysconfig.lua similarity index 100% rename from package/gluon-core/files/usr/lib/lua/gluon/sysconfig.lua rename to package/gluon-core/luasrc/usr/lib/lua/gluon/sysconfig.lua diff --git a/package/gluon-core/luasrc/usr/lib/lua/gluon/sysctl.lua b/package/gluon-core/luasrc/usr/lib/lua/gluon/sysctl.lua new file mode 100644 index 00000000..ee429437 --- /dev/null +++ b/package/gluon-core/luasrc/usr/lib/lua/gluon/sysctl.lua @@ -0,0 +1,12 @@ +local util = require 'gluon.util' + + +module 'gluon.sysctl' + +function set(name, value) + local new + if value then + new = name .. '=' .. value .. '\n' + end + util.replace_prefix('/etc/sysctl.conf', name .. '=', new) +end diff --git a/package/gluon-core/files/usr/lib/lua/gluon/users.lua b/package/gluon-core/luasrc/usr/lib/lua/gluon/users.lua similarity index 100% rename from package/gluon-core/files/usr/lib/lua/gluon/users.lua rename to package/gluon-core/luasrc/usr/lib/lua/gluon/users.lua diff --git a/package/gluon-core/luasrc/usr/lib/lua/gluon/util.lua b/package/gluon-core/luasrc/usr/lib/lua/gluon/util.lua new file mode 100644 index 00000000..80888c8b --- /dev/null +++ b/package/gluon-core/luasrc/usr/lib/lua/gluon/util.lua @@ -0,0 +1,255 @@ +-- 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 close_stdio(stream, mode) + local null = nixio.open('/dev/null', mode) + if null then + nixio.dup(null, nixio[stream]) + if null:fileno() > 2 then + null:close() + end + end +end + + +local io = io +local os = os +local string = string +local tonumber = tonumber +local ipairs = ipairs +local pairs = pairs +local table = table + +local nixio = require 'nixio' +local hash = require 'hash' +local sysconfig = require 'gluon.sysconfig' +local site = require 'gluon.site_config' +local fs = require 'nixio.fs' + + +module 'gluon.util' + +function trim(str) + return str:gsub("^%s*(.-)%s*$", "%1") +end + +function contains(table, value) + for k, v in pairs(table) do + if value == v then + return k + end + end + return false +end + +function add_to_set(t, itm) + for _,v in ipairs(t) do + if v == itm then return false end + end + table.insert(t, itm) + return true +end + +function remove_from_set(t, itm) + local i = 1 + local changed = false + while i <= #t do + if t[i] == itm then + table.remove(t, i) + changed = true + else + i = i + 1 + end + end + return changed +end + +function exec(...) + local pid, errno, error = nixio.fork() + if pid == 0 then + close_stdio('stdin', 'r') + close_stdio('stdout', 'w') + close_stdio('stderr', 'w') + + nixio.execp(...) + os.exit(127) + elseif pid > 0 then + local wpid, status, code = nixio.waitpid(pid) + return wpid and status == 'exited' and code + else + return nil, errno, error + end +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 readline(fd) + local line = fd:read('*l') + fd:close() + return line +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 + +function get_mesh_devices(uconn) + local dump = uconn:call("network.interface", "dump", {}) + local devices = {} + for _, interface in ipairs(dump.interface) do + if ( (interface.proto == "gluon_mesh") and interface.up ) then + table.insert(devices, interface.device) + end + end + return devices +end + +local function find_phy_by_path(path) + for phy in fs.glob('/sys/devices/' .. path .. '/ieee80211/phy*') do + return phy:match('([^/]+)$') + end + + for phy in fs.glob('/sys/devices/platform/' .. 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 trim(fs.readfile(file)) == addr then + return file:match('([^/]+)/macaddress$') + end + end +end + +function find_phy(config) + if not config or config.type ~= 'mac80211' then + return nil + elseif config.path then + return find_phy_by_path(config.path) + elseif config.macaddr then + return find_phy_by_macaddr(config.macaddr) + else + return nil + end +end + +local function get_addresses(uci, radio) + local phy = find_phy(uci:get_all('wireless', radio)) + if not phy then + return function() end + end + + return io.lines('/sys/class/ieee80211/' .. phy .. '/addresses') +end + +-- Generates a (hopefully) unique MAC address +-- The parameter defines the ID to add to the MAC address +-- +-- IDs defined so far: +-- 0: client0; WAN +-- 1: mesh0 +-- 2: ibss0 +-- 3: wan_radio0 (private WLAN); batman-adv primary address +-- 4: client1; LAN +-- 5: mesh1 +-- 6: ibss1 +-- 7: wan_radio1 (private WLAN); mesh VPN +function generate_mac(i) + if i > 7 or i < 0 then return nil end -- max allowed id (0b111) + + local hashed = string.sub(hash.md5(sysconfig.primary_mac), 0, 12) + local m1, m2, m3, m4, m5, m6 = string.match(hashed, '(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)') + + m1 = tonumber(m1, 16) + m6 = tonumber(m6, 16) + + m1 = nixio.bit.bor(m1, 0x02) -- set locally administered bit + m1 = nixio.bit.band(m1, 0xFE) -- unset the multicast bit + + -- It's necessary that the first 45 bits of the MAC address don't + -- vary on a single hardware interface, since some chips are using + -- a hardware MAC filter. (e.g 'rt305x') + + m6 = nixio.bit.band(m6, 0xF8) -- zero the last three bits (space needed for counting) + m6 = m6 + i -- add virtual interface id + + return string.format('%02x:%s:%s:%s:%s:%02x', m1, m2, m3, m4, m5, m6) +end + +local function get_wlan_mac_from_driver(uci, radio, vif) + local primary = sysconfig.primary_mac:lower() + + local i = 1 + for addr in get_addresses(uci, radio) do + if addr:lower() ~= primary then + if i == vif then + return addr + end + + i = i + 1 + end + end +end + +function get_wlan_mac(uci, radio, index, vif) + local addr = get_wlan_mac_from_driver(uci, radio, vif) + if addr then + return addr + end + + return generate_mac(4*(index-1) + (vif-1)) +end + +-- Iterate over all radios defined in UCI calling +-- f(radio, index, site.wifiX) for each radio found while passing +-- site.wifi24 for 2.4 GHz devices and site.wifi5 for 5 GHz ones. +function iterate_radios(uci, f) + 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 + f(radio, index, site.wifi24) + elseif hwmode == '11a' or hwmode == '11na' then + f(radio, index, site.wifi5) + end + end +end diff --git a/package/gluon-cron/Makefile b/package/gluon-cron/Makefile deleted file mode 100644 index ac92a92d..00000000 --- a/package/gluon-cron/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -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 deleted file mode 100755 index 27a05e1d..00000000 --- a/package/gluon-cron/files/etc/init.d/gluon-cron +++ /dev/null @@ -1,18 +0,0 @@ -#!/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/src/Makefile b/package/gluon-cron/src/Makefile deleted file mode 100644 index 3f4c7a50..00000000 --- a/package/gluon-cron/src/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -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 deleted file mode 100644 index 11a87c42..00000000 --- a/package/gluon-cron/src/gluon-crond.c +++ /dev/null @@ -1,316 +0,0 @@ -/* - 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 index 93b7f9a5..2b622902 100644 --- a/package/gluon-ebtables-filter-multicast/Makefile +++ b/package/gluon-ebtables-filter-multicast/Makefile @@ -8,6 +8,7 @@ PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) include $(INCLUDE_DIR)/package.mk + define Package/gluon-ebtables-filter-multicast SECTION:=gluon CATEGORY:=Gluon 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 deleted file mode 100644 index ec0013a3..00000000 --- a/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/100-mcast-chain +++ /dev/null @@ -1 +0,0 @@ -chain('MULTICAST_OUT', 'DROP') 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 deleted file mode 100644 index 25a95f39..00000000 --- a/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/110-mcast-allow-icmp +++ /dev/null @@ -1 +0,0 @@ -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 index a7b67414..0058ed86 100644 --- 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 @@ -1,2 +1,3 @@ -rule 'MULTICAST_OUT -p IPv6 --ip6-protocol 0 -j RETURN' -- hop-by-hop -rule 'MULTICAST_OUT -p IPv6 --ip6-protocol ipv6-icmp -j RETURN' +rule 'MULTICAST_OUT_ICMPV6 -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type echo-request -j RETURN' +rule 'MULTICAST_OUT_ICMPV6 -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type 139 -j RETURN' -- ICMP Node Information Query +rule 'MULTICAST_OUT_ICMPV6 -j ACCEPT' 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 deleted file mode 100644 index c52f122f..00000000 --- a/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/300-mcast +++ /dev/null @@ -1,2 +0,0 @@ -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-multicast/files/lib/gluon/ebtables/355-mcast-drop b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/355-mcast-drop new file mode 100644 index 00000000..46ac01a5 --- /dev/null +++ b/package/gluon-ebtables-filter-multicast/files/lib/gluon/ebtables/355-mcast-drop @@ -0,0 +1 @@ +rule ('MULTICAST_OUT -j DROP') diff --git a/package/gluon-ebtables-filter-ra-dhcp/Makefile b/package/gluon-ebtables-filter-ra-dhcp/Makefile index ea6a737d..acec081f 100644 --- a/package/gluon-ebtables-filter-ra-dhcp/Makefile +++ b/package/gluon-ebtables-filter-ra-dhcp/Makefile @@ -8,6 +8,7 @@ PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) include $(INCLUDE_DIR)/package.mk + define Package/gluon-ebtables-filter-ra-dhcp SECTION:=gluon CATEGORY:=Gluon diff --git a/package/gluon-ebtables-segment-mld/Makefile b/package/gluon-ebtables-segment-mld/Makefile new file mode 100644 index 00000000..e3aacde1 --- /dev/null +++ b/package/gluon-ebtables-segment-mld/Makefile @@ -0,0 +1,51 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-ebtables-segment-mld +PKG_VERSION:=1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + +define Package/gluon-ebtables-segment-mld + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Ebtables filters for IGMP/MLD packets + DEPENDS:=+gluon-core +gluon-ebtables +endef + +define Package/gluon-ebtables-segment-mld/description + Gluon community wifi mesh firmware framework: Ebtables filters for + IGMP/MLD packets + + These filters drop IGMP/MLD packets before they enter the mesh and + filter any IGMP/MLD packets coming from the mesh. + + IGMP/MLD have the concept of a local, elected Querier. For more + decentralization and increased robustness, the idea of this package is + to split the IGMP/MLD domain a querier is responsible for, allowing to + have a querier per node. The split IGMP/MLD domain will also reduce + overhead for this packet type, increasing scalability. + + Beware of the consequences of using this package though: You might need + to explicitly, manually mark ports on snooping switches leading towards + your mesh node as multicast router ports for now (Multicast Router + Discovery, MRD, not implemented yet). +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-ebtables-segment-mld/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,gluon-ebtables-segment-mld)) diff --git a/package/gluon-ebtables-segment-mld/files/lib/gluon/ebtables/100-mcast-in-chain b/package/gluon-ebtables-segment-mld/files/lib/gluon/ebtables/100-mcast-in-chain new file mode 100644 index 00000000..69d6bf18 --- /dev/null +++ b/package/gluon-ebtables-segment-mld/files/lib/gluon/ebtables/100-mcast-in-chain @@ -0,0 +1,2 @@ +chain('MULTICAST_IN', 'RETURN', 'nat') +chain('MULTICAST_IN_ICMPV6', 'RETURN', 'nat') diff --git a/package/gluon-ebtables-segment-mld/files/lib/gluon/ebtables/101-mcast-in-rule b/package/gluon-ebtables-segment-mld/files/lib/gluon/ebtables/101-mcast-in-rule new file mode 100644 index 00000000..4eef2e7e --- /dev/null +++ b/package/gluon-ebtables-segment-mld/files/lib/gluon/ebtables/101-mcast-in-rule @@ -0,0 +1,2 @@ +rule ('PREROUTING -d Multicast --logical-in br-client -i bat0 -j MULTICAST_IN', 'nat') +rule ('MULTICAST_IN -p IPv6 --ip6-protocol ipv6-icmp -j MULTICAST_IN_ICMPV6', 'nat') diff --git a/package/gluon-ebtables-segment-mld/files/lib/gluon/ebtables/105-mcast-drop-igmp b/package/gluon-ebtables-segment-mld/files/lib/gluon/ebtables/105-mcast-drop-igmp new file mode 100644 index 00000000..08052721 --- /dev/null +++ b/package/gluon-ebtables-segment-mld/files/lib/gluon/ebtables/105-mcast-drop-igmp @@ -0,0 +1,2 @@ +rule('MULTICAST_OUT -p IPv4 --ip-protocol igmp -j DROP') +rule('MULTICAST_IN -p IPv4 --ip-protocol igmp -j DROP', 'nat') diff --git a/package/gluon-ebtables-segment-mld/files/lib/gluon/ebtables/105-mcast-drop-mld b/package/gluon-ebtables-segment-mld/files/lib/gluon/ebtables/105-mcast-drop-mld new file mode 100644 index 00000000..b6090c22 --- /dev/null +++ b/package/gluon-ebtables-segment-mld/files/lib/gluon/ebtables/105-mcast-drop-mld @@ -0,0 +1,9 @@ +rule('MULTICAST_OUT_ICMPV6 -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type 130 -j DROP') -- MLD Query +rule('MULTICAST_OUT_ICMPV6 -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type 131 -j DROP') -- MLDv1 Report +rule('MULTICAST_OUT_ICMPV6 -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type 132 -j DROP') -- MLDv1 Done +rule('MULTICAST_OUT_ICMPV6 -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type 143 -j DROP') -- MLDv2 Report + +rule('MULTICAST_IN_ICMPV6 -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type 130 -j DROP', 'nat') -- MLD Query +rule('MULTICAST_IN_ICMPV6 -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type 131 -j DROP', 'nat') -- MLDv1 Report +rule('MULTICAST_IN_ICMPV6 -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type 132 -j DROP', 'nat') -- MLDv1 Done +rule('MULTICAST_IN_ICMPV6 -p IPv6 --ip6-protocol ipv6-icmp --ip6-icmp-type 143 -j DROP', 'nat') -- MLDv2 Report diff --git a/package/gluon-ebtables-source-filter/Makefile b/package/gluon-ebtables-source-filter/Makefile new file mode 100644 index 00000000..ebcbb5dc --- /dev/null +++ b/package/gluon-ebtables-source-filter/Makefile @@ -0,0 +1,43 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-ebtables-source-filter +PKG_VERSION:=1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include ../gluon.mk + + +define Package/gluon-ebtables-source-filter + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Ebtables rules to filter unreasonable L2 traffic. + DEPENDS:=+gluon-core +gluon-ebtables +endef + +define Package/gluon-ebtables-source-filter/description + This package adds an additional layer-2 filter-ruleset to prevent unreasonable + traffic entering the network via the nodes. +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-ebtables-source-filter/install + $(CP) ./files/* $(1)/ +endef + +define Package/gluon-ebtables-source-filter/postinst +#!/bin/sh +$(call GluonCheckSite,check_site.lua) +endef + +$(eval $(call BuildPackage,gluon-ebtables-source-filter)) diff --git a/package/gluon-ebtables-source-filter/check_site.lua b/package/gluon-ebtables-source-filter/check_site.lua new file mode 100644 index 00000000..815c7296 --- /dev/null +++ b/package/gluon-ebtables-source-filter/check_site.lua @@ -0,0 +1,2 @@ +need_string_match('prefix4', '^%d+.%d+.%d+.%d+/%d+$', false) +need_string_array_match('extra_prefixes6', '^[%x:]+/%d+$', false) diff --git a/package/gluon-ebtables-source-filter/files/lib/gluon/ebtables/100-local-forward-chain b/package/gluon-ebtables-source-filter/files/lib/gluon/ebtables/100-local-forward-chain new file mode 100644 index 00000000..b9f4467d --- /dev/null +++ b/package/gluon-ebtables-source-filter/files/lib/gluon/ebtables/100-local-forward-chain @@ -0,0 +1 @@ +chain('LOCAL_FORWARD', 'DROP') diff --git a/package/gluon-ebtables-source-filter/files/lib/gluon/ebtables/110-local-forward-allow-arp b/package/gluon-ebtables-source-filter/files/lib/gluon/ebtables/110-local-forward-allow-arp new file mode 100644 index 00000000..e8de3120 --- /dev/null +++ b/package/gluon-ebtables-source-filter/files/lib/gluon/ebtables/110-local-forward-allow-arp @@ -0,0 +1,6 @@ +prefix4 = require('gluon.site_config').prefix4 + +if prefix4 then + rule('LOCAL_FORWARD -p ARP --arp-ip-src ' .. prefix4 .. ' --arp-ip-dst ' .. prefix4 .. ' -j RETURN') + rule('LOCAL_FORWARD -p ARP --arp-ip-src 0.0.0.0 --arp-ip-dst ' .. prefix4 .. ' -j RETURN') +end diff --git a/package/gluon-ebtables-source-filter/files/lib/gluon/ebtables/110-local-forward-allow-ipv4 b/package/gluon-ebtables-source-filter/files/lib/gluon/ebtables/110-local-forward-allow-ipv4 new file mode 100644 index 00000000..048e700f --- /dev/null +++ b/package/gluon-ebtables-source-filter/files/lib/gluon/ebtables/110-local-forward-allow-ipv4 @@ -0,0 +1,6 @@ +prefix4 = require('gluon.site_config').prefix4 + +if prefix4 then + rule('LOCAL_FORWARD -p IPv4 --ip-protocol udp --ip-destination-port 67 -j RETURN') + rule('LOCAL_FORWARD -p IPv4 --ip-src ' .. prefix4 .. ' -j RETURN') +end diff --git a/package/gluon-ebtables-source-filter/files/lib/gluon/ebtables/110-local-forward-allow-ipv6 b/package/gluon-ebtables-source-filter/files/lib/gluon/ebtables/110-local-forward-allow-ipv6 new file mode 100644 index 00000000..9b2d1147 --- /dev/null +++ b/package/gluon-ebtables-source-filter/files/lib/gluon/ebtables/110-local-forward-allow-ipv6 @@ -0,0 +1,9 @@ +site = require('gluon.site_config') + +rule('LOCAL_FORWARD -p IPv6 --ip6-src fe80::/64 -j RETURN') +rule('LOCAL_FORWARD -p IPv6 --ip6-src ::/128 --ip6-proto ipv6-icmp -j RETURN') +rule('LOCAL_FORWARD -p IPv6 --ip6-src ' .. site.prefix6 .. ' -j RETURN') + +for _, prefix in ipairs(site.extra_prefixes6 or {}) do + rule('LOCAL_FORWARD -p IPv6 --ip6-src ' .. prefix .. ' -j RETURN') +end diff --git a/package/gluon-ebtables-source-filter/files/lib/gluon/ebtables/300-local-forward-rules b/package/gluon-ebtables-source-filter/files/lib/gluon/ebtables/300-local-forward-rules new file mode 100644 index 00000000..6c5a9257 --- /dev/null +++ b/package/gluon-ebtables-source-filter/files/lib/gluon/ebtables/300-local-forward-rules @@ -0,0 +1 @@ +rule('FORWARD --logical-in br-client -i ! bat0 -j LOCAL_FORWARD') diff --git a/package/gluon-ebtables/Makefile b/package/gluon-ebtables/Makefile index 39c654c1..43185c73 100644 --- a/package/gluon-ebtables/Makefile +++ b/package/gluon-ebtables/Makefile @@ -8,6 +8,7 @@ PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) include $(INCLUDE_DIR)/package.mk + define Package/gluon-ebtables SECTION:=gluon CATEGORY:=Gluon diff --git a/package/gluon-ebtables/files/etc/init.d/gluon-ebtables b/package/gluon-ebtables/files/etc/init.d/gluon-ebtables index 5a770452..e6bffe96 100755 --- a/package/gluon-ebtables/files/etc/init.d/gluon-ebtables +++ b/package/gluon-ebtables/files/etc/init.d/gluon-ebtables @@ -24,12 +24,15 @@ exec_file() { local file="$1" /usr/bin/lua -e " - function rule(command) + function rule(command, table) + table = table or 'filter' os.execute($EBTABLES_RULE) end - function chain(name, policy) + function chain(name, policy, table) + table = table or 'filter' os.execute($EBTABLES_CHAIN) end + " "$file" } @@ -48,8 +51,8 @@ exec_all() { start() { ( - export EBTABLES_RULE='"ebtables -A " .. command' - export EBTABLES_CHAIN='"ebtables -N " .. name .. " -P " .. policy' + export EBTABLES_RULE='"ebtables -t " .. table .. " -A " .. command' + export EBTABLES_CHAIN='"ebtables -t " .. table .. " -N " .. name .. " -P " .. policy' if [ -z "$1" ]; then exec_all '' @@ -61,8 +64,8 @@ start() { stop() { ( - export EBTABLES_RULE='"ebtables -D " .. command' - export EBTABLES_CHAIN='"ebtables -X " .. name' + export EBTABLES_RULE='"ebtables -t " .. table .. " -D " .. command' + export EBTABLES_CHAIN='"ebtables -t " .. table .. " -X " .. name' if [ -z "$1" ]; then exec_all '-r' diff --git a/package/gluon-ebtables/files/lib/gluon/ebtables/100-dir-chain b/package/gluon-ebtables/files/lib/gluon/ebtables/100-dir-chain index 31c19c53..e6bf98e3 100644 --- a/package/gluon-ebtables/files/lib/gluon/ebtables/100-dir-chain +++ b/package/gluon-ebtables/files/lib/gluon/ebtables/100-dir-chain @@ -1,2 +1,5 @@ chain('IN_ONLY', 'RETURN') chain('OUT_ONLY', 'RETURN') + +chain('MULTICAST_OUT', 'RETURN') +chain('MULTICAST_OUT_ICMPV6', '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 index b1cd4e24..74486ae5 100644 --- a/package/gluon-ebtables/files/lib/gluon/ebtables/101-dir-rules +++ b/package/gluon-ebtables/files/lib/gluon/ebtables/101-dir-rules @@ -1,2 +1,7 @@ -rule 'IN_ONLY --logical-in br-client -i ! bat0 -j DROP' -rule 'OUT_ONLY --logical-out br-client -o ! bat0 -j DROP' +rule 'IN_ONLY --logical-in br-client -i bat0 -j RETURN' +rule 'IN_ONLY --logical-in br-client -i local-port -j RETURN' +rule 'IN_ONLY --logical-in br-client -j DROP' + +rule 'OUT_ONLY --logical-out br-client -o bat0 -j RETURN' +rule 'OUT_ONLY --logical-out br-client -o local-port -j RETURN' +rule 'OUT_ONLY --logical-out br-client -j DROP' diff --git a/package/gluon-ebtables/files/lib/gluon/ebtables/350-mcast-dir-rules b/package/gluon-ebtables/files/lib/gluon/ebtables/350-mcast-dir-rules new file mode 100644 index 00000000..01609068 --- /dev/null +++ b/package/gluon-ebtables/files/lib/gluon/ebtables/350-mcast-dir-rules @@ -0,0 +1,4 @@ +rule 'OUTPUT -d Multicast --logical-out br-client -o bat0 -j MULTICAST_OUT' +rule 'FORWARD -d Multicast --logical-out br-client -o bat0 -j MULTICAST_OUT' + +rule 'MULTICAST_OUT -p IPv6 --ip6-protocol ipv6-icmp -j MULTICAST_OUT_ICMPV6' diff --git a/package/gluon-l3roamd/Makefile b/package/gluon-l3roamd/Makefile new file mode 100644 index 00000000..6e5d5606 --- /dev/null +++ b/package/gluon-l3roamd/Makefile @@ -0,0 +1,33 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-l3roamd +PKG_VERSION:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include ../gluon.mk + +define Package/gluon-l3roamd + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Configure l3roamd for babel + DEPENDS:=+gluon-core +gluon-mesh-babel +l3roamd +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile + $(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/) +endef + +define Package/gluon-l3roamd/install + $(CP) ./files/* $(1)/ + $(CP) $(PKG_BUILD_DIR)/luadest/* $(1)/ +endef + +$(eval $(call BuildPackage,gluon-l3roamd)) diff --git a/package/gluon-l3roamd/files/etc/init.d/gluon-l3roamd b/package/gluon-l3roamd/files/etc/init.d/gluon-l3roamd new file mode 100755 index 00000000..a14e96ee --- /dev/null +++ b/package/gluon-l3roamd/files/etc/init.d/gluon-l3roamd @@ -0,0 +1,27 @@ +#!/bin/sh /etc/rc.common + +START=55 + +USE_PROCD=1 +PROG=/usr/sbin/l3roamd + +start_service () { + procd_open_instance + procd_set_param stdout 1 + procd_set_param stderr 1 + procd_set_param respawn ${respawn_threshold:-3660} ${respawn_timeout:-5} ${respawn_retry:-0} + interfaces=$(for dev in $( ubus call network.interface dump | jsonfilter -e "@.interface[@.proto='gluon_mesh' && @.up=true].device");do echo " -m $dev"; done; + [ "$(ifstatus client | jsonfilter -e "@.up")" = "true" ] && echo " -i local-node") + procd_set_param command "$PROG" -p $(lua -e 'print(require("gluon.site_config").prefix6)') $interfaces -t 11 -a $(uci get network.loopback.ip6addr | cut -d/ -f1) -4 0:0:0:0:0:ffff::/96 + procd_close_instance +} + +service_triggers() { + local script=$(readlink "$initscript") + local name=$(basename "${script:-$initscript}") + + procd_open_trigger + procd_add_raw_trigger "interface.*" 0 "/etc/init.d/$name" reload + procd_close_trigger +} + diff --git a/package/gluon-l3roamd/luasrc/lib/gluon/upgrade/380-gluon-l3roamd-route b/package/gluon-l3roamd/luasrc/lib/gluon/upgrade/380-gluon-l3roamd-route new file mode 100755 index 00000000..237280f1 --- /dev/null +++ b/package/gluon-l3roamd/luasrc/lib/gluon/upgrade/380-gluon-l3roamd-route @@ -0,0 +1,20 @@ +#!/usr/bin/lua + +local uci = require('simple-uci').cursor() +local site = require 'gluon.site_config' + +uci:delete('network', 'l3roam') +uci:section('network', 'interface', 'l3roam', { + ifname = 'l3roam0', + proto = 'none', +}) + +uci:delete('network', 'l3roamd_client') +uci:section('network', 'route6', 'l3roamd_client', { + interface = 'l3roam', + target = site.prefix6, + gateway = '::', + table = '10', +}) + +uci:save('network') diff --git a/package/gluon-legacy/Makefile b/package/gluon-legacy/Makefile deleted file mode 100644 index 7320fba6..00000000 --- a/package/gluon-legacy/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -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 deleted file mode 100644 index 1ec26de0..00000000 --- a/package/gluon-legacy/check_site.lua +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100755 index 78436676..00000000 --- a/package/gluon-legacy/files/lib/gluon/upgrade/000-legacy +++ /dev/null @@ -1,11 +0,0 @@ -#!/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 deleted file mode 100755 index b48e42b8..00000000 --- a/package/gluon-legacy/files/lib/gluon/upgrade/019-legacy-interfaces +++ /dev/null @@ -1,40 +0,0 @@ -#!/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 deleted file mode 100755 index 36da0632..00000000 --- a/package/gluon-legacy/files/lib/gluon/upgrade/210-legacy-wireless +++ /dev/null @@ -1,24 +0,0 @@ -#!/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 deleted file mode 100755 index 0b97e120..00000000 --- a/package/gluon-legacy/files/lib/gluon/upgrade/290-legacy-setup-mode +++ /dev/null @@ -1,22 +0,0 @@ -#!/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 deleted file mode 100755 index c67afe14..00000000 --- a/package/gluon-legacy/files/lib/gluon/upgrade/290-legacy-simple-tc +++ /dev/null @@ -1,29 +0,0 @@ -#!/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 deleted file mode 100755 index 468a35a6..00000000 --- a/package/gluon-legacy/files/lib/gluon/upgrade/390-legacy-mesh-vpn-fastd +++ /dev/null @@ -1,37 +0,0 @@ -#!/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 deleted file mode 100755 index efb6b675..00000000 --- a/package/gluon-legacy/files/lib/gluon/upgrade/990-legacy-late +++ /dev/null @@ -1,11 +0,0 @@ -#!/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 index d0e99373..0583f96c 100644 --- a/package/gluon-lock-password/Makefile +++ b/package/gluon-lock-password/Makefile @@ -8,6 +8,7 @@ PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) include $(INCLUDE_DIR)/package.mk + define Package/gluon-lock-password SECTION:=gluon CATEGORY:=Gluon diff --git a/package/gluon-luci-admin/Makefile b/package/gluon-luci-admin/Makefile deleted file mode 100644 index 3e20d179..00000000 --- a/package/gluon-luci-admin/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -# 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 deleted file mode 100644 index 55c0a248..00000000 --- a/package/gluon-luci-admin/files/usr/lib/lua/luci/controller/admin/index.lua +++ /dev/null @@ -1,39 +0,0 @@ ---[[ -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 deleted file mode 100644 index 29aecb95..00000000 --- a/package/gluon-luci-admin/files/usr/lib/lua/luci/controller/admin/upgrade.lua +++ /dev/null @@ -1,135 +0,0 @@ ---[[ -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 deleted file mode 100644 index e9ceba70..00000000 --- a/package/gluon-luci-admin/files/usr/lib/lua/luci/model/cbi/admin/info.lua +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index 5797b623..00000000 --- a/package/gluon-luci-admin/files/usr/lib/lua/luci/model/cbi/admin/remote.lua +++ /dev/null @@ -1,105 +0,0 @@ ---[[ -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 deleted file mode 100644 index 53947f3c..00000000 --- a/package/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/expertmode.htm +++ /dev/null @@ -1,56 +0,0 @@ -<% 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 deleted file mode 100644 index da403c1b..00000000 --- a/package/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/info.htm +++ /dev/null @@ -1,45 +0,0 @@ -<%- - local fs = require 'nixio.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_reboot.htm b/package/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/upgrade_reboot.htm deleted file mode 100644 index 3e89e778..00000000 --- a/package/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/upgrade_reboot.htm +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - <%: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-autoupdater/Makefile b/package/gluon-luci-autoupdater/Makefile deleted file mode 100644 index 650c4692..00000000 --- a/package/gluon-luci-autoupdater/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -# 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 deleted file mode 100644 index 64e1acbd..00000000 --- a/package/gluon-luci-autoupdater/files/usr/lib/lua/luci/controller/admin/autoupdater.lua +++ /dev/null @@ -1,19 +0,0 @@ ---[[ -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 deleted file mode 100644 index a8f9d3b3..00000000 --- a/package/gluon-luci-autoupdater/files/usr/lib/lua/luci/model/cbi/admin/autoupdater.lua +++ /dev/null @@ -1,29 +0,0 @@ ---[[ -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-mesh-vpn-fastd/check_site.lua b/package/gluon-luci-mesh-vpn-fastd/check_site.lua deleted file mode 100644 index 42ff5a50..00000000 --- a/package/gluon-luci-mesh-vpn-fastd/check_site.lua +++ /dev/null @@ -1,2 +0,0 @@ -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 deleted file mode 100644 index 8141c44a..00000000 --- a/package/gluon-luci-mesh-vpn-fastd/files/usr/lib/lua/luci/controller/admin/mesh_vpn_fastd.lua +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index 14bb5783..00000000 --- a/package/gluon-luci-mesh-vpn-fastd/files/usr/lib/lua/luci/model/cbi/admin/mesh_vpn_fastd.lua +++ /dev/null @@ -1,41 +0,0 @@ -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 deleted file mode 100644 index 0899fa1d..00000000 --- a/package/gluon-luci-mesh-vpn-fastd/files/usr/lib/lua/luci/view/gluon/cbi/mesh-vpn-fastd-mode.htm +++ /dev/null @@ -1,32 +0,0 @@ -
-
- /> -
-
- 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-node-role/Makefile b/package/gluon-luci-node-role/Makefile deleted file mode 100644 index ded7bd3f..00000000 --- a/package/gluon-luci-node-role/Makefile +++ /dev/null @@ -1,41 +0,0 @@ -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/files/usr/lib/lua/luci/controller/admin/noderole.lua b/package/gluon-luci-node-role/files/usr/lib/lua/luci/controller/admin/noderole.lua deleted file mode 100644 index cfca1275..00000000 --- a/package/gluon-luci-node-role/files/usr/lib/lua/luci/controller/admin/noderole.lua +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index e7832ad9..00000000 --- a/package/gluon-luci-node-role/files/usr/lib/lua/luci/model/cbi/admin/noderole.lua +++ /dev/null @@ -1,34 +0,0 @@ -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-portconfig/Makefile b/package/gluon-luci-portconfig/Makefile deleted file mode 100644 index 007c5fea..00000000 --- a/package/gluon-luci-portconfig/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -# 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 deleted file mode 100644 index 037b56c8..00000000 --- a/package/gluon-luci-portconfig/files/usr/lib/lua/luci/controller/admin/portconfig.lua +++ /dev/null @@ -1,19 +0,0 @@ ---[[ -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 deleted file mode 100644 index 8166539c..00000000 --- a/package/gluon-luci-portconfig/files/usr/lib/lua/luci/model/cbi/admin/portconfig.lua +++ /dev/null @@ -1,149 +0,0 @@ ---[[ -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-private-wifi/Makefile b/package/gluon-luci-private-wifi/Makefile deleted file mode 100644 index 604929dd..00000000 --- a/package/gluon-luci-private-wifi/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -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 deleted file mode 100644 index e11ba58b..00000000 --- a/package/gluon-luci-private-wifi/files/usr/lib/lua/luci/controller/admin/privatewifi.lua +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index d3ddcd72..00000000 --- a/package/gluon-luci-private-wifi/files/usr/lib/lua/luci/model/cbi/admin/privatewifi.lua +++ /dev/null @@ -1,63 +0,0 @@ -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-theme/files/etc/uci-defaults/luci-theme-gluon b/package/gluon-luci-theme/files/etc/uci-defaults/luci-theme-gluon deleted file mode 100755 index 795bd186..00000000 --- a/package/gluon-luci-theme/files/etc/uci-defaults/luci-theme-gluon +++ /dev/null @@ -1,6 +0,0 @@ -#!/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 deleted file mode 100644 index 6b709030..00000000 --- a/package/gluon-luci-theme/files/usr/lib/lua/luci/view/themes/gluon/footer.htm +++ /dev/null @@ -1,19 +0,0 @@ -<%# -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 deleted file mode 100644 index 2fe1004b..00000000 --- a/package/gluon-luci-theme/files/usr/lib/lua/luci/view/themes/gluon/header.htm +++ /dev/null @@ -1,168 +0,0 @@ -<%# -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 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 deleted file mode 100644 index eb9833df..00000000 --- a/package/gluon-luci-theme/files/www/luci-static/gluon/cascade.css +++ /dev/null @@ -1,2 +0,0 @@ -.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 deleted file mode 100644 index bfcfc58c..00000000 --- a/package/gluon-luci-theme/sass/cascade.scss +++ /dev/null @@ -1,1029 +0,0 @@ -/* 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 deleted file mode 100644 index 462eab9f..00000000 --- a/package/gluon-luci-wifi-config/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -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 deleted file mode 100644 index 2ff1cb84..00000000 --- a/package/gluon-luci-wifi-config/files/usr/lib/lua/luci/controller/admin/wifi-config.lua +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index 66393961..00000000 --- a/package/gluon-luci-wifi-config/files/usr/lib/lua/luci/model/cbi/admin/wifi-config.lua +++ /dev/null @@ -1,150 +0,0 @@ -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 .. '_mesh_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-mesh-batman-adv-14/Makefile b/package/gluon-mesh-batman-adv-14/Makefile deleted file mode 100644 index be65cafa..00000000 --- a/package/gluon-mesh-batman-adv-14/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -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 deleted file mode 100644 index 84137237..00000000 --- a/package/gluon-mesh-batman-adv-14/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/compat +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100755 index b3ed1e88..00000000 --- a/package/gluon-mesh-batman-adv-14/files/lib/gluon/upgrade/350-gluon-mesh-batman-adv-14 +++ /dev/null @@ -1,40 +0,0 @@ -#!/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 deleted file mode 100644 index 14a39a61..00000000 --- a/package/gluon-mesh-batman-adv-15/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -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 deleted file mode 100644 index d44224b3..00000000 --- a/package/gluon-mesh-batman-adv-15/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/compat +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100755 index 96f7d310..00000000 --- a/package/gluon-mesh-batman-adv-15/files/lib/gluon/upgrade/350-gluon-mesh-batman-adv-15 +++ /dev/null @@ -1,40 +0,0 @@ -#!/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 deleted file mode 100644 index 8358089c..00000000 --- a/package/gluon-mesh-batman-adv-core/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -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 +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 deleted file mode 100644 index e76ca9e9..00000000 --- a/package/gluon-mesh-batman-adv-core/check_site.lua +++ /dev/null @@ -1,16 +0,0 @@ -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 deleted file mode 100644 index f93a11f9..00000000 --- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/batadv +++ /dev/null @@ -1,41 +0,0 @@ -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 deleted file mode 100644 index d3754222..00000000 --- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/wifi +++ /dev/null @@ -1,41 +0,0 @@ -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 deleted file mode 100644 index d55f8340..00000000 --- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/addresses +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index 97180b81..00000000 --- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh/bat0/interfaces +++ /dev/null @@ -1,52 +0,0 @@ -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 deleted file mode 100644 index 1fef5e10..00000000 --- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh_interfaces +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index abb317e9..00000000 --- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/version +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100644 index 235865ed..00000000 --- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/clients +++ /dev/null @@ -1,20 +0,0 @@ -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 deleted file mode 100644 index a1be9ac0..00000000 --- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/gateway +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index 01f6b4ab..00000000 --- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/traffic +++ /dev/null @@ -1,14 +0,0 @@ -local ethtool = require 'ethtool_stats' - -local fields = ethtool.interface_stats('bat0') - -local traffic = {} -for _, class in ipairs({'rx', 'tx', 'forward', 'mgmt_rx', 'mgmt_tx'}) do - traffic[class] = { - bytes = fields[class .. '_bytes'], - packets = fields[class], - } -end -traffic['tx']['dropped'] = fields['tx_dropped'] - -return traffic 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 deleted file mode 100755 index f84a104d..00000000 --- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/upgrade/300-gluon-mesh-batman-adv-core-wan +++ /dev/null @@ -1,14 +0,0 @@ -#!/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 deleted file mode 100755 index 43c4e4d4..00000000 --- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/upgrade/310-gluon-mesh-batman-adv-core-mesh +++ /dev/null @@ -1,99 +0,0 @@ -#!/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', - hop_penalty = 15, - 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 deleted file mode 100755 index 50753c8b..00000000 --- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/upgrade/320-gluon-mesh-batman-adv-core-wireless +++ /dev/null @@ -1,119 +0,0 @@ -#!/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 deleted file mode 100755 index d40c5729..00000000 --- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/upgrade/330-gluon-mesh-batman-adv-core-mesh-on-wan +++ /dev/null @@ -1,18 +0,0 @@ -#!/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 deleted file mode 100755 index d9831bfc..00000000 --- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/upgrade/340-gluon-mesh-batman-adv-core-mesh-on-lan +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/lua - -local site = require 'gluon.site_config' -local util = require 'gluon.util' -local sysconfig = require 'gluon.sysconfig' - -local uci = require('luci.model.uci').cursor() -local lutil = require 'luci.util' - -if sysconfig.lan_ifname and not uci:get('network', 'mesh_lan') then - local enable = site.mesh_on_lan - - if enable then - local interfaces = uci:get('network', 'client', 'ifname') - - if interfaces and lutil.contains(interfaces:split(' '), sysconfig.lan_ifname) then - enable = false - end - end - - uci:section('network', 'interface', 'mesh_lan', - { ifname = sysconfig.lan_ifname - , proto = 'batadv' - , mesh = 'bat0' - , macaddr = util.generate_mac(1, 1) - , auto = enable and 1 or 0 - }) - - uci:save('network') - uci:commit('network') -end - diff --git a/package/gluon-mesh-batman-adv/Makefile b/package/gluon-mesh-batman-adv/Makefile new file mode 100644 index 00000000..9aa979fc --- /dev/null +++ b/package/gluon-mesh-batman-adv/Makefile @@ -0,0 +1,70 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-mesh-batman-adv +PKG_VERSION:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) +PKG_BUILD_DEPENDS := respondd + +include ../gluon.mk + + +define Package/gluon-mesh-batman-adv/common + SECTION:=gluon + CATEGORY:=Gluon + PROVIDES:=gluon-mesh-batman-adv + DEPENDS:=+gluon-core +libgluonutil +gluon-client-bridge +gluon-ebtables +firewall +libiwinfo +kmod-dummy +libnl-tiny +endef + +define Package/gluon-mesh-batman-adv-14 +$(Package/gluon-mesh-batman-adv/common) + TITLE:=Support for batman-adv meshing (compat level 14) + CONFLICTS:=gluon-mesh-batman-adv-15 + DEPENDS+=+kmod-batman-adv-legacy +endef + +define Package/gluon-mesh-batman-adv-15 +$(Package/gluon-mesh-batman-adv/common) + TITLE:=Support for batman-adv meshing (compat level 15) + DEPENDS+=+kmod-batman-adv +batctl +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ +endef + +define Build/Compile + $(call Build/Compile/Default) + $(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/) +endef + +define Package/gluon-mesh-batman-adv/common/install + $(CP) ./files/* $(1)/ + $(CP) $(PKG_BUILD_DIR)/luadest/* $(1)/ + $(INSTALL_DIR) $(1)/lib/gluon/respondd + $(CP) $(PKG_BUILD_DIR)/respondd.so $(1)/lib/gluon/respondd/mesh-batman-adv.so + + $(INSTALL_DIR) $(1)/lib/gluon/mesh-batman-adv +endef + +define Package/gluon-mesh-batman-adv-14/install +$(Package/gluon-mesh-batman-adv/common/install) + echo 14 > $(1)/lib/gluon/mesh-batman-adv/compat +endef + +define Package/gluon-mesh-batman-adv-15/install +$(Package/gluon-mesh-batman-adv/common/install) + echo 15 > $(1)/lib/gluon/mesh-batman-adv/compat +endef + +define Package/gluon-mesh-batman-adv/common/postinst +#!/bin/sh +$(call GluonCheckSite,check_site.lua) +endef +Package/gluon-mesh-batman-adv-14/postinst := $(Package/gluon-mesh-batman-adv/common/postinst) +Package/gluon-mesh-batman-adv-15/postinst := $(Package/gluon-mesh-batman-adv/common/postinst) + + +$(eval $(call BuildPackage,gluon-mesh-batman-adv-14)) +$(eval $(call BuildPackage,gluon-mesh-batman-adv-15)) diff --git a/package/gluon-mesh-batman-adv/check_site.lua b/package/gluon-mesh-batman-adv/check_site.lua new file mode 100644 index 00000000..384b3224 --- /dev/null +++ b/package/gluon-mesh-batman-adv/check_site.lua @@ -0,0 +1,3 @@ +if need_table('mesh', nil, false) and need_table('mesh.batman_adv', nil, false) then + need_number('mesh.batman_adv.gw_sel_class', false) +end diff --git a/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/30-gluon-mesh-batman-adv b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/30-gluon-mesh-batman-adv new file mode 100755 index 00000000..a372c960 --- /dev/null +++ b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/30-gluon-mesh-batman-adv @@ -0,0 +1,3 @@ +#!/bin/sh + +ubus call network.interface.gluon_bat0 renew diff --git a/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/setup.d/30-gluon-mesh-batman-adv b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/setup.d/30-gluon-mesh-batman-adv new file mode 100755 index 00000000..373b872c --- /dev/null +++ b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/setup.d/30-gluon-mesh-batman-adv @@ -0,0 +1,13 @@ +#!/bin/sh + +if [ "$FIXED_MTU" -eq 0 ]; then + # In case on VLAN on IBSS, first set MTU of the underlying interface + for lower in /sys/class/net/"$IFNAME"/lower_*/wireless; do + lower="${lower%%\/wireless}" + lower="${lower##*\/lower_}" + ip link set dev "$lower" mtu 1536 + break + done + + ip link set dev "$IFNAME" mtu 1532 +fi diff --git a/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/teardown.d/70-gluon-mesh-batman-adv b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/teardown.d/70-gluon-mesh-batman-adv new file mode 100755 index 00000000..355b89b0 --- /dev/null +++ b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/teardown.d/70-gluon-mesh-batman-adv @@ -0,0 +1,5 @@ +#!/bin/sh + +lock /var/lock/gluon_bat0.lock +(echo 'none' > "/sys/class/net/$IFNAME/batman_adv/mesh_iface") 2>/dev/null +lock -u /var/lock/gluon_bat0.lock diff --git a/package/gluon-mesh-batman-adv/files/lib/gluon/ebtables/250-next-node b/package/gluon-mesh-batman-adv/files/lib/gluon/ebtables/250-next-node new file mode 100644 index 00000000..54dd7e32 --- /dev/null +++ b/package/gluon-mesh-batman-adv/files/lib/gluon/ebtables/250-next-node @@ -0,0 +1,24 @@ +local site = require 'gluon.site_config' +local next_node = site.next_node + +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') + +if next_node.ip4 then + rule('FORWARD --logical-out br-client -o bat0 -p ARP --arp-ip-src ' .. next_node.ip4 .. ' -j DROP') + rule('FORWARD --logical-out br-client -o bat0 -p ARP --arp-ip-dst ' .. next_node.ip4 .. ' -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') +end + +if next_node.ip6 then + 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') +end diff --git a/package/gluon-radvd/files/lib/gluon/ebtables/300-radv-input-output b/package/gluon-mesh-batman-adv/files/lib/gluon/ebtables/300-radv-input-output similarity index 100% rename from package/gluon-radvd/files/lib/gluon/ebtables/300-radv-input-output rename to package/gluon-mesh-batman-adv/files/lib/gluon/ebtables/300-radv-input-output diff --git a/package/gluon-mesh-batman-adv/files/lib/gluon/respondd/client.dev b/package/gluon-mesh-batman-adv/files/lib/gluon/respondd/client.dev new file mode 100644 index 00000000..b051c6c5 --- /dev/null +++ b/package/gluon-mesh-batman-adv/files/lib/gluon/respondd/client.dev @@ -0,0 +1 @@ +client diff --git a/package/gluon-mesh-batman-adv/files/lib/netifd/proto/gluon_bat0.sh b/package/gluon-mesh-batman-adv/files/lib/netifd/proto/gluon_bat0.sh new file mode 100755 index 00000000..781d91c3 --- /dev/null +++ b/package/gluon-mesh-batman-adv/files/lib/netifd/proto/gluon_bat0.sh @@ -0,0 +1,59 @@ +#!/bin/sh + +. /lib/functions.sh +. ../netifd-proto.sh +init_proto "$@" + +proto_gluon_bat0_init_config() { + no_device=1 + available=1 + renew_handler=1 +} + +proto_gluon_bat0_renew() { + local config="$1" + + lock /var/lock/gluon_bat0.lock + + local ifdump="$(ubus call network.interface dump)" + + echo "$ifdump" | jsonfilter \ + -e "@.interface[@.proto='gluon_mesh' && @.up=true]['device','data']" \ + | while read dev; do + read data + + echo bat0 > "/sys/class/net/$dev/batman_adv/mesh_iface" + + ! [ "$(echo "$data" | jsonfilter -e "@.transitive")" = 'true' ] + transitive=$? + + (echo "$transitive" > "/sys/class/net/$dev/batman_adv/no_rebroadcast") 2>/dev/null + done + + lock -u /var/lock/gluon_bat0.lock +} + +proto_gluon_bat0_setup() { + local config="$1" + + local primary0_mac="$(lua -lgluon.util -e 'print(gluon.util.generate_mac(3))')" + + ip link add primary0 type dummy + echo 1 > /proc/sys/net/ipv6/conf/primary0/disable_ipv6 + ip link set primary0 address "$primary0_mac" mtu 1532 up + echo bat0 > /sys/class/net/primary0/batman_adv/mesh_iface + + proto_init_update primary0 1 + proto_send_update "$config" + + proto_gluon_bat0_renew "$1" +} + +proto_gluon_bat0_teardown() { + local config="$1" + + ip link del bat0 + ip link del primary0 +} + +add_protocol gluon_bat0 diff --git a/package/gluon-mesh-batman-adv/files/usr/lib/autoupdater/abort.d/10start-network b/package/gluon-mesh-batman-adv/files/usr/lib/autoupdater/abort.d/10start-network new file mode 100755 index 00000000..f04d55cc --- /dev/null +++ b/package/gluon-mesh-batman-adv/files/usr/lib/autoupdater/abort.d/10start-network @@ -0,0 +1,5 @@ +#!/bin/sh + +. /lib/gluon/autoupdater/lib.sh + +pidof netifd >/dev/null || start_enabled network diff --git a/package/gluon-mesh-batman-adv/files/usr/lib/autoupdater/upgrade.d/10stop-network b/package/gluon-mesh-batman-adv/files/usr/lib/autoupdater/upgrade.d/10stop-network new file mode 100755 index 00000000..b02580a3 --- /dev/null +++ b/package/gluon-mesh-batman-adv/files/usr/lib/autoupdater/upgrade.d/10stop-network @@ -0,0 +1,8 @@ +#!/bin/sh + +. /lib/gluon/autoupdater/lib.sh + +wifi down +sleep 1 +stop network +ip link del bat0 diff --git a/package/gluon-mesh-batman-adv/luasrc/lib/gluon/radvd/arguments b/package/gluon-mesh-batman-adv/luasrc/lib/gluon/radvd/arguments new file mode 100755 index 00000000..83a49453 --- /dev/null +++ b/package/gluon-mesh-batman-adv/luasrc/lib/gluon/radvd/arguments @@ -0,0 +1,6 @@ +#!/usr/bin/lua +local site = require "gluon.site_config" +io.write("-i local-node -p " .. site.prefix6) +if site.dns and site.dns.servers then + io.write(" --rdnss " .. site.next_node.ip6) +end diff --git a/package/gluon-mesh-batman-adv/luasrc/lib/gluon/upgrade/310-gluon-mesh-batman-adv-mesh b/package/gluon-mesh-batman-adv/luasrc/lib/gluon/upgrade/310-gluon-mesh-batman-adv-mesh new file mode 100755 index 00000000..8153f075 --- /dev/null +++ b/package/gluon-mesh-batman-adv/luasrc/lib/gluon/upgrade/310-gluon-mesh-batman-adv-mesh @@ -0,0 +1,44 @@ +#!/usr/bin/lua + +local sysconfig = require 'gluon.sysconfig' +local site = require 'gluon.site_config' +local util = require 'gluon.util' + +local uci = require('simple-uci').cursor() + + +local gw_sel_class +if site.mesh and site.mesh.batman_adv then + gw_sel_class = site.mesh.batman_adv.gw_sel_class +end + +uci:delete('batman-adv', 'bat0') +uci:section('batman-adv', 'mesh', 'bat0', { + orig_interval = 5000, + gw_mode = 'client', + gw_sel_class = gw_sel_class, + hop_penalty = 15, + multicast_mode = false, +}) +uci:save('batman-adv') + +uci:delete('network', 'gluon_bat0') +uci:section('network', 'interface', 'gluon_bat0', { + proto = 'gluon_bat0', +}) + +uci:delete('network', 'bat0') +uci:section('network', 'interface', 'bat0', { + ifname = 'bat0', + proto = 'none', + auto = true, + macaddr = sysconfig.primary_mac, + multicast_router = 2, + learning = true, +}) + +local interfaces = uci:get_list('network', 'client', 'ifname') +util.add_to_set(interfaces, 'bat0') +uci:set_list('network', 'client', 'ifname', interfaces) + +uci:save('network') diff --git a/package/gluon-mesh-batman-adv/luasrc/lib/gluon/upgrade/320-gluon-mesh-batman-adv-client-bridge b/package/gluon-mesh-batman-adv/luasrc/lib/gluon/upgrade/320-gluon-mesh-batman-adv-client-bridge new file mode 100755 index 00000000..2bfcdd57 --- /dev/null +++ b/package/gluon-mesh-batman-adv/luasrc/lib/gluon/upgrade/320-gluon-mesh-batman-adv-client-bridge @@ -0,0 +1,65 @@ +#!/usr/bin/lua + +-- This script must be ordered after 300-gluon-client-bridge-network, as +-- it overrides parts of network.client + + +local site = require 'gluon.site_config' +local sysconfig = require 'gluon.sysconfig' +local sysctl = require 'gluon.sysctl' + +local uci = require('simple-uci').cursor() + + +uci:section('network', 'interface', 'client', { + ipv6 = true, + proto = 'dhcpv6', + reqprefix = 'no', + peerdns = not (site.dns and site.dns.servers), + sourcefilter = false, + keep_ra_dnslifetime = true, + robustness = 3, + query_interval = 2000, + query_response_interval = 500, +}) + +uci:delete('network', 'client_lan') + +uci:delete('network', 'local_node_route6') +uci:section('network', 'route6', 'local_node_route6', { + interface = 'client', + target = site.prefix6, + gateway = '::', +}) + +uci:save('network') + + +uci:section('firewall', 'zone', 'client', { + input = 'ACCEPT', + output = 'ACCEPT', + forward = 'REJECT', +}) + +uci:section('firewall', 'rule', 'client_dns', { + name = 'client_dns', + src = 'client', + dest_port = '53', + target = 'REJECT', +}) + +uci:delete('firewall', 'local_node') +uci:section('firewall', 'zone', 'local_node', { + name = 'local_node', + network = {'local_node'}, + input = 'ACCEPT', + output = 'ACCEPT', + forward = 'REJECT', +}) + +uci:delete('firewall', 'local_node_dns') + +uci:save('firewall') + + +sysctl.set('net.ipv6.conf.local-node.forwarding', 0) diff --git a/package/gluon-mesh-batman-adv/luasrc/lib/gluon/upgrade/330-gluon-mesh-batman-adv-mac-addresses b/package/gluon-mesh-batman-adv/luasrc/lib/gluon/upgrade/330-gluon-mesh-batman-adv-mac-addresses new file mode 100755 index 00000000..a8e69d78 --- /dev/null +++ b/package/gluon-mesh-batman-adv/luasrc/lib/gluon/upgrade/330-gluon-mesh-batman-adv-mac-addresses @@ -0,0 +1,10 @@ +#!/usr/bin/lua + +local util = require 'gluon.util' +local uci = require('simple-uci').cursor() + + +-- fix up potentially duplicate MAC addresses (for meshing) +uci:set('network', 'wan', 'macaddr', util.generate_mac(0)) +uci:set('network', 'mesh_lan', 'macaddr', util.generate_mac(4)) +uci:save('network') diff --git a/package/gluon-mesh-batman-adv/src/Makefile b/package/gluon-mesh-batman-adv/src/Makefile new file mode 100644 index 00000000..9206a067 --- /dev/null +++ b/package/gluon-mesh-batman-adv/src/Makefile @@ -0,0 +1,24 @@ +all: respondd.so + +CFLAGS += -Wall + +ifeq ($(origin PKG_CONFIG), undefined) + PKG_CONFIG = pkg-config + ifeq ($(shell which $(PKG_CONFIG) 2>/dev/null),) + $(error $(PKG_CONFIG) not found) + endif +endif + +ifeq ($(origin LIBNL_CFLAGS) $(origin LIBNL_LDLIBS), undefined undefined) + LIBNL_NAME ?= libnl-tiny + ifeq ($(shell $(PKG_CONFIG) --modversion $(LIBNL_NAME) 2>/dev/null),) + $(error No $(LIBNL_NAME) development libraries found!) + endif + LIBNL_CFLAGS += $(shell $(PKG_CONFIG) --cflags $(LIBNL_NAME)) + LIBNL_LDLIBS += $(shell $(PKG_CONFIG) --libs $(LIBNL_NAME)) +endif +CFLAGS += $(LIBNL_CFLAGS) +LDLIBS += $(LIBNL_LDLIBS) + +respondd.so: respondd.c batadv-netlink.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -o $@ $^ $(LDLIBS) -lgluonutil -liwinfo -luci diff --git a/package/gluon-mesh-batman-adv/src/batadv-netlink.c b/package/gluon-mesh-batman-adv/src/batadv-netlink.c new file mode 100644 index 00000000..aeea7624 --- /dev/null +++ b/package/gluon-mesh-batman-adv/src/batadv-netlink.c @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2009-2016 B.A.T.M.A.N. contributors: + * + * Marek Lindner , Andrew Lunn + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * + */ + +#include "batadv-netlink.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "batman_adv.h" + +#ifndef __maybe_unused +#define __maybe_unused __attribute__((unused)) +#endif + +struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { + [BATADV_ATTR_HARD_IFINDEX] = { .type = NLA_U32 }, + [BATADV_ATTR_ORIG_ADDRESS] = { .type = NLA_UNSPEC, + .minlen = ETH_ALEN, + .maxlen = ETH_ALEN }, + [BATADV_ATTR_TT_FLAGS] = { .type = NLA_U32 }, + [BATADV_ATTR_FLAG_BEST] = { .type = NLA_FLAG }, + [BATADV_ATTR_LAST_SEEN_MSECS] = { .type = NLA_U32 }, + [BATADV_ATTR_NEIGH_ADDRESS] = { .type = NLA_UNSPEC, + .minlen = ETH_ALEN, + .maxlen = ETH_ALEN }, + [BATADV_ATTR_TQ] = { .type = NLA_U8 }, + [BATADV_ATTR_ROUTER] = { .type = NLA_UNSPEC, + .minlen = ETH_ALEN, + .maxlen = ETH_ALEN }, +}; + +static int nlquery_error_cb(struct sockaddr_nl *nla __maybe_unused, + struct nlmsgerr *nlerr, void *arg) +{ + struct batadv_nlquery_opts *query_opts = arg; + + query_opts->err = nlerr->error; + + return NL_STOP; +} + +static int nlquery_stop_cb(struct nl_msg *msg, void *arg) +{ + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct batadv_nlquery_opts *query_opts = arg; + int *error = nlmsg_data(nlh); + + if (*error) + query_opts->err = *error; + + return NL_STOP; +} + +int batadv_nl_query_common(const char *mesh_iface, + enum batadv_nl_commands nl_cmd, + nl_recvmsg_msg_cb_t callback, int flags, + struct batadv_nlquery_opts *query_opts) +{ + struct nl_sock *sock; + struct nl_msg *msg; + struct nl_cb *cb; + int ifindex; + int family; + int ret; + + query_opts->err = 0; + + sock = nl_socket_alloc(); + if (!sock) + return -ENOMEM; + + ret = genl_connect(sock); + if (ret < 0) { + query_opts->err = ret; + goto err_free_sock; + } + + family = genl_ctrl_resolve(sock, BATADV_NL_NAME); + if (family < 0) { + query_opts->err = -EOPNOTSUPP; + goto err_free_sock; + } + + ifindex = if_nametoindex(mesh_iface); + if (!ifindex) { + query_opts->err = -ENODEV; + goto err_free_sock; + } + + cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!cb) { + query_opts->err = -ENOMEM; + goto err_free_sock; + } + + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, callback, query_opts); + nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, nlquery_stop_cb, query_opts); + nl_cb_err(cb, NL_CB_CUSTOM, nlquery_error_cb, query_opts); + + msg = nlmsg_alloc(); + if (!msg) { + query_opts->err = -ENOMEM; + goto err_free_cb; + } + + genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, flags, + nl_cmd, 1); + + nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, ifindex); + nl_send_auto_complete(sock, msg); + nlmsg_free(msg); + + nl_recvmsgs(sock, cb); + +err_free_cb: + nl_cb_put(cb); +err_free_sock: + nl_socket_free(sock); + + return query_opts->err; +} diff --git a/package/gluon-mesh-batman-adv/src/batadv-netlink.h b/package/gluon-mesh-batman-adv/src/batadv-netlink.h new file mode 100644 index 00000000..8b85a6c2 --- /dev/null +++ b/package/gluon-mesh-batman-adv/src/batadv-netlink.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2009-2016 B.A.T.M.A.N. contributors: + * + * Marek Lindner , Andrew Lunn + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * + */ + +#ifndef _BATADV_NETLINK_H +#define _BATADV_NETLINK_H + +#include +#include +#include +#include +#include + +#include "batman_adv.h" + +struct batadv_nlquery_opts { + int err; +}; + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) +#endif + +#ifndef container_of +#define container_of(ptr, type, member) __extension__ ({ \ + const __typeof__(((type *)0)->member) *__pmember = (ptr); \ + (type *)((char *)__pmember - offsetof(type, member)); }) +#endif + +int batadv_nl_query_common(const char *mesh_iface, + enum batadv_nl_commands nl_cmd, + nl_recvmsg_msg_cb_t callback, int flags, + struct batadv_nlquery_opts *query_opts); + +static inline bool batadv_nl_missing_attrs(struct nlattr *attrs[], + const enum batadv_nl_attrs mandatory[], + size_t num) +{ + size_t i; + + for (i = 0; i < num; i++) { + if (!attrs[mandatory[i]]) + return true; + } + + return false; +} + +extern struct nla_policy batadv_netlink_policy[]; + +#endif /* _BATADV_NETLINK_H */ diff --git a/package/gluon-mesh-batman-adv/src/batman_adv.h b/package/gluon-mesh-batman-adv/src/batman_adv.h new file mode 100644 index 00000000..734fe83a --- /dev/null +++ b/package/gluon-mesh-batman-adv/src/batman_adv.h @@ -0,0 +1,208 @@ +/* Copyright (C) 2016 B.A.T.M.A.N. contributors: + * + * Matthias Schiffer + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _UAPI_LINUX_BATMAN_ADV_H_ +#define _UAPI_LINUX_BATMAN_ADV_H_ + +#define BATADV_NL_NAME "batadv" + +#define BATADV_NL_MCAST_GROUP_TPMETER "tpmeter" + +/** + * enum batadv_tt_client_flags - TT client specific flags + * @BATADV_TT_CLIENT_DEL: the client has to be deleted from the table + * @BATADV_TT_CLIENT_ROAM: the client roamed to/from another node and the new + * update telling its new real location has not been received/sent yet + * @BATADV_TT_CLIENT_WIFI: this client is connected through a wifi interface. + * This information is used by the "AP Isolation" feature + * @BATADV_TT_CLIENT_ISOLA: this client is considered "isolated". This + * information is used by the Extended Isolation feature + * @BATADV_TT_CLIENT_NOPURGE: this client should never be removed from the table + * @BATADV_TT_CLIENT_NEW: this client has been added to the local table but has + * not been announced yet + * @BATADV_TT_CLIENT_PENDING: this client is marked for removal but it is kept + * in the table for one more originator interval for consistency purposes + * @BATADV_TT_CLIENT_TEMP: this global client has been detected to be part of + * the network but no nnode has already announced it + * + * Bits from 0 to 7 are called _remote flags_ because they are sent on the wire. + * Bits from 8 to 15 are called _local flags_ because they are used for local + * computations only. + * + * Bits from 4 to 7 - a subset of remote flags - are ensured to be in sync with + * the other nodes in the network. To achieve this goal these flags are included + * in the TT CRC computation. + */ +enum batadv_tt_client_flags { + BATADV_TT_CLIENT_DEL = (1 << 0), + BATADV_TT_CLIENT_ROAM = (1 << 1), + BATADV_TT_CLIENT_WIFI = (1 << 4), + BATADV_TT_CLIENT_ISOLA = (1 << 5), + BATADV_TT_CLIENT_NOPURGE = (1 << 8), + BATADV_TT_CLIENT_NEW = (1 << 9), + BATADV_TT_CLIENT_PENDING = (1 << 10), + BATADV_TT_CLIENT_TEMP = (1 << 11), +}; + +/** + * enum batadv_nl_attrs - batman-adv netlink attributes + * + * @BATADV_ATTR_UNSPEC: unspecified attribute to catch errors + * @BATADV_ATTR_VERSION: batman-adv version string + * @BATADV_ATTR_ALGO_NAME: name of routing algorithm + * @BATADV_ATTR_MESH_IFINDEX: index of the batman-adv interface + * @BATADV_ATTR_MESH_IFNAME: name of the batman-adv interface + * @BATADV_ATTR_MESH_ADDRESS: mac address of the batman-adv interface + * @BATADV_ATTR_HARD_IFINDEX: index of the non-batman-adv interface + * @BATADV_ATTR_HARD_IFNAME: name of the non-batman-adv interface + * @BATADV_ATTR_HARD_ADDRESS: mac address of the non-batman-adv interface + * @BATADV_ATTR_ORIG_ADDRESS: originator mac address + * @BATADV_ATTR_TPMETER_RESULT: result of run (see batadv_tp_meter_status) + * @BATADV_ATTR_TPMETER_TEST_TIME: time (msec) the run took + * @BATADV_ATTR_TPMETER_BYTES: amount of acked bytes during run + * @BATADV_ATTR_TPMETER_COOKIE: session cookie to match tp_meter session + * @BATADV_ATTR_PAD: attribute used for padding for 64-bit alignment + * @BATADV_ATTR_ACTIVE: Flag indicating if the hard interface is active + * @BATADV_ATTR_TT_ADDRESS: Client MAC address + * @BATADV_ATTR_TT_TTVN: Translation table version + * @BATADV_ATTR_TT_LAST_TTVN: Previous translation table version + * @BATADV_ATTR_TT_CRC32: CRC32 over translation table + * @BATADV_ATTR_TT_VID: VLAN ID + * @BATADV_ATTR_TT_FLAGS: Translation table client flags + * @BATADV_ATTR_FLAG_BEST: Flags indicating entry is the best + * @BATADV_ATTR_LAST_SEEN_MSECS: Time in milliseconds since last seen + * @BATADV_ATTR_NEIGH_ADDRESS: Neighbour MAC address + * @BATADV_ATTR_TQ: TQ to neighbour + * @BATADV_ATTR_THROUGHPUT: Estimated throughput to Neighbour + * @BATADV_ATTR_BANDWIDTH_UP: Reported uplink bandwidth + * @BATADV_ATTR_BANDWIDTH_DOWN: Reported downlink bandwidth + * @BATADV_ATTR_ROUTER: Gateway router MAC address + * @BATADV_ATTR_BLA_OWN: Flag indicating own originator + * @BATADV_ATTR_BLA_ADDRESS: Bridge loop avoidance claim MAC address + * @BATADV_ATTR_BLA_VID: BLA VLAN ID + * @BATADV_ATTR_BLA_BACKBONE: BLA gateway originator MAC address + * @BATADV_ATTR_BLA_CRC: BLA CRC + * @__BATADV_ATTR_AFTER_LAST: internal use + * @NUM_BATADV_ATTR: total number of batadv_nl_attrs available + * @BATADV_ATTR_MAX: highest attribute number currently defined + */ +enum batadv_nl_attrs { + BATADV_ATTR_UNSPEC, + BATADV_ATTR_VERSION, + BATADV_ATTR_ALGO_NAME, + BATADV_ATTR_MESH_IFINDEX, + BATADV_ATTR_MESH_IFNAME, + BATADV_ATTR_MESH_ADDRESS, + BATADV_ATTR_HARD_IFINDEX, + BATADV_ATTR_HARD_IFNAME, + BATADV_ATTR_HARD_ADDRESS, + BATADV_ATTR_ORIG_ADDRESS, + BATADV_ATTR_TPMETER_RESULT, + BATADV_ATTR_TPMETER_TEST_TIME, + BATADV_ATTR_TPMETER_BYTES, + BATADV_ATTR_TPMETER_COOKIE, + BATADV_ATTR_PAD, + BATADV_ATTR_ACTIVE, + BATADV_ATTR_TT_ADDRESS, + BATADV_ATTR_TT_TTVN, + BATADV_ATTR_TT_LAST_TTVN, + BATADV_ATTR_TT_CRC32, + BATADV_ATTR_TT_VID, + BATADV_ATTR_TT_FLAGS, + BATADV_ATTR_FLAG_BEST, + BATADV_ATTR_LAST_SEEN_MSECS, + BATADV_ATTR_NEIGH_ADDRESS, + BATADV_ATTR_TQ, + BATADV_ATTR_THROUGHPUT, + BATADV_ATTR_BANDWIDTH_UP, + BATADV_ATTR_BANDWIDTH_DOWN, + BATADV_ATTR_ROUTER, + BATADV_ATTR_BLA_OWN, + BATADV_ATTR_BLA_ADDRESS, + BATADV_ATTR_BLA_VID, + BATADV_ATTR_BLA_BACKBONE, + BATADV_ATTR_BLA_CRC, + /* add attributes above here, update the policy in netlink.c */ + __BATADV_ATTR_AFTER_LAST, + NUM_BATADV_ATTR = __BATADV_ATTR_AFTER_LAST, + BATADV_ATTR_MAX = __BATADV_ATTR_AFTER_LAST - 1 +}; + +/** + * enum batadv_nl_commands - supported batman-adv netlink commands + * + * @BATADV_CMD_UNSPEC: unspecified command to catch errors + * @BATADV_CMD_GET_MESH_INFO: Query basic information about batman-adv device + * @BATADV_CMD_TP_METER: Start a tp meter session + * @BATADV_CMD_TP_METER_CANCEL: Cancel a tp meter session + * @BATADV_CMD_GET_ROUTING_ALGOS: Query the list of routing algorithms. + * @BATADV_CMD_GET_HARDIFS: Query list of hard interfaces + * @BATADV_CMD_GET_TRANSTABLE_LOCAL: Query list of local translations + * @BATADV_CMD_GET_TRANSTABLE_GLOBAL Query list of global translations + * @BATADV_CMD_GET_ORIGINATORS: Query list of originators + * @BATADV_CMD_GET_NEIGHBORS: Query list of neighbours + * @BATADV_CMD_GET_GATEWAYS: Query list of gateways + * @BATADV_CMD_GET_BLA_CLAIM: Query list of bridge loop avoidance claims + * @BATADV_CMD_GET_BLA_BACKBONE: Query list of bridge loop avoidance backbones + * @__BATADV_CMD_AFTER_LAST: internal use + * @BATADV_CMD_MAX: highest used command number + */ +enum batadv_nl_commands { + BATADV_CMD_UNSPEC, + BATADV_CMD_GET_MESH_INFO, + BATADV_CMD_TP_METER, + BATADV_CMD_TP_METER_CANCEL, + BATADV_CMD_GET_ROUTING_ALGOS, + BATADV_CMD_GET_HARDIFS, + BATADV_CMD_GET_TRANSTABLE_LOCAL, + BATADV_CMD_GET_TRANSTABLE_GLOBAL, + BATADV_CMD_GET_ORIGINATORS, + BATADV_CMD_GET_NEIGHBORS, + BATADV_CMD_GET_GATEWAYS, + BATADV_CMD_GET_BLA_CLAIM, + BATADV_CMD_GET_BLA_BACKBONE, + /* add new commands above here */ + __BATADV_CMD_AFTER_LAST, + BATADV_CMD_MAX = __BATADV_CMD_AFTER_LAST - 1 +}; + +/** + * enum batadv_tp_meter_reason - reason of a tp meter test run stop + * @BATADV_TP_REASON_COMPLETE: sender finished tp run + * @BATADV_TP_REASON_CANCEL: sender was stopped during run + * @BATADV_TP_REASON_DST_UNREACHABLE: receiver could not be reached or didn't + * answer + * @BATADV_TP_REASON_RESEND_LIMIT: (unused) sender retry reached limit + * @BATADV_TP_REASON_ALREADY_ONGOING: test to or from the same node already + * ongoing + * @BATADV_TP_REASON_MEMORY_ERROR: test was stopped due to low memory + * @BATADV_TP_REASON_CANT_SEND: failed to send via outgoing interface + * @BATADV_TP_REASON_TOO_MANY: too many ongoing sessions + */ +enum batadv_tp_meter_reason { + BATADV_TP_REASON_COMPLETE = 3, + BATADV_TP_REASON_CANCEL = 4, + /* error status >= 128 */ + BATADV_TP_REASON_DST_UNREACHABLE = 128, + BATADV_TP_REASON_RESEND_LIMIT = 129, + BATADV_TP_REASON_ALREADY_ONGOING = 130, + BATADV_TP_REASON_MEMORY_ERROR = 131, + BATADV_TP_REASON_CANT_SEND = 132, + BATADV_TP_REASON_TOO_MANY = 133, +}; + +#endif /* _UAPI_LINUX_BATMAN_ADV_H_ */ diff --git a/package/gluon-mesh-batman-adv/src/respondd.c b/package/gluon-mesh-batman-adv/src/respondd.c new file mode 100644 index 00000000..60df1523 --- /dev/null +++ b/package/gluon-mesh-batman-adv/src/respondd.c @@ -0,0 +1,774 @@ +/* + Copyright (c) 2016, 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 + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "batadv-netlink.h" + + +#define _STRINGIFY(s) #s +#define STRINGIFY(s) _STRINGIFY(s) + +struct neigh_netlink_opts { + struct json_object *interfaces; + struct batadv_nlquery_opts query_opts; +}; + +struct gw_netlink_opts { + struct json_object *obj; + struct batadv_nlquery_opts query_opts; +}; + +struct clients_netlink_opts { + size_t total; + size_t wifi; + struct batadv_nlquery_opts query_opts; +}; + + +static struct json_object * get_addresses(void) { + FILE *f = fopen("/proc/net/if_inet6", "r"); + if (!f) + return NULL; + + char *line = NULL; + size_t len = 0; + + struct json_object *ret = json_object_new_array(); + + while (getline(&line, &len, f) >= 0) { + /* IF_NAMESIZE would be enough, but adding 1 here is simpler than subtracting 1 in the format string */ + char ifname[IF_NAMESIZE+1]; + unsigned int flags; + struct in6_addr addr; + char buf[INET6_ADDRSTRLEN]; + + if (sscanf(line, + "%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8 + "%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8 + " %*2x %*2x %*2x %2x %"STRINGIFY(IF_NAMESIZE)"s", + &addr.s6_addr[0], &addr.s6_addr[1], &addr.s6_addr[2], &addr.s6_addr[3], + &addr.s6_addr[4], &addr.s6_addr[5], &addr.s6_addr[6], &addr.s6_addr[7], + &addr.s6_addr[8], &addr.s6_addr[9], &addr.s6_addr[10], &addr.s6_addr[11], + &addr.s6_addr[12], &addr.s6_addr[13], &addr.s6_addr[14], &addr.s6_addr[15], + &flags, ifname) != 18) + continue; + + if (strcmp(ifname, "br-client")) + continue; + + if (flags & (IFA_F_TENTATIVE|IFA_F_DEPRECATED)) + continue; + + inet_ntop(AF_INET6, &addr, buf, sizeof(buf)); + + json_object_array_add(ret, json_object_new_string(buf)); + } + + fclose(f); + free(line); + + return ret; +} + +static void add_if_not_empty(struct json_object *obj, const char *key, struct json_object *val) { + if (json_object_array_length(val)) + json_object_object_add(obj, key, val); + else + json_object_put(val); +} + +static bool interface_file_exists(const char *ifname, const char *name) { + const char *format = "/sys/class/net/%s/%s"; + char path[strlen(format) + strlen(ifname) + strlen(name)]; + snprintf(path, sizeof(path), format, ifname, name); + + return !access(path, F_OK); +} + +static void mesh_add_subif(const char *ifname, struct json_object *wireless, + struct json_object *tunnel, struct json_object *other) { + struct json_object *address = gluonutil_wrap_and_free_string(gluonutil_get_interface_address(ifname)); + + char lowername[IFNAMSIZ]; + strncpy(lowername, ifname, sizeof(lowername)-1); + lowername[sizeof(lowername)-1] = 0; + + const char *format = "/sys/class/net/%s/lower_*"; + char pattern[strlen(format) + IFNAMSIZ]; + + /* In case of VLAN and bridge interfaces, we want the lower interface + * to determine the interface type (but not for the interface address) */ + while (true) { + snprintf(pattern, sizeof(pattern), format, lowername); + size_t pattern_len = strlen(pattern); + + glob_t lower; + if (glob(pattern, GLOB_NOSORT, NULL, &lower)) + break; + + strncpy(lowername, lower.gl_pathv[0] + pattern_len - 1, sizeof(lowername)-1); + + globfree(&lower); + } + + if (interface_file_exists(lowername, "wireless")) + json_object_array_add(wireless, address); + else if (interface_file_exists(lowername, "tun_flags")) + json_object_array_add(tunnel, address); + else + json_object_array_add(other, address); + +} + +static struct json_object * get_mesh_subifs(const char *ifname) { + struct json_object *wireless = json_object_new_array(); + struct json_object *tunnel = json_object_new_array(); + struct json_object *other = json_object_new_array(); + + const char *format = "/sys/class/net/%s/lower_*"; + char pattern[strlen(format) + strlen(ifname) - 1]; + snprintf(pattern, sizeof(pattern), format, ifname); + + size_t pattern_len = strlen(pattern); + + glob_t lower; + if (!glob(pattern, GLOB_NOSORT, NULL, &lower)) { + size_t i; + for (i = 0; i < lower.gl_pathc; i++) { + mesh_add_subif(lower.gl_pathv[i] + pattern_len - 1, + wireless, tunnel, other); + } + + globfree(&lower); + } + + struct json_object *ret = json_object_new_object(); + add_if_not_empty(ret, "wireless", wireless); + add_if_not_empty(ret, "tunnel", tunnel); + add_if_not_empty(ret, "other", other); + return ret; +} + +static struct json_object * get_mesh(void) { + struct json_object *ret = json_object_new_object(); + struct json_object *bat0_interfaces = json_object_new_object(); + json_object_object_add(bat0_interfaces, "interfaces", get_mesh_subifs("bat0")); + json_object_object_add(ret, "bat0", bat0_interfaces); + return ret; +} + +static struct json_object * get_batman_adv_compat(void) { + FILE *f = fopen("/lib/gluon/mesh-batman-adv/compat", "r"); + if (!f) + return NULL; + + struct json_object *ret = NULL; + + int compat; + if (fscanf(f, "%i", &compat) == 1) + ret = json_object_new_int(compat); + + fclose(f); + + return ret; +} + +static struct json_object * respondd_provider_nodeinfo(void) { + struct json_object *ret = json_object_new_object(); + + struct json_object *network = json_object_new_object(); + json_object_object_add(network, "addresses", get_addresses()); + json_object_object_add(network, "mesh", get_mesh()); + json_object_object_add(ret, "network", network); + + struct json_object *software = json_object_new_object(); + struct json_object *software_batman_adv = json_object_new_object(); + json_object_object_add(software_batman_adv, "version", gluonutil_wrap_and_free_string(gluonutil_read_line("/sys/module/batman_adv/version"))); + json_object_object_add(software_batman_adv, "compat", get_batman_adv_compat()); + json_object_object_add(software, "batman-adv", software_batman_adv); + json_object_object_add(ret, "software", software); + + return ret; +} + +static const enum batadv_nl_attrs gateways_mandatory[] = { + BATADV_ATTR_ORIG_ADDRESS, + BATADV_ATTR_ROUTER, +}; + +static int parse_gw_list_netlink_cb(struct nl_msg *msg, void *arg) +{ + struct nlattr *attrs[BATADV_ATTR_MAX+1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct batadv_nlquery_opts *query_opts = arg; + struct genlmsghdr *ghdr; + uint8_t *orig; + uint8_t *router; + struct gw_netlink_opts *opts; + char addr[18]; + + opts = container_of(query_opts, struct gw_netlink_opts, query_opts); + + if (!genlmsg_valid_hdr(nlh, 0)) + return NL_OK; + + ghdr = nlmsg_data(nlh); + + if (ghdr->cmd != BATADV_CMD_GET_GATEWAYS) + return NL_OK; + + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_netlink_policy)) + return NL_OK; + + if (batadv_nl_missing_attrs(attrs, gateways_mandatory, + ARRAY_SIZE(gateways_mandatory))) + return NL_OK; + + if (!attrs[BATADV_ATTR_FLAG_BEST]) + return NL_OK; + + orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); + router = nla_data(attrs[BATADV_ATTR_ROUTER]); + + sprintf(addr, "%02x:%02x:%02x:%02x:%02x:%02x", + orig[0], orig[1], orig[2], orig[3], orig[4], orig[5]); + + json_object_object_add(opts->obj, "gateway", json_object_new_string(addr)); + + sprintf(addr, "%02x:%02x:%02x:%02x:%02x:%02x", + router[0], router[1], router[2], router[3], router[4], router[5]); + + json_object_object_add(opts->obj, "gateway_nexthop", json_object_new_string(addr)); + + return NL_STOP; +} + +static void add_gateway(struct json_object *obj) { + struct gw_netlink_opts opts = { + .obj = obj, + .query_opts = { + .err = 0, + }, + }; + + batadv_nl_query_common("bat0", BATADV_CMD_GET_GATEWAYS, + parse_gw_list_netlink_cb, NLM_F_DUMP, + &opts.query_opts); +} + +static inline bool ethtool_ioctl(int fd, struct ifreq *ifr, void *data) { + ifr->ifr_data = data; + + return (ioctl(fd, SIOCETHTOOL, ifr) >= 0); +} + +static uint32_t ethtool_get_stats_length(int fd, struct ifreq *ifr) { + const size_t sset_info_len = sizeof(struct ethtool_sset_info) + sizeof(uint32_t); + struct ethtool_sset_info *sset_info = alloca(sset_info_len); + memset(sset_info, 0, sset_info_len); + + sset_info->cmd = ETHTOOL_GSSET_INFO; + sset_info->sset_mask = 1ull << ETH_SS_STATS; + + if (!ethtool_ioctl(fd, ifr, sset_info)) + return 0; + + return sset_info->sset_mask ? sset_info->data[0] : 0; +} + +static struct ethtool_gstrings * ethtool_get_stats_strings(int fd, struct ifreq *ifr) { + uint32_t n_stats = ethtool_get_stats_length(fd, ifr); + + if (!n_stats) + return NULL; + + struct ethtool_gstrings *strings = calloc(1, sizeof(*strings) + n_stats * ETH_GSTRING_LEN); + + strings->cmd = ETHTOOL_GSTRINGS; + strings->string_set = ETH_SS_STATS; + strings->len = n_stats; + + if (!ethtool_ioctl(fd, ifr, strings)) { + free(strings); + return NULL; + } + + return strings; +} + + +static struct json_object * get_traffic(void) { + struct ethtool_gstrings *strings = NULL; + struct ethtool_stats *stats = NULL; + + struct ifreq ifr = {}; + strncpy(ifr.ifr_name, "bat0", IF_NAMESIZE); + + struct json_object *ret = NULL; + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) + return NULL; + + strings = ethtool_get_stats_strings(fd, &ifr); + if (!strings) + goto out; + + stats = calloc(1, sizeof(struct ethtool_stats) + strings->len * sizeof(uint64_t)); + stats->cmd = ETHTOOL_GSTATS; + stats->n_stats = strings->len; + + if (!ethtool_ioctl(fd, &ifr, stats)) + goto out; + + struct json_object *rx = json_object_new_object(); + struct json_object *tx = json_object_new_object(); + struct json_object *forward = json_object_new_object(); + struct json_object *mgmt_rx = json_object_new_object(); + struct json_object *mgmt_tx = json_object_new_object(); + + size_t i; + for (i = 0; i < strings->len; i++) { + if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "rx", ETH_GSTRING_LEN)) + json_object_object_add(rx, "packets", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "rx_bytes", ETH_GSTRING_LEN)) + json_object_object_add(rx, "bytes", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "tx", ETH_GSTRING_LEN)) + json_object_object_add(tx, "packets", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "tx_dropped", ETH_GSTRING_LEN)) + json_object_object_add(tx, "dropped", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "tx_bytes", ETH_GSTRING_LEN)) + json_object_object_add(tx, "bytes", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "forward", ETH_GSTRING_LEN)) + json_object_object_add(forward, "packets", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "forward_bytes", ETH_GSTRING_LEN)) + json_object_object_add(forward, "bytes", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "mgmt_rx", ETH_GSTRING_LEN)) + json_object_object_add(mgmt_rx, "packets", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "mgmt_rx_bytes", ETH_GSTRING_LEN)) + json_object_object_add(mgmt_rx, "bytes", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "mgmt_tx", ETH_GSTRING_LEN)) + json_object_object_add(mgmt_tx, "packets", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "mgmt_tx_bytes", ETH_GSTRING_LEN)) + json_object_object_add(mgmt_tx, "bytes", json_object_new_int64(stats->data[i])); + } + + ret = json_object_new_object(); + json_object_object_add(ret, "rx", rx); + json_object_object_add(ret, "tx", tx); + json_object_object_add(ret, "forward", forward); + json_object_object_add(ret, "mgmt_rx", mgmt_rx); + json_object_object_add(ret, "mgmt_tx", mgmt_tx); + + out: + free(stats); + free(strings); + close(fd); + return ret; +} + +static void count_iface_stations(size_t *wifi24, size_t *wifi5, const char *ifname) { + const struct iwinfo_ops *iw = iwinfo_backend(ifname); + if (!iw) + return; + + int freq; + if (iw->frequency(ifname, &freq) < 0) + return; + + size_t *wifi; + if (freq >= 2400 && freq < 2500) + wifi = wifi24; + else if (freq >= 5000 && freq < 6000) + wifi = wifi5; + else + return; + + int len; + char buf[IWINFO_BUFSIZE]; + if (iw->assoclist(ifname, buf, &len) < 0) + return; + + struct iwinfo_assoclist_entry *entry; + for (entry = (struct iwinfo_assoclist_entry *)buf; (char*)(entry+1) <= buf + len; entry++) + (*wifi)++; +} + +static void count_stations(size_t *wifi24, size_t *wifi5) { + struct uci_context *ctx = uci_alloc_context(); + ctx->flags &= ~UCI_FLAG_STRICT; + + + struct uci_package *p; + if (uci_load(ctx, "wireless", &p)) + goto end; + + + struct uci_element *e; + uci_foreach_element(&p->sections, e) { + struct uci_section *s = uci_to_section(e); + if (strcmp(s->type, "wifi-iface")) + continue; + + const char *network = uci_lookup_option_string(ctx, s, "network"); + if (!network || strcmp(network, "client")) + continue; + + const char *mode = uci_lookup_option_string(ctx, s, "mode"); + if (!mode || strcmp(mode, "ap")) + continue; + + const char *ifname = uci_lookup_option_string(ctx, s, "ifname"); + if (!ifname) + continue; + + count_iface_stations(wifi24, wifi5, ifname); + } + + end: + uci_free_context(ctx); +} + +static const enum batadv_nl_attrs clients_mandatory[] = { + BATADV_ATTR_TT_FLAGS, +}; + +static int parse_clients_list_netlink_cb(struct nl_msg *msg, void *arg) +{ + struct nlattr *attrs[BATADV_ATTR_MAX+1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct batadv_nlquery_opts *query_opts = arg; + struct genlmsghdr *ghdr; + struct clients_netlink_opts *opts; + uint32_t flags; + + opts = container_of(query_opts, struct clients_netlink_opts, query_opts); + + if (!genlmsg_valid_hdr(nlh, 0)) + return NL_OK; + + ghdr = nlmsg_data(nlh); + + if (ghdr->cmd != BATADV_CMD_GET_TRANSTABLE_LOCAL) + return NL_OK; + + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_netlink_policy)) + return NL_OK; + + if (batadv_nl_missing_attrs(attrs, clients_mandatory, + ARRAY_SIZE(clients_mandatory))) + return NL_OK; + + flags = nla_get_u32(attrs[BATADV_ATTR_TT_FLAGS]); + + if (flags & BATADV_TT_CLIENT_NOPURGE) + return NL_OK; + + if (flags & BATADV_TT_CLIENT_WIFI) + opts->wifi++; + + opts->total++; + + return NL_OK; +} + +static struct json_object * get_clients(void) { + size_t wifi24 = 0, wifi5 = 0; + struct clients_netlink_opts opts = { + .total = 0, + .wifi = 0, + .query_opts = { + .err = 0, + }, + }; + + batadv_nl_query_common("bat0", BATADV_CMD_GET_TRANSTABLE_LOCAL, + parse_clients_list_netlink_cb, NLM_F_DUMP, + &opts.query_opts); + + count_stations(&wifi24, &wifi5); + + struct json_object *ret = json_object_new_object(); + json_object_object_add(ret, "total", json_object_new_int(opts.total)); + json_object_object_add(ret, "wifi", json_object_new_int(opts.wifi)); + json_object_object_add(ret, "wifi24", json_object_new_int(wifi24)); + json_object_object_add(ret, "wifi5", json_object_new_int(wifi5)); + return ret; +} + + +static struct json_object * respondd_provider_statistics(void) { + struct json_object *ret = json_object_new_object(); + + json_object_object_add(ret, "clients", get_clients()); + json_object_object_add(ret, "traffic", get_traffic()); + + add_gateway(ret); + + return ret; +} + + +static struct json_object * ifnames2addrs(struct json_object *interfaces) { + struct json_object *ret = json_object_new_object(); + + json_object_object_foreach(interfaces, ifname, interface) { + char *ifaddr = gluonutil_get_interface_address(ifname); + if (!ifaddr) + continue; + + struct json_object *obj = json_object_new_object(); + json_object_object_add(obj, "neighbours", json_object_get(interface)); + json_object_object_add(ret, ifaddr, obj); + + free(ifaddr); + } + + json_object_put(interfaces); + + return ret; +} + +static const enum batadv_nl_attrs parse_orig_list_mandatory[] = { + BATADV_ATTR_ORIG_ADDRESS, + BATADV_ATTR_NEIGH_ADDRESS, + BATADV_ATTR_TQ, + BATADV_ATTR_HARD_IFINDEX, + BATADV_ATTR_LAST_SEEN_MSECS, +}; + +static int parse_orig_list_netlink_cb(struct nl_msg *msg, void *arg) +{ + struct nlattr *attrs[BATADV_ATTR_MAX+1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct batadv_nlquery_opts *query_opts = arg; + struct genlmsghdr *ghdr; + uint8_t *orig; + uint8_t *dest; + uint8_t tq; + uint32_t hardif; + uint32_t lastseen; + char ifname_buf[IF_NAMESIZE], *ifname; + struct neigh_netlink_opts *opts; + char mac1[18]; + + opts = container_of(query_opts, struct neigh_netlink_opts, query_opts); + + if (!genlmsg_valid_hdr(nlh, 0)) + return NL_OK; + + ghdr = nlmsg_data(nlh); + + if (ghdr->cmd != BATADV_CMD_GET_ORIGINATORS) + return NL_OK; + + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_netlink_policy)) + return NL_OK; + + if (batadv_nl_missing_attrs(attrs, parse_orig_list_mandatory, + ARRAY_SIZE(parse_orig_list_mandatory))) + return NL_OK; + + if (!attrs[BATADV_ATTR_FLAG_BEST]) + return NL_OK; + + orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); + dest = nla_data(attrs[BATADV_ATTR_NEIGH_ADDRESS]); + tq = nla_get_u8(attrs[BATADV_ATTR_TQ]); + hardif = nla_get_u32(attrs[BATADV_ATTR_HARD_IFINDEX]); + lastseen = nla_get_u32(attrs[BATADV_ATTR_LAST_SEEN_MSECS]); + + if (memcmp(orig, dest, 6) != 0) + return NL_OK; + + ifname = if_indextoname(hardif, ifname_buf); + if (!ifname) + return NL_OK; + + sprintf(mac1, "%02x:%02x:%02x:%02x:%02x:%02x", + orig[0], orig[1], orig[2], orig[3], orig[4], orig[5]); + + struct json_object *obj = json_object_new_object(); + if (!obj) + return NL_OK; + + struct json_object *interface; + if (!json_object_object_get_ex(opts->interfaces, ifname, &interface)) { + interface = json_object_new_object(); + json_object_object_add(opts->interfaces, ifname, interface); + } + + json_object_object_add(obj, "tq", json_object_new_int(tq)); + json_object_object_add(obj, "lastseen", json_object_new_double(lastseen / 1000.)); + json_object_object_add(interface, mac1, obj); + + return NL_OK; +} + +static struct json_object * get_batadv(void) { + struct neigh_netlink_opts opts = { + .query_opts = { + .err = 0, + }, + }; + int ret; + + opts.interfaces = json_object_new_object(); + if (!opts.interfaces) + return NULL; + + ret = batadv_nl_query_common("bat0", BATADV_CMD_GET_ORIGINATORS, + parse_orig_list_netlink_cb, NLM_F_DUMP, + &opts.query_opts); + if (ret < 0) { + json_object_put(opts.interfaces); + return NULL; + } + + return ifnames2addrs(opts.interfaces); +} + +static struct json_object * get_wifi_neighbours(const char *ifname) { + const struct iwinfo_ops *iw = iwinfo_backend(ifname); + if (!iw) + return NULL; + + int len; + char buf[IWINFO_BUFSIZE]; + if (iw->assoclist(ifname, buf, &len) < 0) + return NULL; + + struct json_object *neighbours = json_object_new_object(); + + struct iwinfo_assoclist_entry *entry; + for (entry = (struct iwinfo_assoclist_entry *)buf; (char*)(entry+1) <= buf + len; entry++) { + struct json_object *obj = json_object_new_object(); + + json_object_object_add(obj, "signal", json_object_new_int(entry->signal)); + json_object_object_add(obj, "noise", json_object_new_int(entry->noise)); + json_object_object_add(obj, "inactive", json_object_new_int(entry->inactive)); + + char mac[18]; + snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x", + entry->mac[0], entry->mac[1], entry->mac[2], + entry->mac[3], entry->mac[4], entry->mac[5]); + + json_object_object_add(neighbours, mac, obj); + } + + struct json_object *ret = json_object_new_object(); + + if (json_object_object_length(neighbours)) + json_object_object_add(ret, "neighbours", neighbours); + else + json_object_put(neighbours); + + return ret; +} + +static struct json_object * get_wifi(void) { + const char *mesh = "bat0"; + + struct json_object *ret = json_object_new_object(); + + const char *format = "/sys/class/net/%s/lower_*"; + char pattern[strlen(format) + strlen(mesh)]; + snprintf(pattern, sizeof(pattern), format, mesh); + + size_t pattern_len = strlen(pattern); + + glob_t lower; + if (!glob(pattern, GLOB_NOSORT, NULL, &lower)) { + size_t i; + for (i = 0; i < lower.gl_pathc; i++) { + const char *ifname = lower.gl_pathv[i] + pattern_len - 1; + char *ifaddr = gluonutil_get_interface_address(ifname); + if (!ifaddr) + continue; + + struct json_object *neighbours = get_wifi_neighbours(ifname); + if (neighbours) + json_object_object_add(ret, ifaddr, neighbours); + + free(ifaddr); + } + + globfree(&lower); + } + + return ret; +} + +static struct json_object * respondd_provider_neighbours(void) { + struct json_object *ret = json_object_new_object(); + + struct json_object *batadv = get_batadv(); + if (batadv) + json_object_object_add(ret, "batadv", batadv); + + struct json_object *wifi = get_wifi(); + if (wifi) + json_object_object_add(ret, "wifi", wifi); + + return ret; +} + + +const struct respondd_provider_info respondd_providers[] = { + {"nodeinfo", respondd_provider_nodeinfo}, + {"statistics", respondd_provider_statistics}, + {"neighbours", respondd_provider_neighbours}, + {} +}; diff --git a/package/gluon-mesh-vpn-core/Makefile b/package/gluon-mesh-vpn-core/Makefile new file mode 100644 index 00000000..057d3bfa --- /dev/null +++ b/package/gluon-mesh-vpn-core/Makefile @@ -0,0 +1,35 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-mesh-vpn-core +PKG_VERSION:=1 + + +include ../gluon.mk + + +define Package/gluon-mesh-vpn-core + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Basic support for connecting meshes via VPN tunnels + DEPENDS:=+gluon-core +gluon-wan-dnsmasq +iptables +iptables-mod-extra +simple-tc +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Compile + $(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/) +endef + +define Package/gluon-mesh-vpn-core/install + $(CP) ./files/* $(1)/ + $(CP) $(PKG_BUILD_DIR)/luadest/* $(1)/ +endef + +define Package/gluon-mesh-vpn-core/postinst +#!/bin/sh +$(call GluonCheckSite,check_site.lua) +endef + +$(eval $(call BuildPackage,gluon-mesh-vpn-core)) diff --git a/package/gluon-mesh-vpn-core/check_site.lua b/package/gluon-mesh-vpn-core/check_site.lua new file mode 100644 index 00000000..94c0887b --- /dev/null +++ b/package/gluon-mesh-vpn-core/check_site.lua @@ -0,0 +1,8 @@ +need_boolean('mesh_vpn.enabled', false) +need_number('mesh_vpn.mtu') + +if need_table('mesh_vpn.bandwidth_limit', nil, false) then + need_boolean('mesh_vpn.bandwidth_limit.enabled', false) + need_number('mesh_vpn.bandwidth_limit.ingress', false) + need_number('mesh_vpn.bandwidth_limit.egress', false) +end diff --git a/package/gluon-mesh-vpn-core/files/lib/gluon/mesh-vpn/iptables.rules b/package/gluon-mesh-vpn-core/files/lib/gluon/mesh-vpn/iptables.rules new file mode 100644 index 00000000..771fb40c --- /dev/null +++ b/package/gluon-mesh-vpn-core/files/lib/gluon/mesh-vpn/iptables.rules @@ -0,0 +1,3 @@ +*nat +-I OUTPUT -m owner --gid-owner gluon-mesh-vpn -o lo -d 127.0.0.1 -p udp --dport 53 -j DNAT --to-destination :54 +COMMIT diff --git a/package/gluon-mesh-vpn-core/luasrc/lib/gluon/upgrade/400-mesh-vpn b/package/gluon-mesh-vpn-core/luasrc/lib/gluon/upgrade/400-mesh-vpn new file mode 100755 index 00000000..6ab719db --- /dev/null +++ b/package/gluon-mesh-vpn-core/luasrc/lib/gluon/upgrade/400-mesh-vpn @@ -0,0 +1,76 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local users = require 'gluon.users' +local util = require 'gluon.util' +local fs = require 'nixio.fs' + +local uci = require('simple-uci').cursor() + + +uci:section('network', 'interface', 'mesh_vpn', { + ifname = 'mesh-vpn', + proto = 'gluon_mesh', + transitive = true, + fixed_mtu = true, + macaddr = util.generate_mac(7), + mtu = site.mesh_vpn.mtu, +}) + +uci:save('network') + + +if fs.access('/etc/config/gluon-simple-tc') then + os.rename('/etc/config/gluon-simple-tc', '/etc/config/simple-tc') +end + +if not uci:get('simple-tc', 'mesh_vpn') then + local config = { + ifname = 'mesh-vpn', + enabled = false, + } + + + if site.mesh_vpn.bandwidth_limit then + if site.mesh_vpn.bandwidth_limit.enabled then + config.enabled = true + end + + config.limit_ingress = site.mesh_vpn.bandwidth_limit.ingress + config.limit_egress = site.mesh_vpn.bandwidth_limit.egress + end + + uci:section('simple-tc', 'interface', 'mesh_vpn', config) + uci:save('simple-tc') +end + + +-- The previously used user and group are removed, we now have a generic group +users.remove_user('gluon-fastd') +users.remove_group('gluon-fastd') + +users.add_group('gluon-mesh-vpn', 800) + +uci:section('firewall', 'include', 'mesh_vpn_dns', { + type = 'restore', + path = '/lib/gluon/mesh-vpn/iptables.rules', + family = 'ipv4', +}) + +uci:save('firewall') + + +-- VPN migration +local has_fastd = fs.access('/lib/gluon/mesh-vpn/fastd') +local fastd_enabled = uci:get_bool("fastd", "mesh_vpn", "enabled") + +local has_tunneldigger = fs.access('/lib/gluon/mesh-vpn/tunneldigger') +local tunneldigger_enabled = uci:get_bool("tunneldigger", "mesh_vpn", "enabled") + +local enabled = fastd_enabled or tunneldigger_enabled or false + +uci:set("fastd", "mesh_vpn", "enabled", has_fastd and enabled) +uci:save("fastd") + +uci:set("tunneldigger", "mesh_vpn", "enabled", has_tunneldigger and enabled) +uci:save("tunneldigger") diff --git a/package/gluon-mesh-vpn-fastd/Makefile b/package/gluon-mesh-vpn-fastd/Makefile index 775f92f1..2a1cc067 100644 --- a/package/gluon-mesh-vpn-fastd/Makefile +++ b/package/gluon-mesh-vpn-fastd/Makefile @@ -4,32 +4,33 @@ PKG_NAME:=gluon-mesh-vpn-fastd PKG_VERSION:=3 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) +PKG_BUILD_DEPENDS := respondd + +include ../gluon.mk -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 + TITLE:=Support for connecting meshes via fastd + DEPENDS:=+gluon-core +libgluonutil +gluon-mesh-vpn-core +fastd endef define Build/Prepare mkdir -p $(PKG_BUILD_DIR) -endef - -define Build/Configure + $(CP) ./src/* $(PKG_BUILD_DIR)/ endef define Build/Compile + $(call Build/Compile/Default) + $(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/) endef define Package/gluon-mesh-vpn-fastd/install $(CP) ./files/* $(1)/ + $(CP) $(PKG_BUILD_DIR)/luadest/* $(1)/ + $(INSTALL_DIR) $(1)/lib/gluon/respondd + $(CP) $(PKG_BUILD_DIR)/respondd.so $(1)/lib/gluon/respondd/mesh-vpn-fastd.so endef define Package/gluon-mesh-vpn-fastd/postinst diff --git a/package/gluon-mesh-vpn-fastd/check_site.lua b/package/gluon-mesh-vpn-fastd/check_site.lua index 7a2c4913..64da9c88 100644 --- a/package/gluon-mesh-vpn-fastd/check_site.lua +++ b/package/gluon-mesh-vpn-fastd/check_site.lua @@ -1,26 +1,30 @@ -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 fastd_methods = {'salsa2012+gmac', 'salsa2012+umac', 'null+salsa2012+gmac', 'null+salsa2012+umac', 'null'} +need_array_of('mesh_vpn.fastd.methods', fastd_methods) +need_boolean('mesh_vpn.fastd.configurable', false) +need_one_of('mesh_vpn.fastd.syslog_level', {'error', 'warn', 'info', 'verbose', 'debug', 'debug2'}, false) local function check_peer(prefix) - return function(k, _) - local table = string.format('%s[%q].', prefix, k) + return function(k, _) + assert_uci_name(k) - need_string(table .. 'key') - need_string_array(table .. 'remotes') - end + local table = string.format('%s[%q].', prefix, k) + + need_string_match(table .. 'key', '^%x+$') + need_string_array(table .. 'remotes') + end end local function check_group(prefix) - return function(k, _) - local table = string.format('%s[%q].', prefix, k) + return function(k, _) + assert_uci_name(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 + 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')) +need_table('mesh_vpn.fastd.groups', check_group('mesh_vpn.fastd.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 deleted file mode 100644 index bbfbda08..00000000 --- a/package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/nodeinfo.d/software/fastd +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index a67b9a07..00000000 --- a/package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/statistics.d/mesh_vpn +++ /dev/null @@ -1,71 +0,0 @@ -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 deleted file mode 100644 index c1a16ee1..00000000 --- a/package/gluon-mesh-vpn-fastd/files/lib/gluon/mesh-vpn-fastd/iptables.rules +++ /dev/null @@ -1,3 +0,0 @@ -*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/mesh-vpn/fastd b/package/gluon-mesh-vpn-fastd/files/lib/gluon/mesh-vpn/fastd new file mode 100644 index 00000000..e69de29b 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 deleted file mode 100755 index 316546bc..00000000 --- a/package/gluon-mesh-vpn-fastd/files/lib/gluon/upgrade/400-mesh-vpn-fastd +++ /dev/null @@ -1,148 +0,0 @@ -#!/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/luasrc/lib/gluon/upgrade/400-mesh-vpn-fastd b/package/gluon-mesh-vpn-fastd/luasrc/lib/gluon/upgrade/400-mesh-vpn-fastd new file mode 100755 index 00000000..91e2d1fb --- /dev/null +++ b/package/gluon-mesh-vpn-fastd/luasrc/lib/gluon/upgrade/400-mesh-vpn-fastd @@ -0,0 +1,104 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local util = require 'gluon.util' + +local uci = require('simple-uci').cursor() + + +local enabled = uci:get('fastd', 'mesh_vpn', 'enabled') +if enabled == nil then + enabled = site.mesh_vpn.enabled or false +end + +local syslog_level = uci:get('fastd', 'mesh_vpn', 'syslog_level') or 'verbose' + +local methods + +if site.mesh_vpn.fastd.configurable then + local has_null = util.contains(site.mesh_vpn.fastd.methods, 'null') + + local old_methods = uci:get('fastd', 'mesh_vpn', 'method') + if old_methods then + has_null = util.contains(old_methods, 'null') + end + + methods = {} + if has_null then + table.insert(methods, 'null') + end + + for _, method in ipairs(site.mesh_vpn.fastd.methods) do + if method ~= 'null' then + table.insert(methods, method) + end + end + +else + methods = site.mesh_vpn.fastd.methods +end + + +uci:section('fastd', 'fastd', 'mesh_vpn', { + enabled = enabled, + group = 'gluon-mesh-vpn', + syslog_level = syslog_level, + interface = 'mesh-vpn', + mode = 'tap', + mtu = site.mesh_vpn.mtu, + secure_handshakes = true, + 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 = true, + 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 = true, + 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.mesh_vpn.fastd.groups) + + +uci:save('fastd') diff --git a/package/gluon-mesh-vpn-fastd/files/lib/gluon/upgrade/410-mesh-vpn-fastd-generate-secret b/package/gluon-mesh-vpn-fastd/luasrc/lib/gluon/upgrade/410-mesh-vpn-fastd-generate-secret similarity index 79% rename from package/gluon-mesh-vpn-fastd/files/lib/gluon/upgrade/410-mesh-vpn-fastd-generate-secret rename to package/gluon-mesh-vpn-fastd/luasrc/lib/gluon/upgrade/410-mesh-vpn-fastd-generate-secret index 68a2fe67..f43e8b1f 100755 --- a/package/gluon-mesh-vpn-fastd/files/lib/gluon/upgrade/410-mesh-vpn-fastd-generate-secret +++ b/package/gluon-mesh-vpn-fastd/luasrc/lib/gluon/upgrade/410-mesh-vpn-fastd-generate-secret @@ -1,6 +1,6 @@ #!/usr/bin/lua -local uci = require 'luci.model.uci' +local uci = require 'simple-uci' local c = uci.cursor() @@ -9,5 +9,4 @@ 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-mesh-vpn-fastd/src/Makefile b/package/gluon-mesh-vpn-fastd/src/Makefile new file mode 100644 index 00000000..3ddc8a58 --- /dev/null +++ b/package/gluon-mesh-vpn-fastd/src/Makefile @@ -0,0 +1,6 @@ +all: respondd.so + +CFLAGS += -Wall + +respondd.so: respondd.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -o $@ $^ $(LDLIBS) -lgluonutil -luci diff --git a/package/gluon-mesh-vpn-fastd/src/respondd.c b/package/gluon-mesh-vpn-fastd/src/respondd.c new file mode 100644 index 00000000..87d69e07 --- /dev/null +++ b/package/gluon-mesh-vpn-fastd/src/respondd.c @@ -0,0 +1,311 @@ +/* + Copyright (c) 2016, 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 + + +static struct json_object * get_peer_groups(struct json_object *groups, struct json_object *peers); + +static struct json_object * get_fastd_version(void) { + FILE *f = popen("exec fastd -v", "r"); + if (!f) + return NULL; + + char *line = NULL; + size_t len = 0; + + ssize_t r = getline(&line, &len, f); + + pclose(f); + + if (r >= 0) { + len = strlen(line); /* The len given by getline is the buffer size, not the string length */ + + if (len && line[len-1] == '\n') + line[len-1] = 0; + } + else { + free(line); + line = NULL; + } + + const char *version = line; + if (strncmp(version, "fastd ", 6) == 0) + version += 6; + + struct json_object *ret = gluonutil_wrap_string(version); + free(line); + return ret; +} + +static struct json_object * get_fastd(void) { + bool enabled = false; + + struct uci_context *ctx = uci_alloc_context(); + ctx->flags &= ~UCI_FLAG_STRICT; + + struct uci_package *p; + if (uci_load(ctx, "fastd", &p)) + goto disabled; + + struct uci_section *s = uci_lookup_section(ctx, p, "mesh_vpn"); + if (!s) + goto disabled; + + const char *enabled_str = uci_lookup_option_string(ctx, s, "enabled"); + if (!enabled_str || !strcmp(enabled_str, "1")) + enabled = true; + + disabled: + + uci_free_context(ctx); + + struct json_object *ret = json_object_new_object(); + json_object_object_add(ret, "version", get_fastd_version()); + json_object_object_add(ret, "enabled", json_object_new_boolean(enabled)); + return ret; +} + +static struct json_object * respondd_provider_nodeinfo(void) { + struct json_object *ret = json_object_new_object(); + + struct json_object *software = json_object_new_object(); + json_object_object_add(software, "fastd", get_fastd()); + json_object_object_add(ret, "software", software); + + return ret; +} + + +static const char * get_status_socket(struct uci_context *ctx, struct uci_section *s) { + return uci_lookup_option_string(ctx, s, "status_socket"); +} + +static struct json_object * read_status(struct uci_context *ctx, struct uci_section *s) { + const char *path = get_status_socket(ctx, s); + + size_t addrlen = strlen(path); + + /* Allocate enough space for arbitrary-length paths */ + char addrbuf[offsetof(struct sockaddr_un, sun_path) + addrlen + 1]; + memset(addrbuf, 0, sizeof(addrbuf)); + + struct sockaddr_un *addr = (struct sockaddr_un *)addrbuf; + addr->sun_family = AF_UNIX; + memcpy(addr->sun_path, path, addrlen+1); + + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) + return NULL; + + if (connect(fd, (struct sockaddr*)addr, sizeof(addrbuf)) < 0) { + close(fd); + return NULL; + } + + struct json_object *ret = NULL; + struct json_tokener *tok = json_tokener_new(); + + do { + char buf[1024]; + size_t len = read(fd, buf, sizeof(buf)); + if (len <= 0) + break; + + ret = json_tokener_parse_ex(tok, buf, len); + } while (!ret && json_tokener_get_error(tok) == json_tokener_continue); + + json_tokener_free(tok); + close(fd); + return ret; +} + +static struct json_object * get_status(void) { + struct json_object *ret = NULL; + + struct uci_context *ctx = uci_alloc_context(); + ctx->flags &= ~UCI_FLAG_STRICT; + + struct uci_package *p; + if (!uci_load(ctx, "fastd", &p)) { + struct uci_section *s = uci_lookup_section(ctx, p, "mesh_vpn"); + + if (s) + ret = read_status(ctx, s); + } + + uci_free_context(ctx); + + return ret; +} + +static bool get_peer_connection(struct json_object **ret, struct json_object *config, struct json_object *peers) { + struct json_object *key_object; + if (!json_object_object_get_ex(config, "key", &key_object)) + return false; + + const char *key = json_object_get_string(key_object); + if (!key) + return false; + + struct json_object *peer, *connection, *established; + if (!json_object_object_get_ex(peers, key, &peer) || + !json_object_object_get_ex(peer, "connection", &connection)) + return false; + + if (json_object_object_get_ex(connection, "established", &established)) { + int64_t established_time = json_object_get_int64(established); + + *ret = json_object_new_object(); + struct json_object *jso = json_object_new_double(established_time/1000.0); + json_object_set_serializer(jso, json_object_double_to_json_string, "%.3f", NULL); + json_object_object_add(*ret, "established", jso); + } + else { + *ret = NULL; + } + + return true; +} + +static struct json_object * get_peer_group(struct json_object *config, struct json_object *peers) { + struct json_object *ret = json_object_new_object(); + + struct json_object *config_peers; + if (json_object_object_get_ex(config, "peers", &config_peers) && + json_object_is_type(config_peers, json_type_object)) { + struct json_object *ret_peers = json_object_new_object(); + + json_object_object_foreach(config_peers, peername, peerconfig) { + struct json_object *obj; + if (get_peer_connection(&obj, peerconfig, peers)) + json_object_object_add(ret_peers, peername, obj); + } + + if (json_object_object_length(ret_peers)) + json_object_object_add(ret, "peers", ret_peers); + else + json_object_put(ret_peers); + } + + struct json_object *config_groups; + if (json_object_object_get_ex(config, "groups", &config_groups)) { + struct json_object *obj = get_peer_groups(config_groups, peers); + if (obj) + json_object_object_add(ret, "groups", obj); + } + + + if (!json_object_object_length(ret)) { + json_object_put(ret); + return NULL; + } + + return ret; +} + +static struct json_object * get_peer_groups(struct json_object *groups, struct json_object *peers) { + if (!json_object_is_type(groups, json_type_object)) + return NULL; + + struct json_object *ret = json_object_new_object(); + + json_object_object_foreach(groups, name, group) { + struct json_object *g = get_peer_group(group, peers); + if (g) + json_object_object_add(ret, name, g); + } + + if (!json_object_object_length(ret)) { + json_object_put(ret); + return NULL; + } + + return ret; +} + +static struct json_object * get_mesh_vpn(void) { + struct json_object *ret = NULL; + struct json_object *status = NULL; + struct json_object *site = NULL; + + status = get_status(); + if (!status) + goto end; + + struct json_object *peers; + if (!json_object_object_get_ex(status, "peers", &peers)) + goto end; + + site = gluonutil_load_site_config(); + if (!site) + goto end; + + struct json_object *mesh_vpn; + if (!json_object_object_get_ex(site, "mesh_vpn", &mesh_vpn)) + goto end; + + struct json_object *mesh_vpn_fastd; + if (!json_object_object_get_ex(mesh_vpn, "fastd", &mesh_vpn_fastd)) + goto end; + + ret = get_peer_group(mesh_vpn_fastd, peers); + + end: + json_object_put(site); + json_object_put(status); + + return ret; +} + +static struct json_object * respondd_provider_statistics(void) { + struct json_object *ret = json_object_new_object(); + + struct json_object *mesh_vpn = get_mesh_vpn(); + if (mesh_vpn) + json_object_object_add(ret, "mesh_vpn", mesh_vpn); + + return ret; +} + + +const struct respondd_provider_info respondd_providers[] = { + {"nodeinfo", respondd_provider_nodeinfo}, + {"statistics", respondd_provider_statistics}, + {} +}; diff --git a/package/gluon-mesh-vpn-tunneldigger/Makefile b/package/gluon-mesh-vpn-tunneldigger/Makefile new file mode 100644 index 00000000..6aadc3b6 --- /dev/null +++ b/package/gluon-mesh-vpn-tunneldigger/Makefile @@ -0,0 +1,38 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-mesh-vpn-tunneldigger +PKG_VERSION:=3 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include ../gluon.mk + +define Package/gluon-mesh-vpn-tunneldigger + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Support for connecting meshes via tunneltigger/L2TPv3 pseudowire + DEPENDS:=+gluon-core +gluon-mesh-vpn-core +tunneldigger +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile + $(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/) +endef + +define Package/gluon-mesh-vpn-tunneldigger/install + $(CP) ./files/* $(1)/ + $(CP) $(PKG_BUILD_DIR)/luadest/* $(1)/ +endef + +define Package/gluon-mesh-vpn-tunneldigger/postinst +#!/bin/sh +$(call GluonCheckSite,check_site.lua) +endef + +$(eval $(call BuildPackage,gluon-mesh-vpn-tunneldigger)) diff --git a/package/gluon-mesh-vpn-tunneldigger/check_site.lua b/package/gluon-mesh-vpn-tunneldigger/check_site.lua new file mode 100644 index 00000000..f218a1ef --- /dev/null +++ b/package/gluon-mesh-vpn-tunneldigger/check_site.lua @@ -0,0 +1 @@ +need_string_array('mesh_vpn.tunneldigger.brokers') diff --git a/package/gluon-mesh-vpn-tunneldigger/files/lib/gluon/mesh-vpn/tunneldigger b/package/gluon-mesh-vpn-tunneldigger/files/lib/gluon/mesh-vpn/tunneldigger new file mode 100644 index 00000000..e69de29b diff --git a/package/gluon-mesh-vpn-tunneldigger/luasrc/lib/gluon/upgrade/400-mesh-vpn-tunneldigger b/package/gluon-mesh-vpn-tunneldigger/luasrc/lib/gluon/upgrade/400-mesh-vpn-tunneldigger new file mode 100755 index 00000000..01500e52 --- /dev/null +++ b/package/gluon-mesh-vpn-tunneldigger/luasrc/lib/gluon/upgrade/400-mesh-vpn-tunneldigger @@ -0,0 +1,34 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local util = require 'gluon.util' + +local uci = require('simple-uci').cursor() + + +local enabled = uci:get('tunneldigger', 'mesh_vpn', 'enabled') +if enabled == nil then + if uci:get_first('tunneldigger', 'broker', 'interface') == "mesh-vpn" then + enabled = uci:get_first('tunneldigger', 'broker', 'enabled') + end +end +if enabled == nil then + enabled = site.mesh_vpn.enabled or false +end + +-- Delete old broker config section +if not uci:get('tunneldigger', 'mesh_vpn') then + uci:delete_all('tunneldigger', 'broker') +end + +uci:section('tunneldigger', 'broker', 'mesh_vpn', { + enabled = enabled, + uuid = util.node_id(), + interface = 'mesh-vpn', + bind_interface = 'br-wan', + group = 'gluon-mesh-vpn', + broker_selection = 'usage', + address = site.mesh_vpn.tunneldigger.brokers, +}) + +uci:save('tunneldigger') diff --git a/package/gluon-neighbour-info/Makefile b/package/gluon-neighbour-info/Makefile index 74aa6e8f..867f32f6 100644 --- a/package/gluon-neighbour-info/Makefile +++ b/package/gluon-neighbour-info/Makefile @@ -6,7 +6,8 @@ PKG_RELEASE:=1 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) -include $(INCLUDE_DIR)/package.mk +include ../gluon.mk + define Package/gluon-neighbour-info SECTION:=gluon @@ -29,9 +30,11 @@ endef define Build/Compile CFLAGS="$(TARGET_CFLAGS)" CPPFLAGS="$(TARGET_CPPFLAGS)" $(MAKE) -C $(PKG_BUILD_DIR) $(TARGET_CONFIGURE_OPTS) + $(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/) endef define Package/gluon-neighbour-info/install + $(CP) $(PKG_BUILD_DIR)/luadest/* $(1)/ $(INSTALL_DIR) $(1)/usr/bin $(INSTALL_BIN) $(PKG_BUILD_DIR)/gluon-neighbour-info $(1)/usr/bin/ endef diff --git a/package/gluon-neighbour-info/luasrc/lib/gluon/upgrade/400-neighbour-info-firewall b/package/gluon-neighbour-info/luasrc/lib/gluon/upgrade/400-neighbour-info-firewall new file mode 100755 index 00000000..aa54de5f --- /dev/null +++ b/package/gluon-neighbour-info/luasrc/lib/gluon/upgrade/400-neighbour-info-firewall @@ -0,0 +1,19 @@ +#!/usr/bin/lua + +local uci = require('simple-uci').cursor() + +-- Allow incoming respondd replies to queries on WAN +-- If the query was via multicast, the response isn't matched by --state RELATED +uci:section('firewall', 'rule', 'wan_respondd_reply', + { + name = 'wan_respondd_reply', + src = 'wan', + src_ip = 'fe80::/64', + src_port = '1001', + dest_port = '32768:61000', -- see /proc/sys/net/ipv4/ip_local_port_range + proto = 'udp', + target = 'ACCEPT', + } +) + +uci:save('firewall') diff --git a/package/gluon-neighbour-info/src/gluon-neighbour-info.c b/package/gluon-neighbour-info/src/gluon-neighbour-info.c index d8536de6..808a1b12 100644 --- a/package/gluon-neighbour-info/src/gluon-neighbour-info.c +++ b/package/gluon-neighbour-info/src/gluon-neighbour-info.c @@ -36,13 +36,17 @@ #include void usage() { - puts("Usage: gluon-neighbour-info [-h] [-s] [-t ] -d -p -i -r "); + puts("Usage: gluon-neighbour-info [-h] [-s] [-l] [-c ] [-t ] -d -p -i -r "); puts(" -p UDP port"); - puts(" -d multicast group, e.g. ff02:0:0:0:0:0:2:1001"); + puts(" -d destination address (unicast ip6 or 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(" -s output as server-sent events of type "); + puts(" or without type if is the empty string"); + puts(" -c only wait for at most replies"); + puts(" -l after timeout (or replies if -c is given),"); + puts(" send another request and loop forever"); puts(" -h this help\n"); } @@ -54,7 +58,7 @@ void getclock(struct timeval *tv) { } /* Assumes a and b are normalized */ -void tv_subtract (struct timeval *r, struct timeval *a, struct timeval *b) { +void tv_subtract (struct timeval *r, const struct timeval *a, const struct timeval *b) { r->tv_usec = a->tv_usec - b->tv_usec; r->tv_sec = a->tv_sec - b->tv_sec; @@ -64,23 +68,23 @@ void tv_subtract (struct timeval *r, struct timeval *a, struct timeval *b) { } } -ssize_t recvtimeout(int socket, void *buffer, size_t length, int flags, struct timeval *timeout, struct timeval *offset) { - struct timeval now, delta; - ssize_t ret; - - setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, timeout, sizeof(*timeout)); - ret = recv(socket, buffer, length, flags); +ssize_t recvtimeout(int socket, void *buffer, size_t length, int flags, const struct timeval *timeout) { + struct timeval now, timeout_left; getclock(&now); - tv_subtract(&delta, &now, offset); - tv_subtract(timeout, timeout, &delta); + tv_subtract(&timeout_left, timeout, &now); - return ret; + if (timeout_left.tv_sec < 0) + return -1; + + setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &timeout_left, sizeof(timeout_left)); + return recv(socket, buffer, length, flags); } -int request(const int sock, const struct sockaddr_in6 *client_addr, const char *request, bool sse, int timeout) { +int request(const int sock, const struct sockaddr_in6 *client_addr, const char *request, const char *sse, double timeout, unsigned int max_count) { ssize_t ret; char buffer[8192]; + unsigned int count = 0; ret = sendto(sock, request, strlen(request), 0, (struct sockaddr *)client_addr, sizeof(struct sockaddr_in6)); @@ -89,20 +93,27 @@ int request(const int sock, const struct sockaddr_in6 *client_addr, const char * exit(EXIT_FAILURE); } - struct timeval tv_timeout, tv_offset; - tv_timeout.tv_sec = timeout; - tv_timeout.tv_usec = 0; + struct timeval tv_timeout; + getclock(&tv_timeout); - getclock(&tv_offset); + tv_timeout.tv_sec += (int) timeout; + tv_timeout.tv_usec += ((int) (timeout * 1000000)) % 1000000; + if (tv_timeout.tv_usec >= 1000000) { + tv_timeout.tv_usec -= 1000000; + tv_timeout.tv_sec += 1; + } - while (1) { - ret = recvtimeout(sock, buffer, sizeof(buffer), 0, &tv_timeout, &tv_offset); + do { + ret = recvtimeout(sock, buffer, sizeof(buffer), 0, &tv_timeout); if (ret < 0) break; - if (sse) - fputs("event: neighbour\ndata: ", stdout); + if (sse) { + if (sse[0] != '\0') + fprintf(stdout, "event: %s\n", sse); + fputs("data: ", stdout); + } fwrite(buffer, sizeof(char), ret, stdout); @@ -112,16 +123,19 @@ int request(const int sock, const struct sockaddr_in6 *client_addr, const char * fputs("\n", stdout); fflush(stdout); - } + count++; + } while (max_count == 0 || count < max_count); - return 0; + if ((max_count == 0 && count == 0) || count < max_count) + return EXIT_FAILURE; + else + return EXIT_SUCCESS; } 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); @@ -131,17 +145,17 @@ int main(int argc, char **argv) { } 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 max_count = 0; + double timeout = 3.0; + char *sse = NULL; + bool loop = false; + int ret = false; int c; - while ((c = getopt(argc, argv, "p:d:r:i:t:sh")) != -1) + while ((c = getopt(argc, argv, "p:d:r:i:t:s:c:lh")) != -1) switch (c) { case 'p': client_addr.sin6_port = htons(atoi(optarg)); @@ -163,10 +177,24 @@ int main(int argc, char **argv) { request_string = optarg; break; case 't': - timeout = atoi(optarg); + timeout = atof(optarg); + if (timeout < 0) { + perror("Negative timeout not supported"); + exit(EXIT_FAILURE); + } break; case 's': - sse = true; + sse = optarg; + break; + case 'l': + loop = true; + break; + case 'c': + max_count = atoi(optarg); + if (max_count < 0) { + perror("Negative count not supported"); + exit(EXIT_FAILURE); + } break; case 'h': usage(); @@ -176,16 +204,32 @@ int main(int argc, char **argv) { fprintf(stderr, "Invalid parameter %c ignored.\n", c); } - if (request_string == NULL) - error(EXIT_FAILURE, 0, "No request string supplied"); + if (request_string == NULL) { + fprintf(stderr, "No request string supplied\n"); + exit(EXIT_FAILURE); + } - if (sse) + if (client_addr.sin6_port == htons(0)) { + fprintf(stderr, "No port supplied\n"); + exit(EXIT_FAILURE); + } + + if (IN6_IS_ADDR_UNSPECIFIED(&client_addr.sin6_addr)) { + fprintf(stderr, "No destination address supplied\n"); + exit(EXIT_FAILURE); + } + + if (sse) { fputs("Content-Type: text/event-stream\n\n", stdout); + fflush(stdout); + } - request(sock, &client_addr, request_string, sse, timeout); + do { + ret = request(sock, &client_addr, request_string, sse, timeout, max_count); + } while(loop); if (sse) fputs("event: eot\ndata: null\n\n", stdout); - return EXIT_SUCCESS; + return ret; } diff --git a/package/gluon-next-node/Makefile b/package/gluon-next-node/Makefile deleted file mode 100644 index df27ecbe..00000000 --- a/package/gluon-next-node/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -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 deleted file mode 100644 index 83889a8e..00000000 --- a/package/gluon-next-node/check_site.lua +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index 0df7abcc..00000000 --- a/package/gluon-next-node/files/lib/gluon/ebtables/250-next-node +++ /dev/null @@ -1,20 +0,0 @@ -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 deleted file mode 100755 index 0ff959fe..00000000 --- a/package/gluon-next-node/files/lib/gluon/upgrade/400-next-node +++ /dev/null @@ -1,55 +0,0 @@ -#!/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 index 0fe8a8dd..59f60dfd 100644 --- a/package/gluon-node-info/Makefile +++ b/package/gluon-node-info/Makefile @@ -5,32 +5,28 @@ PKG_VERSION:=1 PKG_RELEASE:=1 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) +PKG_BUILD_DEPENDS := respondd + +include ../gluon.mk -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. + DEPENDS:=+gluon-core +libgluonutil endef define Build/Prepare mkdir -p $(PKG_BUILD_DIR) -endef - -define Build/Configure -endef - -define Build/Compile + $(CP) ./src/* $(PKG_BUILD_DIR)/ endef define Package/gluon-node-info/install $(CP) ./files/* $(1)/ + + $(INSTALL_DIR) $(1)/lib/gluon/respondd + $(CP) $(PKG_BUILD_DIR)/respondd.so $(1)/lib/gluon/respondd/node-info.so endef define Package/gluon-node-info/postinst 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 deleted file mode 100644 index 72bf8878..00000000 --- a/package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/location +++ /dev/null @@ -1,7 +0,0 @@ -if uci:get_first('gluon-node-info', 'location', 'share_location', false) then - return { - latitude = tonumber(uci:get_first('gluon-node-info', 'location', 'latitude')), - longitude = tonumber(uci:get_first('gluon-node-info', 'location', 'longitude')), - altitude = tonumber(uci:get_first('gluon-node-info', 'location', 'altitude')), - } -end 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 deleted file mode 100644 index 8a2a611d..00000000 --- a/package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/owner +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index 38de47d7..00000000 --- a/package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/system/role +++ /dev/null @@ -1,4 +0,0 @@ -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 index a17b9461..6ee047ec 100755 --- 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 @@ -1,11 +1,10 @@ #!/usr/bin/lua -local uci = require('luci.model.uci').cursor() +local uci = require('simple-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 index 6e54a234..d7a440fb 100755 --- 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 @@ -1,7 +1,7 @@ #!/usr/bin/lua local site = require 'gluon.site_config' -local uci = require('luci.model.uci').cursor() +local uci = require('simple-uci').cursor() local config = 'gluon-node-info' local role = uci:get(config, uci:get_first(config, 'system'), 'role') @@ -15,5 +15,4 @@ 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-node-info/files/lib/gluon/upgrade/520-node-info-whitespace-fix b/package/gluon-node-info/files/lib/gluon/upgrade/520-node-info-whitespace-fix new file mode 100755 index 00000000..62cd4beb --- /dev/null +++ b/package/gluon-node-info/files/lib/gluon/upgrade/520-node-info-whitespace-fix @@ -0,0 +1,15 @@ +#!/usr/bin/lua +local uci = require('simple-uci').cursor() +local util = require 'gluon.util' + +local sname = uci:get_first('gluon-node-info', 'location') +if sname then + local options = {'longitude', 'latitude', 'altitude'} + for _, option in ipairs(options) do + local value = uci:get('gluon-node-info', sname, option) + if value then + uci:set('gluon-node-info', sname, option, util.trim(value)) + end + end + uci:save('gluon-node-info') +end diff --git a/package/gluon-node-info/src/Makefile b/package/gluon-node-info/src/Makefile new file mode 100644 index 00000000..3ddc8a58 --- /dev/null +++ b/package/gluon-node-info/src/Makefile @@ -0,0 +1,6 @@ +all: respondd.so + +CFLAGS += -Wall + +respondd.so: respondd.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -o $@ $^ $(LDLIBS) -lgluonutil -luci diff --git a/package/gluon-node-info/src/respondd.c b/package/gluon-node-info/src/respondd.c new file mode 100644 index 00000000..3b0e07dc --- /dev/null +++ b/package/gluon-node-info/src/respondd.c @@ -0,0 +1,144 @@ +/* + Copyright (c) 2016, 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 + + +static struct uci_section * get_first_section(struct uci_package *p, const char *type) { + struct uci_element *e; + uci_foreach_element(&p->sections, e) { + struct uci_section *s = uci_to_section(e); + if (!strcmp(s->type, type)) + return s; + } + + return NULL; +} + +static const char * get_first_option(struct uci_context *ctx, struct uci_package *p, const char *type, const char *option) { + struct uci_section *s = get_first_section(p, type); + if (s) + return uci_lookup_option_string(ctx, s, option); + else + return NULL; +} + +static struct json_object * get_number(struct uci_context *ctx, struct uci_section *s, const char *name) { + const char *val = uci_lookup_option_string(ctx, s, name); + if (!val || !*val) + return NULL; + + char *end; + double d = strtod(val, &end); + if (*end) + return NULL; + + struct json_object *jso = json_object_new_double(d); + json_object_set_serializer(jso, json_object_double_to_json_string, "%.8f", NULL); + return jso; +} + +static void maybe_add_number(struct uci_context *ctx, struct uci_section *s, const char *name, struct json_object *parent) { + struct json_object *jso = get_number(ctx, s, name); + if (jso) + json_object_object_add(parent, name, jso); +} + +static struct json_object * get_location(struct uci_context *ctx, struct uci_package *p) { + struct uci_section *s = get_first_section(p, "location"); + if (!s) + return NULL; + + const char *share = uci_lookup_option_string(ctx, s, "share_location"); + if (!share || strcmp(share, "1")) + return NULL; + + struct json_object *ret = json_object_new_object(); + + maybe_add_number(ctx, s, "latitude", ret); + maybe_add_number(ctx, s, "longitude", ret); + maybe_add_number(ctx, s, "altitude", ret); + + return ret; +} + +static struct json_object * get_owner(struct uci_context *ctx, struct uci_package *p) { + const char *contact = get_first_option(ctx, p, "owner", "contact"); + if (!contact || !*contact) + return NULL; + + struct json_object *ret = json_object_new_object(); + json_object_object_add(ret, "contact", gluonutil_wrap_string(contact)); + return ret; +} + +static struct json_object * get_system(struct uci_context *ctx, struct uci_package *p) { + struct json_object *ret = json_object_new_object(); + + const char *role = get_first_option(ctx, p, "system", "role"); + if (role && *role) + json_object_object_add(ret, "role", gluonutil_wrap_string(role)); + + return ret; +} + +static struct json_object * respondd_provider_nodeinfo(void) { + struct json_object *ret = json_object_new_object(); + + struct uci_context *ctx = uci_alloc_context(); + ctx->flags &= ~UCI_FLAG_STRICT; + + struct uci_package *p; + if (!uci_load(ctx, "gluon-node-info", &p)) { + struct json_object *location = get_location(ctx, p); + if (location) + json_object_object_add(ret, "location", location); + + struct json_object *owner = get_owner(ctx, p); + if (owner) + json_object_object_add(ret, "owner", owner); + + json_object_object_add(ret, "system", get_system(ctx, p)); + } + + uci_free_context(ctx); + + return ret; +} + + +const struct respondd_provider_info respondd_providers[] = { + {"nodeinfo", respondd_provider_nodeinfo}, + {} +}; diff --git a/package/gluon-radvd/Makefile b/package/gluon-radvd/Makefile index 4736af60..ba04c04e 100644 --- a/package/gluon-radvd/Makefile +++ b/package/gluon-radvd/Makefile @@ -5,13 +5,14 @@ PKG_VERSION:=3 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) -include $(INCLUDE_DIR)/package.mk +include ../gluon.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 + DEPENDS:=+gluon-core +uradvd endef define Package/gluon-radvd/description @@ -20,20 +21,18 @@ 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) + $(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/) endef define Package/gluon-radvd/install $(CP) ./files/* $(1)/ - $(INSTALL_DIR) $(1)/usr/sbin - $(INSTALL_BIN) $(PKG_BUILD_DIR)/gluon-radvd $(1)/usr/sbin/ + $(CP) $(PKG_BUILD_DIR)/luadest/* $(1)/ 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 index 14815e76..d38b9441 100755 --- a/package/gluon-radvd/files/etc/init.d/gluon-radvd +++ b/package/gluon-radvd/files/etc/init.d/gluon-radvd @@ -1,15 +1,14 @@ #!/bin/sh /etc/rc.common +USE_PROCD=1 START=50 -SERVICE_WRITE_PID=1 -SERVICE_DAEMONIZE=1 +start_service() { + [ -x /lib/gluon/radvd/arguments ] || return 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 + procd_open_instance + procd_set_param command /usr/sbin/uradvd $(/lib/gluon/radvd/arguments) + procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5} + procd_set_param stderr 1 + procd_close_instance } diff --git a/package/gluon-radvd/files/usr/lib/autoupdater/abort.d/80gluon-radvd b/package/gluon-radvd/files/usr/lib/autoupdater/abort.d/80gluon-radvd new file mode 100755 index 00000000..5784fa5f --- /dev/null +++ b/package/gluon-radvd/files/usr/lib/autoupdater/abort.d/80gluon-radvd @@ -0,0 +1,6 @@ +#!/bin/sh + +. /lib/gluon/autoupdater/lib.sh + + +start_enabled gluon-radvd diff --git a/package/gluon-radvd/files/usr/lib/autoupdater/download.d/20gluon-radvd b/package/gluon-radvd/files/usr/lib/autoupdater/download.d/20gluon-radvd new file mode 100755 index 00000000..ade50616 --- /dev/null +++ b/package/gluon-radvd/files/usr/lib/autoupdater/download.d/20gluon-radvd @@ -0,0 +1,6 @@ +#!/bin/sh + +. /lib/gluon/autoupdater/lib.sh + + +stop gluon-radvd diff --git a/package/gluon-radvd/files/lib/gluon/upgrade/500-radvd-remove-user b/package/gluon-radvd/luasrc/lib/gluon/upgrade/500-radvd-remove-user similarity index 100% rename from package/gluon-radvd/files/lib/gluon/upgrade/500-radvd-remove-user rename to package/gluon-radvd/luasrc/lib/gluon/upgrade/500-radvd-remove-user diff --git a/package/gluon-radvd/src/Makefile b/package/gluon-radvd/src/Makefile deleted file mode 100644 index f0bc9034..00000000 --- a/package/gluon-radvd/src/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index bd57eabc..00000000 --- a/package/gluon-radvd/src/gluon-radvd.c +++ /dev/null @@ -1,647 +0,0 @@ -/* - 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-respondd/Makefile b/package/gluon-respondd/Makefile new file mode 100644 index 00000000..ea40f8df --- /dev/null +++ b/package/gluon-respondd/Makefile @@ -0,0 +1,35 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-respondd +PKG_VERSION:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include ../gluon.mk + + +define Package/gluon-respondd + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Provides node information to the network + DEPENDS:=+gluon-core +libplatforminfo +libgluonutil +libuci +ubus +respondd +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ +endef + +define Build/Compile + $(call Build/Compile/Default) + $(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/) +endef + +define Package/gluon-respondd/install + $(CP) ./files/* $(1)/ + $(CP) $(PKG_BUILD_DIR)/luadest/* $(1)/ + $(INSTALL_DIR) $(1)/lib/gluon/respondd + $(CP) $(PKG_BUILD_DIR)/respondd.so $(1)/lib/gluon/respondd/respondd.so +endef + +$(eval $(call BuildPackage,gluon-respondd)) diff --git a/package/gluon-respondd/files/etc/init.d/gluon-respondd b/package/gluon-respondd/files/etc/init.d/gluon-respondd new file mode 100755 index 00000000..2af79687 --- /dev/null +++ b/package/gluon-respondd/files/etc/init.d/gluon-respondd @@ -0,0 +1,29 @@ +#!/bin/sh /etc/rc.common + +USE_PROCD=1 +START=50 + +DAEMON=/usr/bin/respondd +MAXDELAY=10 + +start_service() { + local ifdump="$(ubus call network.interface dump)" + + local meshdevs=$(for dev in $(echo "$ifdump" | jsonfilter -e "@.interface[@.proto='gluon_mesh' && @.up=true].device"); do echo " -i $dev";done;) + local clientdevs=$(for dev in $(echo "$ifdump" | jsonfilter -e "@.interface[@.interface='$(cat /lib/gluon/respondd/client.dev 2>/dev/null)' && @.up=true].device"); do echo " -i $dev -t $MAXDELAY";done;) + + procd_open_instance + procd_set_param command $DAEMON -d /usr/lib/respondd -d /lib/gluon/respondd -p 1001 -g ff02::2:1001 $meshdevs $clientdevs -g ff05::2:1001 $clientdevs + procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5} + procd_set_param stderr 1 + procd_close_instance +} + +service_triggers() { + local script=$(readlink "$initscript") + local name=$(basename ${script:-$initscript}) + + procd_open_trigger + procd_add_raw_trigger "interface.*" 0 "/etc/init.d/$name" reload + procd_close_trigger +} diff --git a/package/gluon-respondd/files/lib/gluon/respondd/neighbours.cache b/package/gluon-respondd/files/lib/gluon/respondd/neighbours.cache new file mode 100644 index 00000000..5caff40c --- /dev/null +++ b/package/gluon-respondd/files/lib/gluon/respondd/neighbours.cache @@ -0,0 +1 @@ +10000 diff --git a/package/gluon-respondd/files/lib/gluon/respondd/nodeinfo.cache b/package/gluon-respondd/files/lib/gluon/respondd/nodeinfo.cache new file mode 100644 index 00000000..67f9d558 --- /dev/null +++ b/package/gluon-respondd/files/lib/gluon/respondd/nodeinfo.cache @@ -0,0 +1 @@ +300000 diff --git a/package/gluon-respondd/files/lib/gluon/respondd/statistics.cache b/package/gluon-respondd/files/lib/gluon/respondd/statistics.cache new file mode 100644 index 00000000..e9c02dad --- /dev/null +++ b/package/gluon-respondd/files/lib/gluon/respondd/statistics.cache @@ -0,0 +1 @@ +5000 diff --git a/package/gluon-respondd/files/usr/lib/autoupdater/abort.d/50gluon-respondd b/package/gluon-respondd/files/usr/lib/autoupdater/abort.d/50gluon-respondd new file mode 100755 index 00000000..d29af306 --- /dev/null +++ b/package/gluon-respondd/files/usr/lib/autoupdater/abort.d/50gluon-respondd @@ -0,0 +1,6 @@ +#!/bin/sh + +. /lib/gluon/autoupdater/lib.sh + + +start_enabled gluon-respondd diff --git a/package/gluon-respondd/files/usr/lib/autoupdater/download.d/50gluon-respondd b/package/gluon-respondd/files/usr/lib/autoupdater/download.d/50gluon-respondd new file mode 100755 index 00000000..3edd5f1d --- /dev/null +++ b/package/gluon-respondd/files/usr/lib/autoupdater/download.d/50gluon-respondd @@ -0,0 +1,6 @@ +#!/bin/sh + +. /lib/gluon/autoupdater/lib.sh + + +stop gluon-respondd diff --git a/package/gluon-respondd/luasrc/lib/gluon/upgrade/400-respondd-firewall b/package/gluon-respondd/luasrc/lib/gluon/upgrade/400-respondd-firewall new file mode 100755 index 00000000..5e303feb --- /dev/null +++ b/package/gluon-respondd/luasrc/lib/gluon/upgrade/400-respondd-firewall @@ -0,0 +1,31 @@ +#!/usr/bin/lua + +local uci = require('simple-uci').cursor() + +uci:delete('firewall', 'wan_announced') + +-- Allow respondd port on WAN to allow resolving neighbours over mesh-on-wan +uci:section('firewall', 'rule', 'wan_respondd', + { + name = 'wan_respondd', + src = 'wan', + src_ip = 'fe80::/64', + dest_port = '1001', + proto = 'udp', + target = 'ACCEPT', + } +) + +-- Restrict respondd queries to link-local addresses to prevent amplification attacks from outside +uci:section('firewall', 'rule', 'client_respondd', + { + name = 'client_respondd', + src = 'client', + src_ip = '!fe80::/64', + dest_port = '1001', + proto = 'udp', + target = 'REJECT', + } +) + +uci:save('firewall') diff --git a/package/gluon-respondd/src/Makefile b/package/gluon-respondd/src/Makefile new file mode 100644 index 00000000..f26b59a2 --- /dev/null +++ b/package/gluon-respondd/src/Makefile @@ -0,0 +1,6 @@ +all: respondd.so + +CFLAGS += -Wall + +respondd.so: respondd.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -o $@ $^ $(LDLIBS) -lgluonutil -lplatforminfo -luci diff --git a/package/gluon-respondd/src/respondd.c b/package/gluon-respondd/src/respondd.c new file mode 100644 index 00000000..bb54f382 --- /dev/null +++ b/package/gluon-respondd/src/respondd.c @@ -0,0 +1,239 @@ +/* + Copyright (c) 2016, 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 + + +static struct json_object * gluon_version(void) { + char *version = gluonutil_read_line("/lib/gluon/gluon-version"); + if (!version) + return NULL; + + char full_version[6 + strlen(version) + 1]; + snprintf(full_version, sizeof(full_version), "gluon-%s", version); + + free(version); + + + return json_object_new_string(full_version); +} + +static struct json_object * get_site_code(void) { + struct json_object *site = gluonutil_load_site_config(); + if (!site) + return NULL; + + struct json_object *ret = NULL; + json_object_object_get_ex(site, "site_code", &ret); + if (ret) + json_object_get(ret); + + json_object_put(site); + return ret; +} + +static struct json_object * get_hostname(void) { + struct json_object *ret = NULL; + + struct uci_context *ctx = uci_alloc_context(); + ctx->flags &= ~UCI_FLAG_STRICT; + + char section[] = "system.@system[0]"; + struct uci_ptr ptr; + if (uci_lookup_ptr(ctx, &ptr, section, true)) + goto error; + + struct uci_section *s = ptr.s; + + const char *hostname = uci_lookup_option_string(ctx, s, "pretty_hostname"); + + if (!hostname) + hostname = uci_lookup_option_string(ctx, s, "hostname"); + + ret = gluonutil_wrap_string(hostname); + +error: + uci_free_context(ctx); + + return ret; +} + +static struct json_object * respondd_provider_nodeinfo(void) { + struct json_object *ret = json_object_new_object(); + + json_object_object_add(ret, "node_id", gluonutil_wrap_and_free_string(gluonutil_get_node_id())); + json_object_object_add(ret, "hostname", get_hostname()); + + struct json_object *hardware = json_object_new_object(); + + const char *model = platforminfo_get_model(); + if (model) + json_object_object_add(hardware, "model", json_object_new_string(model)); + + json_object_object_add(hardware, "nproc", json_object_new_int(sysconf(_SC_NPROCESSORS_ONLN))); + json_object_object_add(ret, "hardware", hardware); + + struct json_object *network = json_object_new_object(); + json_object_object_add(network, "mac", gluonutil_wrap_and_free_string(gluonutil_get_sysconfig("primary_mac"))); + json_object_object_add(ret, "network", network); + + struct json_object *software = json_object_new_object(); + struct json_object *software_firmware = json_object_new_object(); + json_object_object_add(software_firmware, "base", gluon_version()); + json_object_object_add(software_firmware, "release", gluonutil_wrap_and_free_string(gluonutil_read_line("/lib/gluon/release"))); + json_object_object_add(software, "firmware", software_firmware); + json_object_object_add(ret, "software", software); + + struct json_object *system = json_object_new_object(); + json_object_object_add(system, "site_code", get_site_code()); + json_object_object_add(ret, "system", system); + + return ret; +} + + +static void add_uptime(struct json_object *obj) { + FILE *f = fopen("/proc/uptime", "r"); + struct json_object* jso; + if (!f) + return; + + double uptime, idletime; + if (fscanf(f, "%lf %lf", &uptime, &idletime) == 2) { + jso = json_object_new_double(uptime); + json_object_set_serializer(jso, json_object_double_to_json_string, "%.2f", NULL); + json_object_object_add(obj, "uptime", jso); + jso = json_object_new_double(idletime); + json_object_set_serializer(jso, json_object_double_to_json_string, "%.2f", NULL); + json_object_object_add(obj, "idletime", jso); + } + + fclose(f); +} + +static void add_loadavg(struct json_object *obj) { + FILE *f = fopen("/proc/loadavg", "r"); + if (!f) + return; + + double loadavg; + unsigned proc_running, proc_total; + if (fscanf(f, "%lf %*f %*f %u/%u", &loadavg, &proc_running, &proc_total) == 3) { + struct json_object *jso = json_object_new_double(loadavg); + json_object_set_serializer(jso, json_object_double_to_json_string, "%.2f", NULL); + json_object_object_add(obj, "loadavg", jso); + + struct json_object *processes = json_object_new_object(); + json_object_object_add(processes, "running", json_object_new_int(proc_running)); + json_object_object_add(processes, "total", json_object_new_int(proc_total)); + json_object_object_add(obj, "processes", processes); + } + + fclose(f); +} + +static struct json_object * get_memory(void) { + FILE *f = fopen("/proc/meminfo", "r"); + if (!f) + return NULL; + + struct json_object *ret = json_object_new_object(); + + char *line = NULL; + size_t len = 0; + + while (getline(&line, &len, f) >= 0) { + char label[32]; + unsigned value; + + if (sscanf(line, "%31[^:]: %u", label, &value) != 2) + continue; + + if (!strcmp(label, "MemTotal")) + json_object_object_add(ret, "total", json_object_new_int(value)); + else if (!strcmp(label, "MemFree")) + json_object_object_add(ret, "free", json_object_new_int(value)); + else if (!strcmp(label, "Buffers")) + json_object_object_add(ret, "buffers", json_object_new_int(value)); + else if (!strcmp(label, "Cached")) + json_object_object_add(ret, "cached", json_object_new_int(value)); + } + + free(line); + fclose(f); + + return ret; +} + +static struct json_object * get_rootfs_usage(void) { + struct statfs s; + if (statfs("/", &s)) + return NULL; + + struct json_object *jso = json_object_new_double(1 - (double)s.f_bfree / s.f_blocks); + json_object_set_serializer(jso, json_object_double_to_json_string, "%.4f", NULL); + return jso; +} + +static struct json_object * respondd_provider_statistics(void) { + struct json_object *ret = json_object_new_object(); + + json_object_object_add(ret, "node_id", gluonutil_wrap_and_free_string(gluonutil_get_node_id())); + + json_object_object_add(ret, "rootfs_usage", get_rootfs_usage()); + json_object_object_add(ret, "memory", get_memory()); + + add_uptime(ret); + add_loadavg(ret); + + return ret; +} + + +static struct json_object * respondd_provider_neighbours(void) { + struct json_object *ret = json_object_new_object(); + json_object_object_add(ret, "node_id", gluonutil_wrap_and_free_string(gluonutil_get_node_id())); + return ret; +} + + +const struct respondd_provider_info respondd_providers[] = { + {"nodeinfo", respondd_provider_nodeinfo}, + {"statistics", respondd_provider_statistics}, + {"neighbours", respondd_provider_neighbours}, + {} +}; diff --git a/package/gluon-setup-mode/Makefile b/package/gluon-setup-mode/Makefile index 55370abe..5840d3fd 100644 --- a/package/gluon-setup-mode/Makefile +++ b/package/gluon-setup-mode/Makefile @@ -8,13 +8,14 @@ PKG_VERSION:=1 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) -include $(GLUONDIR)/include/package.mk +include ../gluon.mk + define Package/gluon-setup-mode SECTION:=gluon CATEGORY:=Gluon TITLE:=Setup mode - DEPENDS:=+gluon-core +uhttpd +dnsmasq + DEPENDS:=+gluon-core +gluon-web +ubus +uhttpd +dnsmasq PROVIDES:=gluon-setup-mode-virtual endef @@ -30,10 +31,12 @@ define Build/Configure endef define Build/Compile + $(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/) endef define Package/gluon-setup-mode/install $(CP) ./files/* $(1)/ + $(CP) $(PKG_BUILD_DIR)/luadest/* $(1)/ endef define Package/gluon-setup-mode/postinst 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 deleted file mode 120000 index 066549b3..00000000 --- a/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/K50dropbear +++ /dev/null @@ -1 +0,0 @@ -/etc/init.d/dropbear \ 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 index b4af677a..27b1a595 100755 --- 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 @@ -1,5 +1,5 @@ #!/bin/sh /etc/rc.common -if /etc/init.d/haveged enabled; then +if [ -x /etc/init.d/haveged ] && /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 index df8a0e2b..80127cc4 100755 --- 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 @@ -10,9 +10,7 @@ boot() { 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 + if [ "$enabled" != 1 -a "$configured" = 1 ]; then # 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 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 deleted file mode 120000 index 066549b3..00000000 --- a/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S50dropbear +++ /dev/null @@ -1 +0,0 @@ -/etc/init.d/dropbear \ No newline at end of file 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 100755 index 00000000..590aede3 --- /dev/null +++ b/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S50dropbear @@ -0,0 +1,21 @@ +#!/bin/sh /etc/rc.common + +USE_PROCD=1 +PROG=/usr/sbin/dropbear +NAME=dropbear + +start_service() { + [ -x /etc/init.d/dropbear ] || return 0 + + . /etc/init.d/dropbear + + [ -s /etc/dropbear/dropbear_rsa_host_key ] || keygen + + . /lib/functions.sh + . /lib/functions/network.sh + + procd_open_instance + procd_set_param command "$PROG" -F -f + procd_set_param respawn + procd_close_instance +} 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 deleted file mode 100755 index b524b2ce..00000000 --- a/package/gluon-setup-mode/files/lib/gluon/setup-mode/rc.d/S50telnet +++ /dev/null @@ -1,12 +0,0 @@ -#!/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 index 53118704..ffe799c9 100755 --- 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 @@ -9,6 +9,6 @@ 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_set_param command "$UHTTPD_BIN" -f -h /lib/gluon/web/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/www/cgi-bin/luci b/package/gluon-setup-mode/files/lib/gluon/setup-mode/www/cgi-bin/luci deleted file mode 100755 index c5c98473..00000000 --- a/package/gluon-setup-mode/files/lib/gluon/setup-mode/www/cgi-bin/luci +++ /dev/null @@ -1,5 +0,0 @@ -#!/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 deleted file mode 100644 index 0a7238b5..00000000 --- a/package/gluon-setup-mode/files/lib/gluon/setup-mode/www/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - -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 deleted file mode 120000 index aea80e05..00000000 --- a/package/gluon-setup-mode/files/lib/gluon/setup-mode/www/luci-static +++ /dev/null @@ -1 +0,0 @@ -/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 deleted file mode 100755 index ae59c7aa..00000000 --- a/package/gluon-setup-mode/files/lib/gluon/upgrade/300-setup-mode +++ /dev/null @@ -1,16 +0,0 @@ -#!/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 deleted file mode 100755 index 9d3b9b0a..00000000 --- a/package/gluon-setup-mode/files/lib/gluon/upgrade/310-setup-mode-migrate +++ /dev/null @@ -1,18 +0,0 @@ -#!/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 deleted file mode 100755 index 3c4a8afe..00000000 --- a/package/gluon-setup-mode/files/lib/gluon/upgrade/320-setup-ifname +++ /dev/null @@ -1,18 +0,0 @@ -#!/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/luasrc/lib/gluon/upgrade/300-setup-mode b/package/gluon-setup-mode/luasrc/lib/gluon/upgrade/300-setup-mode new file mode 100755 index 00000000..248861ee --- /dev/null +++ b/package/gluon-setup-mode/luasrc/lib/gluon/upgrade/300-setup-mode @@ -0,0 +1,14 @@ +#!/usr/bin/lua + +local site = require 'gluon.site_config' +local uci = require('simple-uci').cursor() + + +if site.setup_mode + and site.setup_mode.skip + and not uci:get_first('gluon-setup-mode', 'setup_mode', 'configured', false) then + local name = uci:get_first("gluon-setup-mode", "setup_mode") + uci:set("gluon-setup-mode", name, "configured", true) + uci:save('gluon-setup-mode') +end + diff --git a/package/gluon-setup-mode/luasrc/lib/gluon/upgrade/310-setup-mode-migrate b/package/gluon-setup-mode/luasrc/lib/gluon/upgrade/310-setup-mode-migrate new file mode 100755 index 00000000..ecaa07f9 --- /dev/null +++ b/package/gluon-setup-mode/luasrc/lib/gluon/upgrade/310-setup-mode-migrate @@ -0,0 +1,14 @@ +#!/usr/bin/lua + +local uci = require('simple-uci').cursor() + + +local old = uci:get_first('gluon-config-mode', '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', true) + + uci:save('gluon-setup-mode') +end + +os.remove('/etc/config/gluon-config-mode') diff --git a/package/gluon-setup-mode/luasrc/lib/gluon/upgrade/320-setup-ifname b/package/gluon-setup-mode/luasrc/lib/gluon/upgrade/320-setup-ifname new file mode 100755 index 00000000..7f0ca7b8 --- /dev/null +++ b/package/gluon-setup-mode/luasrc/lib/gluon/upgrade/320-setup-ifname @@ -0,0 +1,29 @@ +#!/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', { + 'cpe210', + 'cpe510', + 'wbs210', + 'wbs510', + 'airgateway', + 'nanostation-m', + 'nanostation-m-xw', + 'unifi-outdoor-plus', + 'uap-pro', + 'unifiac-pro' +}) or platform.match('ar71xx', 'mikrotik') 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-simple-tc/Makefile b/package/gluon-simple-tc/Makefile deleted file mode 100644 index b01b9641..00000000 --- a/package/gluon-simple-tc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -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 deleted file mode 100644 index 95d4fd81..00000000 --- a/package/gluon-simple-tc/check_site.lua +++ /dev/null @@ -1,10 +0,0 @@ -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 deleted file mode 100644 index c9b784c6..00000000 --- a/package/gluon-simple-tc/files/etc/config/gluon-simple-tc +++ /dev/null @@ -1,7 +0,0 @@ -# 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 deleted file mode 100644 index 8dd82781..00000000 --- a/package/gluon-simple-tc/files/etc/hotplug.d/net/50-gluon-simple-tc +++ /dev/null @@ -1,26 +0,0 @@ -[ "$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 deleted file mode 120000 index 44318d6e..00000000 --- a/package/gluon-simple-tc/files/etc/modules-boot.d/30-gluon-simple-tc +++ /dev/null @@ -1 +0,0 @@ -../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 deleted file mode 100644 index 72b238c7..00000000 --- a/package/gluon-simple-tc/files/etc/modules.d/30-gluon-simple-tc +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100755 index 037cb45f..00000000 --- a/package/gluon-simple-tc/files/lib/gluon/upgrade/300-simple-tc-site-defaults +++ /dev/null @@ -1,23 +0,0 @@ -#!/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 deleted file mode 100644 index 502c6232..00000000 --- a/package/gluon-simple-tc/src/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index 9e5bb206..00000000 --- a/package/gluon-simple-tc/src/gluon-simple-tc.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - 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 deleted file mode 100644 index 25731dfb..00000000 --- a/package/gluon-simple-tc/src/include/linux/pkt_cls.h +++ /dev/null @@ -1,483 +0,0 @@ -#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 deleted file mode 100644 index d62316ba..00000000 --- a/package/gluon-simple-tc/src/include/linux/pkt_sched.h +++ /dev/null @@ -1,846 +0,0 @@ -#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 deleted file mode 100644 index 248fdd3f..00000000 --- a/package/gluon-simple-tc/src/include/linux/rtnetlink.h +++ /dev/null @@ -1,639 +0,0 @@ -#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 index 7816c9d3..124dc49b 100644 --- a/package/gluon-site/Makefile +++ b/package/gluon-site/Makefile @@ -1,15 +1,19 @@ 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-base/host +GLUON_SITEDIR = '$(call qstrip,$(CONFIG_GLUON_SITEDIR))' +GLUON_SITE_VERSION = $(shell ( cd $(GLUON_SITEDIR) && git --git-dir=.git describe --always --dirty=+ ) 2>/dev/null || echo unknown) +PKG_VERSION:=$(if $(DUMP),x,$(GLUON_SITE_VERSION)) + + +PKG_CONFIG_DEPENDS := CONFIG_GLUON_RELEASE CONFIG_GLUON_SITEDIR +PKG_FILE_DEPENDS := $(GLUON_SITEDIR)/site.conf $(GLUON_SITEDIR)/i18n/ +PKG_BUILD_DEPENDS := lua-cjson/host PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) -include $(GLUONDIR)/include/package.mk +include ../gluon.mk PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) @@ -20,6 +24,18 @@ define Package/gluon-site TITLE:=Site-specific files of Gluon endef +define Package/gluon-site/config +config GLUON_RELEASE + string "Gluon release number" + depends on PACKAGE_gluon-site + default "" + +config GLUON_SITEDIR + string "Gluon site configuration directory" + depends on PACKAGE_gluon-site + default "" +endef + define Build/Prepare mkdir -p $(PKG_BUILD_DIR) endef @@ -28,13 +44,15 @@ define Build/Configure endef define Build/Compile + GLUON_SITEDIR='$(call qstrip,$(CONFIG_GLUON_SITEDIR))' lua -e 'print(require("cjson").encode(assert(dofile("../../scripts/site_config.lua"))))' > $(PKG_BUILD_DIR)/site.json $(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 + $(INSTALL_DATA) $(PKG_BUILD_DIR)/site.json $(1)/lib/gluon/ + echo '$(GLUON_SITE_VERSION)' > $(1)/lib/gluon/site-version + echo '$(call qstrip,$(CONFIG_GLUON_RELEASE))' > $(1)/lib/gluon/release $(call GluonInstallI18N,gluon-site,$(1)) endef diff --git a/package/gluon-status-page-api/Makefile b/package/gluon-status-page-api/Makefile new file mode 100644 index 00000000..27afccd1 --- /dev/null +++ b/package/gluon-status-page-api/Makefile @@ -0,0 +1,42 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-status-page-api +PKG_VERSION:=1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) +PKG_BUILD_DEPENDS := respondd + +include ../gluon.mk + + +define Package/gluon-status-page-api + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=API for gluon-status-page + DEPENDS:=+gluon-core +uhttpd +sse-multiplex +gluon-neighbour-info +gluon-respondd +libiwinfo +libjson-c +libnl-tiny +libubus-lua +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ +endef + +define Build/Compile + $(call Build/Compile/Default) + $(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/) +endef + +define Package/gluon-status-page-api/install + $(INSTALL_DIR) $(1)/lib/gluon/status-page/providers + $(INSTALL_BIN) $(PKG_BUILD_DIR)/neighbours-batadv $(1)/lib/gluon/status-page/providers/ + $(INSTALL_BIN) $(PKG_BUILD_DIR)/stations $(1)/lib/gluon/status-page/providers/ + + $(INSTALL_DIR) $(1)/lib/gluon/respondd + $(CP) $(PKG_BUILD_DIR)/respondd.so $(1)/lib/gluon/respondd/status-page-api.so + + $(CP) ./files/* $(1)/ + $(CP) $(PKG_BUILD_DIR)/luadest/* $(1)/ +endef + +$(eval $(call BuildPackage,gluon-status-page-api)) diff --git a/package/gluon-status-page-api/files/lib/gluon/status-page/www/cgi-bin/dyn/neighbours-batadv b/package/gluon-status-page-api/files/lib/gluon/status-page/www/cgi-bin/dyn/neighbours-batadv new file mode 100755 index 00000000..075e8b8b --- /dev/null +++ b/package/gluon-status-page-api/files/lib/gluon/status-page/www/cgi-bin/dyn/neighbours-batadv @@ -0,0 +1,7 @@ +#!/bin/sh + +echo 'Access-Control-Allow-Origin: *' + +CMD='exec /lib/gluon/status-page/providers/neighbours-batadv' + +exec /usr/sbin/sse-multiplex "$CMD" diff --git a/package/gluon-status-page-api/files/lib/gluon/status-page/www/cgi-bin/dyn/neighbours-nodeinfo b/package/gluon-status-page-api/files/lib/gluon/status-page/www/cgi-bin/dyn/neighbours-nodeinfo new file mode 100755 index 00000000..657f17e5 --- /dev/null +++ b/package/gluon-status-page-api/files/lib/gluon/status-page/www/cgi-bin/dyn/neighbours-nodeinfo @@ -0,0 +1,13 @@ +#!/bin/sh + +badrequest() { + echo 'Status: 400 Bad Request' + echo + exit 1 +} + +echo 'Access-Control-Allow-Origin: *' + +batctl if | cut -d: -f1 | grep -qxF "$QUERY_STRING" || badrequest + +exec /usr/bin/gluon-neighbour-info -s neighbour -i "$QUERY_STRING" -d ff02::2:1001 -p 1001 -r nodeinfo diff --git a/package/gluon-status-page-api/files/lib/gluon/status-page/www/cgi-bin/dyn/stations b/package/gluon-status-page-api/files/lib/gluon/status-page/www/cgi-bin/dyn/stations new file mode 100755 index 00000000..258122fb --- /dev/null +++ b/package/gluon-status-page-api/files/lib/gluon/status-page/www/cgi-bin/dyn/stations @@ -0,0 +1,15 @@ +#!/bin/sh + +badrequest() { + echo 'Status: 400 Bad Request' + echo + exit 1 +} + +echo 'Access-Control-Allow-Origin: *' + +batctl if | cut -d: -f1 | grep -qxF "$QUERY_STRING" || badrequest + +CMD="exec /lib/gluon/status-page/providers/stations '$QUERY_STRING'" + +exec /usr/sbin/sse-multiplex "$CMD" diff --git a/package/gluon-status-page-api/files/lib/gluon/status-page/www/cgi-bin/dyn/statistics b/package/gluon-status-page-api/files/lib/gluon/status-page/www/cgi-bin/dyn/statistics new file mode 100755 index 00000000..ef0dd3d8 --- /dev/null +++ b/package/gluon-status-page-api/files/lib/gluon/status-page/www/cgi-bin/dyn/statistics @@ -0,0 +1,7 @@ +#!/bin/sh + +echo 'Access-Control-Allow-Origin: *' + +CMD='exec gluon-neighbour-info -s "" -l -d ::1 -p 1001 -t 3 -r statistics' + +exec /usr/sbin/sse-multiplex "$CMD" diff --git a/package/gluon-status-page-api/files/lib/gluon/status-page/www/cgi-bin/nodeinfo b/package/gluon-status-page-api/files/lib/gluon/status-page/www/cgi-bin/nodeinfo new file mode 100755 index 00000000..d34381fa --- /dev/null +++ b/package/gluon-status-page-api/files/lib/gluon/status-page/www/cgi-bin/nodeinfo @@ -0,0 +1,8 @@ +#!/bin/sh + +cat </dev/null),) + $(error $(PKG_CONFIG) not found) + endif +endif + +ifeq ($(origin LIBNL_CFLAGS) $(origin LIBNL_LDLIBS), undefined undefined) + LIBNL_NAME ?= libnl-tiny + ifeq ($(shell $(PKG_CONFIG) --modversion $(LIBNL_NAME) 2>/dev/null),) + $(error No $(LIBNL_NAME) development libraries found!) + endif + LIBNL_CFLAGS += $(shell $(PKG_CONFIG) --cflags $(LIBNL_NAME)) + LIBNL_LDLIBS += $(shell $(PKG_CONFIG) --libs $(LIBNL_NAME)) +endif + +CFLAGS_JSONC = $(shell pkg-config --cflags json-c) +LDFLAGS_JSONC = $(shell pkg-config --libs json-c) + +all: neighbours-batadv stations respondd.so + +neighbours-batadv: neighbours-batadv.c batadv-netlink.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_JSONC) $(LIBNL_CFLAGS) $(LDFLAGS) $(LDFLAGS_JSONC) $(LIBNL_LDLIBS) -Wall -o $@ $^ $(LDLIBS) + +stations: stations.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_JSONC) $(LDFLAGS) $(LDFLAGS_JSONC) -Wall -o $@ $^ $(LDLIBS) -liwinfo + +respondd.so: respondd.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -o $@ $^ $(LDLIBS) diff --git a/package/gluon-status-page-api/src/batadv-netlink.c b/package/gluon-status-page-api/src/batadv-netlink.c new file mode 100644 index 00000000..ca965d48 --- /dev/null +++ b/package/gluon-status-page-api/src/batadv-netlink.c @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2009-2016 B.A.T.M.A.N. contributors: + * + * Marek Lindner , Andrew Lunn + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * + */ + +#include "batadv-netlink.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "batman_adv.h" + +#ifndef __maybe_unused +#define __maybe_unused __attribute__((unused)) +#endif + +struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { + [BATADV_ATTR_HARD_IFINDEX] = { .type = NLA_U32 }, + [BATADV_ATTR_ORIG_ADDRESS] = { .type = NLA_UNSPEC, + .minlen = ETH_ALEN, + .maxlen = ETH_ALEN }, + [BATADV_ATTR_FLAG_BEST] = { .type = NLA_FLAG }, + [BATADV_ATTR_LAST_SEEN_MSECS] = { .type = NLA_U32 }, + [BATADV_ATTR_NEIGH_ADDRESS] = { .type = NLA_UNSPEC, + .minlen = ETH_ALEN, + .maxlen = ETH_ALEN }, + [BATADV_ATTR_TQ] = { .type = NLA_U8 }, +}; + +static int nlquery_error_cb(struct sockaddr_nl *nla __maybe_unused, + struct nlmsgerr *nlerr, void *arg) +{ + struct batadv_nlquery_opts *query_opts = arg; + + query_opts->err = nlerr->error; + + return NL_STOP; +} + +static int nlquery_stop_cb(struct nl_msg *msg, void *arg) +{ + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct batadv_nlquery_opts *query_opts = arg; + int *error = nlmsg_data(nlh); + + if (*error) + query_opts->err = *error; + + return NL_STOP; +} + +int batadv_nl_query_common(const char *mesh_iface, + enum batadv_nl_commands nl_cmd, + nl_recvmsg_msg_cb_t callback, int flags, + struct batadv_nlquery_opts *query_opts) +{ + struct nl_sock *sock; + struct nl_msg *msg; + struct nl_cb *cb; + int ifindex; + int family; + int ret; + + query_opts->err = 0; + + sock = nl_socket_alloc(); + if (!sock) + return -ENOMEM; + + ret = genl_connect(sock); + if (ret < 0) { + query_opts->err = ret; + goto err_free_sock; + } + + family = genl_ctrl_resolve(sock, BATADV_NL_NAME); + if (family < 0) { + query_opts->err = -EOPNOTSUPP; + goto err_free_sock; + } + + ifindex = if_nametoindex(mesh_iface); + if (!ifindex) { + query_opts->err = -ENODEV; + goto err_free_sock; + } + + cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!cb) { + query_opts->err = -ENOMEM; + goto err_free_sock; + } + + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, callback, query_opts); + nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, nlquery_stop_cb, query_opts); + nl_cb_err(cb, NL_CB_CUSTOM, nlquery_error_cb, query_opts); + + msg = nlmsg_alloc(); + if (!msg) { + query_opts->err = -ENOMEM; + goto err_free_cb; + } + + genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, flags, + nl_cmd, 1); + + nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, ifindex); + nl_send_auto_complete(sock, msg); + nlmsg_free(msg); + + nl_recvmsgs(sock, cb); + +err_free_cb: + nl_cb_put(cb); +err_free_sock: + nl_socket_free(sock); + + return query_opts->err; +} diff --git a/package/gluon-status-page-api/src/batadv-netlink.h b/package/gluon-status-page-api/src/batadv-netlink.h new file mode 100644 index 00000000..8b85a6c2 --- /dev/null +++ b/package/gluon-status-page-api/src/batadv-netlink.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2009-2016 B.A.T.M.A.N. contributors: + * + * Marek Lindner , Andrew Lunn + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * + */ + +#ifndef _BATADV_NETLINK_H +#define _BATADV_NETLINK_H + +#include +#include +#include +#include +#include + +#include "batman_adv.h" + +struct batadv_nlquery_opts { + int err; +}; + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) +#endif + +#ifndef container_of +#define container_of(ptr, type, member) __extension__ ({ \ + const __typeof__(((type *)0)->member) *__pmember = (ptr); \ + (type *)((char *)__pmember - offsetof(type, member)); }) +#endif + +int batadv_nl_query_common(const char *mesh_iface, + enum batadv_nl_commands nl_cmd, + nl_recvmsg_msg_cb_t callback, int flags, + struct batadv_nlquery_opts *query_opts); + +static inline bool batadv_nl_missing_attrs(struct nlattr *attrs[], + const enum batadv_nl_attrs mandatory[], + size_t num) +{ + size_t i; + + for (i = 0; i < num; i++) { + if (!attrs[mandatory[i]]) + return true; + } + + return false; +} + +extern struct nla_policy batadv_netlink_policy[]; + +#endif /* _BATADV_NETLINK_H */ diff --git a/package/gluon-status-page-api/src/batman_adv.h b/package/gluon-status-page-api/src/batman_adv.h new file mode 100644 index 00000000..734fe83a --- /dev/null +++ b/package/gluon-status-page-api/src/batman_adv.h @@ -0,0 +1,208 @@ +/* Copyright (C) 2016 B.A.T.M.A.N. contributors: + * + * Matthias Schiffer + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _UAPI_LINUX_BATMAN_ADV_H_ +#define _UAPI_LINUX_BATMAN_ADV_H_ + +#define BATADV_NL_NAME "batadv" + +#define BATADV_NL_MCAST_GROUP_TPMETER "tpmeter" + +/** + * enum batadv_tt_client_flags - TT client specific flags + * @BATADV_TT_CLIENT_DEL: the client has to be deleted from the table + * @BATADV_TT_CLIENT_ROAM: the client roamed to/from another node and the new + * update telling its new real location has not been received/sent yet + * @BATADV_TT_CLIENT_WIFI: this client is connected through a wifi interface. + * This information is used by the "AP Isolation" feature + * @BATADV_TT_CLIENT_ISOLA: this client is considered "isolated". This + * information is used by the Extended Isolation feature + * @BATADV_TT_CLIENT_NOPURGE: this client should never be removed from the table + * @BATADV_TT_CLIENT_NEW: this client has been added to the local table but has + * not been announced yet + * @BATADV_TT_CLIENT_PENDING: this client is marked for removal but it is kept + * in the table for one more originator interval for consistency purposes + * @BATADV_TT_CLIENT_TEMP: this global client has been detected to be part of + * the network but no nnode has already announced it + * + * Bits from 0 to 7 are called _remote flags_ because they are sent on the wire. + * Bits from 8 to 15 are called _local flags_ because they are used for local + * computations only. + * + * Bits from 4 to 7 - a subset of remote flags - are ensured to be in sync with + * the other nodes in the network. To achieve this goal these flags are included + * in the TT CRC computation. + */ +enum batadv_tt_client_flags { + BATADV_TT_CLIENT_DEL = (1 << 0), + BATADV_TT_CLIENT_ROAM = (1 << 1), + BATADV_TT_CLIENT_WIFI = (1 << 4), + BATADV_TT_CLIENT_ISOLA = (1 << 5), + BATADV_TT_CLIENT_NOPURGE = (1 << 8), + BATADV_TT_CLIENT_NEW = (1 << 9), + BATADV_TT_CLIENT_PENDING = (1 << 10), + BATADV_TT_CLIENT_TEMP = (1 << 11), +}; + +/** + * enum batadv_nl_attrs - batman-adv netlink attributes + * + * @BATADV_ATTR_UNSPEC: unspecified attribute to catch errors + * @BATADV_ATTR_VERSION: batman-adv version string + * @BATADV_ATTR_ALGO_NAME: name of routing algorithm + * @BATADV_ATTR_MESH_IFINDEX: index of the batman-adv interface + * @BATADV_ATTR_MESH_IFNAME: name of the batman-adv interface + * @BATADV_ATTR_MESH_ADDRESS: mac address of the batman-adv interface + * @BATADV_ATTR_HARD_IFINDEX: index of the non-batman-adv interface + * @BATADV_ATTR_HARD_IFNAME: name of the non-batman-adv interface + * @BATADV_ATTR_HARD_ADDRESS: mac address of the non-batman-adv interface + * @BATADV_ATTR_ORIG_ADDRESS: originator mac address + * @BATADV_ATTR_TPMETER_RESULT: result of run (see batadv_tp_meter_status) + * @BATADV_ATTR_TPMETER_TEST_TIME: time (msec) the run took + * @BATADV_ATTR_TPMETER_BYTES: amount of acked bytes during run + * @BATADV_ATTR_TPMETER_COOKIE: session cookie to match tp_meter session + * @BATADV_ATTR_PAD: attribute used for padding for 64-bit alignment + * @BATADV_ATTR_ACTIVE: Flag indicating if the hard interface is active + * @BATADV_ATTR_TT_ADDRESS: Client MAC address + * @BATADV_ATTR_TT_TTVN: Translation table version + * @BATADV_ATTR_TT_LAST_TTVN: Previous translation table version + * @BATADV_ATTR_TT_CRC32: CRC32 over translation table + * @BATADV_ATTR_TT_VID: VLAN ID + * @BATADV_ATTR_TT_FLAGS: Translation table client flags + * @BATADV_ATTR_FLAG_BEST: Flags indicating entry is the best + * @BATADV_ATTR_LAST_SEEN_MSECS: Time in milliseconds since last seen + * @BATADV_ATTR_NEIGH_ADDRESS: Neighbour MAC address + * @BATADV_ATTR_TQ: TQ to neighbour + * @BATADV_ATTR_THROUGHPUT: Estimated throughput to Neighbour + * @BATADV_ATTR_BANDWIDTH_UP: Reported uplink bandwidth + * @BATADV_ATTR_BANDWIDTH_DOWN: Reported downlink bandwidth + * @BATADV_ATTR_ROUTER: Gateway router MAC address + * @BATADV_ATTR_BLA_OWN: Flag indicating own originator + * @BATADV_ATTR_BLA_ADDRESS: Bridge loop avoidance claim MAC address + * @BATADV_ATTR_BLA_VID: BLA VLAN ID + * @BATADV_ATTR_BLA_BACKBONE: BLA gateway originator MAC address + * @BATADV_ATTR_BLA_CRC: BLA CRC + * @__BATADV_ATTR_AFTER_LAST: internal use + * @NUM_BATADV_ATTR: total number of batadv_nl_attrs available + * @BATADV_ATTR_MAX: highest attribute number currently defined + */ +enum batadv_nl_attrs { + BATADV_ATTR_UNSPEC, + BATADV_ATTR_VERSION, + BATADV_ATTR_ALGO_NAME, + BATADV_ATTR_MESH_IFINDEX, + BATADV_ATTR_MESH_IFNAME, + BATADV_ATTR_MESH_ADDRESS, + BATADV_ATTR_HARD_IFINDEX, + BATADV_ATTR_HARD_IFNAME, + BATADV_ATTR_HARD_ADDRESS, + BATADV_ATTR_ORIG_ADDRESS, + BATADV_ATTR_TPMETER_RESULT, + BATADV_ATTR_TPMETER_TEST_TIME, + BATADV_ATTR_TPMETER_BYTES, + BATADV_ATTR_TPMETER_COOKIE, + BATADV_ATTR_PAD, + BATADV_ATTR_ACTIVE, + BATADV_ATTR_TT_ADDRESS, + BATADV_ATTR_TT_TTVN, + BATADV_ATTR_TT_LAST_TTVN, + BATADV_ATTR_TT_CRC32, + BATADV_ATTR_TT_VID, + BATADV_ATTR_TT_FLAGS, + BATADV_ATTR_FLAG_BEST, + BATADV_ATTR_LAST_SEEN_MSECS, + BATADV_ATTR_NEIGH_ADDRESS, + BATADV_ATTR_TQ, + BATADV_ATTR_THROUGHPUT, + BATADV_ATTR_BANDWIDTH_UP, + BATADV_ATTR_BANDWIDTH_DOWN, + BATADV_ATTR_ROUTER, + BATADV_ATTR_BLA_OWN, + BATADV_ATTR_BLA_ADDRESS, + BATADV_ATTR_BLA_VID, + BATADV_ATTR_BLA_BACKBONE, + BATADV_ATTR_BLA_CRC, + /* add attributes above here, update the policy in netlink.c */ + __BATADV_ATTR_AFTER_LAST, + NUM_BATADV_ATTR = __BATADV_ATTR_AFTER_LAST, + BATADV_ATTR_MAX = __BATADV_ATTR_AFTER_LAST - 1 +}; + +/** + * enum batadv_nl_commands - supported batman-adv netlink commands + * + * @BATADV_CMD_UNSPEC: unspecified command to catch errors + * @BATADV_CMD_GET_MESH_INFO: Query basic information about batman-adv device + * @BATADV_CMD_TP_METER: Start a tp meter session + * @BATADV_CMD_TP_METER_CANCEL: Cancel a tp meter session + * @BATADV_CMD_GET_ROUTING_ALGOS: Query the list of routing algorithms. + * @BATADV_CMD_GET_HARDIFS: Query list of hard interfaces + * @BATADV_CMD_GET_TRANSTABLE_LOCAL: Query list of local translations + * @BATADV_CMD_GET_TRANSTABLE_GLOBAL Query list of global translations + * @BATADV_CMD_GET_ORIGINATORS: Query list of originators + * @BATADV_CMD_GET_NEIGHBORS: Query list of neighbours + * @BATADV_CMD_GET_GATEWAYS: Query list of gateways + * @BATADV_CMD_GET_BLA_CLAIM: Query list of bridge loop avoidance claims + * @BATADV_CMD_GET_BLA_BACKBONE: Query list of bridge loop avoidance backbones + * @__BATADV_CMD_AFTER_LAST: internal use + * @BATADV_CMD_MAX: highest used command number + */ +enum batadv_nl_commands { + BATADV_CMD_UNSPEC, + BATADV_CMD_GET_MESH_INFO, + BATADV_CMD_TP_METER, + BATADV_CMD_TP_METER_CANCEL, + BATADV_CMD_GET_ROUTING_ALGOS, + BATADV_CMD_GET_HARDIFS, + BATADV_CMD_GET_TRANSTABLE_LOCAL, + BATADV_CMD_GET_TRANSTABLE_GLOBAL, + BATADV_CMD_GET_ORIGINATORS, + BATADV_CMD_GET_NEIGHBORS, + BATADV_CMD_GET_GATEWAYS, + BATADV_CMD_GET_BLA_CLAIM, + BATADV_CMD_GET_BLA_BACKBONE, + /* add new commands above here */ + __BATADV_CMD_AFTER_LAST, + BATADV_CMD_MAX = __BATADV_CMD_AFTER_LAST - 1 +}; + +/** + * enum batadv_tp_meter_reason - reason of a tp meter test run stop + * @BATADV_TP_REASON_COMPLETE: sender finished tp run + * @BATADV_TP_REASON_CANCEL: sender was stopped during run + * @BATADV_TP_REASON_DST_UNREACHABLE: receiver could not be reached or didn't + * answer + * @BATADV_TP_REASON_RESEND_LIMIT: (unused) sender retry reached limit + * @BATADV_TP_REASON_ALREADY_ONGOING: test to or from the same node already + * ongoing + * @BATADV_TP_REASON_MEMORY_ERROR: test was stopped due to low memory + * @BATADV_TP_REASON_CANT_SEND: failed to send via outgoing interface + * @BATADV_TP_REASON_TOO_MANY: too many ongoing sessions + */ +enum batadv_tp_meter_reason { + BATADV_TP_REASON_COMPLETE = 3, + BATADV_TP_REASON_CANCEL = 4, + /* error status >= 128 */ + BATADV_TP_REASON_DST_UNREACHABLE = 128, + BATADV_TP_REASON_RESEND_LIMIT = 129, + BATADV_TP_REASON_ALREADY_ONGOING = 130, + BATADV_TP_REASON_MEMORY_ERROR = 131, + BATADV_TP_REASON_CANT_SEND = 132, + BATADV_TP_REASON_TOO_MANY = 133, +}; + +#endif /* _UAPI_LINUX_BATMAN_ADV_H_ */ diff --git a/package/gluon-status-page-api/src/neighbours-batadv.c b/package/gluon-status-page-api/src/neighbours-batadv.c new file mode 100644 index 00000000..7d5d0211 --- /dev/null +++ b/package/gluon-status-page-api/src/neighbours-batadv.c @@ -0,0 +1,130 @@ +#include +#include +#include +#include +#include + +#include "batadv-netlink.h" + +#define STR(x) #x +#define XSTR(x) STR(x) + +struct neigh_netlink_opts { + struct json_object *obj; + struct batadv_nlquery_opts query_opts; +}; + +static const enum batadv_nl_attrs parse_orig_list_mandatory[] = { + BATADV_ATTR_ORIG_ADDRESS, + BATADV_ATTR_NEIGH_ADDRESS, + BATADV_ATTR_TQ, + BATADV_ATTR_HARD_IFINDEX, + BATADV_ATTR_LAST_SEEN_MSECS, +}; + +static int parse_orig_list_netlink_cb(struct nl_msg *msg, void *arg) +{ + struct nlattr *attrs[BATADV_ATTR_MAX+1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct batadv_nlquery_opts *query_opts = arg; + struct genlmsghdr *ghdr; + uint8_t *orig; + uint8_t *dest; + uint8_t tq; + uint32_t hardif; + uint32_t lastseen; + char ifname_buf[IF_NAMESIZE], *ifname; + struct neigh_netlink_opts *opts; + char mac1[18]; + + opts = container_of(query_opts, struct neigh_netlink_opts, query_opts); + + if (!genlmsg_valid_hdr(nlh, 0)) + return NL_OK; + + ghdr = nlmsg_data(nlh); + + if (ghdr->cmd != BATADV_CMD_GET_ORIGINATORS) + return NL_OK; + + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_netlink_policy)) + return NL_OK; + + if (batadv_nl_missing_attrs(attrs, parse_orig_list_mandatory, + ARRAY_SIZE(parse_orig_list_mandatory))) + return NL_OK; + + if (!attrs[BATADV_ATTR_FLAG_BEST]) + return NL_OK; + + orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); + dest = nla_data(attrs[BATADV_ATTR_NEIGH_ADDRESS]); + tq = nla_get_u8(attrs[BATADV_ATTR_TQ]); + hardif = nla_get_u32(attrs[BATADV_ATTR_HARD_IFINDEX]); + lastseen = nla_get_u32(attrs[BATADV_ATTR_LAST_SEEN_MSECS]); + + if (memcmp(orig, dest, 6) != 0) + return NL_OK; + + ifname = if_indextoname(hardif, ifname_buf); + if (!ifname) + return NL_OK; + + sprintf(mac1, "%02x:%02x:%02x:%02x:%02x:%02x", + orig[0], orig[1], orig[2], orig[3], orig[4], orig[5]); + + struct json_object *neigh = json_object_new_object(); + if (!neigh) + return NL_OK; + + json_object_object_add(neigh, "tq", json_object_new_int(tq)); + json_object_object_add(neigh, "lastseen", json_object_new_double(lastseen / 1000.)); + json_object_object_add(neigh, "ifname", json_object_new_string(ifname)); + + json_object_object_add(opts->obj, mac1, neigh); + + return NL_OK; +} + +static json_object *neighbours(void) { + struct neigh_netlink_opts opts = { + .query_opts = { + .err = 0, + }, + }; + int ret; + + opts.obj = json_object_new_object(); + if (!opts.obj) + return NULL; + + ret = batadv_nl_query_common("bat0", BATADV_CMD_GET_ORIGINATORS, + parse_orig_list_netlink_cb, NLM_F_DUMP, + &opts.query_opts); + if (ret < 0) { + json_object_put(opts.obj); + return NULL; + } + + return opts.obj; +} + +int main(void) { + struct json_object *obj; + + printf("Content-type: text/event-stream\n\n"); + fflush(stdout); + + while (1) { + obj = neighbours(); + if (obj) { + printf("data: %s\n\n", json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PLAIN)); + fflush(stdout); + json_object_put(obj); + } + sleep(10); + } + + return 0; +} diff --git a/package/gluon-status-page-api/src/respondd.c b/package/gluon-status-page-api/src/respondd.c new file mode 100644 index 00000000..f6a0e51e --- /dev/null +++ b/package/gluon-status-page-api/src/respondd.c @@ -0,0 +1,47 @@ +/* + Copyright (c) 2016, 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 + + +static struct json_object * respondd_provider_nodeinfo(void) { + struct json_object *ret = json_object_new_object(); + + struct json_object *software = json_object_new_object(); + struct json_object *software_status_page = json_object_new_object(); + json_object_object_add(software_status_page, "api", json_object_new_int(1)); + json_object_object_add(software, "status-page", software_status_page); + json_object_object_add(ret, "software", software); + + return ret; +} + +const struct respondd_provider_info respondd_providers[] = { + {"nodeinfo", respondd_provider_nodeinfo}, + {} +}; diff --git a/package/gluon-status-page-api/src/stations.c b/package/gluon-status-page-api/src/stations.c new file mode 100644 index 00000000..24775a07 --- /dev/null +++ b/package/gluon-status-page-api/src/stations.c @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define NETIF_PREFIX "/sys/class/net/" +#define VIRTIF_PREFIX "/sys/devices/virtual/net/" +#define LOWERGLOB_SUFFIX "/lower_*" + +static struct json_object *get_stations(const struct iwinfo_ops *iw, const char *ifname) { + int len; + char buf[IWINFO_BUFSIZE]; + struct json_object *stations = json_object_new_object(); + + if (iw->assoclist(ifname, buf, &len) == -1) + return stations; + + // This is just: for entry in assoclist(ifname) + for (struct iwinfo_assoclist_entry *entry = (struct iwinfo_assoclist_entry *)buf; + (char*)(entry+1) <= buf + len; entry++) { + struct json_object *station = json_object_new_object(); + + json_object_object_add(station, "signal", json_object_new_int(entry->signal)); + json_object_object_add(station, "noise", json_object_new_int(entry->noise)); + json_object_object_add(station, "inactive", json_object_new_int(entry->inactive)); + + char macstr[18]; + + snprintf(macstr, sizeof(macstr), "%02x:%02x:%02x:%02x:%02x:%02x", + entry->mac[0], entry->mac[1], entry->mac[2], + entry->mac[3], entry->mac[4], entry->mac[5]); + + json_object_object_add(stations, macstr, station); + } + + return stations; +} + +static void badrequest() { + printf("Status: 400 Bad Request\n\n"); + exit(1); +} + +// recurse down to the lowest layer-2 interface +static int interface_get_lowest(const char *ifname, char *hwifname); +static int interface_get_lowest(const char *ifname, char *hwifname) { + glob_t globbuf; + char *fnamebuf = alloca(1 + strlen(VIRTIF_PREFIX) + IF_NAMESIZE + + strlen(LOWERGLOB_SUFFIX)); + char *lowentry = NULL; + + + sprintf(fnamebuf, "%s%s%s", VIRTIF_PREFIX, ifname, LOWERGLOB_SUFFIX); + glob(fnamebuf, GLOB_NOSORT | GLOB_NOESCAPE, NULL, &globbuf); + + if (globbuf.gl_pathc == 1) { + lowentry = alloca(1 + strlen(globbuf.gl_pathv[0])); + strncpy(lowentry, globbuf.gl_pathv[0], 1 + strlen(globbuf.gl_pathv[0])); + } + + globfree(&globbuf); + + if (!lowentry) { + char *path = alloca(1 + strlen(NETIF_PREFIX) + strlen(ifname)); + sprintf(path, "%s%s", NETIF_PREFIX, ifname); + + if(access(path, F_OK) != 0) + return false; + + strncpy(hwifname, ifname, IF_NAMESIZE - 1); + return true; + } else { + char buf[PATH_MAX]; + ssize_t len; + + if ((len = readlink(lowentry, buf, sizeof(buf)-1)) != -1) + buf[len] = '\0'; + else + return false; + + if (strncmp(buf, "../", 3) == 0) { + return interface_get_lowest(strrchr(buf, '/') + 1, hwifname); + } else { + return false; + } + } +} + +int main(int argc, char *argv[]) { + if (argc != 2) + badrequest(); + + const char *ifname = argv[1]; + char hwifname[IF_NAMESIZE] = ""; + + if (strlen(ifname) >= IF_NAMESIZE) + badrequest(); + + if (strcspn(ifname, "/\\[]{}*?") != strlen(ifname)) + badrequest(); + + if (!interface_get_lowest(ifname, hwifname)) + badrequest(); + + const struct iwinfo_ops *iw = iwinfo_backend(hwifname); + + if (iw == NULL) + badrequest(); + + printf("Content-type: text/event-stream\n\n"); + + while (true) { + struct json_object *obj; + obj = get_stations(iw, hwifname); + printf("data: %s\n\n", json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PLAIN)); + fflush(stdout); + json_object_put(obj); + usleep(150000); + } + + return 0; +} diff --git a/package/gluon-status-page/Makefile b/package/gluon-status-page/Makefile index 4e44e2b2..7b496ddd 100644 --- a/package/gluon-status-page/Makefile +++ b/package/gluon-status-page/Makefile @@ -1,18 +1,50 @@ include $(TOPDIR)/rules.mk PKG_NAME:=gluon-status-page -PKG_VERSION:=1 +PKG_VERSION:=2 PKG_RELEASE:=1 -PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) +PKG_BUILD_DEPENDS:=node/host include $(INCLUDE_DIR)/package.mk + +RJS_VERSION:=2.1.10 +RJS:=r-$(RJS_VERSION).js +define Download/rjs + FILE:=$(RJS) + URL:=http://requirejs.org/docs/release/$(RJS_VERSION) + URL_FILE:=r.js + HASH:=d0b7cfd962a7f8ac52a5d528df486341eed856609d9c75fa2566a32900f5b143 +endef +$(eval $(call Download,rjs)) + +BACON_VERSION:=0.7.71 +BACON:=Bacon-$(BACON_VERSION).js +define Download/Bacon + FILE:=$(BACON) + URL:=http://cdnjs.cloudflare.com/ajax/libs/bacon.js/$(BACON_VERSION) + URL_FILE:=Bacon.js + HASH:=93d840d2167964ced7c53598f7d07151c3bfb1d8a7c3e8cff44cadd7dea25f1d +endef +$(eval $(call Download,Bacon)) + +ALMOND_VERSION:=0.3.1 +ALMOND:=almond-$(ALMOND_VERSION).js +define Download/almond + FILE:=$(ALMOND) + URL:=https://raw.githubusercontent.com/jrburke/almond/$(ALMOND_VERSION) + URL_FILE:=almond.js + HASH:=3df2baac13da29dab646f9b9ddd2c5e09d91a49ae3a4f3befb40ce1dd60937f2 +endef +$(eval $(call Download,almond)) + 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 + DEPENDS:=+gluon-status-page-api endef define Package/gluon-status-page/description @@ -22,16 +54,25 @@ endef define Build/Prepare mkdir -p $(PKG_BUILD_DIR) + $(CP) $(DL_DIR)/$(RJS) $(PKG_BUILD_DIR)/r.js + $(CP) $(DL_DIR)/$(BACON) $(PKG_BUILD_DIR)/Bacon.js + $(CP) $(DL_DIR)/$(ALMOND) $(PKG_BUILD_DIR)/almond.js endef define Build/Configure + $(CP) ./src/* $(PKG_BUILD_DIR)/ endef define Build/Compile + cd $(PKG_BUILD_DIR) && \ + node r.js -o build.js && \ + node r.js -o cssIn=css/main.css out=style.css && \ + $(M4) index.html.m4 > index.html endef define Package/gluon-status-page/install - $(CP) ./files/* $(1)/ + $(INSTALL_DIR) $(1)/lib/gluon/status-page/www/ + $(INSTALL_DATA) $(PKG_BUILD_DIR)/index.html $(1)/lib/gluon/status-page/www/ 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 deleted file mode 100755 index b31e2f73..00000000 --- a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/status +++ /dev/null @@ -1,161 +0,0 @@ -#!/usr/bin/lua - -local util = require("luci.util") -local fs = require("nixio.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 deleted file mode 100644 index 75700015..00000000 --- a/package/gluon-status-page/files/lib/gluon/status-page/www/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - 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 deleted file mode 100644 index e17102d0..00000000 --- a/package/gluon-status-page/files/lib/gluon/status-page/www/status.js +++ /dev/null @@ -1,9 +0,0 @@ -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/iconfont-config.json b/package/gluon-status-page/iconfont-config.json new file mode 100644 index 00000000..af8718cc --- /dev/null +++ b/package/gluon-status-page/iconfont-config.json @@ -0,0 +1,100 @@ +{ + "name": "statuspage", + "css_prefix_text": "icon-", + "css_use_suffix": false, + "hinting": true, + "units_per_em": 1000, + "ascent": 850, + "glyphs": [ + { + "uid": "12f4ece88e46abd864e40b35e05b11cd", + "css": "ok", + "code": 59397, + "src": "fontawesome" + }, + { + "uid": "5211af474d3a9848f67f945e2ccaf143", + "css": "cancel", + "code": 59399, + "src": "fontawesome" + }, + { + "uid": "e15f0d620a7897e2035c18c80142f6d9", + "css": "link-ext", + "code": 59407, + "src": "fontawesome" + }, + { + "uid": "c76b7947c957c9b78b11741173c8349b", + "css": "attention", + "code": 59403, + "src": "fontawesome" + }, + { + "uid": "559647a6f430b3aeadbecd67194451dd", + "css": "menu", + "code": 59392, + "src": "fontawesome" + }, + { + "uid": "2d6150442079cbda7df64522dc24f482", + "css": "down-dir", + "code": 59393, + "src": "fontawesome" + }, + { + "uid": "80cd1022bd9ea151d554bec1fa05f2de", + "css": "up-dir", + "code": 59394, + "src": "fontawesome" + }, + { + "uid": "9dc654095085167524602c9acc0c5570", + "css": "left-dir", + "code": 59395, + "src": "fontawesome" + }, + { + "uid": "fb1c799ffe5bf8fb7f8bcb647c8fe9e6", + "css": "right-dir", + "code": 59396, + "src": "fontawesome" + }, + { + "uid": "a73c5deb486c8d66249811642e5d719a", + "css": "arrows-cw", + "code": 59400, + "src": "fontawesome" + }, + { + "uid": "750058837a91edae64b03d60fc7e81a7", + "css": "ellipsis-vert", + "code": 59401, + "src": "fontawesome" + }, + { + "uid": "56a21935a5d4d79b2e91ec00f760b369", + "css": "sort", + "code": 59404, + "src": "fontawesome" + }, + { + "uid": "94103e1b3f1e8cf514178ec5912b4469", + "css": "sort-down", + "code": 59405, + "src": "fontawesome" + }, + { + "uid": "65b3ce930627cabfb6ac81ac60ec5ae4", + "css": "sort-up", + "code": 59406, + "src": "fontawesome" + }, + { + "uid": "cda0cdcfd38f5f1d9255e722dad42012", + "css": "spinner", + "code": 59402, + "src": "fontawesome" + } + ] +} \ No newline at end of file diff --git a/package/gluon-status-page/src/build.js b/package/gluon-status-page/src/build.js new file mode 100644 index 00000000..a1b1d703 --- /dev/null +++ b/package/gluon-status-page/src/build.js @@ -0,0 +1,10 @@ +({ + paths: { + "bacon": "../Bacon" + }, + baseUrl: "js/", + name: "../almond", + include: "main", + optimize: "uglify2", + out: "app.js", +}) diff --git a/package/gluon-status-page/src/css/animation.css b/package/gluon-status-page/src/css/animation.css new file mode 100644 index 00000000..e6edbf3c --- /dev/null +++ b/package/gluon-status-page/src/css/animation.css @@ -0,0 +1,12 @@ +/* + Animation example, for spinners +*/ +.animate-spin { + animation: spin 2s linear infinite; + display: inline-block; +} +@keyframes spin { + 100% { + transform: rotate(360deg); + } +} diff --git a/package/gluon-status-page/src/css/font.css b/package/gluon-status-page/src/css/font.css new file mode 100644 index 00000000..c26ee355 --- /dev/null +++ b/package/gluon-status-page/src/css/font.css @@ -0,0 +1,53 @@ +@font-face { + font-family: 'statuspage'; + src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAABBIABEAAAAAGvAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABgAAAABwAAAAcbmIpTEdERUYAAAGcAAAAHQAAACAAQAAET1MvMgAAAbwAAABEAAAAVolbUzJjbWFwAAACAAAAAFAAAAFaNCnF72N2dCAAAAJQAAAACgAAAAoAAAAAZnBnbQAAAlwAAAWUAAALcIiQkFlnYXNwAAAH8AAAAAgAAAAIAAAAEGdseWYAAAf4AAAFIQAAB5Aqg1+6aGVhZAAADRwAAAAvAAAANgs/y+hoaGVhAAANTAAAAB8AAAAkD4gG32htdHgAAA1sAAAAOAAAAExf6AFkbG9jYQAADaQAAAAoAAAAKA0UDxRtYXhwAAANzAAAAB4AAAAgALUAX25hbWUAAA3sAAABUQAAAo4VwGZqcG9zdAAAD0AAAACYAAAAzEaEO/VwcmVwAAAP2AAAAGUAAAB73WsDhXdlYmYAABBAAAAABgAAAAaP4VXgAAAAAQAAAADMPaLPAAAAANAeRhwAAAAA0gZAYHjaY2BkYGDgA2IJBhBgYmAEQiEgZgHzGAAFEABFAAAAeNpjYGQNZpzAwMrAwirEOouBgVEeQjNfZ0hhEmBgYGJgZWbACgLSXFMYHFT/vOBnO/vvLMMOtrMMS4DCjCA5AKFmDF942mNgYGBmgGAZBkYGEAgB8hjBfBYGCyDNxcDBwASEDKp/XrC+4P//H6QIyGZ4wQ5i32KXYJFghuqFAkY2BrgAI1AnSDcKYGQY9gAAyR8MCgAAAAAAAAAAAAAAAHjarVZpcxNHEJ3VYcs2PoIPEjaBWcZyjHZWmMsIEMbsShbgHPKV7EKOXUt27otP/Ab9ml6RVJFv/LS8Hh3YYCdVVChK/ab37Uz3655ek9CSxF5Yj6TcfCmmtjZpZOdJSDdsWo7iQ9nZCylTTP4uiIJotdS+7TgkIhKBqnWFJYLY98jSJONDjzJatiW9alJu6Ul32RoP6q369tPQUY7dCSU1m6FD65EtqcKoEkUy7ZGSNi3D1V9JWuHnK8x81QwlgugkksabYQyP5GfjjFYZrcZ2HEWRTZYbRYpEMzyIIo+yWmKfXDFBQPmgGVJe+TSifIQfkRV7lNMKccl2mt/3JT/pHc6/JOJ6i7IlB/5AdmQHe6cr+SLS2grjpp1sR6GK8HR9J8Qjm5Pqn+xRXtNo4HZFpifNCJbKV5BY+Qll9g/JauF8ypc8GtWSg5wIWi9zYl/yDrQeR0yJaybIgu6OToig7pecodhj+rj4471dLBchBMg4lvWOSrgQRilhs5okbQQ5iJKyRZXUekdMnPI6LeItYb9O7ehLZ7RJqDsxnq2Hjq2cqOR4NKnTTKZO7aTm0ZQGUUo6Ezzm1wGUH9Ekr7axmsTKo2lsM2MkkVCghXNpKohlJ5Y0BdE8mtGbu2Gaa9eiRZo8UM89ek9vboWbOz2n7cA/a/xndSqmg70wnZ4OyEp8mna5SdG6fnqGfybxQ9YCKpEtNsOUxUO2fgfl5WNLjsJrA2z3nvMr6H32RMikgfgb8B4v1SkFTIWYVVAL3bTWtSzL1GpWi1Rk6rshTStf1mkCTTkOfWNfxjj+r5kZS0wJ3+/E6dkRl5659iXINIfcZl2P5nVqsV2AzmzP6TTL9n2d5th+oNM82/M6HWFr63SU7Yc6LbD9SKdjbC9oQZPuOwRyEYFcwAYSgbB1EAjbSwiErUIgbBcRCNsiAmG7hEDYfoxA2C4jELaXtayafippHDsTywBFiAOjOe7IZW4qV1PJpRKui0anNuQpcqukonhW/SsD/eKRN6yBtUC6RNb8ikmufFSV44+uaHnTxLkCjlV/e3NcnxMPZb9Y+FPwv9qaqqRXrHlkchV5I9CT40TXJhWPrunyuapH1/+Lig5rgX4DpRALRVmWDb6ZkPBRp9NQDVzlEDMbMw/X9bplzc/h/JsYIQvofvw3FBoL3INOWUlZ7WCv1dePZbm3B+WwJ1iSYr7M61vhi4zMSvtFZil7PvJ5wBUwKpVhqw1creDNexLzkOlN8kwQtxVlg6SNx5kgsYFjHjBvvpMgJExdtYHaKZywgbxgzCnY74RDVG+U5XB7oX0ejZR/a1fsyBkVTRD4bfZG2OuzUPJbrIGEJ7/U10BVIU3FuKmASyPlhmrwYVyt20YyTqCvqNgNy7KKDx9H3HdKjmUg+UgRq0dHP629Qp3Uuf3KKG7fO/0IgkFpYv72vpnioJR3tZJlVm0DU7calVPXmsPFqw7dzaPue8fZJ3LWNN10T9z0vqZVt4ODuVkQ7dsclKVMLqjrww4bqMvNpdDqZVyS3nYPMCwwoN+hFRv/V/dx+DxXqgqj40i9nagfo89iDPIPOH9H9QXo5zFMuYaU53uXE59u3MPZMl3FXayf4t/ArLXmZukacEPTDZiHrFodusoNfKcGOj3S3I70EPCx7grxAGATwGLwie5axvMpgPF8xhwf4HPmMGgyh8EWcxhsM2cNYIc5DHaZw2CPOQy+YM46wJfMYRAyh0HEHAZPmBMAPGUOg6+Yw+Br5jD4hjn3Ab5lDoOYOQwS5jDY13RrKHOLF3QXqG1QFejA9BMW97A41FQZsr/jhWF/bxCzfzCIqT9quj2k/sQLQ/3ZIKb+YhBTf9V0Z0j9jReG+rtBTP3DIKY+0y/GcpnBX0a+S4UDyi42n/P3xPsHwhpAtgABAAH//wAPeNp9VU1oG0cUnje7WlmKvJKsXa0dR9qMFK+symslki1VUezEgtiN6gajhkBFUcE9RSY1rZuWYoIIpqQmh+IkB9OmoYeS+lCCoTQ/t+TQlBB0aKGU4qan5pBLKD4EHOR13+zKpHFJdRjNmzfvm+/Nm/ctAbL9EwgpCHzcWpfWXCvET3SSJt6bA/He0C5RMFMjMJTLs0zYrSpSgsUMYXgop73EdqNtRqQJ3aRJtnFbT9L/sYoX9X5hcM9FfYD201OXIwM0Gb0cQS89tWRvWuIRhCBXqIlLwjqRifS9VwAzFXQoSW6QYgnAI0USGRC7LKIVwjgIKzzyIJ9qlISJg6EhxoqDIdoYeRgFDcKKFEfauFEZUXFIRltET0JND6MBKmKM9PcTG6NMFuiaS3uOEUKMHKYeVGweZYUigwNicixkEYU2dW4P7mmRiPmcB2IsIUYnYuziGMPBIYcGT8YwC5yIwjMxmyLR+109CDXKF0w7/gKh7jOuKaJifNBjcziMHDQPDnobBalc0K+w6l6Yok/w74qut5KsyjZ/0umKyb5kzLpO/2bsCnuLtZK6TgvMxj679dD1wJUi+xC7l2Pnh/IeMHYc4MHBz0/x4JAG4yyDKWuVIWwVZzDlHGitwpSu8xOsVfRW0f0orTt+mwH6MUav6dyv16IYw3EwZi8hFN9jTVqTiiROxknHD9lEr0DNlIqFz/LC+yEK2cy+fC6f07KZcAQoYbF9Cbc0CKHhLsIyopZvF4YXN3cYjHhMdEtuKQX8iVL7vVytNN9fBs+Ub7+3+4+AUrYGrXvXrPvzl/DylTL8BgevQZFbWFJmOSErj76wntoRf8k9MsfBkn01WVluKHO90O3zWE1roXHmsgamcL0DsnC28eElzYxguIlP8upVe2OP03lb63ADc9zuuVS8V/EJ7Z7jedk9FXd6LN+2E227CI7NEyqZa+YYHUmvpUfpS+a1h2aJjqYfmiN0jJ7ZduIS/QT3jPF5iZCO9r0v4CxIduPtD5BhMkomiHqk6+jYyKvZ/a8YLNKt+H0S7bAbMRPl7zaEjzgsA14/rmBLxQzgExm4y54MAvxrTxRkuu2JGfXlGXHu87nmR9/Mi3PfvcemP52ePl+Dewurn4mN2/PjJz+uipXGcSqXZ94Qj86VWO7YQTFTMX8sVcfEwrsF2pys15frdTp54gPX/NcI0joxXnvnQq3mYm83GrcajWfXiic5ypuwe7gsVqYrHSWx0FcQD1QOiAWrD2+gyvMXSNdWzf1EamL2cZLFmgwmoqpdE64WmTA2qlsGrnMJA0JKGKuSy4eGEgaWwS3hApYth+XjtqR2CbNd48fHFeF0MqWUEhuxvqOhlDAX6vb/ElCp6pX9z2S/N6TIf8qKPeSlcjyZjG/ceG0i3ocSOCHObj71Bmmnj8o+j8/naR3CwB7594CqBojTJ9+KSy6ujRHsk90hL6V2WbJtfTRQDIK2TNlS5yj0i3K5U/rW7TeNDkAJVOFXW8Y0LkPbeszPpEVHByn857ydB+xAdHRQqLV5t3VwB8kdpFDSX2Th5L7eQbBWCXIEcz+UjouYe0/7exUBu/cl1IAwfp9yqLN2z6htTQA8L2E4xDVcM9Lg6NndRaGPl6O1NjlDZ8vCjcm6GigH1LuLrfLiXUHupI8fKElGJ/hHpqDd39S8zHuuE4rCzfN3qMK3zrzeOjZZp7PH4DQvlHVp8c4d+Dmwiz6+j9JiRjZv6Xg9DzbDPt+5TkzlH7P8hqoAAAB42mNgZGBgAOI5Ufuj4vltvjLIczCAwCU2hwQE/T+Og4HtLJDLwcAEEgUACxEJCgB42mNgZGBgO/vvLMMODgYGhv//gCRQBAUIAwCOkwV5AHja42CAAKZVDAwsQJrtNpCeCMFMtxm8gJiBg4Ghm82doRYkx7iNgYGdASwmBFMHwkA+AwBxgwmlAAAAAAAAAAAACABWAHgAmgC8ANwBCgFQAcICDAKMAuQDHgNAA2IDyHjaY2BkYGAQZvBg4GAAASYwWQzEagyiICYAEIYBFQAAeNp1kU1OwlAUhc8TNP4kjAwDRx0YoxNEgsYw0mhwrgmOC1YoImKpJk6IC3ARrsA4dAHG+LMCXYRr8OvrowOCaW577rnn3nfuq6SCnpSTyS9I6hIpNlomS/EMmpHDOfgHh/Na1aPDsyrq1eE5ND8OL6qhX4eXtGYOHX5X0Yznf6hs7h3+1Lx5dvhLBfOS4u+cVsybDnSlge4UKVRbHcXytA67wbeisrZUBTVReChTVai+fPVgfN3Q0bGVIfkecU7Whw1Q9MAltXhfUo/Rx3QMOdFnTqBjog3TI4+mKqZx3kRfgyzpDu3JHp5LOJ/WeUT0rdq3Ds+y3Ya6RVGBjdkg2SKyrj3VJ/bxmJbUujAt+JK9tRi2pk2e//Y/hWlm1bHLur1TT/v4bNs737W1CtOqPDXwTvYvtnXBlICzBm7nwO5Xz6ae6BompBYlDv4AFmJmQgAAAHjabY1bDsIgFEQZrAV8G90GPyauwMR9NC0qKV4aHtblK/XXk8zM+RvG2Y8j+8/hGzAOjhkqzFFDQEJhgSVWWGODLXbYi0z2dL5eqqehLDs/ku5sqPNQRjpzS0VUsPfHZNz3ddtQa5xqQvBj1O24Ns7ZIdqoXyYkEQdLZIJqUjKUrKcq+pBUKV0OxGR5kM5Sr807fQBTyi/YeNpj8N7BcCIoYiMjY1/kBsadHAwcDMkFGxlYnTYyMGhBaA4UeicDAwMnMouZwWWjCmNHYMQGh46IjcwpLhvVQLxdHA0MjCwOHckhESAlkUCwkYFHawfj/9YNLL0bmRhcAAfTIrgAAAAAAVXgj+AAAA==) format('woff'); + font-weight: normal; + font-style: normal; +} + +[class^="icon-"]:before, [class*=" icon-"]:before { + font-family: "statuspage"; + font-style: normal; + font-weight: normal; + speak: none; + + display: inline-block; + text-decoration: inherit; + width: 1em; + margin-right: .2em; + text-align: center; + /* opacity: .8; */ + + /* For safety - reset parent styles, that can break glyph codes*/ + font-variant: normal; + text-transform: none; + + /* fix buttons height, for twitter bootstrap */ + line-height: 1em; + + /* Animation center compensation - margins should be symmetric */ + /* remove if not needed */ + margin-left: .2em; + + /* you can be more comfortable with increased icons size */ + /* font-size: 120%; */ + + /* Uncomment for 3D effect */ + /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ +} + +.icon-menu:before { content: '\e800'; } /* '' */ +.icon-down-dir:before { content: '\e801'; } /* '' */ +.icon-up-dir:before { content: '\e802'; } /* '' */ +.icon-left-dir:before { content: '\e803'; } /* '' */ +.icon-right-dir:before { content: '\e804'; } /* '' */ +.icon-ok:before { content: '\e805'; } /* '' */ +.icon-cancel:before { content: '\e807'; } /* '' */ +.icon-arrows-cw:before { content: '\e808'; } /* '' */ +.icon-ellipsis-vert:before { content: '\e809'; } /* '' */ +.icon-spinner:before { content: '\e80a'; } /* '' */ +.icon-attention:before { content: '\e80b'; } /* '' */ +.icon-sort:before { content: '\e80c'; } /* '' */ +.icon-sort-down:before { content: '\e80d'; } /* '' */ +.icon-sort-up:before { content: '\e80e'; } /* '' */ +.icon-link-ext:before { content: '\e80f'; } /* '' */ diff --git a/package/gluon-status-page/src/css/main.css b/package/gluon-status-page/src/css/main.css new file mode 100644 index 00000000..0604802e --- /dev/null +++ b/package/gluon-status-page/src/css/main.css @@ -0,0 +1,171 @@ +@import "reset.css"; +@import "font.css"; +@import "menu.css"; +@import "animation.css"; + +body { + background: rgba(0, 0, 0, 0.12); + font-family: Roboto, Lucida Grande, sans, Arial; + color: rgba(0, 0, 0, 0.87); + font-size: 14px; +} + + +a { + color: rgba(220, 0, 103, 0.87); + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +header { + display: flex; + padding: 0 14px; + background: #dc0067; + color: rgba(255, 255, 255, 0.98); + position: absolute; + top: 0; + width: 100%; + box-sizing: border-box; + height: 20vh; + z-index: -1; + box-shadow: 0px 5px 6px rgba(0, 0, 0, 0.16), 0px 1.5px 3px rgba(0, 0, 0, 0.23); + white-space: nowrap; +} + +header h1, header .icons { + font-size: 24px; + margin: 10px 0; + padding: 6px 0; +} + +header h1 { + text-overflow: ellipsis; + overflow: hidden; + flex: 1; +} + +header h1:hover { + text-decoration: underline; + cursor: pointer; +} + +h1 { + font-weight: bold; +} + +h2, h3 { + font-size: 16px; + color: rgba(0, 0, 0, 0.54); +} + +h2 { + padding: 16px 16px; +} + +h3 { + padding: 16px 16px 8px; +} + +.container { + max-width: 90vw; + margin: 64px auto 24px auto; + background: rgb(253, 253, 253); + box-shadow: 0px 5px 20px rgba(0, 0, 0, 0.19), 0px 3px 6px rgba(0, 0, 0, 0.23); +} + +.container .frame { + box-sizing: border-box; +} + +.vertical-split { + display: flex; +} + +.vertical-split > .frame { + flex: 1; + border-style: solid; + border-color: rgba(0, 0, 0, 0.12); +} + +.vertical-split > .frame + .frame { + border-width: 0 0 0 1px; +} + +dl, pre { + padding: 0 16px 16px; +} + +table { + margin: 0 16px; +} + +dt, th { + font-weight: bold; + color: rgba(0, 0, 0, 0.87); +} + +dt { + margin-bottom: 4px; +} + +th { + text-align: left; + padding: 4px 16px 4px 0; +} + +dd, td { + font-weight: normal; + font-size: 0.9em; + color: rgba(0, 0, 0, 0.54); +} + +dd { + padding-bottom: 16px; +} + +table.datatable { + width: calc(100% - 32px); +} + +table.datatable td { + font-size: 1em; + padding: 4px 0; +} + +table.datatable tr.inactive { + opacity: 0.33; +} + +table.datatable tr.highlight { + background: rgba(255, 180, 0, 0.25); +} + +div.signalgraph { + margin: 16px; +} + +@media only screen and (max-width: 1250px) { + .container { + max-width: none; + margin: 56px 0 0; + } + + header { + height: 56px; + z-index: 1; + position: fixed; + } +} + +@media only screen and (max-width: 700px) { + .vertical-split { + display: block; + } + + .vertical-split > .frame + .frame { + border-width: 1px 0 0 0; + } +} diff --git a/package/gluon-status-page/src/css/menu.css b/package/gluon-status-page/src/css/menu.css new file mode 100644 index 00000000..b29e4a41 --- /dev/null +++ b/package/gluon-status-page/src/css/menu.css @@ -0,0 +1,50 @@ +.noscroll { + overflow: hidden; +} + +.menu-background { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + z-index: 10; +} + +.menu { + background: rgba(255, 255, 255, 1); + position: fixed; + z-index: 11; + padding: 8px 0; + box-shadow: 0 1px 6px rgba(0, 0, 0, 0.12), 0 1px 4px rgba(0, 0, 0, 0.24); + overflow-y: auto; + max-height: 80vh; + + transform-origin: top left; + animation: new-menu-animation .08s ease-out forwards; +} + +@keyframes new-menu-animation { + from { + transform: scaleY(0); + } + to { + transform: scaleY(1); + } +} + +.menu li { + cursor: pointer; + display: block; + font-size: 16px; + padding: 16px 32px 16px 16px; + color: rgba(0, 0, 0, 0.87); +} + +.menu li:hover { + background: rgba(0, 0, 0, 0.07); +} + +.menu li:active { + background: rgba(0, 0, 0, 0.07); +} diff --git a/package/gluon-status-page/src/css/reset.css b/package/gluon-status-page/src/css/reset.css new file mode 100644 index 00000000..f6ca1484 --- /dev/null +++ b/package/gluon-status-page/src/css/reset.css @@ -0,0 +1,86 @@ +/* +html5doctor.com Reset Stylesheet v1.6.1 +Last Updated: 2010-09-17 +Author: Richard Clark - http://richclarkdesign.com +*/ +html, body, div, span, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +abbr, address, cite, code, +del, dfn, em, img, ins, kbd, q, samp, +small, strong, sub, sup, var, +b, i, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, figcaption, figure, +footer, header, hgroup, menu, nav, section, summary, +time, mark, audio, video { + margin:0; + padding:0; + border:0; + outline:0; + font-size:100%; + vertical-align:baseline; + background:transparent; +} +body { + line-height:1; +} +article,aside,details,figcaption,figure, +footer,header,hgroup,menu,nav,section { + display:block; +} +nav ul { + list-style:none; +} +blockquote, q { + quotes:none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content:''; + content:none; +} +a { + margin:0; + padding:0; + font-size:100%; + vertical-align:baseline; + background:transparent; +} +/* change colours to suit your needs */ +ins { + background-color:#ff9; + color:#000; + text-decoration:none; +} +/* change colours to suit your needs */ +mark { + background-color:#ff9; + color:#000; + font-style:italic; + font-weight:bold; +} +del { + text-decoration: line-through; +} +abbr[title], dfn[title] { + border-bottom:1px dotted; + cursor:help; +} +table { + border-collapse:collapse; + border-spacing:0; +} +/* change border colour to suit your needs */ +hr { + display:block; + height:1px; + border:0; + border-top:1px solid #cccccc; + margin:1em 0; + padding:0; +} +input, select { + vertical-align:middle; +} diff --git a/package/gluon-status-page/src/index.html.m4 b/package/gluon-status-page/src/index.html.m4 new file mode 100644 index 00000000..2726f2e3 --- /dev/null +++ b/package/gluon-status-page/src/index.html.m4 @@ -0,0 +1,18 @@ + + + + + + + + + + + + diff --git a/package/gluon-status-page/src/js/lib/gui.js b/package/gluon-status-page/src/js/lib/gui.js new file mode 100644 index 00000000..3d771005 --- /dev/null +++ b/package/gluon-status-page/src/js/lib/gui.js @@ -0,0 +1,157 @@ +"use strict" +define([ "lib/gui/nodeinfo" + , "lib/gui/statistics" + , "lib/gui/neighbours" + , "lib/gui/menu" + , "lib/streams" + , "lib/neighbourstream" + ], function ( NodeInfo + , Statistics + , Neighbours + , Menu + , Streams + , NeighbourStream + ) { + + function VerticalSplit(parent) { + var el = document.createElement("div") + el.className = "vertical-split" + parent.appendChild(el) + + el.push = function (child) { + var header = document.createElement("h2") + header.appendChild(child.title) + + var div = document.createElement("div") + div.className = "frame" + div.node = child + div.appendChild(header) + + el.appendChild(div) + + child.render(div) + + return function () { + div.node.destroy() + el.removeChild(div) + } + } + + el.clear = function () { + while (el.firstChild) { + el.firstChild.node.destroy() + el.removeChild(el.firstChild) + } + } + + return el + } + + var h1 + + return function (mgmtBus, nodesBus) { + function setTitle(node, state) { + var title = node ? node.hostname : "(not connected)" + + document.title = title + h1.textContent = title + + var icon = document.createElement("i") + icon.className = "icon-down-dir" + + h1.appendChild(icon) + + switch (state) { + case "connect": + stateIcon.className = "icon-arrows-cw animate-spin" + break + case "fail": + stateIcon.className = "icon-attention" + break + default: + stateIcon.className = "" + break + } + } + + var nodes = [] + + function nodeMenu() { + var myNodes = nodes.slice() + + myNodes.sort(function (a, b) { + a = a.hostname + b = b.hostname + return (a < b) ? -1 : (a > b) + }) + + var menu = myNodes.map(function (d) { + return [d.hostname, function () { + mgmtBus.pushEvent("goto", d) + }] + }) + + new Menu(menu).apply(this) + } + + var header = document.createElement("header") + h1 = document.createElement("h1") + header.appendChild(h1) + + h1.onclick = nodeMenu + + var icons = document.createElement("p") + icons.className = "icons" + header.appendChild(icons) + + var stateIcon = document.createElement("i") + icons.appendChild(stateIcon) + + document.body.appendChild(header) + + var container = document.createElement("div") + container.className = "container" + + document.body.appendChild(container) + + setTitle() + + var content = new VerticalSplit(container) + + function nodeChanged(nodeInfo) { + setTitle(nodeInfo, "connect") + + content.clear() + content.push(new NodeInfo(nodeInfo)) + } + + function nodeNotArrived(nodeInfo) { + setTitle(nodeInfo, "fail") + } + + function nodeArrived(nodeInfo, ip) { + setTitle(nodeInfo) + + var neighbourStream = new NeighbourStream(mgmtBus, nodesBus, ip) + var statisticsStream = new Streams.Statistics(ip) + + content.push(new Statistics(statisticsStream)) + content.push(new Neighbours(nodeInfo, neighbourStream, mgmtBus)) + } + + function newNodes(d) { + nodes = [] + for (var nodeId in d) + nodes.push(d[nodeId]) + } + + mgmtBus.onEvent({ "goto": nodeChanged + , "arrived": nodeArrived + , "gotoFailed": nodeNotArrived + }) + + nodesBus.map(".nodes").onValue(newNodes) + + return this + } +}) diff --git a/package/gluon-status-page/src/js/lib/gui/menu.js b/package/gluon-status-page/src/js/lib/gui/menu.js new file mode 100644 index 00000000..712f2d0f --- /dev/null +++ b/package/gluon-status-page/src/js/lib/gui/menu.js @@ -0,0 +1,39 @@ +"use strict" +define(function () { + return function (menu) { + return function () { + var background = document.createElement("div") + background.className = "menu-background" + document.body.appendChild(background) + document.body.classList.add("noscroll") + + var offset = this.getBoundingClientRect() + var container = document.createElement("ul") + container.className = "menu" + container.style.top = offset.top + "px" + container.style.left = offset.left + "px" + + background.onclick = destroy + + menu.forEach(function (item) { + var li = document.createElement("li") + li.textContent = item[0] + li.action = item[1] + li.onclick = function () { + destroy() + this.action() + } + + container.appendChild(li) + }) + + document.body.appendChild(container) + + function destroy() { + document.body.classList.remove("noscroll") + document.body.removeChild(background) + document.body.removeChild(container) + } + } + } +}) diff --git a/package/gluon-status-page/src/js/lib/gui/neighbours.js b/package/gluon-status-page/src/js/lib/gui/neighbours.js new file mode 100644 index 00000000..f6ce9e42 --- /dev/null +++ b/package/gluon-status-page/src/js/lib/gui/neighbours.js @@ -0,0 +1,274 @@ +"use strict" +define([ "lib/helper", "lib/gui/signalgraph", "lib/gui/signal"], +function (Helper, SignalGraph, Signal) { + + var graphColors = ["#396AB1", "#DA7C30", "#3E9651", "#CC2529", "#535154", "#6B4C9A", "#922428", "#948B3D"] + //graphColors = ["#7293CB", "#E1974C", "#84BA5B", "#D35E60", "#808585", "#9067A7", "#AB6857", "#CCC210"]; + + var inactiveTime = 200 + + function SignalEntry(graph, color, stream) { + var signal = new Signal(color) + var remove = graph.add(signal) + + var unsubscribe = stream.onValue(update) + + this.destroy = function () { + unsubscribe() + remove() + } + + this.getSignal = function () { + return signal + } + + return this + + function update(d) { + if ("wifi" in d) + signal.set(d.wifi.inactive > inactiveTime ? null : d.wifi.signal) + } + } + + function TableEntry(parent, nodeInfo, color, stream, mgmtBus, signal) { + var el = parent.insertRow() + + var tdHostname = el.insertCell() + var tdTQ = el.insertCell() + var tdSignal = el.insertCell() + var tdDistance = el.insertCell() + var tdInactive = el.insertCell() + + var marker = document.createElement("span") + marker.textContent = "⬤ " + marker.style.color = color + tdHostname.appendChild(marker) + + var hostname = document.createElement("span") + tdHostname.appendChild(hostname) + + var infoSet = false + var unsubscribe = stream.onValue(update) + + el.onmouseenter = function () { + el.classList.add("highlight") + signal.setHighlight(true) + } + + el.onmouseleave = function () { + el.classList.remove("highlight") + signal.setHighlight(false) + } + + el.destroy = function () { + unsubscribe() + parent.tBodies[0].removeChild(el) + } + + return el + + function update(d) { + if ("wifi" in d) { + var signal = d.wifi.signal + var inactive = d.wifi.inactive + + el.classList.toggle("inactive", inactive > inactiveTime) + + tdSignal.textContent = signal + tdInactive.textContent = Math.round(inactive / 1000) + " s" + } + + if ("batadv" in d) + tdTQ.textContent = Math.round(d.batadv.tq / 2.55) + " %" + else + tdTQ.textContent = "‒" + + if (infoSet) + return + + if ("nodeInfo" in d) { + infoSet = true + + var link = document.createElement("a") + link.textContent = d.nodeInfo.hostname + link.href = "#" + link.nodeInfo = d.nodeInfo + link.onclick = function () { + mgmtBus.pushEvent("goto", this.nodeInfo) + return false + } + + while (hostname.firstChild) + hostname.removeChild(hostname.firstChild) + + hostname.appendChild(link) + + try { + var distance = Helper.haversine(nodeInfo.location.latitude, nodeInfo.location.longitude, + d.nodeInfo.location.latitude, d.nodeInfo.location.longitude) + + tdDistance.textContent = Math.round(distance * 1000) + " m" + } catch (e) { + tdDistance.textContent = "‒" + } + } else + hostname.textContent = d.id + } + } + + function Interface(parent, nodeInfo, iface, stream, mgmtBus) { + var colors = graphColors.slice(0) + + var el = document.createElement("div") + el.ifname = iface + parent.appendChild(el) + + var h = document.createElement("h3") + h.textContent = iface + el.appendChild(h) + + var table = document.createElement("table") + var tr = table.insertRow() + table.classList.add("datatable") + + var th = document.createElement("th") + th.textContent = Helper._("Node") + tr.appendChild(th) + + th = document.createElement("th") + th.textContent = "TQ" + tr.appendChild(th) + + th = document.createElement("th") + th.textContent = "dBm" + tr.appendChild(th) + + th = document.createElement("th") + th.textContent = Helper._("Distance") + tr.appendChild(th) + + th = document.createElement("th") + th.textContent = Helper._("Inactive") + tr.appendChild(th) + + el.appendChild(table) + + var wrapper = document.createElement("div") + wrapper.className = "signalgraph" + el.appendChild(wrapper) + + var canvas = document.createElement("canvas") + canvas.className = "signal-history" + canvas.height = 200 + wrapper.appendChild(canvas) + + var graph = new SignalGraph(canvas, -100, 0, true) + + var stopStream = stream.skipDuplicates(sameKeys).onValue(update) + + var managedNeighbours = {} + + function update(d) { + var notUpdated = new Set() + var id + + for (id in managedNeighbours) + notUpdated.add(id) + + for (id in d) { + if (!(id in managedNeighbours)) { + var neighbourStream = stream.map("." + id).filter( function (d) { return d !== undefined }) + var color = colors.shift() + var signal = new SignalEntry(graph, color, neighbourStream) + managedNeighbours[id] = { views: [ signal, + new TableEntry(table, nodeInfo, color, neighbourStream, mgmtBus, signal.getSignal()) + ], + color: color + } + } + + notUpdated.delete(id) + } + + notUpdated.forEach(function (id) { + managedNeighbours[id].views.forEach( function (d) { d.destroy() }) + colors.push(managedNeighbours[id].color) + delete managedNeighbours[id] + }) + } + + + el.destroy = function () { + stopStream() + + for (var id in managedNeighbours) + managedNeighbours[id].views.forEach( function (d) { d.destroy() }) + + el.removeChild(h) + el.removeChild(wrapper) + el.removeChild(table) + } + } + + function sameKeys(a, b) { + a = Object.keys(a).sort() + b = Object.keys(b).sort() + + return !(a < b || a > b) + } + + function getter(k) { + return function(obj) { + return obj[k] + } + } + + return function (nodeInfo, stream, mgmtBus) { + var stopStream, div + + function render(el) { + div = document.createElement("div") + el.appendChild(div) + + stopStream = stream.skipDuplicates(sameKeys).onValue(update) + + function update(d) { + var have = {} + var remove = [] + if (div.hasChildNodes()) { + var children = div.childNodes + for (var i = 0; i < children.length; i++) { + var a = children[i] + if (a.ifname in d) + have[a.ifname] = true + else { + a.destroy() + remove.push(a) + } + } + } + + remove.forEach(function (d) { div.removeChild(d) }) + + for (var k in d) { + if (!(k in have)) + new Interface(div, nodeInfo, k, stream.map(getter(k)), mgmtBus) + } + } + } + + function destroy() { + stopStream() + + while (div.firstChild) { + div.firstChild.destroy() + div.removeChild(div.firstChild) + } + } + + return { title: document.createTextNode(Helper._("Neighbors")) + , render: render + , destroy: destroy + } + } +}) diff --git a/package/gluon-status-page/src/js/lib/gui/nodeinfo.js b/package/gluon-status-page/src/js/lib/gui/nodeinfo.js new file mode 100644 index 00000000..1441b34e --- /dev/null +++ b/package/gluon-status-page/src/js/lib/gui/nodeinfo.js @@ -0,0 +1,54 @@ +"use strict" +define(["lib/helper"], function (Helper) { + return function (nodeInfo) { + var el = document.createElement("div") + + update(nodeInfo) + + function dlEntry(dl, dict, key, prettyName) { + var v = Helper.dictGet(dict, key.split(".")) + + if (v === null) + return + + var dt = document.createElement("dt") + var dd = document.createElement("dd") + + dt.textContent = prettyName + if (v instanceof Array) { + var tn = v.map(function (d) { return document.createTextNode(d) }) + tn.forEach(function (node) { + if (dd.hasChildNodes()) + dd.appendChild(document.createElement("br")) + + dd.appendChild(node) + }) + } else + dd.textContent = v + + dl.appendChild(dt) + dl.appendChild(dd) + } + + function update(nodeInfo) { + var list = document.createElement("dl") + + dlEntry(list, nodeInfo, "hostname", Helper._("Node name")) + dlEntry(list, nodeInfo, "owner.contact", Helper._("Contact")) + dlEntry(list, nodeInfo, "hardware.model", Helper._("Model")) + dlEntry(list, nodeInfo, "network.mac", Helper._("Primary MAC")) + dlEntry(list, nodeInfo, "network.addresses", Helper._("IP Address")) + dlEntry(list, nodeInfo, "software.firmware.release", Helper._("Firmware")) + dlEntry(list, nodeInfo, "software.fastd.enabled", "Mesh-VPN") + dlEntry(list, nodeInfo, "software.autoupdater.enabled", Helper._("Automatic updates")) + dlEntry(list, nodeInfo, "software.autoupdater.branch", Helper._("Branch")) + + el.appendChild(list) + } + + return { title: document.createTextNode(Helper._("Overview")) + , render: function (d) { d.appendChild(el) } + , destroy: function () {} + } + } +}) diff --git a/package/gluon-status-page/src/js/lib/gui/signal.js b/package/gluon-status-page/src/js/lib/gui/signal.js new file mode 100644 index 00000000..d91c63fb --- /dev/null +++ b/package/gluon-status-page/src/js/lib/gui/signal.js @@ -0,0 +1,48 @@ +"use strict" +define(function () { + return function (color) { + var canvas = document.createElement("canvas") + var ctx = canvas.getContext("2d") + var v = null + var radius = 1.2 + var highlight = false + + function drawPixel(x, y) { + ctx.beginPath() + ctx.fillStyle = color + ctx.arc(x, y, radius, 0, Math.PI * 2, false) + ctx.closePath() + ctx.fill() + } + + this.resize = function (w, h) { + canvas.width = w + canvas.height = h + } + + this.draw = function (x, scale) { + var y = scale(v) + + ctx.clearRect(x, 0, 5, canvas.height) + + if (y) + drawPixel(x, y) + } + + this.canvas = canvas + + this.set = function (d) { + v = d + } + + this.setHighlight = function (d) { + highlight = d + } + + this.getHighlight = function () { + return highlight + } + + return this + } +}) diff --git a/package/gluon-status-page/src/js/lib/gui/signalgraph.js b/package/gluon-status-page/src/js/lib/gui/signalgraph.js new file mode 100644 index 00000000..231ce628 --- /dev/null +++ b/package/gluon-status-page/src/js/lib/gui/signalgraph.js @@ -0,0 +1,137 @@ +"use strict" +define(function () { + return function (canvas, min, max) { + var i = 0 + var graphWidth + var last = 0 + + var signals = [] + + var ctx = canvas.getContext("2d") + + resize() + + window.addEventListener("resize", resize, false) + window.requestAnimationFrame(step) + + function step(timestamp) { + var delta = timestamp - last + + if (delta > 40) { + draw() + last = timestamp + } + + window.requestAnimationFrame(step) + } + + function drawGrid() { + var gridctx = ctx + var nLines = Math.floor(canvas.height / 40) + gridctx.save() + gridctx.lineWidth = 0.5 + gridctx.strokeStyle = "rgba(0, 0, 0, 0.25)" + gridctx.fillStyle = "rgba(0, 0, 0, 0.5)" + gridctx.textAlign = "end" + gridctx.textBaseline = "bottom" + + gridctx.beginPath() + + for (var i = 0; i < nLines; i++) { + var y = canvas.height - i * 40 + gridctx.moveTo(0, y - 0.5) + gridctx.lineTo(canvas.width, y - 0.5) + var dBm = Math.round(scaleInverse(y, min, max, canvas.height)) + " dBm" + + gridctx.save() + gridctx.strokeStyle = "rgba(255, 255, 255, 0.9)" + gridctx.lineWidth = 4 + gridctx.miterLimit = 2 + gridctx.strokeText(dBm, canvas.width - 5, y - 2.5) + gridctx.fillText(dBm, canvas.width - 5, y - 2.5) + gridctx.restore() + } + + gridctx.stroke() + + gridctx.strokeStyle = "rgba(0, 0, 0, 0.83)" + gridctx.lineWidth = 1.5 + gridctx.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1) + + gridctx.restore() + } + + function draw() { + var anyHighlight = signals.some( function (d) { return d.getHighlight() }) + + signals.forEach( function (d) { + d.draw(i, function (v) { + return scale(v, min, max, canvas.height) + }) + }) + + ctx.clearRect(0, 0, canvas.width, canvas.height) + + ctx.save() + + signals.forEach( function (d) { + if (anyHighlight) + ctx.globalAlpha = 0.1 + + if (d.getHighlight()) + ctx.globalAlpha = 1 + + ctx.drawImage(d.canvas, 0, 0) + }) + + ctx.restore() + + ctx.save() + ctx.beginPath() + ctx.strokeStyle = "rgba(255, 180, 0, 0.15)" + ctx.lineWidth = 5 + ctx.moveTo(i + 2.5, 0) + ctx.lineTo(i + 2.5, canvas.height) + ctx.stroke() + + drawGrid() + + i = (i + 1) % graphWidth + } + + function scaleInverse(n, min, max, height) { + return (min * n + max * height - max * n) / height + } + + function scale(n, min, max, height) { + return (1 - (n - min) / (max - min)) * height + } + + function resize() { + var newWidth = canvas.parentNode.clientWidth + + if (newWidth === 0 || newWidth === canvas.width) + return + + var lastImage = ctx.getImageData(0, 0, newWidth, canvas.height) + canvas.width = newWidth + graphWidth = canvas.width + ctx.putImageData(lastImage, 0, 0) + + signals.forEach( function (d) { + d.resize(canvas.width, canvas.height) + }) + } + + this.add = function (d) { + signals.push(d) + d.resize(canvas.width, canvas.height) + + return function () { + signals = signals.filter( function (e) { return e !== d } ) + } + } + + return this + } +}) diff --git a/package/gluon-status-page/src/js/lib/gui/statistics.js b/package/gluon-status-page/src/js/lib/gui/statistics.js new file mode 100644 index 00000000..2f3e6e27 --- /dev/null +++ b/package/gluon-status-page/src/js/lib/gui/statistics.js @@ -0,0 +1,282 @@ +"use strict" +define(["lib/helper"], function (Helper) { + function streamElement(type, stream) { + var el = document.createElement(type) + el.destroy = stream.onValue(update) + + function update(d) { + el.textContent = d + } + + return el + } + + function streamNode(stream) { + var el = document.createTextNode("") + el.destroy = stream.onValue(update) + + function update(d) { + el.textContent = d + } + + return el + } + + function mkRow(table, label, stream, sorted) { + + var i = -1 + + if (sorted) { + for (i = 0; i < table.rows.length; i++) { + if (label < table.rows[i].firstChild.textContent) + break + } + } + + var tr = table.insertRow(i) + var th = document.createElement("th") + var td = streamElement("td", stream) + th.textContent = label + tr.appendChild(th) + tr.appendChild(td) + + tr.destroy = function () { + td.destroy() + table.tBodies[0].removeChild(tr) + } + + return tr + } + + function mkTrafficRow(table, children, label, stream, selector) { + var tr = table.insertRow() + var th = document.createElement("th") + th.textContent = label + tr.appendChild(th) + var td = tr.insertCell() + + var traffic = stream.slidingWindow(2, 2) + var pkts = streamNode(traffic.map(deltaUptime(selector + ".packets")).map(prettyPackets)) + var bw = streamNode(traffic.map(deltaUptime(selector + ".bytes")).map(prettyBits)) + var bytes = streamNode(stream.map(selector).map(".bytes").map(prettyBytes)) + + td.appendChild(pkts) + td.appendChild(document.createElement("br")) + td.appendChild(bw) + td.appendChild(document.createElement("br")) + td.appendChild(bytes) + + children.push(pkts) + children.push(bw) + children.push(bytes) + } + + function mkMeshVPN(el, stream) { + var children = {} + var init = false + var h = document.createElement("h3") + h.textContent = "Mesh-VPN" + + var table = document.createElement("table") + + var unsubscribe = stream.onValue( function (d) { + function addPeer(peer, path) { + return { peer: peer, path: path } + } + + function addPeers(d, path) { + if (!("peers" in d)) + return [] + + var peers = [] + + for (var peer in d.peers) + peers.push(addPeer(peer, path + ".peers." + peer)) + + return peers + } + + function addGroup(d, path) { + var peers = [] + + peers = peers.concat(addPeers(d, path)) + + if ("groups" in d) + for (var group in d.groups) + peers = peers.concat(addGroup(d.groups[group], path + ".groups." + group)) + + return peers + } + + if (d === undefined) + clear() + + else { + if (!init) { + init = true + el.appendChild(h) + el.appendChild(table) + } + + var peers = addGroup(d, "") + var paths = new Set(peers.map(function (d) { return d.path } )) + + for (var path in children) + if (!paths.has(path)) { + children[path].destroy() + delete children[path] + } + + peers.forEach( function (peer) { + if (!(peer.path in children)) + children[peer.path] = mkRow(table, peer.peer, + stream.startWith(d) + .map(peer.path) + .filter(function (d) { return d !== undefined }) + .map(prettyPeer), true) + }) + } + }) + + function clear() { + if (init) { + init = false + el.removeChild(h) + el.removeChild(table) + } + + for (var peer in children) + children[peer].destroy() + + children = {} + } + + function destroy() { + unsubscribe() + clear() + } + + return { destroy: destroy } + } + + function deltaUptime(selector) { + return function (d) { + var deltaTime = d[1].uptime - d[0].uptime + var d0 = Helper.dictGet(d[0], selector.split(".").splice(1)) + var d1 = Helper.dictGet(d[1], selector.split(".").splice(1)) + + return (d1 - d0) / deltaTime + } + } + + function prettyPeer(d) { + if (d === null) + return Helper._("not connected") + else + return Helper._("connected") + " (" + prettyUptime(d.established) + ")" + } + + function prettyPackets(d) { + var v = Helper.formatNumberFixed(d, 0) + return v + " "+ Helper._("Packets/s") + } + + function prettyPrefix(prefixes, step, d) { + var prefix = 0 + + while (d > step && prefix < prefixes.length - 1) { + d /= step + prefix++ + } + + d = Helper.formatNumber(d, 3) + return d + " " + prefixes[prefix] + } + + function prettySize(d) { + return prettyPrefix([ "", "k", "M", "G", "T" ], 1024, d) + } + + function prettyBits(d) { + return prettySize(d * 8) + "bps" + } + + function prettyBytes(d) { + return prettySize(d) + "B" + } + + function prettyUptime(seconds) { + var minutes = Math.round(seconds / 60) + + var days = Math.floor(minutes / 1440) + var hours = Math.floor((minutes % 1440) / 60) + minutes = Math.floor(minutes % 60) + + var out = "" + + if (days === 1) + out += "1 " + Helper._("Day") + ", " + else if (days > 1) + out += days + " " + Helper._("Days") + ", " + + out += hours + ":" + + if (minutes < 10) + out += "0" + + out += minutes + + return out + } + + function prettyNVRAM(usage) { + return Helper.formatNumber(usage * 100, 3) + "% " + Helper._("used") + } + + function prettyLoad(load) { + return Helper.formatNumberFixed(load, 2) + } + + function prettyRAM(memory) { + var usage = 1 - (memory.free + memory.buffers + memory.cached) / memory.total + return prettyNVRAM(usage) + } + + return function (stream) { + var children = [] + var el = document.createElement("div") + var table = document.createElement("table") + + children.push(mkRow(table, Helper._("Uptime"), stream.map(".uptime").map(prettyUptime))) + children.push(mkRow(table, Helper._("Load average"), stream.map(".loadavg").map(prettyLoad))) + children.push(mkRow(table, "RAM", stream.map(".memory").map(prettyRAM))) + children.push(mkRow(table, "NVRAM", stream.map(".rootfs_usage").map(prettyNVRAM))) + children.push(mkRow(table, Helper._("Gateway"), stream.map(".gateway"))) + children.push(mkRow(table, Helper._("Clients"), stream.map(".clients.total"))) + + el.appendChild(table) + + var h = document.createElement("h3") + h.textContent = Helper._("Traffic") + el.appendChild(h) + + table = document.createElement("table") + + mkTrafficRow(table, children, Helper._("Transmitted"), stream, ".traffic.tx") + mkTrafficRow(table, children, Helper._("Received"), stream, ".traffic.rx") + mkTrafficRow(table, children, Helper._("Forwarded"), stream, ".traffic.forward") + + el.appendChild(table) + + children.push(mkMeshVPN(el, stream.map(".mesh_vpn"))) + + function destroy() { + children.forEach(function (d) {d.destroy()}) + } + + return { title: document.createTextNode(Helper._("Statistic")) + , render: function (d) { d.appendChild(el) } + , destroy: destroy + } + } +}) diff --git a/package/gluon-status-page/src/js/lib/helper.js b/package/gluon-status-page/src/js/lib/helper.js new file mode 100644 index 00000000..5640e76f --- /dev/null +++ b/package/gluon-status-page/src/js/lib/helper.js @@ -0,0 +1,167 @@ +"use strict" +define([ "bacon" ], function (Bacon) { + function get(url) { + return Bacon.fromBinder(function(sink) { + var req = new XMLHttpRequest() + req.open("GET", url) + + req.onload = function() { + if (req.status === 200) + sink(new Bacon.Next(req.response)) + else + sink(new Bacon.Error(req.statusText)) + sink(new Bacon.End()) + } + + req.onerror = function() { + sink(new Bacon.Error("network error")) + sink(new Bacon.End()) + } + + req.send() + + return function () {} + }) + } + + function getJSON(url) { + return get(url).map(JSON.parse) + } + + function buildUrl(ip, object, param) { + var url = "http://[" + ip + "]/cgi-bin/" + object + if (param) url += "?" + param + + return url + } + + function request(ip, object, param) { + return getJSON(buildUrl(ip, object, param)) + } + + function dictGet(dict, key) { + var k = key.shift() + + if (!(k in dict)) + return null + + if (key.length === 0) + return dict[k] + + return dictGet(dict[k], key) + } + + function localizeNumber(d) { + var sep = ',' + return d.replace('.', sep) + } + + function formatNumberFixed(d, digits) { + return localizeNumber(d.toFixed(digits)) + } + + function formatNumber(d, digits) { + digits-- + + for (var v = d; v >= 10 && digits > 0; v /= 10) + digits-- + + // avoid toPrecision as it might produce strings in exponential notation + return formatNumberFixed(d, digits) + } + + function haversine() { + var radians = Array.prototype.map.call(arguments, function(deg) { return deg / 180.0 * Math.PI }) + var lat1 = radians[0], lon1 = radians[1], lat2 = radians[2], lon2 = radians[3] + var R = 6372.8 // km + var dLat = lat2 - lat1 + var dLon = lon2 - lon1 + var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2) + var c = 2 * Math.asin(Math.sqrt(a)) + return R * c + } + + function _(s) { + var i, lang, langs, dict = { + "de": { + "Node": "Knoten", + "Distance": "Entfernung", + "Inactive": "Inaktiv", + "Node name": "Knotenname", + "Contact": "Kontakt", + "Model": "Modell", + "Primary MAC": "Primäre MAC", + "IP Address": "IP-Adresse", + "Automatic updates": "Automatische Updates", + "Overview": "Übersicht", + "used": "belegt", + "Uptime": "Laufzeit", + "Load average": "Systemlast", + "Transmitted": "Gesendet", + "Received": "Empfangen", + "Forwarded": "Weitergeleitet", + "Day": "Tag", + "Days": "Tage", + "connected": "verbunden", + "not connected": "nicht verbunden", + "Packets/s": "Pakete/s", + "Statistic": "Statistik", + "Neighbors": "Nachbarknoten" + }, + "ru": { + "Node": "Узел", + "Distance": "Дальность", + "Inactive": "Не активен", + "Node name": "Имя узла", + "Contact": "Контакт", + "Model": "Модель", + "Primary MAC": "Основной MAC", + "IP Address": "IP Адрес", + "Automatic updates": "Автоматические обновления", + "Overview": "Обзор", + "used": "используется", + "Uptime": "Время работы", + "Load average": "Загрузка системы", + "Gateway": "Шлюз", + "Clients": "Клиенты", + "Transmitted": "Передано", + "Received": "Получено", + "Forwarded": "Переправленно", + "Day": "День", + "Days": "Дней", + "connected": "подключено", + "not connected": "не подключено", + "Packets/s": "Пакетов/c", + "Statistic": "Статистика", + "Traffic": "Трафик", + "Neighbors": "Соседи", + "Firmware": "Прошивка", + "Branch": "Ветка" + } + } + if (navigator.languages) + langs = navigator.languages + else if (navigator.language) + langs = [navigator.language] + else + langs = [] + for (i=0; i 0) + return [undefined, [new Bacon.Error(acc), ev]] + else if (ev.hasValue()) + return [[], [ev, new Bacon.End()]] + }) + + race.onValue(onEpoch(gotoEpoch, function (d) { + mgmtBus.pushEvent("arrived", [nodeInfo, d]) + })) + + race.onError(onEpoch(gotoEpoch, function () { + mgmtBus.pushEvent("gotoFailed", nodeInfo) + })) + } + + function scanNodeInfo(a, nodeInfo) { + a.nodes[nodeInfo.node_id] = nodeInfo + + var mesh = Helper.dictGet(nodeInfo, ["network", "mesh"]) + + if (mesh) + for (var m in mesh) + for (var ifname in mesh[m].interfaces) + mesh[m].interfaces[ifname].forEach( function (d) { + a.macs[d] = nodeInfo + }) + + return a + } + + var lsavailable = false + try { + localStorage.setItem("t", "t") + localStorage.removeItem("t") + lsavailable = true + } catch(e) { + lsavailable = false + } + + + if ( lsavailable && localStorage.nodes) + JSON.parse(localStorage.nodes).forEach(nodesBusIn.push) + + nodesBus.map(".nodes").onValue(function (nodes) { + var out = [] + + for (var k in nodes) + out.push(nodes[k]) + + if (lsavailable) + localStorage.nodes = JSON.stringify(out) + }) + + var bootstrap = Helper.getJSON(bootstrapUrl) + + bootstrap.onError(function () { + console.log("FIXME bootstrapping failed") + }) + + bootstrap.onValue(function (d) { + mgmtBus.pushEvent("nodeinfo", d) + mgmtBus.pushEvent("goto", d) + }) +}) diff --git a/package/gluon-wan-dnsmasq/Makefile b/package/gluon-wan-dnsmasq/Makefile index 3722210f..92e1edaa 100644 --- a/package/gluon-wan-dnsmasq/Makefile +++ b/package/gluon-wan-dnsmasq/Makefile @@ -5,13 +5,14 @@ PKG_VERSION:=1 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) -include $(INCLUDE_DIR)/package.mk +include ../gluon.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 + DEPENDS:=+gluon-core +libubus-lua +dnsmasq +libpacketmark endef define Package/gluon-wan-dnsmasq/description @@ -26,10 +27,12 @@ define Build/Configure endef define Build/Compile + $(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/) endef define Package/gluon-wan-dnsmasq/install $(CP) ./files/* $(1)/ + $(CP) $(PKG_BUILD_DIR)/luadest/* $(1)/ endef $(eval $(call BuildPackage,gluon-wan-dnsmasq)) 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 index 22bed039..78799c9c 100755 --- a/package/gluon-wan-dnsmasq/files/etc/init.d/gluon-wan-dnsmasq +++ b/package/gluon-wan-dnsmasq/files/etc/init.d/gluon-wan-dnsmasq @@ -18,7 +18,10 @@ 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 + export LD_PRELOAD=libpacketmark.so + export LIBPACKETMARK_MARK=$PACKET_MARK + + service_start /usr/sbin/dnsmasq -x $SERVICE_PID_FILE -u root -i lo -p $PORT -h -r $RESOLV_CONF } stop() { diff --git a/package/gluon-wan-dnsmasq/files/lib/gluon/wan-dnsmasq/update.lua b/package/gluon-wan-dnsmasq/luasrc/lib/gluon/wan-dnsmasq/update.lua similarity index 59% rename from package/gluon-wan-dnsmasq/files/lib/gluon/wan-dnsmasq/update.lua rename to package/gluon-wan-dnsmasq/luasrc/lib/gluon/wan-dnsmasq/update.lua index 88a86507..d1a3d99e 100755 --- a/package/gluon-wan-dnsmasq/files/lib/gluon/wan-dnsmasq/update.lua +++ b/package/gluon-wan-dnsmasq/luasrc/lib/gluon/wan-dnsmasq/update.lua @@ -5,28 +5,41 @@ local RESOLV_CONF = RESOLV_CONF_DIR .. '/resolv.conf' local ubus = require('ubus').connect() -local uci = require('luci.model.uci').cursor() +local uci = require('simple-uci').cursor() local fs = require 'nixio.fs' local new_servers = '' +local function append_server(server) + new_servers = new_servers .. 'nameserver ' .. server .. '\n' +end + + +local function handle_interface(status) + local ifname = status.device + local servers = status.inactive['dns-server'] -local function append_servers(servers) for _, server in ipairs(servers) do - new_servers = new_servers .. 'nameserver ' .. server .. '\n' + if server:match('^fe80:') then + append_server(server .. '%' .. ifname) + else + append_server(server) + end end end local function append_interface_servers(iface) - append_servers(ubus:call('network.interface.' .. iface, 'status', {}).inactive['dns-server']) + handle_interface(ubus:call('network.interface.' .. iface, 'status', {})) end local static = uci:get_first('gluon-wan-dnsmasq', 'static', 'server') if type(static) == 'table' and #static > 0 then - append_servers(static) + for _, server in ipairs(static) do + append_server(server) + end else pcall(append_interface_servers, 'wan6') pcall(append_interface_servers, 'wan') diff --git a/package/gluon-web-admin/Makefile b/package/gluon-web-admin/Makefile new file mode 100644 index 00000000..726cbbe8 --- /dev/null +++ b/package/gluon-web-admin/Makefile @@ -0,0 +1,42 @@ +# Copyright (C) 2013 Nils Schneider +# This is free software, licensed under the Apache 2.0 license. + +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-web-admin +PKG_VERSION:=1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include ../gluon.mk + +PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG) + + +define Package/gluon-web-admin + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Web-based simple administration interface for mesh nodes + DEPENDS:=gluon-config-mode-core-virtual +pretty-hostname +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile + $(call GluonBuildI18N,gluon-web-admin,i18n) + $(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/) +endef + +define Package/gluon-web-admin/install + $(CP) ./files/* $(1)/ + $(CP) $(PKG_BUILD_DIR)/luadest/* $(1)/ + $(call GluonInstallI18N,gluon-web-admin,$(1)) +endef + +$(eval $(call BuildPackage,gluon-web-admin)) diff --git a/package/gluon-web-admin/files/lib/gluon/web/view/admin/info.html b/package/gluon-web-admin/files/lib/gluon/web/view/admin/info.html new file mode 100644 index 00000000..6e93b707 --- /dev/null +++ b/package/gluon-web-admin/files/lib/gluon/web/view/admin/info.html @@ -0,0 +1,46 @@ +<%- + local fs = require 'nixio.fs' + local uci = require('simple-uci').cursor() + local lutil = require 'gluon.web.util' + local pretty_hostname = require 'pretty_hostname' + + local site = require 'gluon.site_config' + local sysconfig = require 'gluon.sysconfig' + local platform = require 'gluon.platform' + local util = require "gluon.util" + + + local keys = { + hostname = translate('Hostname'), + primary_mac = translate('MAC address'), + model = translate('Hardware model'), + version = translate('Gluon version'), + release = translate('Firmware release'), + site = translate('Site'), + pubkey = translate('Public VPN key'), + } + + local values = { + hostname = pretty_hostname.get(uci), + 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_bool("fastd", "mesh_vpn", "enabled") + if meshvpn_enabled then + local pubkey = util.trim(lutil.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]%>
<%=pcdata(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-web-admin/files/lib/gluon/web/view/admin/upgrade.html similarity index 52% rename from package/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/upgrade.htm rename to package/gluon-web-admin/files/lib/gluon/web/view/admin/upgrade.html index a2b82235..5ce815f7 100644 --- a/package/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/upgrade.htm +++ b/package/gluon-web-admin/files/lib/gluon/web/view/admin/upgrade.html @@ -1,5 +1,4 @@ <%# -LuCI - Lua Configuration Interface Copyright 2008 Steven Barth Copyright 2008-2009 Jo-Philipp Wich @@ -12,44 +11,40 @@ You may obtain a copy of the License at $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 %> -
-
-