Compare commits

..

1 Commits

Author SHA1 Message Date
Matthias Schiffer
d8b66a10b8
docs: remove remaining CSS workaround
Remove a workaround for a CSS issue in older Firefox versions, which was
recently fixed (at some point between Firefox 102 and 108). Firefox 108+
now displays the bullet points at the right vertical position even without
the hack in [1].

[1] https://gluon.readthedocs.io/en/latest/releases/v2018.1.html#site-conf
2023-01-13 19:55:42 +01:00
127 changed files with 1297 additions and 3268 deletions

3
.ecrc
View File

@ -1,3 +0,0 @@
{
"Exclude": ["docs/_build"]
}

View File

@ -35,9 +35,6 @@ indent_size = 2
[*.lua]
[{Makefile,*.mk}]
indent_style = unset
[*.md]
indent_style = space
indent_size = 4
@ -61,7 +58,3 @@ indent_size = 2
[CMakeLists.txt]
indent_style = space
indent_size = 2
[{docs,contrib/ci}/*site*/**/*.conf]
indent_style = space
indent_size = 2

View File

@ -1,4 +1,4 @@
# Docs: <https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/customizing-dependency-updates>
# Docs: <https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/customizing-dependency-updates>
version: 2

View File

@ -13,7 +13,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Create backport PRs
uses: korthout/backport-action@v1.2.0
uses: korthout/backport-action@v1.0.1
with:
# Config README: https://github.com/korthout/backport-action#backport-action
pull_description: |-

View File

@ -34,7 +34,7 @@ jobs:
strategy:
fail-fast: false
matrix:
# Read back changed targets to create build matrix
# Read back changd targets to create build matrix
target: ${{ fromJSON(needs.changed.outputs.targets) }}
runs-on: ubuntu-latest
steps:

View File

@ -30,25 +30,3 @@ jobs:
run: ln -s ./docs/site-example ./site
- name: Lint shell code
run: make lint-sh
editorconfig:
name: Editorconfig
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Dependencies
run: sudo apt install curl tar
- name: Install editorconfig-checker
env:
VERSION: 2.7.0
OS: linux
ARCH: amd64
run: |
curl -O -L -C - https://github.com/editorconfig-checker/editorconfig-checker/releases/download/$VERSION/ec-$OS-$ARCH.tar.gz
tar xzf ec-$OS-$ARCH.tar.gz
sudo mv ./bin/ec-$OS-$ARCH /usr/bin/editorconfig-checker
sudo chmod +x /usr/bin/editorconfig-checker
- name: Install example site
run: ln -s ./docs/site-example ./site
- name: Lint editorconfig
run: make lint-editorconfig

View File

@ -29,7 +29,6 @@ files["package/**/check_site.lua"] = {
"need",
"need_alphanumeric_key",
"need_array",
"need_array_elements_exclusive",
"need_array_of",
"need_boolean",
"need_chanlist",
@ -51,7 +50,6 @@ files["package/**/check_site.lua"] = {
files["package/**/luasrc/lib/gluon/config-mode/*"] = {
globals = {
"MultiListValue",
"DynamicList",
"Flag",
"Form",

View File

@ -11,10 +11,6 @@ sphinx:
# Optionally set the version of Python and requirements required to build your docs
python:
version: 3.8
install:
- requirements: docs/requirements.txt
build:
os: ubuntu-22.04
tools:
python: "3.8"

View File

@ -1,30 +0,0 @@
workspace:
base: /build
#clone:
# git:
# image: woodpeckerci/plugin-git
# settings:
# recursive: true
pipeline:
build-${TARGET}:
image: "ubuntu:latest"
pull: true
environment:
- input_version=v2022.1.4
- GLUON_SITEDIR=../site
- FORCE_UNSAFE_CONFIGURE=1
- GLUON_TARGET=${TARGET}
- GLUON_DEPRECATED=1
commands:
- echo ${TARGET}
# - git config --global init.defaultBranch main
# - sed -i 's/install/install file/' contrib/actions/install-dependencies.sh
# - sh contrib/actions/install-dependencies.sh
# - sh contrib/actions/run-build.sh ${TARGET}
matrix:
TARGET:
- ath79-generic
- x86-64

View File

@ -23,8 +23,8 @@ 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 is 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
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.

View File

@ -1,7 +1,7 @@
The code of Project Gluon may be distributed under the following terms, unless
noted otherwise in individual files or subtrees.
Copyright (c) Project Gluon
Copyright (c) 2013-2022, Project Gluon
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -151,10 +151,7 @@ list-targets: FORCE
echo "$$target"
done
lint: lint-editorconfig lint-lua lint-sh
lint-editorconfig: FORCE
@scripts/lint-editorconfig.sh
lint: lint-lua lint-sh
lint-lua: FORCE
@scripts/lint-lua.sh

View File

@ -1,5 +1,5 @@
[![Build Gluon](https://github.com/freifunk-gluon/gluon/actions/workflows/build-gluon.yml/badge.svg?branch=master)](https://github.com/freifunk-gluon/gluon/actions/workflows/build-gluon.yml)
[![License](https://img.shields.io/badge/License-BSD%202--Clause-orange.svg)](https://opensource.org/license/bsd-2-clause/)
[![License](https://img.shields.io/badge/License-BSD%202--Clause-orange.svg)](https://opensource.org/licenses/BSD-2-Clause)
[![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/freifunk-gluon/gluon?sort=semver)](https://github.com/freifunk-gluon/gluon/releases/latest)
# Gluon

View File

@ -3,6 +3,6 @@
set -e
apt-get -y update
apt-get -y install git build-essential python3 gawk unzip libncurses5-dev zlib1g-dev libssl-dev libelf-dev wget rsync time qemu-utils
apt-get -y install git subversion build-essential python3 gawk unzip libncurses5-dev zlib1g-dev libssl-dev wget time qemu-utils
apt-get -y clean
rm -rf /var/lib/apt/lists/*

View File

@ -1 +0,0 @@
../minimal-site/i18n

View File

@ -1 +0,0 @@
../minimal-site/modules

View File

@ -1,176 +0,0 @@
-- This is an example site configuration for Gluon v2022.1
--
-- Take a look at the documentation located at
-- https://gluon.readthedocs.io/ for details.
--
-- This configuration will not work as is. You're required to make
-- community specific changes to it!
{
-- Used for generated hostnames, e.g. freifunk-abcdef123456. (optional)
-- hostname_prefix = 'freifunk-',
-- Name of the community.
site_name = 'Continuous Integration',
-- Shorthand of the community.
site_code = 'ci',
-- 32 bytes of random data, encoded in hexadecimal
-- This data must be unique among all sites and domains!
-- Can be generated using: echo $(hexdump -v -n 32 -e '1/1 "%02x"' </dev/urandom)
domain_seed = 'e9608c4ff338b920992d629190e9ff11049de1dfc3f299eac07792dfbcda341c',
-- Prefixes used by clients within the mesh.
-- prefix6 is required, prefix4 can be omitted if next_node.ip4
-- is not set.
prefix6 = 'fdff:cafe:cafe:cafe::/64',
-- Prefixes used by nodes within the mesh
node_prefix6 = 'fdff:cafe:cafe:cafe::/64',
-- Timezone of your community.
-- See https://openwrt.org/docs/guide-user/base-system/system_configuration#time_zones
timezone = 'CET-1CEST,M3.5.0,M10.5.0/3',
-- List of NTP servers in your community.
-- Must be reachable using IPv6!
-- ntp_servers = {'1.ntp.services.ffxx'},
-- Wireless regulatory domain of your community.
regdom = 'DE',
-- Wireless configuration for 2.4 GHz interfaces.
wifi24 = {
-- Wireless channel.
channel = 1,
-- ESSIDs used for client network.
ap = {
ssid = 'gluon-ci-ssid',
-- disabled = true, -- (optional)
-- Configuration for a backward compatible OWE network below.
owe_ssid = 'owe.gluon-ci-ssid', -- (optional - SSID for OWE client network)
owe_transition_mode = true, -- (optional - enables transition-mode - requires ssid as well as owe_ssid)
},
mesh = {
-- Adjust these values!
id = 'ueH3uXjdp', -- usually you don't want users to connect to this mesh-SSID, so use a cryptic id that no one will accidentally mistake for the client WiFi
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.
wifi5 = {
channel = 44,
outdoor_chanlist = '100-140',
ap = {
ssid = 'gluon-ci-ssid',
-- disabled = true, -- (optional)
-- Configuration for a backward compatible OWE network below.
owe_ssid = 'owe.gluon-ci-ssid', -- (optional - SSID for OWE client network)
owe_transition_mode = true, -- (optional - enables transition-mode - requires ssid as well as owe_ssid)
},
mesh = {
-- Adjust these values!
id = 'ueH3uXjdp',
mcast_rate = 12000,
},
},
-- The next node feature allows clients to always reach the node it is
-- connected to using a known IP address.
next_node = {
-- anycast IPs of all nodes
name = { 'nextnode.location.community.example.org', 'nextnode', 'nn' },
ip4 = '10.0.0.1',
ip6 = 'fd::1',
},
-- Options specific to routing protocols (optional)
mesh = {
vxlan = true,
olsrd = {},
},
mesh_vpn = {
-- enabled = true,
fastd = {
-- Refer to https://fastd.readthedocs.io/en/latest/ to better understand
-- what these options do.
-- List of crypto-methods to use.
methods = {'salsa2012+umac'},
mtu = 1312,
-- configurable = true,
-- syslog_level = 'warn',
groups = {
backbone = {
-- Limit number of connected peers to reduce bandwidth.
limit = 1,
-- List of peers.
peers = {
},
-- Optional: nested peer groups
-- groups = {
-- backbone_sub = {
-- ...
-- },
-- ...
-- },
},
-- 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,
},
},
autoupdater = {
-- Default branch (optional), can be overridden by setting GLUON_AUTOUPDATER_BRANCH when building.
-- Set GLUON_AUTOUPDATER_ENABLED to enable the autoupdater by default for newly installed nodes.
branch = 'stable',
-- List of branches. You may define multiple branches.
branches = {
stable = {
name = 'stable',
-- List of mirrors to fetch images from. IPv6 required!
mirrors = {'http://1.updates.services.ffhl/stable/sysupgrade'},
-- Number of good signatures required.
-- Have multiple maintainers sign your build and only
-- accept it when a sufficient number of them have
-- signed it.
good_signatures = 0,
-- List of public keys of maintainers.
pubkeys = {
},
},
},
},
}

View File

@ -1,57 +0,0 @@
## gluon site.mk makefile example
## GLUON_FEATURES
# Specify Gluon features/packages to enable;
# Gluon will automatically enable a set of packages
# depending on the combination of features listed
GLUON_FEATURES := \
autoupdater \
ebtables-filter-multicast \
ebtables-filter-ra-dhcp \
ebtables-limit-arp \
mesh-olsrd \
mesh-vpn-fastd \
respondd \
status-page \
web-advanced \
web-wizard
GLUON_FEATURES_standard := \
wireless-encryption-wpa3
## GLUON_SITE_PACKAGES
# Specify additional Gluon/OpenWrt packages to include here;
# A minus sign may be prepended to remove a packages from the
# selection that would be enabled by default or due to the
# chosen feature flags
GLUON_SITE_PACKAGES := iwinfo
## DEFAULT_GLUON_RELEASE
# version string to use for images
# gluon relies on
# opkg compare-versions "$1" '>>' "$2"
# to decide if a version is newer or not.
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.
# e.g.:
# $ make images GLUON_RELEASE=23.42+5
# would generate images named like this:
# gluon-ff%site_code%-23.42+5-%router_model%.bin
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

View File

@ -5,6 +5,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
file \
git \
subversion \
python3 \
build-essential \
gawk \
@ -23,12 +24,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN mkdir /tmp/ec &&\
wget -O /tmp/ec/ec-linux-amd64.tar.gz https://github.com/editorconfig-checker/editorconfig-checker/releases/download/2.7.0/ec-linux-amd64.tar.gz &&\
tar -xvzf /tmp/ec/ec-linux-amd64.tar.gz &&\
mv bin/ec-linux-amd64 /usr/local/bin/editorconfig-checker &&\
rm -rf /tmp/ec
RUN useradd -d /gluon gluon
USER gluon

View File

@ -1,10 +0,0 @@
/*
This fixes the vertical position of list markers when the first
element in the <li> is a <pre> block
Scrolling inside the <pre> block is still working as expected
*/
.rst-content pre.literal-block,
.rst-content div[class^='highlight'] pre {
overflow: visible;
}

View File

@ -20,7 +20,7 @@
# -- Project information -----------------------------------------------------
project = 'Gluon'
copyright = 'Project Gluon'
copyright = '2015-2022, Project Gluon'
author = 'Project Gluon'
# The short X.Y version
@ -71,13 +71,6 @@ pygments_style = None
# Don't highlight code blocks unless requested explicitly
highlight_language = 'none'
# Ignore links to the config mode, as well as anchors on on hackint, which are
# used to mark channel names and do not exist. Regular links are not effected.
linkcheck_ignore = [
'http://192.168.1.1',
'https://webirc.hackint.org/#'
]
# -- Options for HTML output -------------------------------------------------
@ -96,7 +89,7 @@ html_theme = 'sphinx_rtd_theme'
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
#
html_static_path = ['_static']
# html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
@ -110,7 +103,7 @@ html_static_path = ['_static']
# These paths are either relative to html_static_path
# or fully qualified paths (eg. https://...)
html_css_files = ['css/custom.css']
# html_css_files = ['css/custom.css']
# -- Options for HTMLHelp output ---------------------------------------------

View File

@ -57,7 +57,7 @@ commits, making `git reflog` the only way to recover them!
make refresh-patches
In order to refresh patches when updating feeds or the OpenWrt base, `make refresh-patches` applies and updates all of their patches without installing feed packages to the OpenWrt build system.
In order to refresh patches when updating feeds or the OpenWrt base, `make refresh-patches` applies and updates all of their patches without installing feed packages to the OpenWrt buildsystem.
This command speeds up the maintenance of updating OpenWrt and feeds.
@ -77,7 +77,7 @@ apply:
- use tabs instead of spaces
- trailing whitespaces must be eliminated
- files need to end with a final newline
- newlines need to have Unix line endings (lf)
- newlines need to have unix line endings (lf)
To that end we provide a ``.editorconfig`` configuration, which is supported by most
of the editors out there.

View File

@ -45,7 +45,7 @@ Some more information on how to use this tool can be found at
Obtaining Stacktraces
.....................
On many targets stack traces can be read from the following
On many targets stacktraces can be read from the following
location after reboot: ::
/sys/kernel/debug/crashlog

View File

@ -1,51 +0,0 @@
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
To use the node's DNS server, both options should be set. The node will cache at
most 'cacheentries' many DNS records in RAM. The 'servers' list will be used to
resolve the received DNS queries if the request cannot be answered from
cache. Gateways should announce the "next node" address via DHCP and RDNSS (if
any). Note that not setting 'servers' here will lead to DNS not working: Once
the gateways all announce the "next node" address for DNS, there is no way for
nodes to automatically determine DNS servers. They have to be baked into the
firmware.
If these settings do not exist, the cache is not initialized 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.
It is suggested to use the same name as the DNS server provides:
e.g. nextnode.location.community.example.org (This way the name also works if a
client uses static DNS Servers). Hint: If next_node.name does not contain a dot
some browsers would open the searchpage instead.
::
dns = {
cacheentries = 5000,
servers = { '2001:db8::1', },
},
next_node = {
name = { 'nextnode.location.community.example.org', 'nextnode', 'nn' },
ip6 = '2001:db8:8::1',
ip4 = '198.51.100.1',
}
Each cache entry will occupy about 90 bytes of RAM.

View File

@ -0,0 +1,26 @@
DNS forwarder
=============
A Gluon node can be configured to act as a DNS forwarder. Requests for the
next-node hostname(s) can be answered locally, without querying the upstream
resolver.
**Note:** While this reduces answer time and allows to use the next-node
hostname without upstream connectivity, this feature should not be used for
next-node hostnames that are FQDN when the zone uses DNSSEC.
One or more upstream resolvers can be configured in the *dns.servers* setting.
When *next_node.name* is set, A and/or AAAA records for the next-node IP
addresses are placed in the dnsmasq configuration.
::
dns = {
servers = { '2001:db8::1', },
},
next_node = {
name = { 'nextnode.location.community.example.org', 'nextnode', 'nn' },
ip6 = '2001:db8:8::1',
ip4 = '198.51.100.1',
}

View File

@ -47,7 +47,7 @@ installed. Please note that at least one alfred daemon is required to run as
.. _alfred-json: https://github.com/ffnord/alfred-json
The following data types are used:
The following datatypes are used:
* `nodeinfo`: 158
* `statistics`: 159

View File

@ -77,7 +77,7 @@ should always appear before ``null`` in the configuration when both are enabled.
fastd v22 or newer is needed for the ``null@l2tp`` method.
It is often not necessary to enable L2TP offloading on supernodes for
performance reasons. Nodes using offloading can communicate with supernodes that
performance reasons. Nodes using offloading can communicate with supornodes that
don't use offloading as long as both use the ``null@l2tp`` method.
@ -107,7 +107,7 @@ However, the important changes to the fastd config on your Supernode are:
Note that in ``multitap`` mode, which is required when using L2TP offloading,
fastd will create one interface per peer on the supernode's. This allows
offloading the L2TP forwarding into the kernel space. But this also means added
complexity with regards to handling those interfaces.
copmlexity with regards to handling those interfaces.
There are two main options on how you can handle this:
@ -191,16 +191,6 @@ negative effects. Only when a previously connected node reboots the effect
comes into play, as the gateway still knows about the old timestamp of the gluon
node.
gluon-mesh-vpn-key-translate
""""""""""""""""""""""""""""
Many communities already possess a collection of active fastd-keys when they
plan migrating their community to WireGuard.
These public keys known on the server-side can be derived into their WireGuard
equivalent using `gluon-mesh-vpn-key-translate <https://github.com/AiyionPrime/gluon-mesh-vpn-key-translate>`__.
The routers do the necessary reencoding of the private key seamlessly
when updating firmware from fastd to the WireGuard variant.
Gateway / Supernode Configuration
"""""""""""""""""""""""""""""""""

View File

@ -25,7 +25,7 @@ Several Freifunk communities in Germany use Gluon as the foundation of their Fre
features/wlan-configuration
features/private-wlan
features/wired-mesh
features/dns-cache
features/dns-forwarder
features/monitoring
features/multidomain
features/authorized-keys

View File

@ -5,9 +5,6 @@ Release Notes
:caption: Gluon 2022.1
:maxdepth: 2
v2022.1.4
v2022.1.3
v2022.1.2
v2022.1.1
v2022.1

View File

@ -88,8 +88,6 @@ New features
* Add support for making nodes a DNS cache for clients
(`#1000 <https://github.com/freifunk-gluon/gluon/pull/1000>`_)
See also: :doc:`../features/dns-cache`
* Add L2TP via tunneldigger as an alternative VPN system
(`#978 <https://github.com/freifunk-gluon/gluon/pull/978>`_)

View File

@ -28,7 +28,7 @@ Bugfixes
As the path to both config mode and status page were changed between versions
users could be affected by a redirect to a no more valid URL.
* batman-adv has received two bugfixes, which were `backported <https://github.com/openwrt/routing/commit/7bf62cc8b556b5046f9bbd37687376fe9ea175bb>`_ from v2018.4
* batman-adv has received two bugfixes, which were `backported <https://github.com/openwrt-routing/packages/commit/7bf62cc8b556b5046f9bbd37687376fe9ea175bb>`_ from v2018.4
Other changes
~~~~~~~~~~~~~

View File

@ -127,10 +127,10 @@ Renamed targets
Status Page
~~~~~~~~~~~
- Gateway nexthop information has been added to the status page when batman-adv
- Gateway nexthop information has been added to the statuspage when batman-adv
is used. This includes its MAC address and prettyname as well as the interface
name towards the selected gateway.
- The site name has been added to the status page. If the node is in a multidomain
- The site name has been added to the statuspage. If the node is in a multidomain
setup it will also show the domain name.
DECT button to enter config mode

View File

@ -34,7 +34,7 @@ Bugfixes
- The Tunneldigger VPN provider was not registered with the Gluon VPN backend, resulting in broken Tunneldigger configurations.
- Disabling Radio interfaces in v2021.1 could lead to null pointer dereferences in the respondd airtime module, as the survey returns no data in this case.
- Disabling Radio interfaces in v2021.1 could lead to nullpointer dereferences in the respondd airtime module, as the survey returns no data in this case.
Known issues

View File

@ -1,37 +0,0 @@
Gluon 2022.1.2
==============
Bugfixes
--------
* Various build-errors which sporadically occur when building with a large thread-count have been fixed
* Android devices do not lose their IPv6 connectivity after extended idle-time
* The 802.11s mesh network is now using 802.11ax HE-modes when supported by hardware
Known issues
------------
* Upgrading EdgeRouter-X from versions before v2020.1.x may lead to a soft-bricked state due to bad blocks on the NAND flash which the NAND driver before this release does not handle well.
(`#1937 <https://github.com/freifunk-gluon/gluon/issues/1937>`_)
* The integration of the BATMAN_V routing algorithm is incomplete.
- Mesh neighbors don't appear on the status page. (`#1726 <https://github.com/freifunk-gluon/gluon/issues/1726>`_)
Many tools have the BATMAN_IV metric hardcoded, these need to be updated to account for the new throughput
metric.
- Throughput values are not correctly acquired for different interface types.
(`#1728 <https://github.com/freifunk-gluon/gluon/issues/1728>`_)
This affects virtual interface types like bridges and VXLAN.
* Default TX power on many Ubiquiti devices is too high, correct offsets are unknown
(`#94 <https://github.com/freifunk-gluon/gluon/issues/94>`_)
Reducing the TX power in the Advanced Settings is recommended.
* In configurations without VXLAN, the MAC address of the WAN interface is modified even when Mesh-on-WAN is disabled
(`#496 <https://github.com/freifunk-gluon/gluon/issues/496>`_)
This may lead to issues in environments where a fixed MAC address is expected (like VMware when promiscuous mode is disallowed).

View File

@ -1,40 +0,0 @@
Gluon 2022.1.3
==============
Bugfixes
--------
* Ipq40xx Wave2 devices temporarily use non-ct firmware again to work around 802.11s unicast package loss in ath10k-ct
(`#2692 <https://github.com/freifunk-gluon/gluon/issues/2692>`_)
* Modify kernel builds slightly to work around a boot hang on various devices based on the QCA9563 SoC - especially the Unifi AC-* devices
(`#2784 <https://github.com/freifunk-gluon/gluon/issues/2784>`_)
* Work around an issue with wifi setup timing by waiting a bit while device initialisation is ongoing
(`#2779 <https://github.com/freifunk-gluon/gluon/issues/2779>`_)
Known issues
------------
* Upgrading EdgeRouter-X from versions before v2020.1.x may lead to a soft-bricked state due to bad blocks on the NAND flash which the NAND driver before this release does not handle well.
(`#1937 <https://github.com/freifunk-gluon/gluon/issues/1937>`_)
* The integration of the BATMAN_V routing algorithm is incomplete.
- Mesh neighbors don't appear on the status page. (`#1726 <https://github.com/freifunk-gluon/gluon/issues/1726>`_)
Many tools have the BATMAN_IV metric hardcoded, these need to be updated to account for the new throughput
metric.
- Throughput values are not correctly acquired for different interface types.
(`#1728 <https://github.com/freifunk-gluon/gluon/issues/1728>`_)
This affects virtual interface types like bridges and VXLAN.
* Default TX power on many Ubiquiti devices is too high, correct offsets are unknown
(`#94 <https://github.com/freifunk-gluon/gluon/issues/94>`_)
Reducing the TX power in the Advanced Settings is recommended.
* In configurations without VXLAN, the MAC address of the WAN interface is modified even when Mesh-on-WAN is disabled
(`#496 <https://github.com/freifunk-gluon/gluon/issues/496>`_)
This may lead to issues in environments where a fixed MAC address is expected (like VMware when promiscuous mode is disallowed).

View File

@ -1,136 +0,0 @@
Gluon 2022.1.4
==============
Added hardware support
----------------------
ath79-generic
~~~~~~~~~~~~~
- LibreRouter
- LibreRouter (v1)
- Teltonika
- RUT230 (v1)
ath79-nand
~~~~~~~~~~
- Aerohive
- HiveAP 121
- NETGEAR
- WNDR4300 (v1)
lantiq-xrx200
~~~~~~~~~~~~~
- Arcadyan
- o2 Box 6431
ramips-mt7621
~~~~~~~~~~~~~
- Cudy
- X6 (v1, v2)
- D-Link
- DAP-X1860 (A1)
- GL.iNet
- GL-MT1300
- Mercusys
- MR70X (v1)
- Xiaomi
- Mi Router 3G
ramips-mt76x8
~~~~~~~~~~~~~
- TP-Link
- RE200 (v3)
realtek-rtl838x
~~~~~~~~~~~~~~~
- D-Link
- DGS-1210-10P
ipq40xx-generic
~~~~~~~~~~~~~~~
- AVM
- FRITZBox 7520
ipq40xx-mikrotik
~~~~~~~~~~~~~~~~
- Mikrotik
- hAP ac2
Bugfixes
--------
* Enterasys WS-AP3705i now uses the correct image-name for use with the autoupdater
(`#2819 <https://github.com/freifunk-gluon/gluon/issues/2819>`_)
* Reduce memory Usage for ath10k on ZyXEL WRE6606 devices
(`#2842 <https://github.com/freifunk-gluon/gluon/issues/2842>`_)
* Replace the Workaround for failed boots on ath79 with a proper fix.
(`#2784 <https://github.com/freifunk-gluon/gluon/issues/2784#issuecomment-1452126501>`_)
* AVM FRITZ!Box 7360 v2 flashed with the incorrect image for v1 will automatically update to the correct image.
* Revert OOM inducing switch of ath79 Wave2 firmware back to -ct
(`#2879 <https://github.com/freifunk-gluon/gluon/pull/2879>`_)
Known issues
------------
* Upgrading EdgeRouter-X from versions before v2020.1.x may lead to a soft-bricked state due to bad blocks on the NAND flash which the NAND driver before this release does not handle well.
(`#1937 <https://github.com/freifunk-gluon/gluon/issues/1937>`_)
* The integration of the BATMAN_V routing algorithm is incomplete.
- Mesh neighbors don't appear on the status page. (`#1726 <https://github.com/freifunk-gluon/gluon/issues/1726>`_)
Many tools have the BATMAN_IV metric hardcoded, these need to be updated to account for the new throughput
metric.
- Throughput values are not correctly acquired for different interface types.
(`#1728 <https://github.com/freifunk-gluon/gluon/issues/1728>`_)
This affects virtual interface types like bridges and VXLAN.
* Default TX power on many Ubiquiti devices is too high, correct offsets are unknown
(`#94 <https://github.com/freifunk-gluon/gluon/issues/94>`_)
Reducing the TX power in the Advanced Settings is recommended.
* In configurations without VXLAN, the MAC address of the WAN interface is modified even when Mesh-on-WAN is disabled
(`#496 <https://github.com/freifunk-gluon/gluon/issues/496>`_)
This may lead to issues in environments where a fixed MAC address is expected (like VMware when promiscuous mode is disallowed).

View File

@ -1 +1 @@
sphinx-rtd-theme==1.2.0
sphinx-rtd-theme==1.1.1

View File

@ -25,20 +25,18 @@ An example configuration can be found in the Gluon repository at *docs/site-exam
Dependencies
------------
To build Gluon, several packages need to be installed on the system. On a
freshly installed Debian Bullseye system the following packages are required:
freshly installed Debian Stretch system the following packages are required:
* `git` (to get Gluon and other dependencies)
* `subversion`
* `python3`
* `build-essential`
* `ecdsautils` (to sign firmware, see `contrib/sign.sh`)
* `gawk`
* `unzip`
* `libncurses-dev` (actually `libncurses5-dev`)
* `libz-dev` (actually `zlib1g-dev`)
* `libssl-dev`
* `libelf-dev` (to build x86-64)
* `wget`
* `rsync`
* `time` (built-in `time` doesn't work)
* `qemu-utils`

View File

@ -15,7 +15,7 @@ Consider these key values:
- and configure `MSS clamping`_ accordingly,
- and announce your link MTU via Router Advertisements and DHCP
.. _MSS clamping: https://tldp.org/HOWTO/Adv-Routing-HOWTO/lartc.cookbook.mtu-mss.html
.. _MSS clamping: https://www.tldp.org/HOWTO/Adv-Routing-HOWTO/lartc.cookbook.mtu-mss.html
- Encapsulation: Account for the overhead created by the configured mesh protocol
encapsulating the payload, which is up to 32 Byte (14 Byte Ethernet + 18 Byte

View File

@ -448,8 +448,13 @@ interfaces \: optional
The ``client`` role requires exclusive control over an interface. When
the ``client`` role is assigned to an interface at the same time as other
roles (like ``'client', 'mesh'`` in the above example), the other roles take
precedence (enabling ``mesh``, but not ``client`` in the example). In that
case, the ``client`` role is removed from the config of the interface.
precedence (enabling ``mesh``, but not ``client`` in the example).
Such a default configuration still fulfills a purpose (and is in fact the
recommended way to enable "Mesh-on-LAN" by default): The "LAN interface
meshing" checkbox in the advanced network settings will only add or remove
the ``mesh`` role, so the ``client`` role must already be in the configuration
to make the LAN port a regular client interface when the checkbox is disabled.
All interface settings are optional. If unset, the following defaults are
used:

View File

@ -57,10 +57,6 @@ ath79-generic
- JT-OR750i
* LibreRouter
- LibreRouter v1 [#missing_radios]_
* Netgear
- WNDR3700 (v1, v2)
@ -143,15 +139,10 @@ ath79-generic
ath79-nand
----------
* Aerohive
- HiveAP 121
* GL.iNet
- GL-AR300M
- GL-AR750S
- GL-XE300
* Netgear
@ -247,10 +238,6 @@ ipq806x-generic
lantiq-xrx200
-------------
* Arcadyan
- VGV7510KW22 (o2 Box 6431)
* AVM
- FRITZ!Box 7360 (v1, v2) [#avmflash]_ [#lan_as_wan]_
@ -258,10 +245,6 @@ lantiq-xrx200
- FRITZ!Box 7362 SL [#eva_ramboot]_ [#lan_as_wan]_
- FRITZ!Box 7412 [#eva_ramboot]_
* TP-Link
- TD-W8970 (v1) [#lan_as_wan]_
lantiq-xway
-----------
@ -360,23 +343,12 @@ ramips-mt7621
* Cudy
- WR1300 (v1)
- WR2100
- X6 (v1, v2)
* D-Link
- DAP-X1860 (A1)
- DIR-860L (B1)
* GL.iNet
- GL-MT1300
* Mercusys
- MR70X (v1)
* NETGEAR
- EX6150 (v1)
@ -524,10 +496,6 @@ Footnotes
.. [#lan_as_wan]
All LAN ports on this device are used as WAN.
.. [#missing_radios]
This device contains more than two WLAN radios, which is currently
unsupported by Gluon. Only the first two radios will work.
.. [#modular_ethernet]
These devices follow a modular principle,
which means even basic functionality like ethernet is provided by an expansion-board,

View File

@ -15,7 +15,7 @@ The following targets for x86 images exist:
There are three images:
* `generic` (compressed "raw" image, can be written to a disk directly or booted with qemu)
* `generic` (compressed "raw" image, can written to a disk directly or booted with qemu)
* `virtualbox` (VDI image)
* `vmware` (VMDK image)

View File

@ -2,15 +2,15 @@ GLUON_FEEDS='packages routing gluon'
OPENWRT_REPO=https://github.com/openwrt/openwrt.git
OPENWRT_BRANCH=openwrt-22.03
OPENWRT_COMMIT=e500494771537b9f42f78e4d907bed18b6383606
OPENWRT_COMMIT=4b7f9e42e2bff91d8eec2f195d0bb3bb6f6c43e2
PACKAGES_PACKAGES_REPO=https://github.com/openwrt/packages.git
PACKAGES_PACKAGES_BRANCH=openwrt-22.03
PACKAGES_PACKAGES_COMMIT=55eed1761207f4dfdb8e7d79138f6f65c8849b50
PACKAGES_PACKAGES_COMMIT=4b30c97b57aa158cbb70190d0aab8bb472875b6a
PACKAGES_ROUTING_REPO=https://github.com/openwrt/routing.git
PACKAGES_ROUTING_BRANCH=openwrt-22.03
PACKAGES_ROUTING_COMMIT=1cc7676b9f32acc30ec47f15fcb70380d5d6ef01
PACKAGES_ROUTING_COMMIT=1a87333f268bcf0a11e3a665a357cb0d4ec2d680
PACKAGES_GLUON_REPO=https://github.com/freifunk-gluon/packages.git
PACKAGES_GLUON_COMMIT=29912ec6308fd10b47763b4cf28a638d07f59973
PACKAGES_GLUON_COMMIT=04d2b6ffbb6ee02012f2733b7752d8db0d12eaff

View File

@ -37,7 +37,7 @@ static struct json_object * get_autoupdater(void) {
return ret;
error:
error:
uci_free_context(ctx);
return NULL;
}

File diff suppressed because one or more lines are too long

View File

@ -273,10 +273,6 @@ input[type=checkbox] {
text-align: center;
font-size: 1.7em;
}
&[disabled] + label {
background-color: #dcdcdc !important;
}
}
input[type=radio] {
@ -370,13 +366,6 @@ input[type=password] {
min-width: 20em;
}
.gluon-multi-list-option-descr {
display: inline-block;
vertical-align: top;
margin-top: 0.35em;
margin-left: 0.4em;
}
.gluon-button {
@include button;

View File

@ -66,7 +66,6 @@ need_boolean(in_site({'poe_passthrough'}), false)
if need_table({'dns'}, nil, false) then
need_string_array_match({'dns', 'servers'}, '^[%x:]+$')
need_number({'dns', 'cacheentries'}, false)
end
need_string_array(in_domain({'next_node', 'name'}), false)
@ -77,11 +76,7 @@ need_boolean(in_domain({'mesh', 'vxlan'}), false)
local interfaces_roles = {'client', 'uplink', 'mesh'}
for _, config in ipairs({'wan', 'lan', 'single'}) do
local default_roles = in_site({'interfaces', config, 'default_roles'})
need_array_of(default_roles, interfaces_roles, false)
need_array_elements_exclusive(default_roles, 'client', 'mesh', false)
need_array_elements_exclusive(default_roles, 'client', 'uplink', false)
need_array_of(in_site({'interfaces', config, 'default_roles'}), interfaces_roles, false)
end
obsolete({'mesh_on_wan'}, 'Use interfaces.wan.default_roles.')

View File

@ -1,10 +1,5 @@
#!/bin/sh
# Work around an issue with wifi setup timing by waiting a bit
# while device initialisation is ongoing.
# https://github.com/freifunk-gluon/gluon/issues/2779
sleep 3
gluon-reconfigure
exit 0

View File

@ -55,14 +55,6 @@ local function merge(a, b)
return m
end
local function contains(table, val)
for i=1,#table do
if table[i] == val then
return true
end
end
return false
end
local function path_to_string(path)
if path.is_value then
@ -378,21 +370,6 @@ function M.need_array_of(path, array, required)
return M.need_array(path, function(e) M.need_one_of(e, array) end, required)
end
function M.need_array_elements_exclusive(path, a, b, required)
local val = need_type(path, 'table', required, 'be an array')
if not val then
return nil
end
if contains(val, a) and contains(val, b) then
config_error(conf_src(path),
'expected %s to contain only one of the elements %s and %s, but not both.',
path_to_string(path), format(a), format(b))
end
return val
end
function M.need_chanlist(path, channels, required)
local valid_chanlist = check_chanlist(channels)
return M.need(path, valid_chanlist, required,

View File

@ -87,9 +87,6 @@ local primary_addrs = {
{'ipq806x', 'generic', {
'netgear,r7800',
}},
{'lantiq', 'xrx200', {
'arcadyan,vgv7510kw22-nor',
}},
{'lantiq', 'xway', {
'netgear,dgn3500b',
}},

View File

@ -67,10 +67,6 @@ elseif platform.match('ramips', 'mt7621', {
'netgear,wac104',
}) then
lan_ifname, wan_ifname = 'lan2 lan3 lan4', 'lan1'
elseif platform.match('lantiq', 'xrx200', {
'arcadyan,vgv7510kw22-nor',
}) then
lan_ifname, wan_ifname = 'lan1 lan2 lan3 lan4', 'wan'
elseif platform.match('realtek', 'rtl838x', {
'd-link,dgs-1210-10p',
}) then

View File

@ -63,19 +63,4 @@ for iface in pairs(interfaces) do
end
end
-- Fix invalid role configurations
uci:foreach('gluon', 'interface', function(interface)
local function has_role(role)
return util.contains(interface.role, role)
end
if has_role('client') and (has_role('mesh') or has_role('uplink')) then
-- remove 'client' role
util.remove_from_set(interface.role, 'client')
uci:set('gluon', interface['.name'], 'role', interface.role)
end
end)
uci:save('gluon')

View File

@ -4,19 +4,6 @@ local uci = require('simple-uci').cursor()
local sysconfig = require 'gluon.sysconfig'
local util = require 'gluon.util'
local json = require 'jsonc'
local function get_network_mac(name)
local board_data = json.load('/etc/board.json')
local network_data = (board_data or {}).network
if network_data == nil then
return nil
end
local ifdata = network_data[name] or {}
return ifdata.macaddr
end
local wan = uci:get_all('network_gluon-old', 'wan') or {}
local wan6 = uci:get_all('network_gluon-old', 'wan6') or {}
@ -40,7 +27,6 @@ uci:section('network', 'interface', 'wan', {
ipaddr = wan.ipaddr,
netmask = wan.netmask,
gateway = wan.gateway,
macaddr = get_network_mac('wan'),
ifname = util.get_role_interfaces(uci, 'uplink'),
type = 'bridge',
igmp_snooping = true,

View File

@ -53,12 +53,16 @@ local function is_outdoor()
end
local function get_channel(radio, config)
if radio.band == '5g' and is_outdoor() then
local channel
if wireless.preserve_channels(uci) then
-- preserved channel always wins
channel = radio.channel
elseif radio.band == '5g' and is_outdoor() then
-- actual channel will be picked and probed from chanlist
return 'auto'
channel = 'auto'
end
return config.channel()
return channel or config.channel()
end
local function get_htmode(radio)
@ -175,20 +179,6 @@ local function configure_mesh_wireless(radio, index, config, disabled)
)
end
local function set_channels(radio, radio_name, config)
if wireless.preserve_channels(uci) then
return
end
local channel = get_channel(radio, config)
uci:set('wireless', radio_name, 'channel', channel)
local chanlist
if radio.band == '5g' and is_outdoor() then
chanlist = config.outdoor_chanlist()
end
uci:set('wireless', radio_name, 'channels', chanlist)
end
wireless.foreach_radio(uci, function(radio, index, config)
local radio_name = radio['.name']
@ -204,13 +194,13 @@ wireless.foreach_radio(uci, function(radio, index, config)
return
end
local channel = get_channel(radio, config)
local htmode = get_htmode(radio)
local beacon_interval = config.beacon_interval()
uci:delete('wireless', radio_name, 'disabled')
set_channels(radio, radio_name, config)
uci:set('wireless', radio_name, 'channel', channel)
uci:set('wireless', radio_name, 'htmode', htmode)
uci:set('wireless', radio_name, 'country', site.regdom())
@ -228,10 +218,13 @@ wireless.foreach_radio(uci, function(radio, index, config)
uci:set_list('wireless', radio_name, 'hostapd_options', hostapd_options)
if is_outdoor() then
uci:set('wireless', radio_name, 'channels', config.outdoor_chanlist())
-- enforce outdoor channels by filtering the regdom for outdoor channels
uci:set('wireless', radio_name, 'country3', '0x4f')
configure_mesh_wireless(radio, index, config, true)
else
uci:delete('wireless', radio_name, 'channels')
uci:delete('wireless', radio_name, 'country3')
configure_mesh_wireless(radio, index, config)
end

View File

@ -43,10 +43,6 @@ local function setup_ncm_qmi(devpath, control_type, delay)
end
if platform.match('ath79', 'nand', {
'glinet,gl-xe300',
}) then
setup_ncm_qmi('/dev/cdc-wdm0', 'qmi', 15)
elseif platform.match('ath79', 'nand', {
'zte,mf281',
}) then
setup_ncm_qmi('/dev/ttyACM0', 'ncm', 15)

View File

@ -12,7 +12,7 @@ uci:set('dhcp', dnsmasq, 'localise_queries', true)
uci:set('dhcp', dnsmasq, 'localservice', false)
uci:set('dhcp', dnsmasq, 'server', dns.servers)
uci:set('dhcp', dnsmasq, 'cachesize', dns.cacheentries)
uci:delete('dhcp', dnsmasq, 'cachesize')
uci:delete('firewall', 'client_dns')
if dns.servers then

View File

@ -26,7 +26,6 @@ local values = {
.. ' / ' .. util.trim(util.readfile('/lib/gluon/site-version')) },
{ 'Firmware release', util.trim(util.readfile('/lib/gluon/release')) },
{ 'Site', site.site_name() },
{ 'Domain', uci:get('gluon', 'core', 'domain') or 'n/a' },
{ 'Public VPN key', pubkey or 'n/a' },
}

View File

@ -25,7 +25,6 @@ end
function M.is_outdoor_device()
if M.match('ath79', 'generic', {
'devolo,dvl1750x',
'librerouter,librerouter-v1',
'plasmacloud,pa300',
'plasmacloud,pa300e',
'tplink,cpe210-v1',
@ -74,7 +73,6 @@ end
function M.is_cellular_device()
if M.match('ath79', 'nand', {
'zte,mf281',
'glinet,gl-xe300',
}) then
return true
elseif M.match('ipq40xx', 'generic', {

View File

@ -10,104 +10,104 @@
static struct json_object * gluon_site_udata(lua_State *L, int narg) {
return *(struct json_object **)luaL_checkudata(L, narg, UDATA);
return *(struct json_object **)luaL_checkudata(L, narg, UDATA);
}
static void gluon_site_push_none(lua_State *L) {
lua_pushlightuserdata(L, gluon_site_push_none);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_pushlightuserdata(L, gluon_site_push_none);
lua_rawget(L, LUA_REGISTRYINDEX);
}
static void gluon_site_do_wrap(lua_State *L, struct json_object *obj) {
struct json_object **objp = lua_newuserdata(L, sizeof(struct json_object *));
*objp = json_object_get(obj);
luaL_getmetatable(L, UDATA);
lua_setmetatable(L, -2);
struct json_object **objp = lua_newuserdata(L, sizeof(struct json_object *));
*objp = json_object_get(obj);
luaL_getmetatable(L, UDATA);
lua_setmetatable(L, -2);
}
static void gluon_site_wrap(lua_State *L, struct json_object *obj) {
if (obj)
gluon_site_do_wrap(L, obj);
else
gluon_site_push_none(L);
if (obj)
gluon_site_do_wrap(L, obj);
else
gluon_site_push_none(L);
}
static int gluon_site_index(lua_State *L) {
struct json_object *obj = gluon_site_udata(L, 1);
const char *key;
lua_Number lua_index;
size_t index;
struct json_object *v = NULL;
struct json_object *obj = gluon_site_udata(L, 1);
const char *key;
lua_Number lua_index;
size_t index;
struct json_object *v = NULL;
switch (json_object_get_type(obj)) {
switch (json_object_get_type(obj)) {
case json_type_object:
key = lua_tostring(L, 2);
if (key)
json_object_object_get_ex(obj, key, &v);
break;
key = lua_tostring(L, 2);
if (key)
json_object_object_get_ex(obj, key, &v);
break;
case json_type_array:
index = lua_index = lua_tonumber(L, 2);
if (lua_index == (lua_Number)index && index >= 1)
v = json_object_array_get_idx(obj, index-1);
break;
index = lua_index = lua_tonumber(L, 2);
if (lua_index == (lua_Number)index && index >= 1)
v = json_object_array_get_idx(obj, index-1);
break;
case json_type_string:
case json_type_null:
break;
case json_type_null:
break;
case json_type_boolean:
case json_type_int:
case json_type_double:
luaL_error(L, "attempt to index a number or boolean value");
__builtin_unreachable();
}
luaL_error(L, "attempt to index a number or boolean value");
__builtin_unreachable();
}
gluon_site_wrap(L, v);
return 1;
gluon_site_wrap(L, v);
return 1;
}
static int gluon_site_call(lua_State *L) {
struct json_object *obj = gluon_site_udata(L, 1);
struct json_object *obj = gluon_site_udata(L, 1);
if (obj) {
lua_jsonc_push_json(L, obj);
} else {
if (lua_isnone(L, 2))
lua_pushnil(L);
else
lua_pushvalue(L, 2);
}
if (obj) {
lua_jsonc_push_json(L, obj);
} else {
if (lua_isnone(L, 2))
lua_pushnil(L);
else
lua_pushvalue(L, 2);
}
return 1;
return 1;
}
static int gluon_site_gc(lua_State *L) {
json_object_put(gluon_site_udata(L, 1));
return 0;
json_object_put(gluon_site_udata(L, 1));
return 0;
}
static const luaL_reg R[] = {
{ "__index", gluon_site_index },
{ "__call", gluon_site_call },
{ "__gc", gluon_site_gc },
{}
{ "__index", gluon_site_index },
{ "__call", gluon_site_call },
{ "__gc", gluon_site_gc },
{}
};
int luaopen_gluon_site(lua_State *L) {
luaL_newmetatable(L, UDATA);
luaL_register(L, NULL, R);
lua_pop(L, 1);
luaL_newmetatable(L, UDATA);
luaL_register(L, NULL, R);
lua_pop(L, 1);
/* Create "none" object */
lua_pushlightuserdata(L, gluon_site_push_none);
gluon_site_do_wrap(L, NULL);
lua_rawset(L, LUA_REGISTRYINDEX);
/* Create "none" object */
lua_pushlightuserdata(L, gluon_site_push_none);
gluon_site_do_wrap(L, NULL);
lua_rawset(L, LUA_REGISTRYINDEX);
struct json_object *site = gluonutil_load_site_config();
gluon_site_wrap(L, site);
json_object_put(site);
struct json_object *site = gluonutil_load_site_config();
gluon_site_wrap(L, site);
json_object_put(site);
return 1;
}

View File

@ -10,7 +10,7 @@
#include "lookup3.h"
static struct addr_list *addr_node_alloc(void *addr,
struct addr_store *store)
struct addr_store *store)
{
struct addr_list *node;
size_t addr_len = store->addr_len;
@ -27,8 +27,8 @@ static struct addr_list *addr_node_alloc(void *addr,
}
static struct addr_list *addr_list_search(void *addr,
size_t addr_len,
struct addr_list *list)
size_t addr_len,
struct addr_list *list)
{
struct addr_list *node = list;
struct addr_list *ret = NULL;
@ -73,7 +73,7 @@ int addr_store_add(void *addr, struct addr_store *store)
{
struct addr_list **bucket = addr_store_get_bucket(addr, store);
struct addr_list *node = addr_list_search(addr, store->addr_len,
*bucket);
*bucket);
if (node) {
node->tic = clock;
@ -91,9 +91,9 @@ int addr_store_add(void *addr, struct addr_store *store)
}
int addr_store_init(size_t addr_len,
void (*destructor)(struct addr_list *),
char *(*ntoa)(void *),
struct addr_store *store)
void (*destructor)(struct addr_list *),
char *(*ntoa)(void *),
struct addr_store *store)
{
int i;

View File

@ -20,9 +20,9 @@ struct addr_store {
};
int addr_store_init(size_t addr_len,
void (*destructor)(struct addr_list *),
char *(*ntoa)(void *),
struct addr_store *store);
void (*destructor)(struct addr_list *),
char *(*ntoa)(void *),
struct addr_store *store);
int addr_store_add(void *addr, struct addr_store *store);
void addr_store_cleanup(struct addr_store *store);

View File

@ -39,8 +39,8 @@ static void ebt_ip_call(char *mod, struct in_addr ip)
int ret;
snprintf(str, sizeof(str),
EBTABLES " %s ARP_LIMIT_DATCHECK -p ARP --arp-ip-dst %s -j mark --mark-or 0x2 --mark-target RETURN",
mod, inet_ntoa(ip));
EBTABLES " %s ARP_LIMIT_DATCHECK -p ARP --arp-ip-dst %s -j mark --mark-or 0x2 --mark-target RETURN",
mod, inet_ntoa(ip));
ret = system(str);
if (ret)
@ -62,8 +62,8 @@ static void ebt_mac_limit_call(char *mod, struct mac_addr *mac)
int ret;
snprintf(str, sizeof(str),
EBTABLES " %s ARP_LIMIT_TLCHECK --source %s --limit 6/min --limit-burst 50 -j RETURN",
mod, mac_ntoa(mac));
EBTABLES " %s ARP_LIMIT_TLCHECK --source %s --limit 6/min --limit-burst 50 -j RETURN",
mod, mac_ntoa(mac));
ret = system(str);
if (ret)
@ -78,8 +78,8 @@ static void ebt_mac_ret_call(char *mod, struct mac_addr *mac, int add)
int ret;
snprintf(str, sizeof(str),
EBTABLES " %s ARP_LIMIT_TLCHECK %s --source %s -j DROP",
mod, add ? "2" : "", mac_ntoa(mac));
EBTABLES " %s ARP_LIMIT_TLCHECK %s --source %s -j DROP",
mod, add ? "2" : "", mac_ntoa(mac));
ret = system(str);
if (ret)

File diff suppressed because it is too large Load Diff

View File

@ -21,8 +21,8 @@ int mac_aton(const char *cp, struct mac_addr *mac)
memset(&m, 0, sizeof(m));
ret = sscanf(cp, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
&m.storage[0], &m.storage[1], &m.storage[2],
&m.storage[3], &m.storage[4], &m.storage[5]);
&m.storage[0], &m.storage[1], &m.storage[2],
&m.storage[3], &m.storage[4], &m.storage[5]);
if (ret != ETH_ALEN)
return 0;
@ -36,8 +36,8 @@ char *mac_ntoa(struct mac_addr *mac)
unsigned char *m = mac->storage;
snprintf(mntoa_buf, sizeof(mntoa_buf),
"%02x:%02x:%02x:%02x:%02x:%02x",
m[0], m[1], m[2], m[3], m[4], m[5]);
"%02x:%02x:%02x:%02x:%02x:%02x",
m[0], m[1], m[2], m[3], m[4], m[5]);
return mntoa_buf;
}

View File

@ -68,7 +68,7 @@ static int parse_orig_list_netlink_cb(struct nl_msg *msg, void *arg)
char mac1[18];
opts = batadv_container_of(query_opts, struct neigh_netlink_opts,
query_opts);
query_opts);
if (!genlmsg_valid_hdr(nlh, 0))
return NL_OK;
@ -79,11 +79,11 @@ static int parse_orig_list_netlink_cb(struct nl_msg *msg, void *arg)
return NL_OK;
if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0),
genlmsg_len(ghdr), batadv_genl_policy))
genlmsg_len(ghdr), batadv_genl_policy))
return NL_OK;
if (batadv_genl_missing_attrs(attrs, parse_orig_list_mandatory,
BATADV_ARRAY_SIZE(parse_orig_list_mandatory)))
BATADV_ARRAY_SIZE(parse_orig_list_mandatory)))
return NL_OK;
orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]);

View File

@ -106,7 +106,7 @@ static bool interface_file_exists(const char *ifname, const char *name) {
}
static void mesh_add_subif(const char *ifname, struct json_object *wireless,
struct json_object *tunnel, struct json_object *other) {
struct json_object *tunnel, struct json_object *other) {
struct json_object *address = gluonutil_wrap_and_free_string(gluonutil_get_interface_address(ifname));
/* In case of VLAN and bridge interfaces, we want the lower interface
@ -144,7 +144,7 @@ static struct json_object * get_mesh_subifs(const char *ifname) {
size_t i;
for (i = 0; i < lower.gl_pathc; i++) {
mesh_add_subif(lower.gl_pathv[i] + pattern_len - 1,
wireless, tunnel, other);
wireless, tunnel, other);
}
globfree(&lower);

View File

@ -57,7 +57,7 @@ static int parse_gw_list_netlink_cb(struct nl_msg *msg, void *arg)
char addr[18];
opts = batadv_container_of(query_opts, struct gw_netlink_opts,
query_opts);
query_opts);
if (!genlmsg_valid_hdr(nlh, 0))
return NL_OK;
@ -68,11 +68,11 @@ static int parse_gw_list_netlink_cb(struct nl_msg *msg, void *arg)
return NL_OK;
if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0),
genlmsg_len(ghdr), batadv_genl_policy))
genlmsg_len(ghdr), batadv_genl_policy))
return NL_OK;
if (batadv_genl_missing_attrs(attrs, gateways_mandatory,
BATADV_ARRAY_SIZE(gateways_mandatory)))
BATADV_ARRAY_SIZE(gateways_mandatory)))
return NL_OK;
if (!attrs[BATADV_ATTR_FLAG_BEST])
@ -105,8 +105,8 @@ static void add_gateway(struct json_object *obj) {
};
batadv_genl_query("bat0", BATADV_CMD_GET_GATEWAYS,
parse_gw_list_netlink_cb, NLM_F_DUMP,
&opts.query_opts);
parse_gw_list_netlink_cb, NLM_F_DUMP,
&opts.query_opts);
}
static inline bool ethtool_ioctl(int fd, struct ifreq *ifr, void *data) {
@ -214,7 +214,7 @@ static struct json_object * get_traffic(void) {
json_object_object_add(ret, "mgmt_rx", mgmt_rx);
json_object_object_add(ret, "mgmt_tx", mgmt_tx);
out:
out:
free(stats);
free(strings);
close(fd);
@ -241,7 +241,7 @@ static int parse_clients_list_netlink_cb(struct nl_msg *msg, void *arg)
uint32_t flags, lastseen;
opts = batadv_container_of(query_opts, struct clients_netlink_opts,
query_opts);
query_opts);
if (!genlmsg_valid_hdr(nlh, 0))
return NL_OK;
@ -252,11 +252,11 @@ static int parse_clients_list_netlink_cb(struct nl_msg *msg, void *arg)
return NL_OK;
if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0),
genlmsg_len(ghdr), batadv_genl_policy))
genlmsg_len(ghdr), batadv_genl_policy))
return NL_OK;
if (batadv_genl_missing_attrs(attrs, clients_mandatory,
BATADV_ARRAY_SIZE(clients_mandatory)))
BATADV_ARRAY_SIZE(clients_mandatory)))
return NL_OK;
flags = nla_get_u32(attrs[BATADV_ATTR_TT_FLAGS]);
@ -282,8 +282,8 @@ static struct json_object * get_clients(void) {
};
batadv_genl_query("bat0", BATADV_CMD_GET_TRANSTABLE_LOCAL,
parse_clients_list_netlink_cb, NLM_F_DUMP,
&opts.query_opts);
parse_clients_list_netlink_cb, NLM_F_DUMP,
&opts.query_opts);
struct json_object *ret = json_object_new_object();

View File

@ -1,19 +0,0 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=gluon-mesh-olsrd
PKG_VERSION=1
include ../gluon.mk
define Package/gluon-mesh-olsrd
TITLE:=olsrd mesh
DEPENDS:= \
+gluon-core \
@IPV6 \
+oonf-olsrd2 \
+firewall \
+gluon-mesh-layer3-common
PROVIDES:=gluon-mesh-provider
endef
$(eval $(call BuildPackageGluon,gluon-mesh-olsrd))

View File

@ -1 +0,0 @@
need_table({'mesh', 'olsrd', 'v2', 'config'}, nil, false)

View File

@ -1,10 +0,0 @@
#!/bin/sh
reload_running() {
if [ -x /etc/init.d/"$1" ] && /etc/init.d/"$1" enabled && /etc/init.d/"$1" running; then
echo "(post-setup.d:$IFNAME) Reloading $1..."
/etc/init.d/"$1" reload
fi
}
reload_running olsrd2

View File

@ -1,10 +0,0 @@
#!/bin/sh
reload_running() {
if [ -x /etc/init.d/"$1" ] && /etc/init.d/"$1" enabled && /etc/init.d/"$1" running; then
echo "(teardown.d:$IFNAME) Reloading $1..."
/etc/init.d/"$1" reload
fi
}
reload_running olsrd2

View File

@ -1,7 +0,0 @@
#!/bin/sh
. /lib/gluon/autoupdater/lib.sh
start_enabled olsrd2
wifi up

View File

@ -1,7 +0,0 @@
#!/bin/sh
. /lib/gluon/autoupdater/lib.sh
stop olsrd2
wifi down

View File

@ -1,163 +0,0 @@
#!/usr/bin/lua
local uci = require('simple-uci').cursor()
local site = require 'gluon.site'
local util = require 'gluon.util'
local wireless = require 'gluon.wireless'
local mesh_interfaces = util.get_role_interfaces(uci, 'mesh')
local uplink_interfaces = util.get_role_interfaces(uci, 'uplink')
local client_interfaces = util.get_role_interfaces(uci, 'client')
local mesh_interfaces_uplink = {}
local mesh_interfaces_client = {}
local mesh_interfaces_other = {}
for _, iface in ipairs(mesh_interfaces) do
if util.contains(uplink_interfaces, iface) then
table.insert(mesh_interfaces_uplink, iface)
elseif util.contains(client_interfaces, iface) then
table.insert(mesh_interfaces_client, iface)
else
table.insert(mesh_interfaces_other, iface)
end
end
local intf = {
wired_mesh = {},
vpn_mesh = {},
radio_mesh = {},
}
intf.all_intfs = {}
for _, l in ipairs({ intf.wired_mesh, intf.vpn_mesh, intf.radio_mesh }) do
for _, n in ipairs(l) do
table.insert(intf.all_intfs, n)
end
end
-- get all mesh radios and mesh lans and then add them to olsrd
wireless.foreach_radio(uci, function(radio, _, _)
local radio_name = radio['.name']
table.insert(intf.radio_mesh, 'mesh_' .. radio_name)
end)
if pcall(function() require 'gluon.mesh-vpn' end) then
local vpn_core = require 'gluon.mesh-vpn'
if vpn_core.enabled() then
-- mesh_vpn is a interface that has the right ifname
-- we can't use mesh-vpn (dash instead of underscore) since it's not a uci interface
table.insert(intf.vpn_mesh, 'mesh_vpn')
end
end
table.insert(intf.wired_mesh, 'loopback')
local has_uplink_mesh = false
local has_other_mesh = false
for _,i in pairs(mesh_interfaces) do
if util.contains(uplink_interfaces, i) then
has_uplink_mesh = true
else
has_other_mesh = true
end
end
if has_uplink_mesh then
table.insert(intf.wired_mesh, 'mesh_uplink')
end
if has_other_mesh then
table.insert(intf.wired_mesh, 'mesh_other')
end
uci:delete_all('olsrd2', 'interface')
if site.mesh.olsrd.v2.enable(true) then
os.execute('/etc/init.d/olsrd2 enable')
local addrs = { }
local lan = { }
local cfg = site.mesh.olsrd.v2
local config = uci:get_first("olsrd2", "olsrv2")
-- set global config
local olsr2Config = {
failfast = 'no',
pidfile = '/var/run/olsrd2.pid',
lockfile = '/var/lock/olsrd2'
}
local extraConf = cfg.config()
if extraConf then
for k, _ in pairs(extraConf) do
olsr2Config[k] = extraConf[k]
end
end
uci:delete_all('olsrd2', 'global')
uci:section('olsrd2', 'global', 'global', olsr2Config)
uci:delete_all('olsrd2', 'telnet')
uci:section('olsrd2', 'telnet', 'telnet', {
})
uci:delete_all('olsrd2', 'http')
uci:section('olsrd2', 'http', 'http', {
})
if cfg.lan() then
lan = cfg.lan()
end
table.insert(addrs, '-127.0.0.1/8')
table.insert(addrs, '-::1/128')
table.insert(addrs, 'default_accept')
uci:set("olsrd2", config, "originator", addrs)
uci:set("olsrd2", config, "lan", lan)
if #intf.wired_mesh then
uci:section('olsrd2', 'interface', 'wired_mesh', {
ifname = intf.wired_mesh,
bindto = addrs,
})
end
if #intf.vpn_mesh then
uci:section('olsrd2', 'interface', 'vpn_mesh', {
ifname = intf.vpn_mesh,
bindto = addrs,
})
end
if #intf.radio_mesh then
uci:section('olsrd2', 'interface', 'radio_mesh', {
ifname = intf.radio_mesh,
bindto = addrs,
})
end
uci:section('olsrd2', 'interface', 'loopback', {
ifname = { 'loopback' },
bindto = addrs,
})
uci:section('firewall', 'rule', 'allow_olsr2_mesh', {
src = 'mesh',
dest_port = '269',
proto = 'udp',
target = 'ACCEPT',
})
else
-- site.mesh.olsrd.v2.enable false
os.execute('/etc/init.d/olsrd2 disable')
uci:delete('firewall', 'allow_olsr2_mesh')
end
uci:save('olsrd2')
uci:save('firewall')
uci:save('network')

View File

@ -1,10 +0,0 @@
#!/usr/bin/lua
local uci = require('simple-uci').cursor()
local util = require 'gluon.util'
local networks = uci:get_list('firewall', 'drop', 'network')
util.remove_from_set(networks, 'client')
uci:set_list('firewall', 'drop', 'network', networks)
uci:save('firewall')

View File

@ -219,7 +219,7 @@ static bool get_peer_connection(struct json_object **ret, struct json_object *co
struct json_object *peer, *connection, *established;
if (!json_object_object_get_ex(peers, key, &peer) ||
!json_object_object_get_ex(peer, "connection", &connection))
!json_object_object_get_ex(peer, "connection", &connection))
return false;
if (json_object_object_get_ex(connection, "established", &established)) {
@ -242,7 +242,7 @@ static struct json_object * get_peer_group(struct json_object *config, struct js
struct json_object *config_peers;
if (json_object_object_get_ex(config, "peers", &config_peers) &&
json_object_is_type(config_peers, json_type_object)) {
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) {
@ -320,7 +320,7 @@ static struct json_object * get_mesh_vpn(void) {
ret = get_peer_group(mesh_vpn_fastd, peers);
end:
end:
json_object_put(site);
json_object_put(status);

View File

@ -6,13 +6,7 @@ include ../gluon.mk
define Package/gluon-mesh-vpn-wireguard
TITLE:=Support for connecting meshes via wireguard
DEPENDS:=+gluon-core +libgluonutil +gluon-mesh-vpn-core +wireguard-tools +wgpeerselector +libubox +libubus
endef
define Package/gluon-mesh-vpn-wireguard/install
$(Gluon/Build/Install)
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/gluon-hex-to-b64 $(1)/usr/sbin/
DEPENDS:=+gluon-core +libgluonutil +gluon-mesh-vpn-core +wireguard-tools +wgpeerselector +libubus
endef
$(eval $(call BuildPackageGluon,gluon-mesh-vpn-wireguard))

View File

@ -1,63 +1,18 @@
#!/usr/bin/lua
local uci = require('simple-uci').cursor()
local unistd = require 'posix.unistd'
local util = require('gluon.util')
local site = require 'gluon.site'
local sp = util.subprocess
local wait = require 'posix.sys.wait'
local wg_private_key = uci:get("network_gluon-old", 'wg_mesh', "private_key")
local private_key = uci:get("network_gluon-old", 'wg_mesh', "private_key")
local function valid_fastd_key(fastd_key)
return fastd_key and fastd_key:match(('%x'):rep(64))
if not private_key or not private_key:match("^" .. ("[%a%d+/]"):rep(42) .. "[AEIMQUYcgkosw480]=$") then
private_key = "generate"
end
local function valid_wireguard_key(wireguard_key)
return wireguard_key and wireguard_key:match("^" .. ("[%a%d+/]"):rep(42) .. "[AEIMQUYcgkosw480]=$")
end
local function migrate_from_fastd_secret(fastd_secret)
local options = {
stdin = sp.PIPE,
stdout = sp.PIPE,
}
local pid, pipe = sp.popen('gluon-hex-to-b64', {}, options)
if not pid then
return
end
local inw = pipe.stdin
local out = pipe.stdout
unistd.write(inw, string.format('%s\n', fastd_secret))
unistd.close(inw)
local wpid, status, code = wait.wait(pid)
if wpid and status == 'exited' and code == 0 then
local result = unistd.read(out, 44)
unistd.close(out)
return result
end
end
if not valid_wireguard_key(wg_private_key) then
local fastd_secret = uci:get('fastd', 'mesh_vpn', 'secret')
if valid_fastd_key(fastd_secret) then
wg_private_key = migrate_from_fastd_secret(fastd_secret)
end
end
if not valid_wireguard_key(wg_private_key) then
wg_private_key = "generate"
end
uci:section('network', 'interface', 'wg_mesh', {
proto = 'wireguard',
fwmark = 1,
private_key = wg_private_key,
private_key = private_key,
})
uci:section('network', 'interface', 'mesh_wg_mesh', {

View File

@ -1,9 +1,6 @@
all: respondd.so gluon-hex-to-b64
all: respondd.so
CFLAGS += -Wall -Werror-implicit-function-declaration
gluon-hex-to-b64: gluon-hex-to-b64.c
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -Wall -o $@ $^ $(LDLIBS) -lubox
respondd.so: respondd.c
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -o $@ $^ $(LDLIBS) -lgluonutil -lubus

View File

@ -1,101 +0,0 @@
// SPDX-FileCopyrightText: 2022 Jan-Niklas Burfeind <gluon@aiyionpri.me>
// SPDX-License-Identifier: BSD-2-Clause
// SPDX-FileContributor: read_hex() by Matthias Schiffer <mschiffer@universe-factory.net>
#include <libubox/utils.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
* how many blocks should be encoded at once - can be configured
*/
#define BLOCK_AMOUNT 32
/**
* smallest possible block size to encode in b64 without further contex
* is three bytes - do not change
*/
#define CHUNK_SIZE (3*BLOCK_AMOUNT)
/** print usage info and exit as failed */
static void usage(void) {
fprintf(stderr, "Usage: gluon-hex-to-b64\n");
exit(1);
}
/**
* read a string of hexadecimal characters and return them as bytes
* return false in case any non-hexadecimal characters are provided
* return true on success
*/
static bool read_hex(uint8_t key[CHUNK_SIZE], const char *hexstr) {
if (strspn(hexstr, "0123456789abcdefABCDEF") != strlen(hexstr))
return false;
size_t i;
for (i = 0; i < CHUNK_SIZE; i++)
sscanf(&hexstr[2 * i], "%02hhx", &key[i]);
return true;
}
int main(int argc, char *argv[]) {
if (argc != 1)
usage();
unsigned char hex_input[CHUNK_SIZE * 2 + 1];
uint8_t as_bytes[CHUNK_SIZE];
int byte_count;
int b64_buflen = B64_ENCODE_LEN(CHUNK_SIZE);
int b64_return;
size_t ret;
char str[b64_buflen];
do {
ret = fread(hex_input, 1, sizeof(hex_input) - 1, stdin);
hex_input[ret] = '\0';
/* in case fread did not fill six characters */
if (ret != sizeof(hex_input)-1) {
/* drop newline by replacing it with a null character */
hex_input[strcspn(hex_input, "\n")] = 0;
/*
* count length of resulting string and make sure it's even,
* as bytes are represented using pairs of hex characters
*/
ret = strlen(hex_input);
if (ret % 2 == 1) {
fprintf(stderr, "Error: Incomplete hex representation of a byte.\n");
exit(EXIT_FAILURE);
}
}
byte_count = ret / 2;
b64_buflen = B64_ENCODE_LEN(byte_count);
/* in case read_hex fails due to invalid characters */
if (!read_hex(as_bytes, hex_input)) {
fprintf(stderr, "Error: Invalid hexadecimal input.\n");
exit(EXIT_FAILURE);
}
b64_return = b64_encode(as_bytes, byte_count, str, b64_buflen);
/* trailing '\0' is not counted by b64_encode(), so we subtract one character */
if (b64_buflen - 1 != b64_return) {
fprintf(stderr, "Error: Encoding bytes as b64 failed.\n");
exit(EXIT_FAILURE);
}
printf("%s", str);
/* repeat until a non full block is read */
} while (ret == sizeof(hex_input)-1);
printf("\n");
exit(EXIT_SUCCESS);
}

View File

@ -48,7 +48,7 @@ static struct json_object * stdout_read(const char *cmd, const char *skip, bool
if (oneword) {
for (int i = 0; i < len; i++) {
if (isspace(line[i])) {
line[i] = 0;
line[i] = 0;
}
}
}

View File

@ -61,7 +61,7 @@ void resize_recvbuffer(char **recvbuffer, size_t *recvbuffer_len, size_t recvlen
}
ssize_t recvtimeout(int socket, char **recvbuffer, size_t *recvbuffer_len,
const struct timeval *timeout) {
const struct timeval *timeout) {
struct timeval now, timeout_left;
ssize_t recvlen;
@ -84,8 +84,8 @@ ssize_t recvtimeout(int socket, char **recvbuffer, size_t *recvbuffer_len,
}
int request(const int sock, char **recvbuffer, size_t *recvbuffer_len,
const struct sockaddr_in6 *client_addr, const char *request,
const char *sse, double timeout, unsigned int max_count) {
const struct sockaddr_in6 *client_addr, const char *request,
const char *sse, double timeout, unsigned int max_count) {
ssize_t ret;
unsigned int count = 0;
@ -251,7 +251,7 @@ int main(int argc, char **argv) {
do {
ret = request(sock, &recvbuffer, &recvbuffer_len, &client_addr,
request_string, sse, timeout, max_count);
request_string, sse, timeout, max_count);
} while(loop);
if (sse)

View File

@ -59,10 +59,10 @@
#ifdef DEBUG
#define CHECK(stmt) \
if(!(stmt)) { \
fprintf(stderr, "check failed: " #stmt "\n"); \
goto check_failed; \
}
if(!(stmt)) { \
fprintf(stderr, "check failed: " #stmt "\n"); \
goto check_failed; \
}
#define DEBUG_MSG(msg, ...) fprintf(stderr, msg "\n", ##__VA_ARGS__)
#else
#define CHECK(stmt) if(!(stmt)) goto check_failed;
@ -78,8 +78,8 @@
#define foreach_safe(item, safe, list) \
for ((item) = (list); \
(item) && (((safe) = item->next) || 1); \
(item) = (safe))
(item) && (((safe) = item->next) || 1); \
(item) = (safe))
struct router {
struct router *next;
@ -103,7 +103,7 @@ static struct global {
};
static int fork_execvp_timeout(struct timespec *timeout, const char *file,
const char *const argv[]);
const char *const argv[]);
static void error_message(int status, int errnum, char *message, ...) {
va_list ap;
@ -120,7 +120,7 @@ static void error_message(int status, int errnum, char *message, ...) {
}
static int timespec_diff(struct timespec *tv1, struct timespec *tv2,
struct timespec *tvdiff)
struct timespec *tvdiff)
{
tvdiff->tv_sec = tv1->tv_sec - tv2->tv_sec;
if (tv1->tv_nsec < tv2->tv_nsec) {
@ -219,8 +219,8 @@ static int init_packet_socket(unsigned int ifindex) {
};
struct sock_fprog radv_filter = {
.len = ARRAY_SIZE(radv_filter_code),
.filter = radv_filter_code,
.len = ARRAY_SIZE(radv_filter_code),
.filter = radv_filter_code,
};
int sock = socket(AF_PACKET, SOCK_DGRAM|SOCK_CLOEXEC, htons(ETH_P_IPV6));
@ -382,7 +382,7 @@ static void expire_routers(void) {
}
static int parse_tt_global(struct nl_msg *msg,
void *arg __attribute__((unused)))
void *arg __attribute__((unused)))
{
static const enum batadv_nl_attrs mandatory[] = {
BATADV_ATTR_TT_ADDRESS,
@ -406,7 +406,7 @@ static int parse_tt_global(struct nl_msg *msg,
return NL_OK;
if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0),
genlmsg_len(ghdr), batadv_genl_policy)) {
genlmsg_len(ghdr), batadv_genl_policy)) {
return NL_OK;
}
@ -428,14 +428,14 @@ static int parse_tt_global(struct nl_msg *msg,
return NL_OK;
DEBUG_MSG("Found originator for " F_MAC ", it's " F_MAC,
F_MAC_VAR(router->src), F_MAC_VAR(mac_b));
F_MAC_VAR(router->src), F_MAC_VAR(mac_b));
router->originator = mac_b;
return NL_OK;
}
static int parse_originator(struct nl_msg *msg,
void *arg __attribute__((unused)))
void *arg __attribute__((unused)))
{
static const enum batadv_nl_attrs mandatory[] = {
@ -460,7 +460,7 @@ static int parse_originator(struct nl_msg *msg,
return NL_OK;
if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0),
genlmsg_len(ghdr), batadv_genl_policy)) {
genlmsg_len(ghdr), batadv_genl_policy)) {
return NL_OK;
}
@ -481,7 +481,7 @@ static int parse_originator(struct nl_msg *msg,
return NL_OK;
DEBUG_MSG("Found TQ for router " F_MAC " (originator " F_MAC "), it's %d",
F_MAC_VAR(router->src), F_MAC_VAR(router->originator), tq);
F_MAC_VAR(router->src), F_MAC_VAR(router->originator), tq);
router->tq = tq;
if (router->tq > G.max_tq)
G.max_tq = router->tq;
@ -490,7 +490,7 @@ static int parse_originator(struct nl_msg *msg,
}
static int parse_tt_local(struct nl_msg *msg,
void *arg __attribute__((unused)))
void *arg __attribute__((unused)))
{
static const enum batadv_nl_attrs mandatory[] = {
BATADV_ATTR_TT_ADDRESS,
@ -512,7 +512,7 @@ static int parse_tt_local(struct nl_msg *msg,
return NL_OK;
if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0),
genlmsg_len(ghdr), batadv_genl_policy)) {
genlmsg_len(ghdr), batadv_genl_policy)) {
return NL_OK;
}
@ -528,7 +528,7 @@ static int parse_tt_local(struct nl_msg *msg,
return NL_OK;
DEBUG_MSG("Found router " F_MAC " in transtable_local, assigning TQ %d",
F_MAC_VAR(router->src), LOCAL_TQ);
F_MAC_VAR(router->src), LOCAL_TQ);
router->tq = LOCAL_TQ;
if (router->tq > G.max_tq)
G.max_tq = router->tq;
@ -770,7 +770,7 @@ int main(int argc, char *argv[]) {
clock_gettime(CLOCK_MONOTONIC, &now);
if (G.routers != NULL &&
timespec_diff(&now, &next_update, &diff)) {
timespec_diff(&now, &next_update, &diff)) {
expire_routers();
// all routers could have expired, check again

View File

@ -15,7 +15,7 @@
&(var).ether_addr_octet[2], &(var).ether_addr_octet[3], \
&(var).ether_addr_octet[4], &(var).ether_addr_octet[5]
#define MAC2ETHER(_ether, _mac) memcpy((_ether).ether_addr_octet, \
(_mac), ETH_ALEN)
(_mac), ETH_ALEN)
#define ether_addr_equal(_a, _b) (memcmp((_a).ether_addr_octet, \
(_b).ether_addr_octet, ETH_ALEN) == 0)
(_b).ether_addr_octet, ETH_ALEN) == 0)

View File

@ -34,8 +34,8 @@ static struct json_object * get_wifi_neighbours(const char *ifname) {
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]);
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);
}

View File

@ -112,7 +112,7 @@ static struct json_object * get_stat(void) {
if (!strcmp(label, "cpu")) {
int64_t user, nice, system, idle, iowait, irq, softirq;
if (sscanf(line, "%*s %"SCNd64" %"SCNd64" %"SCNd64" %"SCNd64" %"SCNd64" %"SCNd64" %"SCNd64,
&user, &nice, &system, &idle, &iowait, &irq, &softirq) != 7)
&user, &nice, &system, &idle, &iowait, &irq, &softirq) != 7)
goto invalid_stat_format;
struct json_object *cpu = json_object_new_object();
@ -253,7 +253,7 @@ static void count_stations(size_t *wifi24, size_t *wifi5, size_t *owe24, size_t
count_iface_stations(wifi24, wifi5, ifname);
}
end:
end:
uci_free_context(ctx);
}

View File

@ -9,7 +9,7 @@ include ../gluon.mk
define Package/gluon-setup-mode
TITLE:=Setup mode
DEPENDS:=+gluon-core +gluon-lock-password +ubus +dnsmasq-full
DEPENDS:=+gluon-core +gluon-lock-password +ubus +dnsmasq
endef
define Package/gluon-setup-mode/description

View File

@ -3,26 +3,18 @@
START=96
start() {
local custom_led
/etc/init.d/led start
. /etc/diag.sh
get_status_led 2> /dev/null
if [ -z "$status_led" ]; then
if [ -z $status_led ]; then
status_led="$running"
fi
if [ -z "$status_led" ]; then
if [ -z $status_led ]; then
status_led="$boot"
fi
custom_led="$(lua -e 'print(require("gluon.setup-mode").get_status_led() or "")')"
if [ -z "$status_led" ]; then
status_led="$custom_led"
fi
status_led_set_timer 1000 300
}

View File

@ -1,14 +0,0 @@
local platform = require 'gluon.platform'
local M = {}
function M.get_status_led()
if platform.match('ath79', 'nand', {
'glinet,gl-xe300',
}) then
return "green:wlan"
end
end
return M

View File

@ -10,116 +10,116 @@
#define XSTR(x) STR(x)
struct neigh_netlink_opts {
struct json_object *obj;
struct batadv_nlquery_opts query_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,
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;
char ifname_buf[IF_NAMESIZE], *ifname;
struct neigh_netlink_opts *opts;
char mac1[18];
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;
char ifname_buf[IF_NAMESIZE], *ifname;
struct neigh_netlink_opts *opts;
char mac1[18];
opts = batadv_container_of(query_opts, struct neigh_netlink_opts, query_opts);
opts = batadv_container_of(query_opts, struct neigh_netlink_opts, query_opts);
if (!genlmsg_valid_hdr(nlh, 0))
return NL_OK;
if (!genlmsg_valid_hdr(nlh, 0))
return NL_OK;
ghdr = nlmsg_data(nlh);
ghdr = nlmsg_data(nlh);
if (ghdr->cmd != BATADV_CMD_GET_ORIGINATORS)
return NL_OK;
if (ghdr->cmd != BATADV_CMD_GET_ORIGINATORS)
return NL_OK;
if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0),
genlmsg_len(ghdr), batadv_genl_policy))
return NL_OK;
if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0),
genlmsg_len(ghdr), batadv_genl_policy))
return NL_OK;
if (batadv_genl_missing_attrs(attrs, parse_orig_list_mandatory,
BATADV_ARRAY_SIZE(parse_orig_list_mandatory)))
return NL_OK;
if (batadv_genl_missing_attrs(attrs, parse_orig_list_mandatory,
BATADV_ARRAY_SIZE(parse_orig_list_mandatory)))
return NL_OK;
orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]);
dest = nla_data(attrs[BATADV_ATTR_NEIGH_ADDRESS]);
tq = nla_get_u8(attrs[BATADV_ATTR_TQ]);
hardif = nla_get_u32(attrs[BATADV_ATTR_HARD_IFINDEX]);
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]);
if (memcmp(orig, dest, 6) != 0)
return NL_OK;
if (memcmp(orig, dest, 6) != 0)
return NL_OK;
ifname = if_indextoname(hardif, ifname_buf);
if (!ifname)
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]);
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;
struct json_object *neigh = json_object_new_object();
if (!neigh)
return NL_OK;
json_object_object_add(neigh, "tq", json_object_new_int(tq * 100 / 255));
json_object_object_add(neigh, "ifname", json_object_new_string(ifname));
json_object_object_add(neigh, "best", json_object_new_boolean(attrs[BATADV_ATTR_FLAG_BEST]));
json_object_object_add(neigh, "tq", json_object_new_int(tq * 100 / 255));
json_object_object_add(neigh, "ifname", json_object_new_string(ifname));
json_object_object_add(neigh, "best", json_object_new_boolean(attrs[BATADV_ATTR_FLAG_BEST]));
json_object_object_add(opts->obj, mac1, neigh);
json_object_object_add(opts->obj, mac1, neigh);
return NL_OK;
return NL_OK;
}
static json_object *neighbours(void) {
struct neigh_netlink_opts opts = {
.query_opts = {
.err = 0,
},
};
int ret;
struct neigh_netlink_opts opts = {
.query_opts = {
.err = 0,
},
};
int ret;
opts.obj = json_object_new_object();
if (!opts.obj)
return NULL;
opts.obj = json_object_new_object();
if (!opts.obj)
return NULL;
ret = batadv_genl_query("bat0", BATADV_CMD_GET_ORIGINATORS,
parse_orig_list_netlink_cb, NLM_F_DUMP,
&opts.query_opts);
if (ret < 0) {
json_object_put(opts.obj);
return NULL;
}
ret = batadv_genl_query("bat0", BATADV_CMD_GET_ORIGINATORS,
parse_orig_list_netlink_cb, NLM_F_DUMP,
&opts.query_opts);
if (ret < 0) {
json_object_put(opts.obj);
return NULL;
}
return opts.obj;
return opts.obj;
}
int main(void) {
struct json_object *obj;
struct json_object *obj;
printf("Content-type: text/event-stream\n\n");
fflush(stdout);
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);
}
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;
return 0;
}

View File

@ -67,7 +67,7 @@
iface = lower:sub(pattern:len())
end
return unistd.access('/sys/class/net/' .. iface .. '/phy80211') ~= nil
return unistd.access('/sys/class/net/' .. iface .. '/wireless') ~= nil
end
local uconn = ubus.connect()

View File

@ -12,115 +12,115 @@
#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();
int len;
char buf[IWINFO_BUFSIZE];
struct json_object *stations = json_object_new_object();
if (iw->assoclist(ifname, buf, &len) == -1)
return stations;
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();
// 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));
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];
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]);
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);
}
json_object_object_add(stations, macstr, station);
}
return stations;
return stations;
}
static void badrequest() {
printf("Status: 400 Bad Request\n\n");
exit(1);
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;
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);
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]));
}
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);
globfree(&globbuf);
if (!lowentry) {
char *path = alloca(1 + strlen(NETIF_PREFIX) + strlen(ifname));
sprintf(path, "%s%s", NETIF_PREFIX, ifname);
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;
if(access(path, F_OK) != 0)
return false;
strncpy(hwifname, ifname, IF_NAMESIZE - 1);
return true;
} else {
char buf[PATH_MAX];
ssize_t len;
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 ((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;
}
}
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();
if (argc != 2)
badrequest();
const char *ifname = argv[1];
char hwifname[IF_NAMESIZE] = "";
const char *ifname = argv[1];
char hwifname[IF_NAMESIZE] = "";
if (strlen(ifname) >= IF_NAMESIZE)
badrequest();
if (strlen(ifname) >= IF_NAMESIZE)
badrequest();
if (strcspn(ifname, "/\\[]{}*?") != strlen(ifname))
badrequest();
if (strcspn(ifname, "/\\[]{}*?") != strlen(ifname))
badrequest();
if (!interface_get_lowest(ifname, hwifname))
badrequest();
if (!interface_get_lowest(ifname, hwifname))
badrequest();
const struct iwinfo_ops *iw = iwinfo_backend(hwifname);
const struct iwinfo_ops *iw = iwinfo_backend(hwifname);
if (iw == NULL)
badrequest();
if (iw == NULL)
badrequest();
printf("Content-type: text/event-stream\n\n");
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);
}
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;
return 0;
}

View File

@ -6,7 +6,7 @@ include ../gluon.mk
define Package/gluon-wan-dnsmasq
TITLE:=Support for a secondary DNS server using the WAN interface
DEPENDS:=+gluon-core +libubus-lua +dnsmasq-full +libpacketmark
DEPENDS:=+gluon-core +libubus-lua +dnsmasq +libpacketmark
endef
define Package/gluon-wan-dnsmasq/description

View File

@ -1,49 +0,0 @@
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Project-Id-Version: PACKAGE VERSION\n"
"PO-Revision-Date: 2023-01-23 13:33+0100\n"
"Last-Translator: Tom Herbers <mail@tomherbers.de>\n"
"Language-Team: German\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
msgid "APN"
msgstr ""
msgid "Cellular"
msgstr ""
msgid "Enabled"
msgstr "Aktiviert"
msgid "IPv4"
msgstr ""
msgid "IPv4/IPv6"
msgstr ""
msgid "IPv6"
msgstr ""
msgid "Password"
msgstr "Passwort"
msgid "SIM PIN"
msgstr ""
msgid "Type"
msgstr "Typ"
msgid "Username"
msgstr "Nutzername"
msgid ""
"You can enable uplink via cellular service. If you decide so, the VPN "
"connection is established using the integrated WWAN modem."
msgstr ""
"Du kannst den Uplink über einen Mobilfunk Service aktivieren. Wenn du "
"dich dafür entscheidest, wird die VPN-Verbindung über das integrierte "
"Mobilfunk-Modem hergestellt."

View File

@ -1,25 +0,0 @@
<%
local br = self.orientation == "horizontal" and '&#160;&#160;&#160;' or '<br>'
local entries = self:entries()
local util = require 'gluon.util'
%>
<div>
<% for i, entry in pairs(entries) do %>
<label<%=
attr("data-index", i) ..
attr("data-depends", self:deplist(entry.deps))
%>>
<input data-update="click change" type="checkbox"<%=
attr("id", id.."."..entry.key) ..
attr("name", id) ..
attr("value", entry.key) ..
attr("checked", (util.contains(self:cfgvalue(), entry.key)) and "checked") ..
attr("data-exclusive-with", self.exclusions[entry.key]) ..
attr("data-update", "change")
%>>
<label<%= attr("for", id.."."..entry.key)%>></label>
<span class="gluon-multi-list-option-descr"><%|entry.value%></span>
</label>
<% if i ~= #entries then write(br) end %>
<% end %>
</div>

View File

@ -1,14 +1,14 @@
<%- if not self.hide then -%>
<%- if self.title or self.content then -%>
<div class="gluon-warning"<%=
attr("id", id) ..
attr("data-index", self.index) ..
attr("data-depends", self:deplist(self.deps))
%>>
<%- if self.content then -%>
<%= self.content %>
<%=self.content%>
<%- else -%>
<b><%= self.title %></b><br>
<%= self.description %>
<b><%=self.title%></b><br>
<%=self.description%>
<%- end -%>
</div>
<%- end -%>

View File

@ -1,15 +1,19 @@
/*
SPDX-License-Identifier: Apache-2.0
SPDX-FileCopyrightText: 2008, Steven Barth <steven@midlink.org>
SPDX-FileCopyrightText: 2008-2012, Jo-Philipp Wich <jow@openwrt.org>
SPDX-FileCopyrightText: 2017, Matthias Schiffer <mschiffer@universe-factory.net>
SPDX-FileCopyrightText: 2023, Leonardo Mörlein <me@irrelefant.net>
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008-2012 Jo-Philipp Wich <jow@openwrt.org>
Copyright 2017 Matthias Schiffer <mschiffer@universe-factory.net>
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
*/
/*
Build using:
uglifyjs javascript/gluon-web-model.js -o javascript/gluon-web-model.min.js -c -m --ie
uglifyjs javascript/gluon-web-model.js -o javascript/gluon-web-model.min.js -c -m --support-ie8
*/
@ -215,20 +219,6 @@
parent.parentNode.style.display = (parent.options.length <= 1) ? 'none' : '';
}
var nodes = document.querySelectorAll('[data-exclusive-with]');
for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
var exclusive_with = JSON.parse(node.getAttribute('data-exclusive-with'));
node.disabled = false;
for (var list_item of exclusive_with) {
var el = document.getElementById(node.name + '.' + list_item);
node.disabled ||= el.checked;
}
if (node.disabled)
node.checked = false;
}
if (state) {
update();
}

File diff suppressed because one or more lines are too long

View File

@ -1,10 +1,8 @@
-- SPDX-License-Identifier: Apache-2.0
-- SPDX-FileCopyrightText: 2008, Steven Barth <steven@midlink.org>
-- SPDX-FileCopyrightText: 2017-2018, Matthias Schiffer <mschiffer@universe-factory.net>
-- SPDX-FileCopyrightText: 2023, Leonardo Mörlein <me@irrelefant.net>
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2017-2018 Matthias Schiffer <mschiffer@universe-factory.net>
-- Licensed to the public under the Apache License 2.0.
local util = require "gluon.web.util"
local gluon_util = require "gluon.util"
local datatypes = require "gluon.web.model.datatypes"
local class = util.class
@ -363,83 +361,6 @@ function ListValue:validate()
end
local MultiListValue = class(AbstractValue)
M.MultiListValue = MultiListValue
function MultiListValue:__init__(...)
AbstractValue.__init__(self, ...)
self.subtemplate = "model/mlvalue"
self.size = 1
self.keys = {}
self.entry_list = {}
end
function MultiListValue:value(key, val, ...)
key = tostring(key)
if self.keys[key] then
return
end
self.keys[key] = true
self.exclusions = {}
val = val or key
table.insert(self.entry_list, {
key = key,
value = tostring(val),
deps = {...},
})
end
function MultiListValue:entries()
local ret = {unpack(self.entry_list)}
return ret
end
function MultiListValue:validate()
for _, val in ipairs(self.data) do
if not self.keys[val] then
return false
end
end
for key, exclusive_with in pairs(self.exclusions) do
if gluon_util.contains(self.data, key) then
for _, exclusion in ipairs(exclusive_with) do
if gluon_util.contains(self.data, exclusion) then
return false
end
end
end
end
return true
end
function MultiListValue:exclusive(a, b)
if not self.exclusions[a] then
self.exclusions[a] = {}
end
if not self.exclusions[b] then
self.exclusions[b] = {}
end
gluon_util.add_to_set(self.exclusions[a], b)
gluon_util.add_to_set(self.exclusions[b], a)
end
function MultiListValue:defaultvalue()
return self.default or {}
end
function MultiListValue:formvalue(http)
return http:formvaluetable(self:id())
end
local DynamicList = class(AbstractValue)
M.DynamicList = DynamicList
@ -508,23 +429,6 @@ function Element:__init__(template, kv, ...)
self.error = false
end
function Element:parse(http)
if not self.datatype then
self.state = M.FORM_VALID
return
end
return AbstractValue:parse(http)
end
function Element:validate()
if not self.datatype then
return true
end
AbstractValue:validate()
end
local Section = class(Node)
M.Section = Section

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