Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 0x4A6F-master
  • 0x4A6F-rpi4
  • autinerd/experimental-openwrt-24.10
  • experimental
  • feature/addMikrotikwAP
  • master
  • nrb/airmax-test
  • nrb/ar9344-reset-sequence
  • nrb/ex400-remove-wps
  • nrb/gluon-master-cpe510
  • nrb/test-radv-filter
  • nrbffs/fastd-remove-delay
  • nrbffs/netgear-ex6120
  • v2018.2.2-ffs
  • v2018.2.3-ffs
  • v2019.1-ffs
  • v2019.1.1-ffs
  • v2019.1.2-ffs
  • v2020.1-ffs
  • v2020.1.1-ffs
  • v2020.1.3-ffs
  • v2020.2-ffs
  • v2020.2.1-ffs
  • v2020.2.2-ffs
  • v2020.2.3-ffs
  • v2021.1-ffs
  • v2021.1.1-ffs
  • v2021.1.2-ffs
  • v2022.1.1-ffs
  • v2022.1.3-ffs
  • v2022.1.4-ffs
  • v2023.1-ffs
  • v2023.2-ffs
  • v2023.2.2-ffs
  • v2023.2.3-ffs
  • v2023.2.4-ffs
  • v2023.2.5-ffs
  • experimental-2022-09-24
  • experimental-2022-09-24-base
  • experimental-2023-03-11
  • experimental-2023-03-11-base
  • experimental-2023-03-12
  • experimental-2023-03-12-base
  • experimental-2023-03-16
  • experimental-2023-03-16-base
  • experimental-2023-03-20
  • experimental-2023-03-20-base
  • experimental-2023-03-23
  • experimental-2023-03-23-base
  • experimental-2023-03-25
  • experimental-2023-03-25-base
  • experimental-2023-03-26
  • experimental-2023-03-26-base
  • experimental-2023-03-30
  • experimental-2023-03-30-base
  • experimental-2023-03-31
  • experimental-2023-03-31-base
  • experimental-2023-04-01
  • experimental-2023-04-01-base
  • experimental-2023-04-08
  • experimental-2023-04-08-base
  • experimental-2023-04-10
  • experimental-2023-04-10-base
  • experimental-2023-04-13
  • experimental-2023-04-13-base
  • experimental-2023-04-15
  • experimental-2023-04-15-base
  • experimental-2023-04-16
  • experimental-2023-04-16-base
  • experimental-2023-04-18
  • experimental-2023-04-18-base
  • experimental-2023-04-20
  • experimental-2023-04-20-base
  • experimental-2023-04-26
  • experimental-2023-04-26-base
  • experimental-2023-04-28
  • experimental-2023-04-28-base
  • experimental-2023-04-30
  • experimental-2023-04-30-base
  • experimental-2023-05-02
  • experimental-2023-05-02-base
  • experimental-2023-05-03
  • experimental-2023-05-03-base
  • experimental-2023-05-12
  • experimental-2023-05-12-base
  • experimental-2023-05-21
  • experimental-2023-05-21-base
  • experimental-2023-05-25
  • experimental-2023-05-25-base
  • experimental-2023-07-02
  • experimental-2023-07-02-base
  • experimental-2023-07-04
  • experimental-2023-07-04-base
  • experimental-2023-07-12
  • experimental-2023-07-12-base
  • experimental-2023-07-16
  • experimental-2023-07-16-base
  • experimental-2023-08-04
  • experimental-2023-08-04-base
  • experimental-2023-08-10
  • experimental-2023-08-10-base
  • experimental-2023-09-08
  • experimental-2023-09-08-base
  • experimental-2023-09-09
  • experimental-2023-09-09-base
  • experimental-2023-09-10
  • experimental-2023-09-10-base
  • experimental-2023-09-11
  • experimental-2023-09-11-base
  • experimental-2023-09-12
  • experimental-2023-09-12-base
  • experimental-2023-09-13
  • experimental-2023-09-13-base
  • experimental-2023-09-15
  • experimental-2023-09-15-base
  • experimental-2023-09-16
  • experimental-2023-09-16-base
  • experimental-2023-09-18
  • experimental-2023-09-18-base
  • experimental-2023-09-20
  • experimental-2023-09-20-base
  • experimental-2023-09-27
  • experimental-2023-09-27-base
  • experimental-2023-09-28
  • experimental-2023-09-28-base
  • experimental-2023-09-29
  • experimental-2023-09-29-base
  • experimental-2023-10-02
  • experimental-2023-10-02-base
  • experimental-2023-10-13
  • experimental-2023-10-13-base
  • experimental-2023-10-14
  • experimental-2023-10-14-base
  • experimental-2023-10-16
  • experimental-2023-10-16-base
  • experimental-2023-10-23
  • experimental-2023-10-23-base
137 results

Target

Select target project
No results found
Select Git revision
  • 0x4A6F-master
  • 0x4A6F-rpi4
  • 2014.3.x
  • 2014.4.x
  • babel
  • hoodselector
  • master
  • radv-filterd
  • v2015.1.x
  • v2016.1.x
  • v2016.2.4-batmanbug
  • v2016.2.x
  • v2018.2.2-ffs
  • v2018.2.x
  • v2014.1
  • v2014.2
  • v2014.3
  • v2014.3.1
  • v2014.4
  • v2015.1
  • v2015.1.1
  • v2015.1.2
  • v2016.1
  • v2016.1.1
  • v2016.1.2
  • v2016.1.3
  • v2016.1.4
  • v2016.1.5
  • v2016.1.6
  • v2016.2
  • v2016.2.1
  • v2016.2.2
  • v2016.2.3
  • v2016.2.4
  • v2016.2.5
  • v2016.2.6
  • v2016.2.7
  • v2017.1
  • v2017.1.1
  • v2017.1.2
  • v2017.1.3
  • v2017.1.4
  • v2017.1.5
  • v2017.1.6
  • v2017.1.7
  • v2017.1.8
  • v2018.1
  • v2018.1.1
  • v2018.1.2
  • v2018.1.3
  • v2018.1.4
  • v2018.2
  • v2018.2-ffs0.1
  • v2018.2.1
  • v2018.2.1-ffs0.1
  • v2018.2.2-ffs0.1
56 results
Show changes

Commits on Source 3080

2,980 additional commits have been omitted to prevent performance issues.
950 files
+ 35554
21916
Compare changes
  • Side-by-side
  • Inline

Files

.ecrc

0 → 100644
+3 −0
Original line number Original line Diff line number Diff line
{
  "Exclude": ["docs/_build"]
}

.editorconfig

0 → 100644
+67 −0
Original line number Original line Diff line number Diff line
# Top-most EditorConfig file
root = true

[*]
end_of_line = lf
insert_final_newline = true
indent_style = tab
charset = utf-8

[Dockerfile]
indent_style = space
indent_size = 4

[/patches/**]
indent_style = unset
indent_size = unset

[*.c]

[*.css]

[*.dia]
indent_style = space
indent_size = 2

[*.h]

[*.html]

[*.js]

[*{.json,.ecrc}]
indent_style = space
indent_size = 2

[*.lua]

[{Makefile,*.mk}]
indent_style = unset

[*.md]
indent_style = space
indent_size = 4

[*.pl]

[*.py]
indent_style = space
indent_size = 4

[*.rst]
indent_style = space
indent_size = 2

[*.sh]

[*.yml]
indent_style = space
indent_size = 2

[CMakeLists.txt]
indent_style = space
indent_size = 2

[{docs,contrib/ci}/*site*/**/*.conf]
indent_style = space
indent_size = 2
+71 −0
Original line number Original line Diff line number Diff line
---
name: Bug report
about: Report a bug in a recent version of Gluon
label: bug
---

<!--

Please carefully fill out the questionnaire below to help improve the
timely triaging of issues. Walk through the questions below and use
them as an inspiration for what information you can provide.

Make use of codeblocks (three backticks before and after) where
appropriate (configuration excerpts, log output, etc.). Example:

```
your code goes here
```

You can use the "Preview" tab to check how your issue is going to look
before you actually send it in.

Thank you for taking the time to report a bug with the Gluon project.

-->

### Bug report

**What is the problem?**
<!--
- What is not working as expected?
- How is it misbehaving?
- When did the problem first start showing up?
- What were you doing when you first noticed the problem?
- On which devices (vendor, model and revision) is it misbehaving?
- Does the issue appear on multiple devices or targets?
-->

**What is the expected behaviour?**
<!--
- How do you think it should work instead?
- Did it work like that before?
-->

**Gluon Version:**
<!--
Please provide a usable Git reference before applying custom patches:

By using a Git reference:
    $ git describe --always
    v2018.2-17-g3abadc28

Or the URL to the relevant Gluon commit
    https://github.com/freifunk-gluon/gluon/commit/<commit hash here>
-->

**Site Configuration:**
<!--
Please provide the URL to your site configuration repository and the
explicit commit used to build the firmware experiencing the problem.

Additionally excerpts of problem-related configuration parts are 
often helpful.
-->

**Custom patches:**
<!--
Be upfront about any custom patches you have applied to your Gluon build, as they might
be part of your problem.
-->

.github/dependabot.yml

0 → 100644
+12 −0
Original line number Original line Diff line number Diff line
# Docs: <https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/customizing-dependency-updates>

version: 2

updates:
  - package-ecosystem: github-actions
    directory: /
    schedule: {interval: monthly}

  - package-ecosystem: pip
    directory: /docs/
    schedule: {interval: monthly}

.github/filters.yml

0 → 100644
+345 −0
Original line number Original line Diff line number Diff line
{
  "armsr-armv7": [
    "targets/armsr-armv7",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
    "targets/armsr.inc"
  ],
  "armsr-armv8": [
    "targets/armsr-armv8",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
    "targets/armsr.inc"
  ],
  "ath79-generic": [
    "targets/ath79-generic",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "ath79-nand": [
    "targets/ath79-nand",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "ath79-mikrotik": [
    "targets/ath79-mikrotik",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
    "targets/mikrotik.inc"
  ],
  "bcm27xx-bcm2708": [
    "targets/bcm27xx-bcm2708",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
    "targets/bcm27xx.inc"
  ],
  "bcm27xx-bcm2709": [
    "targets/bcm27xx-bcm2709",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
    "targets/bcm27xx.inc"
  ],
  "ipq40xx-generic": [
    "targets/ipq40xx-generic",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "ipq40xx-mikrotik": [
    "targets/ipq40xx-mikrotik",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
    "targets/mikrotik.inc"
  ],
  "ipq806x-generic": [
    "targets/ipq806x-generic",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "lantiq-xrx200": [
    "targets/lantiq-xrx200",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "lantiq-xrx200_legacy": [
    "targets/lantiq-xrx200_legacy",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "lantiq-xway": [
    "targets/lantiq-xway",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "mediatek-filogic": [
    "targets/mediatek-filogic",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "mediatek-mt7622": [
    "targets/mediatek-mt7622",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "mvebu-cortexa53": [
    "targets/mvebu-cortexa53",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "mpc85xx-p1010": [
    "targets/mpc85xx-p1010",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "mpc85xx-p1020": [
    "targets/mpc85xx-p1020",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "qualcommax-ipq807x": [
    "targets/qualcommax-ipq807x",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "ramips-mt7620": [
    "targets/ramips-mt7620",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "ramips-mt7621": [
    "targets/ramips-mt7621",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "ramips-mt76x8": [
    "targets/ramips-mt76x8",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "rockchip-armv8": [
    "targets/rockchip-armv8",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "sunxi-cortexa7": [
    "targets/sunxi-cortexa7",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "x86-generic": [
    "targets/x86-generic",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
    "targets/x86.inc"
  ],
  "x86-geode": [
    "targets/x86-geode",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "x86-legacy": [
    "targets/x86-legacy",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
    "targets/x86.inc"
  ],
  "x86-64": [
    "targets/x86-64",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
    "targets/x86.inc",
    "contrib/ci/minimal-site/**",
    "package/**"
  ],
  "bcm27xx-bcm2710": [
    "targets/bcm27xx-bcm2710",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
    "targets/bcm27xx.inc"
  ],
  "bcm27xx-bcm2711": [
    "targets/bcm27xx-bcm2711",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
    "targets/bcm27xx.inc"
  ],
  "ipq40xx-chromium": [
    "targets/ipq40xx-chromium",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "kirkwood-generic": [
    "targets/kirkwood-generic",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "mvebu-cortexa9": [
    "targets/mvebu-cortexa9",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ]
}

.github/labeler.yml

0 → 100644
+89 −0
Original line number Original line Diff line number Diff line
---
"3. topic: batman-adv":
  - changed-files:
    - any-glob-to-any-file:
      - docs/package/gluon-mesh-batman-adv*
      - package/gluon-alfred/**
      - package/gluon-client-bridge/**
      - package/gluon-mesh-batman-adv/**
      - package/libbatadv/**
"3. topic: build":
  - changed-files:
    - any-glob-to-any-file:
      - Makefile
      - scripts/**
"3. topic: config-mode":
  - changed-files:
    - any-glob-to-any-file:
      - docs/dev/web/config-mode.rst
      - docs/package/gluon-config-mode-*
      - package/gluon-config-mode-*/**
      - package/gluon-web*/**
"3. topic: continuous integration":
  - changed-files:
    - any-glob-to-any-file:
      - .github/workflows/*
      - contrib/actions/**
      - contrib/ci/**
"3. topic: docs":
  - changed-files:
    - any-glob-to-any-file:
      - docs/**
"3. topic: fastd":
  - changed-files:
    - any-glob-to-any-file:
      - docs/features/fastd*
      - package/gluon-mesh-vpn-fastd/**
"3. topic: firewall":
  - changed-files:
    - any-glob-to-any-file:
      - package/**/*-firewall
      - package/gluon-ebtables-*/**
"3. topic: hardware":
  - changed-files:
    - any-glob-to-any-file:
      - package/gluon-core/luasrc/lib/gluon/upgrade/010-primary-mac
      - package/gluon-core/luasrc/usr/lib/lua/gluon/platform.lua
      - targets/*
"3. topic: multidomain":
  - changed-files:
    - any-glob-to-any-file:
      - docs/features/multidomain*
      - docs/multidomain-site-example/**
      - package/gluon-config-mode-domain-select/**
      - package/gluon-scheduled-domain-switch/**
"3. topic: olsr":
  - changed-files:
    - any-glob-to-any-file:
      - package/gluon-l3roamd/**
      - package/gluon-mesh-olsrd/**
      - package/gluon-mmfd/**
"3. topic: package":
  - changed-files:
    - any-glob-to-any-file:
      - package/**
"3. topic: respondd":
  - changed-files:
    - any-glob-to-any-file:
      - package/**/*respondd*
      - package/gluon-respondd/**
"3. topic: status-page":
  - changed-files:
    - any-glob-to-any-file:
      - package/gluon-status-page/**
"3. topic: tests":
  - changed-files:
    - any-glob-to-any-file:
      - tests/**
"3. topic: wireguard":
  - changed-files:
    - any-glob-to-any-file:
      - package/gluon-mesh-vpn-wireguard/**
"3. topic: wireless":
  - changed-files:
    - any-glob-to-any-file:
      - package/gluon-mesh-wireless-sae/**
      - package/gluon-private-wifi/**
      - package/gluon-web-private-wifi/**
      - package/gluon-web-wifi-config/**
      - package/gluon-wireless-encryption-wpa3/**
+20 −0
Original line number Original line Diff line number Diff line
name: Backport
on:
  pull_request_target:
    types: [closed, labeled]
permissions:
  contents: write # so it can comment
  pull-requests: write # so it can create pull requests
jobs:
  backport:
    name: Backport Pull Request
    if: github.repository_owner == 'freifunk-gluon' && github.event.pull_request.merged == true && (github.event_name != 'labeled' || startsWith('backport', github.event.label.name))
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v5
      - name: Create backport PRs
        uses: korthout/backport-action@v3.3.0
        with:
          # Config README: https://github.com/korthout/backport-action#backport-action
          pull_description: |-
            Automatic backport to `${target_branch}`, triggered by a label in #${pull_number}.
+48 −0
Original line number Original line Diff line number Diff line
# Based on the example from https://docs.github.com/en/actions/publishing-packages/publishing-docker-images
name: Create and publish a Docker image

on:
  push:
    branches:
      - 'main'
      - 'next'
      - 'v202[0-9].[0-9].x'
    tags:
      - 'v*'
  pull_request:

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}-build

jobs:
  build-and-push-image:
    runs-on: ubuntu-22.04
    permissions: write-all
    steps:
      - name: Checkout repository
        uses: actions/checkout@v5
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
      - name: Log in to the Container registry
        uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1
        if: ${{ github.repository_owner == 'freifunk-gluon' && github.event_name == 'push' }}
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
      - name: Build and push Docker image
        uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
        with:
          context: ./contrib/docker
          push: ${{ github.repository_owner == 'freifunk-gluon' && github.event_name == 'push' }}
          platforms: linux/amd64,linux/arm64
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
+29 −0
Original line number Original line Diff line number Diff line
name: Build Documentation
on:
  push:
    paths:
      - 'docs/**'
      - '.github/workflows/build-docs.yml'
  pull_request:
    types: [opened, synchronize, reopened]
    paths:
      - 'docs**/'
      - '.github/workflows/build-docs.yml'
permissions:
  contents: read

jobs:
  build-documentation:
    name: docs
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v5
      - name: Install Dependencies
        run: sudo pip3 install -r docs/requirements.txt
      - name: Build documentation
        run: make -C docs html
      - name: Archive build output
        uses: actions/upload-artifact@v4
        with:
          name: docs_output
          path: docs/_build/html
+80 −0
Original line number Original line Diff line number Diff line
name: Build Gluon
on:
  push:
    branches:
      - main
      - next
      - 'v20[2-9][0-9].[0-9].x'
  pull_request:
    types: [opened, synchronize, reopened]
  workflow_dispatch:

permissions:
  contents: read

concurrency:
  group: ${{ github.workflow }}-${{ github.ref || github.run_id }}-${{ github.event.pull_request.number || github.run_id }}
  cancel-in-progress: true

jobs:
  changed:
    permissions:
      contents: read  # for dorny/paths-filter to fetch a list of changed files
      pull-requests: read  # for dorny/paths-filter to read pull requests
    runs-on: ubuntu-22.04
    outputs:
      targets: ${{ steps.filter.outputs.changes }}
    steps:
      - uses: actions/checkout@v5

      # Filter targets based on changed files
      - uses: dorny/paths-filter@v3
        id: filter
        with:
          filters: .github/filters.yml

  build_firmware:
    needs: changed
    if: ${{ needs.changed.outputs.targets != '[]' && needs.changed.outputs.targets != '' }}
    strategy:
      fail-fast: false
      matrix:
        # Read back changed targets to create build matrix
        target: ${{ fromJSON(needs.changed.outputs.targets) }}
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v5

      - name: Show system information
        run: contrib/actions/show-system-info.sh

      - name: Remove non-required software
        run: contrib/actions/free-runner-space.sh

      - name: Build Docker container
        run: docker build -t gluon-ci-container contrib/docker

      - name: Build Gluon
        run: docker run --rm -v $PWD:/gluon-ci -w /gluon-ci --user "$(id -u):$(id -g)" gluon-ci-container contrib/actions/run-build.sh ${{ matrix.target }}

      - name: Check Image size
        run: contrib/check-image-size.py --github-actions --overhead 256 output/meta/openwrt-profiles/${{ matrix.target }}.json

      - name: Archive build logs
        if: ${{ !cancelled() }}
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.target }}_logs
          path: openwrt/logs

      - name: Archive build output
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.target }}_output
          path: output

      - name: Archive metadata
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.target }}_metadata
          path: output/meta
+51 −0
Original line number Original line Diff line number Diff line
---
name: "Update OpenWrt base"

on:
  workflow_dispatch:
    inputs:
      branch:
        description: "Branch to create update for"
        required: true
        default: "main"

jobs:
  update-openwrt:
    runs-on: ubuntu-22.04
    env:
      COMMIT_NAME: Gluon CI Bot
      COMMIT_EMAIL: bot@freifunk-gluon.github.io
    steps:
      - name: Clone Gluon
        uses: actions/checkout@v5
        with:
          ref: ${{ github.event.inputs.branch }}
      
      - name: Configure Git User and E-Mail
        run: git config --global user.name "${{ env.COMMIT_NAME }}" && git config --global user.email "${{ env.COMMIT_EMAIL }}"
      
      - name: Get update branch name
        id: branch-name
        run: echo "branch-name=update-openwrt-${{ github.event.inputs.branch }}-$(date +%s)" >> $GITHUB_OUTPUT

      - name: Link example Site
        run: ln -s docs/site-example site
      
      - name: Invoke update-modules
        run: make update-modules
      
      - name: Refresh patches
        run: make refresh-patches
      
      - name: Check if unstaged commits exist
        run: git diff --exit-code || echo "::warning::Patches need a manual refresh"
      
      - name: Checkout individual branch name
        run: git checkout -b ${{ steps.branch-name.outputs.branch-name }}
      
      - name: Push branch
        run: git push origin HEAD

      - name: Emit PR creation message
        run:
          echo "::notice::Create pull-request at https://github.com/${{ github.repository }}/compare/${{ github.event.inputs.branch }}...${{ steps.branch-name.outputs.branch-name }}?quick_pull=1"
+22 −0
Original line number Original line Diff line number Diff line
name: Check generated CI
on:
  push:
  pull_request:
    types: [opened, synchronize, reopened]
permissions:
  contents: read

jobs:
  check-ci:
    name: Check generated CI
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v5
      - name: Install example site
        run: ln -s ./docs/site-example ./site
      - name: Update CI
        run: make update-ci
      - name: Show diff
        run: git status; git diff
      - name: Patch status
        run: git diff-files --quiet
+30 −0
Original line number Original line Diff line number Diff line
---
name: Check patches
on:
  push:
    paths:
      - 'modules'
      - 'patches/**'
      - '.github/workflows/check-patches.yml'
  pull_request:
    types: [opened, synchronize, reopened]
    paths:
      - 'modules'
      - 'patches/**'
      - '.github/workflows/check-patches.yml'
permissions:
  contents: read

jobs:
  check-patches:
    name: Check patches
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v5
      - name: Refresh patches
        run: make refresh-patches GLUON_SITEDIR="contrib/ci/minimal-site"
      - name: Show diff
        run: git status; git diff
      - name: Patch status
        run: git diff-files --quiet
+21 −0
Original line number Original line Diff line number Diff line
name: "Label PRs"

on:
  # only execute base branch actions
  pull_request_target:

permissions:
  contents: read

jobs:
  labels:
    permissions:
      contents: read  # for actions/labeler to determine modified files
      pull-requests: write  # for actions/labeler to add labels to PRs
    runs-on: ubuntu-22.04
    if: github.repository_owner == 'freifunk-gluon'
    steps:
    - uses: actions/labeler@v5
      with:
        repo-token: ${{ secrets.GITHUB_TOKEN }}
        sync-labels: true
+54 −0
Original line number Original line Diff line number Diff line
name: Lint
on:
  push:
  pull_request:
    types: [opened, synchronize, reopened]
permissions:
  contents: read

jobs:
  lua:
    name: Lua
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v5
      - name: Install Dependencies
        run: sudo apt-get -y update && sudo apt-get -y install lua-check
      - name: Install example site
        run: ln -s ./docs/site-example ./site
      - name: Lint Lua code
        run: make lint-lua

  sh:
    name: Shell
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v5
      - name: Install Dependencies
        run: sudo apt-get -y update && sudo apt-get -y install shellcheck
      - name: Install example site
        run: ln -s ./docs/site-example ./site
      - name: Lint shell code
        run: make lint-sh

  editorconfig:
    name: Editorconfig
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v5
      - 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
+5 −1
Original line number Original line Diff line number Diff line
*~
*~
/lede
/openwrt
/output
/output
/site
/site
/tmp
/tmp
/packages
/packages
.bash_history
.subversion
.wget-hsts
/.scmversion

.luacheckrc

0 → 100644
+119 −0
Original line number Original line Diff line number Diff line
codes = true
std = "min"
self = false

read_globals = {
	"getfenv",
	"setfenv",
	"unpack",
}

include_files = {
	"**/*.lua",
	"package/**/luasrc/**/*",
	"targets/*",
	"package/features",
}

exclude_files = {
	"**/*.mk",
}

files["package/**/check_site.lua"] = {
	read_globals = {
		"alternatives",
		"extend",
		"in_domain",
		"in_site",
		"value",
		"need",
		"need_alphanumeric_key",
		"need_array",
		"need_array_elements_exclusive",
		"need_array_of",
		"need_boolean",
		"need_chanlist",
		"need_domain_name",
		"need_number",
		"need_number_range",
		"need_one_of",
		"need_string",
		"need_string_array",
		"need_string_array_match",
		"need_string_match",
		"need_table",
		"need_value",
		"obsolete",
		"table_keys",
		"this_domain",
	},
}

files["package/**/luasrc/lib/gluon/config-mode/*"] = {
	globals = {
		"MultiListValue",
		"DynamicList",
		"Flag",
		"Form",
		"i18n",
		"ListValue",
		"renderer.render",
		"renderer.render_string",
		"Section",
		"TextValue",
		"_translate",
		"translate",
		"translatef",
		"Value",
		"Element",
	},
}

files["package/**/luasrc/lib/gluon/**/controller/*"] = {
	read_globals = {
		"_",
		"alias",
		"call",
		"entry",
		"model",
		"node",
		"template",
	},
}

files["package/**/luasrc/lib/gluon/ebtables/*"] = {
	read_globals = {
		"chain",
		"rule",
	},
	max_line_length = false,
}

files["targets/*"] = {
	read_globals = {
		"class",
		"config",
		"defaults",
		"device",
		"env",
		"exec",
		"exec_capture",
		"exec_capture_raw",
		"exec_raw",
		"factory_image",
		"include",
		"istrue",
		"no_opkg",
		"packages",
		"sysupgrade_image",
		"try_config",
	},
}

files["package/features"] = {
	read_globals = {
		"_",
		"feature",
		"when",
	},
}

.readthedocs.yaml

0 → 100644
+20 −0
Original line number Original line Diff line number Diff line
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

# Required
version: 2

# Build documentation in the docs/ directory with Sphinx
sphinx:
  configuration: docs/conf.py

# Optionally set the version of Python and requirements required to build your docs
python:
   install:
   - requirements: docs/requirements.txt

build:
    os: ubuntu-22.04
    tools:
        python: "3.11"
+9 −9
Original line number Original line Diff line number Diff line
@@ -23,19 +23,19 @@ 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
They might even refuse the idea altogether - after all, they have to sleep well
after merging the changes, too.
after merging the changes, too.


The preferred way to discuss in the IRC channel ([#gluon] on irc.hackint.org)
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
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
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
kindly ask you to review it first. In general, looking for duplicates may save
you some time.
you some time.


Develop on top of master
Develop on top of main
------------------------
----------------------
If you are not developing something specific to a release (like for example a
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),
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
develop it on top of the main branch. New features and even feature changes
aren't usually backported to old releases, but will be included in the upcoming
aren't usually backported to old releases, but will be included in the upcoming
release, which will be built from master.
release, which will be built from main.


Use descriptive commit messages
Use descriptive commit messages
-------------------------------
-------------------------------
@@ -47,7 +47,7 @@ triggered and what you did to fix it. If in question, have a glance at the
existing commit messages to get the idea.
existing commit messages to get the idea.




[packages]: http://gluon.readthedocs.org/en/latest/user/site.html#packages
[packages]: https://gluon.readthedocs.io/en/latest/user/site.html#packages
[#gluon]: https://webirc.hackint.org/#gluon
[#gluon]: https://chat.hackint.org/?join=gluon
[mailing list]: mailto:gluon@luebeck.freifunk.net
[mailing list]: mailto:gluon@luebeck.freifunk.net
[list of rejected features]: https://github.com/freifunk-gluon/gluon/issues?q=label%3Arejected
[list of rejected features]: https://github.com/freifunk-gluon/gluon/issues?q=label%3A%222.+status%3A+rejected%22
+7 −4
Original line number Original line Diff line number Diff line
BSD 2-Clause License

The code of Project Gluon may be distributed under the following terms, unless
The code of Project Gluon may be distributed under the following terms, unless
noted otherwise in individual files or subtrees.
noted otherwise in individual files or subtrees.


Copyright (c) 2013-2017, Project Gluon
Copyright (c) Project Gluon
All rights reserved.
All rights reserved.


Redistribution and use in source and binary forms, with or without
Redistribution and use in source and binary forms, with or without
@@ -25,10 +27,11 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.




LEDE and OpenWrt are licensed under the terms of the GNU General Public License
OpenWrt is licensed under the terms of the GNU General Public License Version 2,
Version 2, which can be found at lede/LICENSE after the lede repository has been
which can be found at openwrt/LICENSE after the OpenWrt repository has been
obtained. This applies to the following repositories:
obtained. This applies to the following repositories:
 * lede

 * openwrt
 * packages/openwrt
 * packages/openwrt
 * packages/routing
 * packages/routing
 * packages/luci
 * packages/luci
+169 −104
Original line number Original line Diff line number Diff line
@@ -4,14 +4,7 @@ LC_ALL:=C
LANG:=C
LANG:=C
export LC_ALL LANG
export LC_ALL LANG



.SHELLFLAGS = -ec
# initialize (possibly already user set) directory variables
GLUON_SITEDIR ?= site
GLUON_TMPDIR ?= tmp
GLUON_OUTPUTDIR ?= output

GLUON_IMAGEDIR ?= $(GLUON_OUTPUTDIR)/images
GLUON_PACKAGEDIR ?= $(GLUON_OUTPUTDIR)/packages


# check for spaces & resolve possibly relative paths
# check for spaces & resolve possibly relative paths
define mkabspath
define mkabspath
@@ -21,45 +14,113 @@ define mkabspath
   override $(1) := $(abspath $($(1)))
   override $(1) := $(abspath $($(1)))
endef
endef


$(eval $(call mkabspath,GLUON_SITEDIR))
escape = '$(subst ','\'',$(1))'
$(eval $(call mkabspath,GLUON_TMPDIR))
$(eval $(call mkabspath,GLUON_OUTPUTDIR))
$(eval $(call mkabspath,GLUON_IMAGEDIR))
$(eval $(call mkabspath,GLUON_PACKAGEDIR))

export GLUON_TMPDIR GLUON_IMAGEDIR GLUON_PACKAGEDIR DEVICES


GLUON_SITEDIR ?= site
$(eval $(call mkabspath,GLUON_SITEDIR))


$(GLUON_SITEDIR)/site.mk:
ifeq ($(realpath $(GLUON_SITEDIR)/site.mk),)
$(error No site configuration was found. Please check out a site configuration to $(GLUON_SITEDIR))
$(error No site configuration was found. Please check out a site configuration to $(GLUON_SITEDIR))
endif


include $(GLUON_SITEDIR)/site.mk
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)
GLUON_RELEASE ?= $(error GLUON_RELEASE not set. GLUON_RELEASE can be set in site.mk or on the command line)


GLUON_DEPRECATED ?= 0

ifneq ($(GLUON_BRANCH),)
  $(warning *** Warning: GLUON_BRANCH has been deprecated, please set GLUON_AUTOUPDATER_BRANCH and GLUON_AUTOUPDATER_ENABLED instead.)
  GLUON_AUTOUPDATER_BRANCH ?= $(GLUON_BRANCH)
  GLUON_AUTOUPDATER_ENABLED ?= 1
endif

ifneq ($(GLUON_FEATURES)$(GLUON_FEATURES_standard)$(GLUON_FEATURES_tiny),)
  $(error GLUON_FEATURES is obsolete, please use the image-customization.lua file instead)
endif

ifneq ($(GLUON_SITE_PACKAGES)$(GLUON_SITE_PACKAGES_standard)$(GLUON_SITE_PACKAGES_tiny),)
  $(error GLUON_SITE_PACKAGES is obsolete, please use the image-customization.lua file instead)
endif

GLUON_AUTOUPDATER_ENABLED ?= 0

# initialize (possibly already user set) directory variables
GLUON_TMPDIR ?= tmp
GLUON_OUTPUTDIR ?= output
GLUON_IMAGEDIR ?= $(GLUON_OUTPUTDIR)/images
GLUON_PACKAGEDIR ?= $(GLUON_OUTPUTDIR)/packages
GLUON_DEBUGDIR ?= $(GLUON_OUTPUTDIR)/debug
GLUON_METADIR ?= $(GLUON_OUTPUTDIR)/meta
GLUON_TARGETSDIR ?= targets
GLUON_PATCHESDIR ?= patches

$(eval $(call mkabspath,GLUON_TMPDIR))
$(eval $(call mkabspath,GLUON_OUTPUTDIR))
$(eval $(call mkabspath,GLUON_IMAGEDIR))
$(eval $(call mkabspath,GLUON_PACKAGEDIR))
$(eval $(call mkabspath,GLUON_TARGETSDIR))
$(eval $(call mkabspath,GLUON_PATCHESDIR))

GLUON_VERSION := $(shell scripts/getversion.sh '.')

# Set default SITE_VERSION if not set by user
GLUON_SITE_VERSION ?= $(shell scripts/getversion.sh '$(GLUON_SITEDIR)')

GLUON_MULTIDOMAIN ?= 0
GLUON_MULTIDOMAIN ?= 0
GLUON_WLAN_MESH ?= 11s
GLUON_AUTOREMOVE ?= 0
GLUON_DEBUG ?= 0
GLUON_DEBUG ?= 1
GLUON_MINIFY ?= 1

# Can be overridden via environment/command line/... to use the Gluon
# build system for non-Gluon builds
define GLUON_BASE_FEEDS ?=
src-link gluon_base ../../package
endef


export GLUON_RELEASE GLUON_REGION GLUON_MULTIDOMAIN GLUON_WLAN_MESH GLUON_DEBUG
GLUON_VARS = \
	GLUON_VERSION GLUON_SITE_VERSION \
	GLUON_RELEASE GLUON_REGION GLUON_MULTIDOMAIN GLUON_AUTOREMOVE GLUON_DEBUG GLUON_MINIFY GLUON_DEPRECATED \
	GLUON_DEVICES GLUON_TARGETSDIR GLUON_PATCHESDIR GLUON_TMPDIR GLUON_IMAGEDIR GLUON_PACKAGEDIR GLUON_DEBUGDIR \
	GLUON_METADIR GLUON_SITEDIR GLUON_AUTOUPDATER_BRANCH GLUON_AUTOUPDATER_ENABLED GLUON_LANGS GLUON_BASE_FEEDS \
	GLUON_TARGET BOARD SUBTARGET

unexport $(GLUON_VARS)
GLUON_ENV = $(foreach var,$(GLUON_VARS),$(var)=$(call escape,$($(var))))


show-release:
show-release:
	@echo '$(GLUON_RELEASE)'
	@echo '$(GLUON_RELEASE)'




update: FORCE
update: FORCE
	@GLUON_SITEDIR='$(GLUON_SITEDIR)' scripts/update.sh
	@
	@GLUON_SITEDIR='$(GLUON_SITEDIR)' scripts/patch.sh
	export $(GLUON_ENV)
	@GLUON_SITEDIR='$(GLUON_SITEDIR)' scripts/feeds.sh
	scripts/update.sh
	scripts/patch.sh
	scripts/feeds.sh


update-patches: FORCE
update-patches: FORCE
	@GLUON_SITEDIR='$(GLUON_SITEDIR)' scripts/update.sh
	@
	@GLUON_SITEDIR='$(GLUON_SITEDIR)' scripts/update-patches.sh
	export $(GLUON_ENV)
	@GLUON_SITEDIR='$(GLUON_SITEDIR)' scripts/patch.sh
	scripts/update.sh
	scripts/update-patches.sh
	scripts/patch.sh

refresh-patches: FORCE
	@
	export $(GLUON_ENV)
	scripts/update.sh
	scripts/patch.sh
	scripts/update-patches.sh


update-feeds: FORCE
update-feeds: FORCE
	@GLUON_SITEDIR='$(GLUON_SITEDIR)' scripts/feeds.sh
	@$(GLUON_ENV) scripts/feeds.sh

update-modules: FORCE
	@scripts/update-modules.sh


update-ci: FORCE
	@$(GLUON_ENV) scripts/update-ci.sh


GLUON_TARGETS :=
GLUON_TARGETS :=


@@ -67,117 +128,121 @@ define GluonTarget
gluon_target := $(1)$$(if $(2),-$(2))
gluon_target := $(1)$$(if $(2),-$(2))
GLUON_TARGETS += $$(gluon_target)
GLUON_TARGETS += $$(gluon_target)
GLUON_TARGET_$$(gluon_target)_BOARD := $(1)
GLUON_TARGET_$$(gluon_target)_BOARD := $(1)
GLUON_TARGET_$$(gluon_target)_SUBTARGET := $(if $(3),$(3),$(2))
GLUON_TARGET_$$(gluon_target)_SUBTARGET := $(2)
endef
endef


include targets/targets.mk
include $(GLUON_TARGETSDIR)/targets.mk




LEDEMAKE = $(MAKE) -C lede
OPENWRTMAKE = $(MAKE) -C openwrt


BOARD := $(GLUON_TARGET_$(GLUON_TARGET)_BOARD)
BOARD := $(GLUON_TARGET_$(GLUON_TARGET)_BOARD)
SUBTARGET := $(GLUON_TARGET_$(GLUON_TARGET)_SUBTARGET)
SUBTARGET := $(GLUON_TARGET_$(GLUON_TARGET)_SUBTARGET)


GLUON_CONFIG_VARS := \
	GLUON_SITEDIR='$(GLUON_SITEDIR)' \
	GLUON_RELEASE='$(GLUON_RELEASE)' \
	GLUON_BRANCH='$(GLUON_BRANCH)' \
	GLUON_LANGS='$(GLUON_LANGS)' \
	BOARD='$(BOARD)' \
	SUBTARGET='$(SUBTARGET)'

LEDE_TARGET := $(BOARD)$(if $(SUBTARGET),-$(SUBTARGET))


export LEDE_TARGET
define CheckTarget

	if [ -z '$(BOARD)' ]; then

		echo 'Please set GLUON_TARGET to a valid target. Gluon supports the following targets:'
CheckTarget := [ '$(LEDE_TARGET)' ] \
		for target in $(GLUON_TARGETS); do
	|| (echo 'Please set GLUON_TARGET to a valid target. Gluon supports the following targets:'; $(foreach target,$(GLUON_TARGETS),echo ' * $(target)';) false)
			echo " * $$target"

		done
CheckExternal := test -d lede || (echo 'You don'"'"'t seem to have obtained the external repositories needed by Gluon; please call `make update` first!'; false)
		exit 1
	fi
endef


define CheckSite
define CheckSite
	@GLUON_SITEDIR='$(GLUON_SITEDIR)' GLUON_SITE_CONFIG='$(1).conf' $(LUA) scripts/site_config.lua \
	if ! GLUON_SITEDIR='$(GLUON_SITEDIR)' GLUON_SITE_CONFIG='$(1).conf' $(LUA) -e 'assert(dofile("scripts/site_config.lua")(os.getenv("GLUON_SITE_CONFIG")))'; then
		|| (echo 'Your site configuration ($(1).conf) did not pass validation.'; false)
		echo 'Your site configuration ($(1).conf) did not pass validation'

		exit 1
	fi
endef
endef


list-targets: FORCE
list-targets: FORCE
	@$(foreach target,$(GLUON_TARGETS),echo '$(target)';)
	@for target in $(GLUON_TARGETS); do
		echo "$$target"
	done


lint: lint-editorconfig lint-lua lint-sh


GLUON_FEATURE_PACKAGES := $(shell scripts/features.sh '$(GLUON_FEATURES)' || echo '__ERROR__')
lint-editorconfig: FORCE
ifneq ($(filter __ERROR__,$(GLUON_FEATURE_PACKAGES)),)
	@scripts/lint-editorconfig.sh
$(error Error while evaluating GLUON_FEATURES)
endif


lint-lua: FORCE
	@scripts/lint-lua.sh

lint-sh: FORCE
	@scripts/lint-sh.sh


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_FEATURE_PACKAGES) $(GLUON_SITE_PACKAGES)))


config: FORCE
LUA := openwrt/staging_dir/hostpkg/bin/lua
	@$(CheckExternal)
	@$(CheckTarget)


	@$(GLUON_CONFIG_VARS) \
$(LUA):
		scripts/target_config.sh '$(GLUON_TARGET)' '$(GLUON_PACKAGES)' \
	+@
		> lede/.config
	+@$(LEDEMAKE) defconfig


	@$(GLUON_CONFIG_VARS) \
	scripts/module_check.sh
		scripts/target_config_check.sh '$(GLUON_TARGET)' '$(GLUON_PACKAGES)'


	$(GLUON_ENV) scripts/basic_openwrt_config.sh > openwrt/.config
	$(OPENWRTMAKE) defconfig
	$(OPENWRTMAKE) tools/install
	$(OPENWRTMAKE) package/lua/host/compile


LUA := lede/staging_dir/hostpkg/bin/lua


$(LUA):
config: $(LUA) FORCE
	@$(CheckExternal)
	+@

	scripts/module_check.sh
	$(CheckTarget)
	$(foreach conf,site $(patsubst $(GLUON_SITEDIR)/%.conf,%,$(wildcard $(GLUON_SITEDIR)/domains/*.conf)),\
		$(call CheckSite,$(conf)); \
	)

	$(OPENWRTMAKE) prepare-tmpinfo
	$(GLUON_ENV) $(LUA) scripts/target_config.lua > openwrt/.config
	$(OPENWRTMAKE) defconfig
	$(GLUON_ENV) $(LUA) scripts/target_config_check.lua


	+@[ -e lede/.config ] || $(LEDEMAKE) defconfig
	+@$(LEDEMAKE) tools/install
	+@$(LEDEMAKE) package/lua/host/install


prepare-target: config $(LUA) ;
container: FORCE
	@scripts/container.sh


all: prepare-target
	$(foreach conf,site $(patsubst $(GLUON_SITEDIR)/%.conf,%,$(wildcard $(GLUON_SITEDIR)/domains/*.conf)),$(call CheckSite,$(conf)))


	@scripts/clean_output.sh
all: config
	+@$(LEDEMAKE)
	+@
	@GLUON_SITEDIR='$(GLUON_SITEDIR)' scripts/copy_output.sh '$(GLUON_TARGET)'
	$(GLUON_ENV) $(LUA) scripts/clean_output.lua
	$(OPENWRTMAKE)
	$(GLUON_ENV) $(LUA) scripts/copy_output.lua


clean download: config
clean download: config
	+@$(LEDEMAKE) $@
	+@$(OPENWRTMAKE) $@


dirclean: FORCE
dirclean: FORCE
	+@[ -e lede/.config ] || $(LEDEMAKE) defconfig
	+@
	+@$(LEDEMAKE) dirclean
	[ -e openwrt/.config ] || $(OPENWRTMAKE) defconfig
	@rm -rf $(GLUON_TMPDIR) $(GLUON_OUTPUTDIR)
	$(OPENWRTMAKE) dirclean
	rm -rf $(GLUON_TMPDIR) $(GLUON_OUTPUTDIR)


manifest: $(LUA) FORCE
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)
	[ '$(GLUON_AUTOUPDATER_BRANCH)' ] || (echo 'Please set GLUON_AUTOUPDATER_BRANCH to create a manifest.'; false)
	@$(CheckExternal)
	echo '$(GLUON_PRIORITY)' | grep -qE '^([0-9]*\.)?[0-9]+$$' || (echo 'Please specify a numeric value for GLUON_PRIORITY to create a manifest.'; false)

	scripts/module_check.sh
	@( \

		echo 'BRANCH=$(GLUON_BRANCH)' && \
	(
		echo "DATE=$$($(LUA) scripts/rfc3339date.lua)" && \
		export $(GLUON_ENV)
		echo 'PRIORITY=$(GLUON_PRIORITY)' && \
		echo 'BRANCH=$(GLUON_AUTOUPDATER_BRANCH)'
		echo && \
		echo "DATE=$$($(LUA) scripts/rfc3339date.lua)"
		$(foreach GLUON_TARGET,$(GLUON_TARGETS), \
		echo 'PRIORITY=$(GLUON_PRIORITY)'
			GLUON_SITEDIR='$(GLUON_SITEDIR)' scripts/generate_manifest.sh '$(GLUON_TARGET)' && \
		echo
		) : \
		for target in $(GLUON_TARGETS); do
	) > 'tmp/$(GLUON_BRANCH).manifest.tmp'
			$(LUA) scripts/generate_manifest.lua "$$target"

		done
	@mkdir -p '$(GLUON_IMAGEDIR)/sysupgrade'
	) > 'tmp/$(GLUON_AUTOUPDATER_BRANCH).manifest.tmp'
	@mv 'tmp/$(GLUON_BRANCH).manifest.tmp' '$(GLUON_IMAGEDIR)/sysupgrade/$(GLUON_BRANCH).manifest'

	mkdir -p '$(GLUON_IMAGEDIR)/sysupgrade'
	mv 'tmp/$(GLUON_AUTOUPDATER_BRANCH).manifest.tmp' '$(GLUON_IMAGEDIR)/sysupgrade/$(GLUON_AUTOUPDATER_BRANCH).manifest'


FORCE: ;
FORCE: ;


.PHONY: FORCE
.PHONY: FORCE
.NOTPARALLEL:
.NOTPARALLEL:
.ONESHELL:
+47 −7
Original line number Original line Diff line number Diff line
Documentation (incomplete at this time, contribute if you can!) may be found at
[![Build Gluon](https://github.com/freifunk-gluon/gluon/actions/workflows/build-gluon.yml/badge.svg?branch=main)](https://github.com/freifunk-gluon/gluon/actions/workflows/build-gluon.yml)
https://gluon.readthedocs.org/.
[![License](https://img.shields.io/badge/License-BSD%202--Clause-orange.svg)](https://opensource.org/license/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

Gluon is a firmware framework to build preconfigured OpenWrt images for public mesh networks.

## Overview

Gluon provides an easy-to-use firmware for a public, decentral WLAN and/or wire based mesh network.
Common network capable devices, like smartphones, laptops or desktop PCs can connect to the mesh network and communicate over it, without the need of passwords for access and without the need of installing special software.
Additionally, internet access and merging mesh clouds can be accomplished over a WAN through VPN connected gateways.

Gluon's features include:

* a decentral mesh network
* easy configuration mode for less techy users
* community-specific technical settings and customizations through a common site.conf and site.mk
* ecdsa signature-based autoupdater
* node status web page
* publication of node information + statistics through respondd
* a variety of preconfigured mesh and VPN protocols:


Supported mesh protocols:

* batman-adv (BATMAN IV fully, BATMAN V partially)
* OLSRv2 (partially)


Supported protocols for node-to-node connections:

* WLAN: 802.11s (with forwarding disabled)
* WAN: VPNs via fastd and Wireguard
* LAN: via VXLAN

## Getting started

We have a huge amount of documentation over at https://gluon.readthedocs.io/.


If you're new to Gluon and ready to get your feet wet, have a look at the
If you're new to Gluon and ready to get your feet wet, have a look at the
[Getting Started Guide](https://gluon.readthedocs.org/en/latest/user/getting_started.html).
[Getting Started Guide](https://gluon.readthedocs.io/en/latest/user/getting_started.html).


**Gluon IRC channel: `#gluon` in [hackint](https://hackint.org/)**
Gluon's developers frequent an IRC chatroom at [#gluon](ircs://irc.hackint.org/#gluon)
on [hackint](https://hackint.org/). There is also a [webchat](https://chat.hackint.org/?join=gluon)
that allows for uncomplicated access from within your browser. This channel is also available as a bridged Matrix Room at [#gluon:hackint.org](https://matrix.to/#/#gluon:hackint.org).


## Issues & Feature requests
## Issues & Feature requests


@@ -17,12 +57,12 @@ the future development of Gluon.


## Use a release!
## Use a release!


Please refrain from using the `master` branch for anything else but development purposes!
Please refrain from using the `main` branch for anything else but development purposes!
Use the most recent release instead. You can list all releases by running `git tag`
Use the most recent release instead. You can list all releases by running `git tag`
and switch to one by running `git checkout v2017.1.5 && make update`.
and switch to one by running `git checkout v2023.2.5 && make update`.


If you're using the autoupdater, do not autoupdate nodes with anything but releases.
If you're using the autoupdater, do not autoupdate nodes with anything but releases.
If you upgrade using random master commits the nodes *will break* eventually.
If you upgrade using random main commits the nodes *might break* eventually.


## Mailinglist
## Mailinglist


+23 −0
Original line number Original line Diff line number Diff line
#!/usr/bin/env bash

# For a List of pre-installed packages on the runner image see
# https://github.com/actions/runner-images/tree/main?tab=readme-ov-file#available-images

echo "Disk space before cleanup"
df -h

# Remove packages not required to run the Gluon build CI
sudo apt-get -y remove \
	dotnet-* \
	firefox \
	google-chrome-stable \
	kubectl \
	microsoft-edge-stable \
	temurin-*-jdk

# Remove Android SDK tools
sudo rm -rf /usr/local/lib/android

echo "Disk space after cleanup"
df -h
Original line number Original line Diff line number Diff line
#!/usr/bin/env python3

# Update target filters using
#   make update-ci

import re
import os
import sys
import json

# these changes trigger rebuilds on all targets
common = [
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
]

# these changes are only built on x86-64
extra = [
    "contrib/ci/minimal-site/**",
    "package/**"
]

_filter = dict()

# INCLUDE_PATTERN matches:
# include '...'
# include "..."
# include("...")
# include('...')
INCLUDE_PATTERN = "^\\s*include *\\(? *[\"']([^\"']+)[\"']"

# construct filters map from stdin
for target in sys.stdin:
    target = target.strip()

    _filter[target] = [
        f"targets/{target}"
    ] + common

    target_file = os.path.join(os.environ['GLUON_TARGETSDIR'], target)
    with open(target_file) as f:
        includes = re.findall(INCLUDE_PATTERN, f.read(), re.MULTILINE)
        _filter[target].extend([f"targets/{i}" for i in includes])

    if target == "x86-64":
        _filter[target].extend(extra)

# print filters to stdout in json format, because json is stdlib and yaml compatible.
print(json.dumps(_filter, indent=2))
+17 −0
Original line number Original line Diff line number Diff line
#!/bin/sh

set -e

export BROKEN=1
export GLUON_AUTOREMOVE=1
export GLUON_DEPRECATED=1
export GLUON_SITEDIR="contrib/ci/minimal-site"
export GLUON_TARGET="$1"
export BUILD_LOG=1

BUILD_THREADS="$(($(nproc) + 1))"

echo "Building Gluon with $BUILD_THREADS threads"

make update
make -j$BUILD_THREADS V=s
+16 −0
Original line number Original line Diff line number Diff line
#!/usr/bin/env bash

echo "-- CPU --"
cat /proc/cpuinfo

echo "-- Memory --"
cat /proc/meminfo

echo "-- Disk --"
df -h

echo "-- Kernel --"
uname -a

echo "-- Network --"
ip addr
+146 −0
Original line number Original line Diff line number Diff line
#!/usr/bin/env python3

import argparse
import json
import sys
from enum import Enum

# Enum Class for checking image size
class ImageSizeCheck(Enum):
    OK = "OK"
    TOO_BIG = "TOO_BIG"
    IGNORED = "IGNORED"
    UNKNOWN = "UNKNOWN"


# Some devices pad their images to IMAGE_SIZE and apply a firmware header.
# Exclude this from the image size check.
excluded_devices = [
    "tplink_cpe210-v1",
    "tplink_cpe210-v2",
    "tplink_cpe210-v3",
    "tplink_cpe220-v3",
    "tplink_cpe510-v1",
    "tplink_cpe510-v2",
    "tplink_cpe510-v3",
    "tplink_cpe710-v1",
    "tplink_wbs210-v1",
    "tplink_wbs210-v2",
    "tplink_wbs510-v1"
]


def open_json(file_path):
    with open(file_path, 'r') as f:
        return json.load(f)


def load_openwrt_profile_json(json_path):
    profiles = []
    profile_json = open_json(json_path)
    for profile_name, profile_data in profile_json["profiles"].items():
        device_profile = {
            "name": profile_name,
        }
        if "image" in profile_data.get("file_size_limits", {}):
            device_profile["max_image_size"] = profile_data["file_size_limits"]["image"]

        for image in profile_data["images"]:
            if image["type"] != "sysupgrade":
                continue
            if "size" in image:
                device_profile["image_size"] = image["size"]
        
        profiles.append(device_profile)
    
    return profiles


def check_image_size_below_limit(profile, overhead=0):
    # Skip devices that pad their images
    if profile["name"] in excluded_devices:
        return ImageSizeCheck.IGNORED

    if "max_image_size" in profile and "image_size" in profile:
        if profile["image_size"] + (overhead * 1024) > profile["max_image_size"]:
            return ImageSizeCheck.TOO_BIG
        else:	
            return ImageSizeCheck.OK
    
    return ImageSizeCheck.UNKNOWN


def print_github_actions_warning(message):
    print('::warning::{}'.format(message))


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Check image size of OpenWrt profiles')
    parser.add_argument(
        'profile_json',
        help='Path to profile.json',
        nargs='+'
    )
    parser.add_argument(
        '--github-actions',
        help='Generate warnings for use with GitHub Actions',
        action='store_true'
    )
    parser.add_argument(
        '--overhead',
        type=int,
        help='Additional size to add to the image size in kilobyte',
        default=0
    )
    args = parser.parse_args()

    if args.profile_json is None:
        print('Error: profile.json not specified')
        sys.exit(1)
    
    # Load all profile.json files
    profiles = []
    for profile_file in args.profile_json:
        profiles.extend(load_openwrt_profile_json(profile_file))

    # Initialize results with all available ImageSizeCheck values
    results = {}
    for check_result in ImageSizeCheck:
        results[check_result] = []

    for profile in profiles:
        check_result = check_image_size_below_limit(profile, args.overhead)
        results[check_result].append(profile)
    
    for check_result, profiles in results.items():
        if len(profiles) == 0:
            continue

        # Group by result type for GitHub Actions
        if args.github_actions:
            print('::group::{}'.format(check_result.value))

        for profile in profiles:
            if check_result == ImageSizeCheck.TOO_BIG:
                msg = 'Image size of profile {} is too big ({} > {})'.format(
                    profile["name"],
                    profile["image_size"] + (args.overhead * 1024),
                    profile["max_image_size"])
                if args.github_actions:
                    print_github_actions_warning(msg)
                else:
                    print("Warning: {}".format(msg))
            elif check_result == ImageSizeCheck.UNKNOWN:
                msg = 'Image size of profile {} is unknown'.format(
                    profile["name"])
                print(msg)
            elif check_result == ImageSizeCheck.IGNORED:
                msg = 'Image size of profile {} is ignored (Image size {})'.format(
                    profile["name"], profile.get("image_size", "unknown"))
                print(msg)
            else:
                msg = 'Image size of profile {} is OK ({} < {})'.format(
                    profile["name"], 
                    profile["image_size"] + (args.overhead * 1024),
                    profile["max_image_size"])
                print(msg)
+1 −0
Original line number Original line Diff line number Diff line
../../../docs/site-example/i18n/
 No newline at end of file
Original line number Original line Diff line number Diff line
features {
	'autoupdater',
	'ebtables-filter-multicast',
	'ebtables-filter-ra-dhcp',
	'ebtables-limit-arp',
	'mesh-batman-adv-15',
	'mesh-vpn-fastd',
	'respondd',
	'status-page',
	'web-advanced',
	'web-wizard',
}

if not device_class('tiny') then
	features {'wireless-encryption-wpa3'}
end
+1 −0
Original line number Original line Diff line number Diff line
../../../docs/site-example/modules
 No newline at end of file
+180 −0
Original line number Original line Diff line number Diff line
-- This is an example site configuration
--
-- 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 within the mesh.
  -- prefix6 is required, prefix4 can be omitted if next_node.ip4
  -- is not set.
  prefix4 = '10.0.0.0/20',
  prefix6 = 'fd::/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',
    },
    mesh = {
      -- Adjust these values!
      id = 'ueH3uXjdp',
      mcast_rate = 12000,
    },
  },

  mesh = {
    vxlan = true,
    batman_adv = {
      routing_algo = 'BATMAN_IV',
    },
  },

  -- 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 = {
    -- 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,

    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 = {
        },
      },
    },
  },
}
+1 −0
Original line number Original line Diff line number Diff line
../../../docs/site-example/site.mk
 No newline at end of file
+1 −0
Original line number Original line Diff line number Diff line
../minimal-site/i18n
 No newline at end of file
Original line number Original line Diff line number Diff line
features {
	'autoupdater',
	'ebtables-filter-multicast',
	'ebtables-filter-ra-dhcp',
	'ebtables-limit-arp',
	'mesh-olsrd',
	'mesh-vpn-fastd',
	'respondd',
	'status-page',
	'web-advanced',
	'web-wizard',
}

packages {
	'iwinfo',
}

if not device_class('tiny') then
	features {'wireless-encryption-wpa3'}
end
+1 −0
Original line number Original line Diff line number Diff line
../minimal-site/modules
 No newline at end of file
+176 −0
Original line number Original line Diff line number Diff line
-- This is an example site configuration
--
-- 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 = {
        },
      },
    },
  },
}
+29 −0
Original line number Original line Diff line number Diff line
##	gluon site.mk makefile example

##	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
+26 −13
Original line number Original line Diff line number Diff line
#!/bin/bash
#!/usr/bin/env bash


# Script to output the dependency graph of Gluon's packages
# Script to output the dependency graph of Gluon's packages
# Limitations:
# 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
#  * Doesn't show dependencies through virtual packages correctly



set -e

shopt -s nullglob
shopt -s nullglob




@@ -25,19 +23,34 @@ print_dep() {
	echo "$(escape_name "$1") -> $(escape_name "$2");"
	echo "$(escape_name "$1") -> $(escape_name "$2");"
}
}


echo 'digraph G {'
print_package() {

	local package="$1" depends="$2"
for makefile in ./package/*/Makefile; do
	# shellcheck disable=SC2086
	dir="$(dirname "$makefile")"
	set -- $depends
	package="$(basename "$dir")"

	deps=$(grep -w DEPENDS "$makefile" | cut -d= -f2 | tr -d +)


	print_node "$package"
	print_node "$package"
	for dep in $deps; do
	for dep in "$@"; do
		print_node "$dep"
		print_node "$dep"
		print_dep "$package" "$dep"
		print_dep "$package" "$dep"
	done
	done
}

make -C openwrt -s prepare-tmpinfo

echo 'digraph G {'

cat ./openwrt/tmp/info/.packageinfo-feeds_gluon_base_* | while read -r key value; do
	case "$key" in
	'Package:')
		package="$value"
		;;
	'Depends:')
		depends="${value//+/}"
		;;
	'@@')
		print_package "$package" "$depends"
		;;
	esac
done | sort -u
done | sort -u


popd >/dev/null
popd >/dev/null
+47 −0
Original line number Original line Diff line number Diff line
FROM debian:bookworm-slim

ARG TARGETOS
ARG TARGETARCH

ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential \
    ca-certificates \
    clang \
    ecdsautils \
    file \
    gawk \
    git \
    libelf-dev \
    libncurses5-dev \
    libnss-unknown \
    libssl-dev \
    llvm \
    lua-check \
    openssh-client \
    python3 \
    python3-dev \
    python3-pyelftools \
    python3-setuptools \
    qemu-utils \
    rsync \
    shellcheck \
    swig \
    time \
    unzip \
    wget \
    zlib1g-dev \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

RUN mkdir /tmp/ec &&\
    wget -O /tmp/ec/ec-${TARGETOS}-${TARGETARCH}.tar.gz https://github.com/editorconfig-checker/editorconfig-checker/releases/download/2.7.0/ec-${TARGETOS}-${TARGETARCH}.tar.gz &&\
    tar -xvzf /tmp/ec/ec-${TARGETOS}-${TARGETARCH}.tar.gz &&\
    mv bin/ec-${TARGETOS}-${TARGETARCH} /usr/local/bin/editorconfig-checker &&\
    rm -rf /tmp/ec

RUN useradd -m -d /gluon -u 100 -g 100 -o gluon
USER gluon

VOLUME /gluon
WORKDIR /gluon
Original line number Original line Diff line number Diff line
@@ -4,7 +4,7 @@ use strict;
use warnings;
use warnings;
use Text::Balanced qw(extract_bracketed extract_delimited extract_tagged);
use Text::Balanced qw(extract_bracketed extract_delimited extract_tagged);


@ARGV >= 1 || die "Usage: $0 <source direcory>\n";
@ARGV >= 1 || die "Usage: $0 <source directory>\n";




my %stringtable;
my %stringtable;
@@ -48,7 +48,7 @@ if( open F, "find @ARGV -type f '(' -name '*.html' -o -name '*.lua' ')' |" )


			my $text = $raw;
			my $text = $raw;


			while( $text =~ s/ ^ .*? (?:translate|translatef|i18n|_) [\n\s]* \( /(/sgx )
			while( $text =~ s/ ^ .*? (?:translate|translatef|_) [\n\s]* \( /(/sgx )
			{
			{
				( my $code, $text ) = extract_bracketed($text, q{('")});
				( my $code, $text ) = extract_bracketed($text, q{('")});


Original line number Original line Diff line number Diff line
#!/bin/bash
#!/usr/bin/env bash


set -e
# Script to list all upgrade scripts in a clear manner
# Script to list all upgrade scripts in a clear manner
# Limitations:
# Limitations:
#  * Does only show scripts of packages whose `files'/`luasrc' directories 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)
@@ -27,7 +28,7 @@ fi


pushd "$(dirname "$0")/.." >/dev/null
pushd "$(dirname "$0")/.." >/dev/null


find ./package packages -name Makefile | while read makefile; do
find ./package packages -name Makefile | grep -v '^packages/packages/' | while read -r makefile; do
	dir="$(dirname "$makefile")"
	dir="$(dirname "$makefile")"


	pushd "$dir" >/dev/null
	pushd "$dir" >/dev/null
@@ -36,13 +37,12 @@ find ./package packages -name Makefile | while read makefile; do
	dirname="$(dirname "$dir" | cut -d/ -f 3-)"
	dirname="$(dirname "$dir" | cut -d/ -f 3-)"
	package="$(basename "$dir")"
	package="$(basename "$dir")"


	for file in "${SUFFIX1}"/*; do
	for file in "${SUFFIX1}"/* "${SUFFIX2}"/*; do
		echo "${GREEN}$(basename "${file}")${RESET}" "(${BLUE}${repo}${RESET}/${dirname}${dirname:+/}${RED}${package}${RESET}/${SUFFIX1})"
		basename="$(basename "${file}")"
	done
		suffix="$(dirname "${file}")"
	for file in "${SUFFIX2}"/*; do
		printf "%s\t%s\n" "${basename}" "${BLUE}${repo}${RESET}/${dirname}${dirname:+/}${RED}${package}${RESET}/${suffix}/${GREEN}${basename}${RESET}"
		echo "${GREEN}$(basename "${file}")${RESET}" "(${BLUE}${repo}${RESET}/${dirname}${dirname:+/}${RED}${package}${RESET}/${SUFFIX2})"
	done
	done
	popd >/dev/null
	popd >/dev/null
done | sort
done | sort | cut -f2-


popd >/dev/null
popd >/dev/null

contrib/push_pkg.sh

0 → 100755
+149 −0
Original line number Original line Diff line number Diff line
#!/bin/sh

set -e

topdir="$(realpath "$(dirname "${0}")/../openwrt")"

# defaults to qemu run script
ssh_host=localhost
build_only=0
preserve_config=1

print_help() {
	echo "$0 [OPTIONS] PACKAGE_DIR [PACKAGE_DIR] ..."
	echo ""
	echo " -h          print this help"
	echo " -r HOST     use a remote machine as target machine. By default if this"
	echo "             option is not given, push_pkg.sh will use a locally"
	echo "             running qemu instance started by run_qemu.sh."
	echo " -p PORT     use PORT as ssh port (default is 22)"
	echo " -b          build only, do not push"
	echo " -P          do not preserve /etc/config. By default, if a package"
	echo "             defines a config file in /etc/config, this config file"
	echo "             will be preserved. If you specify this flag, the package"
	echo "             default will be installed instead."
	echo ""
	echo ' To change gluon variables, run e.g. "make config GLUON_MINIFY=0"'
	echo ' because then the gluon logic will be triggered, and openwrt/.config'
	echo ' will be regenerated. The variables from openwrt/.config are already'
	echo ' automatically used for this script.'
	echo
}

while getopts "p:r:hbP" opt
do
	case $opt in
		P) preserve_config=0;;
		p) ssh_port="${OPTARG}";;
		r) ssh_host="${OPTARG}"; [ -z "$ssh_port" ] && ssh_port=22;;
		b) build_only=1;;
		h) print_help; exit 0;;
		*) ;;
	esac
done
shift $(( OPTIND - 1 ))

[ -z "$ssh_port" ] && ssh_port=2223

if [ "$build_only" -eq 0 ]; then
	remote_info=$(ssh -p "${ssh_port}" "root@${ssh_host}" '
		source /etc/os-release
		printf "%s\\t%s\\n" "$OPENWRT_BOARD" "$OPENWRT_ARCH"
	')
	REMOTE_OPENWRT_BOARD="$(echo "$remote_info" | cut -f 1)"
	REMOTE_OPENWRT_ARCH="$(echo "$remote_info" | cut -f 2)"

	# check target
	if ! grep -q "CONFIG_TARGET_ARCH_PACKAGES=\"${REMOTE_OPENWRT_ARCH}\"" "${topdir}/.config"; then
		echo "Configured OpenWrt Target is not matching with the target machine!" 1>&2
		echo
		printf "%s" "    Configured architecture: " 1>&2
		grep "CONFIG_TARGET_ARCH_PACKAGES" "${topdir}/.config" 1>&2
		echo "Target machine architecture: ${REMOTE_OPENWRT_ARCH}" 1>&2
		echo 1>&2
		echo "To switch the local with the run with the corresponding GLUON_TARGET:"  1>&2
		echo "  make GLUON_TARGET=... config" 1>&2
		exit 1
	fi
fi

if [ $# -lt 1 ]; then
	echo ERROR: Please specify a PACKAGE_DIR. For example:
	echo
	echo " \$ $0 package/gluon-core"
	exit 1
fi

while [ $# -gt 0 ]; do

	pkgdir="$1"; shift
	echo "Package: ${pkgdir}"

	if ! [ -f "${pkgdir}/Makefile" ]; then
		echo "ERROR: ${pkgdir} does not contain a Makefile"
		exit 1
	fi

	if ! grep -q BuildPackage "${pkgdir}/Makefile"; then
		echo "ERROR: ${pkgdir}/Makefile does not contain a BuildPackage command"
		exit 1
	fi

	opkg_packages="$(make TOPDIR="${topdir}" -C "${pkgdir}" DUMP=1 | awk '/^Package: / { print $2 }')"

	search_package() {
		find "$2" -name "$1_*.ipk" -printf '%f\n'
	}

	make TOPDIR="${topdir}" -C "${pkgdir}" clean
	make TOPDIR="${topdir}" -C "${pkgdir}" compile

	if [ "$build_only" -eq 1 ]; then
		continue
	fi

	# IPv6 addresses need brackets around the ${ssh_host} for scp!
	if echo "${ssh_host}" | grep -q :; then
		BL=[
		BR=]
	fi

	for pkg in ${opkg_packages}; do

		for feed in "${topdir}/bin/packages/${REMOTE_OPENWRT_ARCH}/"*/ "${topdir}/bin/targets/${REMOTE_OPENWRT_BOARD}/packages/"; do
			printf "%s" "searching ${pkg} in ${feed}: "
			filename=$(search_package "${pkg}" "${feed}")
			if [ -n "${filename}" ]; then
				echo found!
				break
			else
				echo not found
			fi
		done

		if [ "$preserve_config" -eq 0 ]; then
			opkg_flags=" --force-maintainer"
		fi

		# shellcheck disable=SC2029
		if [ -n "$filename" ]; then
			scp -O -P "${ssh_port}" "$feed/$filename" "root@${BL}${ssh_host}${BR}:/tmp/${filename}"
			ssh -p "${ssh_port}" "root@${ssh_host}" "
				set -e
				echo Running opkg:
				opkg install --force-reinstall ${opkg_flags} '/tmp/${filename}'
				rm '/tmp/${filename}'
				gluon-reconfigure
			"
		else
			# Some packages (e.g. procd-seccomp) seem to contain BuildPackage commands
			# which do not generate *.ipk files. Till this point, I am not aware why
			# this is happening. However, dropping a warning if the corresponding
			# *.ipk is not found (maybe due to other reasons as well), seems to
			# be more reasonable than aborting. Before this commit, the command
			# has failed.
			echo "Warning: ${pkg}*.ipk not found! Ignoring." 1>&2
		fi

	done
done

contrib/run_qemu.sh

0 → 100755
+15 −0
Original line number Original line Diff line number Diff line
#!/bin/sh

# Note: You can exit the qemu instance by first pressing "CTRL + a" then "c".
#       Then you enter the command mode of qemu and can exit by typing "quit".

qemu-system-x86_64 \
	-d 'cpu_reset' \
	-enable-kvm \
	-gdb tcp::1234 \
	-nographic \
	-netdev user,id=wan,hostfwd=tcp::2223-10.0.2.15:22 \
	-device virtio-net-pci,netdev=wan,addr=0x06,id=nic1 \
	-netdev user,id=lan,hostfwd=tcp::6080-192.168.1.1:80,hostfwd=tcp::2222-192.168.1.1:22,net=192.168.1.100/24 \
	-device virtio-net-pci,netdev=lan,addr=0x05,id=nic2 \
	"$@"
+18 −7
Original line number Original line Diff line number Diff line
@@ -2,7 +2,7 @@


set -e
set -e


if [ $# -ne 2 -o "-h" = "$1" -o "--help" = "$1" -o ! -r "$1" -o ! -r "$2" ]; then
if [ $# -ne 2 ] || [ "-h" = "$1" ] || [ "--help" = "$1" ] || [ ! -r "$1" ] || [ ! -r "$2" ]; then
	cat <<EOHELP
	cat <<EOHELP
Usage: $0 <secret> <manifest>
Usage: $0 <secret> <manifest>


@@ -15,7 +15,7 @@ The script may be performed multiple times to the same document
to indicate an approval by multiple developers.
to indicate an approval by multiple developers.


See also
See also
 * ecdsautils on https://github.com/tcatm/ecdsautils
 * ecdsautils on https://github.com/freifunk-gluon/ecdsautils


EOHELP
EOHELP
	exit 1
	exit 1
@@ -29,11 +29,22 @@ lower="$(mktemp)"


trap 'rm -f "$upper" "$lower"' EXIT
trap 'rm -f "$upper" "$lower"' EXIT


awk 'BEGIN    { sep=0 }
awk 'BEGIN    {
     /^---$/ { sep=1; next }
	sep = 0
              { if(sep==0) print > "'"$upper"'";
}
                else       print > "'"$lower"'"}' \

    "$manifest"
/^---$/ {
	sep = 1;
	next
}

{
	if(sep == 0) {
		print > "'"$upper"'"
	} else {
		print > "'"$lower"'"
	}
}' "$manifest"


ecdsasign "$upper" < "$SECRET" >> "$lower"
ecdsasign "$upper" < "$SECRET" >> "$lower"


+26 −15
Original line number Original line Diff line number Diff line
#!/bin/sh
#!/bin/sh


if [ $# -eq 0 -o "-h" = "$1" -o "-help" = "$1" -o "--help" = "$1" ]; then
if [ $# -eq 0 ] || [ "-h" = "$1" ] || [ "-help" = "$1" ] || [ "--help" = "$1" ]; then
	cat <<EOHELP
	cat <<EOHELP
Usage: $0 <public> <signed manifest>
Usage: $0 <public> <signed manifest>


@@ -8,8 +8,8 @@ sigtest.sh checks if a manifest is signed by the public key <public>. There is
no output, success or failure is indicated via the return code.
no output, success or failure is indicated via the return code.


See also:
See also:
 * ecdsautils in https://github.com/tcatm/ecdsautils
 * ecdsautils in https://github.com/freifunk-gluon/ecdsautils
 * http://gluon.readthedocs.org/en/latest/features/autoupdater.html
 * https://gluon.readthedocs.io/en/latest/features/autoupdater.html


EOHELP
EOHELP
	exit 1
	exit 1
@@ -21,13 +21,24 @@ upper="$(mktemp)"
lower="$(mktemp)"
lower="$(mktemp)"
ret=1
ret=1


awk "BEGIN    { sep=0 }
awk 'BEGIN    {
    /^---\$/ { sep=1; next }
	sep = 0
              { if(sep==0) print > \"$upper\";
}
                else       print > \"$lower\"}" \
    "$manifest"


while read line
/^---$/ {
	sep = 1;
	next
}

{
	if(sep == 0) {
		print > "'"$upper"'"
	} else {
		print > "'"$lower"'"
	}
}' "$manifest"

while read -r line
do
do
	if ecdsaverify -s "$line" -p "$public" "$upper"; then
	if ecdsaverify -s "$line" -p "$public" "$upper"; then
		ret=0
		ret=0
+10 −168
Original line number Original line Diff line number Diff line
# Makefile for Sphinx documentation
# Minimal makefile for Sphinx documentation
#
#


# You can set these variables from the command line.
# You can set these variables from the command line.
SPHINXOPTS    =
SPHINXOPTS    = -W --keep-going
SPHINXBUILD   = sphinx-build
SPHINXBUILD   = sphinx-build
PAPER         =
SOURCEDIR     = .
BUILDDIR      = _build
BUILDDIR      = _build


# User-friendly check for sphinx-build
# Put it first so that "make" without argument is like "make help".
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif

# Internal variables.
PAPEROPT_a4     = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .

.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext

help:
help:
	@echo "Please use \`make <target>' where <target> is one of"
	@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
	@echo "  html       to make standalone HTML files"
	@echo "  dirhtml    to make HTML files named index.html in directories"
	@echo "  singlehtml to make a single large HTML file"
	@echo "  pickle     to make pickle files"
	@echo "  json       to make JSON files"
	@echo "  htmlhelp   to make HTML files and a HTML help project"
	@echo "  qthelp     to make HTML files and a qthelp project"
	@echo "  devhelp    to make HTML files and a Devhelp project"
	@echo "  epub       to make an epub"
	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
	@echo "  latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
	@echo "  text       to make text files"
	@echo "  man        to make manual pages"
	@echo "  texinfo    to make Texinfo files"
	@echo "  info       to make Texinfo files and run them through makeinfo"
	@echo "  gettext    to make PO message catalogs"
	@echo "  changes    to make an overview of all changed/added/deprecated items"
	@echo "  xml        to make Docutils-native XML files"
	@echo "  pseudoxml  to make pseudoxml-XML files for display purposes"
	@echo "  linkcheck  to check all external links for integrity"
	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"

clean:
	rm -rf $(BUILDDIR)/*

html:
	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
	@echo
	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."

dirhtml:
	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
	@echo
	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."

singlehtml:
	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
	@echo
	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."

pickle:
	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
	@echo
	@echo "Build finished; now you can process the pickle files."

json:
	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
	@echo
	@echo "Build finished; now you can process the JSON files."

htmlhelp:
	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
	@echo
	@echo "Build finished; now you can run HTML Help Workshop with the" \
	      ".hhp project file in $(BUILDDIR)/htmlhelp."

qthelp:
	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
	@echo
	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Gluon.qhcp"
	@echo "To view the help file:"
	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Gluon.qhc"

devhelp:
	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
	@echo
	@echo "Build finished."
	@echo "To view the help file:"
	@echo "# mkdir -p $$HOME/.local/share/devhelp/Gluon"
	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Gluon"
	@echo "# devhelp"

epub:
	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
	@echo
	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."

latex:
	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
	@echo
	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
	@echo "Run \`make' in that directory to run these through (pdf)latex" \
	      "(use \`make latexpdf' here to do that automatically)."

latexpdf:
	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
	@echo "Running LaTeX files through pdflatex..."
	$(MAKE) -C $(BUILDDIR)/latex all-pdf
	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."

latexpdfja:
	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
	@echo "Running LaTeX files through platex and dvipdfmx..."
	$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."

text:
	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
	@echo
	@echo "Build finished. The text files are in $(BUILDDIR)/text."

man:
	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
	@echo
	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."

texinfo:
	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
	@echo
	@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
	@echo "Run \`make' in that directory to run these through makeinfo" \
	      "(use \`make info' here to do that automatically)."

info:
	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
	@echo "Running Texinfo files through makeinfo..."
	make -C $(BUILDDIR)/texinfo info
	@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."

gettext:
	$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
	@echo
	@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."

changes:
	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
	@echo
	@echo "The overview file is in $(BUILDDIR)/changes."

linkcheck:
	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
	@echo
	@echo "Link check complete; look for any errors in the above output " \
	      "or in $(BUILDDIR)/linkcheck/output.txt."

doctest:
	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
	@echo "Testing of doctests in the sources finished, look at the " \
	      "results in $(BUILDDIR)/doctest/output.txt."


xml:
.PHONY: help Makefile
	$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
	@echo
	@echo "Build finished. The XML files are in $(BUILDDIR)/xml."


pseudoxml:
# Catch-all target: route all unknown targets to Sphinx using the new
	$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
# "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
	@echo
%: Makefile
	@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+3 −0
Original line number Original line Diff line number Diff line
.strike {
	text-decoration: line-through;
}
+102 −175
Original line number Original line Diff line number Diff line
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
#
#
# Gluon documentation build configuration file, created by
# Configuration file for the Sphinx documentation builder.
# sphinx-quickstart on Wed Jan 29 00:45:53 2014.
#
#
# This file is execfile()d with the current directory set to its
# This file does only contain a selection of the most common options. For a
# containing dir.
# full list see the documentation:
#
# http://www.sphinx-doc.org/en/master/config
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.


import sys
# -- Path setup --------------------------------------------------------------
import os


# If extensions (or modules to document with autodoc) are in another directory,
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
# sys.path.insert(0, os.path.abspath('.'))


# -- General configuration ------------------------------------------------

# -- Project information -----------------------------------------------------

project = 'Gluon'
copyright = 'Project Gluon'
author = 'Project Gluon'

# The short X.Y version
version = '2023.2.5'
# The full version, including alpha/beta/rc tags
release = version


# -- General configuration ---------------------------------------------------


# If your documentation needs a minimal Sphinx version, state it here.
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# needs_sphinx = '1.0'


# Add any Sphinx extension module names here, as strings. They can be
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
# ones.
extensions = [
extensions = [
    'sphinx.ext.mathjax',
]
]


# Add any paths that contain templates here, relative to this directory.
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
templates_path = ['_templates']


# The suffix of source filenames.
# The suffix(es) of source filenames.
source_suffix = '.rst'
# You can specify multiple suffix as a list of string:

#
# The encoding of source files.
# source_suffix = ['.rst', '.md']
#source_encoding = 'utf-8-sig'
source_suffix = {'.rst': 'restructuredtext'}


# The master toctree document.
# The master toctree document.
master_doc = 'index'
master_doc = 'index'


# General information about the project.
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 = '2017.1+'
# The full version, including alpha/beta/rc tags.
release = '2017.1+'

# The language for content autogenerated by Sphinx. Refer to documentation
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
# for a list of supported languages.
#language = None
#

# This is also used if you do content translation via gettext catalogs.
# There are two options for replacing |today|: either, you set today to some
# Usually you set "language" from the command line for these cases.
# non-false value, then it is used:
language = 'en'
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'


# List of patterns, relative to source directory, that match files and
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# This pattern also affects html_static_path and html_extra_path.

exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None

# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True

# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True

# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False


# The name of the Pygments (syntax highlighting) style to use.
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
pygments_style = None


# A list of ignored prefixes for module index sorting.
# Don't highlight code blocks unless requested explicitly
#modindex_common_prefix = []
highlight_language = 'none'


# If true, keep warnings as "system message" paragraphs in the built documents.
# Ignore links to the config mode, as well as anchors on on hackint, which are
#keep_warnings = False
# used to mark channel names and do not exist. Regular links are not effected.
linkcheck_ignore = [
    'http://192.168.1.1',
    'https://chat.hackint.org'
]




# -- Options for HTML output ----------------------------------------------
# -- Options for HTML output -------------------------------------------------


# The theme to use for HTML and HTML Help pages.  See the documentation for
# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
# a list of builtin themes.
#html_theme = 'default'
#
html_theme = 'sphinx_rtd_theme'


# Theme options are theme-specific and customize the look and feel of a theme
# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# further.  For a list of options available for each theme, see the
# documentation.
# documentation.
#
# html_theme_options = {}
# html_theme_options = {}


# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []

# The name for this set of Sphinx documents.  If None, it defaults to
# "<project> v<release> documentation".
#html_title = None

# A shorter title for the navigation bar.  Default is the same as html_title.
#html_short_title = None

# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None

# The name of an image file (within the static path) to use as favicon of the
# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None

# Add any paths that contain custom static files (such as style sheets) here,
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
# so a file named "default.css" will overwrite the builtin "default.css".
#html_static_path = ['_static']
#

html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []

# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'

# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True


# Custom sidebar templates, maps document names to template names.
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# The default sidebars (for documents that don't match any pattern) are
# defined by theme itself.  Builtin themes are using these templates by
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
# 'searchbox.html']``.
#
# html_sidebars = {}
# html_sidebars = {}


# Additional templates that should be rendered to pages, maps page names to
# These paths are either relative to html_static_path
# template names.
# or fully qualified paths (eg. https://...)
#html_additional_pages = {}
html_css_files = ['css/custom.css']

# If false, no module index is generated.
#html_domain_indices = True


# If false, no index is generated.
#html_use_index = True


# If true, the index is split into individual pages for each letter.
# -- Options for HTMLHelp output ---------------------------------------------
#html_split_index = False

# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True

# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True

# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True

# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it.  The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''

# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None


# Output file base name for HTML help builder.
# Output file base name for HTML help builder.
htmlhelp_basename = 'Gluondoc'
htmlhelp_basename = 'Gluondoc'




# -- Options for LaTeX output ---------------------------------------------
# -- Options for LaTeX output ------------------------------------------------


latex_elements = {
latex_elements = {
    # The paper size ('letterpaper' or 'a4paper').
    # The paper size ('letterpaper' or 'a4paper').
    #
    # 'papersize': 'letterpaper',
    # 'papersize': 'letterpaper',


    # The font size ('10pt', '11pt' or '12pt').
    # The font size ('10pt', '11pt' or '12pt').
    #
    # 'pointsize': '10pt',
    # 'pointsize': '10pt',


    # Additional stuff for the LaTeX preamble.
    # Additional stuff for the LaTeX preamble.
    #
    # 'preamble': '',
    # 'preamble': '',

    # Latex figure (float) alignment
    #
    # 'figure_align': 'htbp',
}
}


# Grouping the document tree into LaTeX files. List of tuples
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# (source start file, target name, title,
#  author, documentclass [howto, manual, or own class]).
#  author, documentclass [howto, manual, or own class]).
latex_documents = [
latex_documents = [
  ('index', 'Gluon.tex', 'Gluon Documentation',
    (master_doc, 'Gluon.tex', 'Gluon Documentation',
    'Project Gluon', 'manual'),
    'Project Gluon', 'manual'),
]
]


# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None

# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False

# If true, show page references after internal links.
#latex_show_pagerefs = False

# If true, show URL addresses after external links.
#latex_show_urls = False

# Documents to append as an appendix to all manuals.
#latex_appendices = []


# If false, no module index is generated.
# -- Options for manual page output ------------------------------------------
#latex_domain_indices = True


# -- Options for manual page output ---------------------------------------


# One entry per manual page. List of tuples
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
# (source start file, name, description, authors, manual section).
man_pages = [
man_pages = [
    ('index', 'gluon', 'Gluon Documentation',
    (master_doc, 'gluon', 'Gluon Documentation',
     ['Project Gluon'], 1)
    [author], 1)
]
]


# If true, show URL addresses after external links.
#man_show_urls = False



# -- Options for Texinfo output ----------------------------------------------
# -- Options for Texinfo output -------------------------------------------


# Grouping the document tree into Texinfo files. List of tuples
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# (source start file, target name, title, author,
#  dir menu entry, description, category)
#  dir menu entry, description, category)
texinfo_documents = [
texinfo_documents = [
  ('index', 'Gluon', 'Gluon Documentation',
    (master_doc, 'Gluon', 'Gluon Documentation',
   'Project Gluon', 'Gluon', 'One line description of project.',
    author, 'Gluon', 'One line description of project.',
    'Miscellaneous'),
    'Miscellaneous'),
]
]


# Documents to append as an appendix to all manuals.
#texinfo_appendices = []


# If false, no module index is generated.
# -- Options for Epub output -------------------------------------------------
#texinfo_domain_indices = True

# Bibliographic Dublin Core info.
epub_title = project


# How to display URL addresses: 'footnote', 'no', or 'inline'.
# The unique identifier of the text. This can be a ISBN number
#texinfo_show_urls = 'footnote'
# or the project homepage.
#
# epub_identifier = ''

# A unique identification for the text.
#
# epub_uid = ''


# If true, do not generate a @detailmenu in the "Top" node's menu.
# A list of files that should not be packed into the epub file.
#texinfo_no_detailmenu = False
epub_exclude_files = ['search.html']
Original line number Original line Diff line number Diff line
@@ -15,10 +15,15 @@ The `main repo`_ does have issues enabled.
IRC
IRC
---
---


Gluon's developers frequent `#gluon on hackint`_. You're welcome to join us!
Gluon's developers frequent the IRC chatroom `#gluon`_ on `hackint`_.
There is a `webchat`_ that allows for easy access from within your
web browser. You're welcome to join us!


.. _#gluon on hackint: irc://irc.hackint.org/#gluon
.. _#gluon: ircs://irc.hackint.org/#gluon
.. _hackint: https://hackint.org/
.. _webchat: https://chat.hackint.org/?join=gluon


.. _working-with-repositories:


Working with repositories
Working with repositories
-------------------------
-------------------------
@@ -32,9 +37,9 @@ rerun


`make update` also applies the patches that can be found in the directories found in
`make update` also applies the patches that can be found in the directories found in
`patches`; the resulting branch will be called `patched`, while the commit specified in `modules`
`patches`; the resulting branch will be called `patched`, while the commit specified in `modules`
can be refered to by the branch `base`.
can be referred to by the branch `base`.


After new patches have been commited on top of the `patched` branch (or existing commits
After new patches have been committed on top of the `patched` branch (or existing commits
since the base commit have been edited or removed), the patch directories can be regenerated
since the base commit have been edited or removed), the patch directories can be regenerated
using
using


@@ -48,18 +53,33 @@ 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
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!
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.

This command speeds up the maintenance of updating OpenWrt and feeds.

Development Guidelines
Development Guidelines
----------------------
----------------------
lua should be used instead of sh whenever sensible. The following criteria
Lua should be used instead of sh whenever sensible. The following criteria
should be considered:
should be considered:


- Is the script doing more than just executing external commands? if so, use lua
- 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
- Is the script parsing/editing json-data? If so, use Lua for speed
- When using sh, use jsonfilter instead of json_* functions 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
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
the code in the project is formatted in the same way. The following basic rules
apply:
apply:


- use tabs instead of spaces
- use tabs instead of spaces
- trailing whitespaces must be eliminated
- trailing whitespace characters must be eliminated
- files need to end with a final newline
- 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.

If you add Lua scripts to gluon, check formatting with ``luacheck``.

docs/dev/build.rst

0 → 100644
+104 −0
Original line number Original line Diff line number Diff line
Build system
============

This page explains internals of the Gluon build system. It is currently very
incomplete; please contribute if you can!

Feed management
---------------

Rather that relying on the *feed.conf* mechanism of OpenWrt directly, Gluon
manages its feeds (*"modules"*) using a collection of scripts. This solution was
selected for multiple reasons:

- Feeds lists from Gluon base and the site repository are combined
- Patchsets are applied to downloaded feed repositories automatically

The following variables specifically affect the feed management:

GLUON_FEEDS
    List of base feeds; defined in file *modules* in Gluon base

GLUON_SITE_FEED
    List of site feeds; defined in file *modules* in site config

\*_REPO, \*_BRANCH, \*_COMMIT
    Git repository URL, branch and
    commit ID of the feeds to use. The branch name may be omitted; the default
    branch will be used in this case.

GLUON_BASE_FEEDS
    Additional feed definitions to be added to *feeds.conf*
    verbatim. By default, this contains a reference to the Gluon base packages;
    when using the Gluon build system to build a non-Gluon system, the variable
    can be set to the empty string.

Helper scripts
--------------

Several tasks of the build process have been separated from the Makefile into
external scripts, which are stored in the *scripts* directory. This was done to
ease maintenance of these scripts and the Makefile, by avoiding a lot of escaping.
These scripts are either bash or Lua scripts that run on the build system.

default_feeds.sh
    Defines the constant ``DEFAULT_FEEDS`` with the names of all feeds listed in
    *openwrt/feeds.conf.default*. This script is only used as an include by other
    scripts.

feeds.sh
    Creates the *openwrt/feeds.conf* file from ``FEEDS`` and ``DEFAULT_FEEDS``. The
    feeds from ``FEEDS`` are linked to the matching subfolder of *packages/* and not
    explicitly defined feeds of ``DEFAULT_FEEDS`` are setup as dummy (src-dummy).
    This *openwrt/feeds.conf* is used to reinstall all packages of all feeds with
    the *openwrt/scripts/feeds* tool.

modules.sh
    Defines the constants ``GLUON_MODULES`` and ``FEEDS`` by reading the *modules*
    files of the Gluon repository root and the site configuration. The returned
    variables look like:

    - ``FEEDS``: "*feedA feedB ...*"
    - ``GLUON_MODULES``: "*openwrt packages/feedA packages/feedB ...*"

    This script is only used as an include by other scripts.

patch.sh
    (Re-)applies the patches from the *patches* directory to all ``GLUON_MODULES``
    and checks out the files to the filesystem.
    This is done for each repo by:

    - creating a temporary clone of the repo to patch
      - only branch *base* is used
    - applying all patches via *git am* on top of this temporary *base* branch
      - this branch is named *patched*
    - copying the temporary clone to the *openwrt* (for OpenWrt Base) or
      *packages* (for feeds) folder
      - *git fetch* is used with the temporary clone as source
      - *git checkout* is called to update the filesystem
    - updating all git submodules

    This solution with a temporary clone ensures that the timestamps of checked
    out files are not changed by any intermediate patch steps, but only when
    updating the checkout with the final result. This avoids triggering unnecessary
    rebuilds.

update.sh
    Sets up a working clone of the ``GLUON_MODULES`` (external repos) from the external
    source and installs it into *packages/* directory. It simply tries to set the *base*
    branch of the cloned repo to the correct commit. If this fails it fetches the
    upstream branch and tries again to set the local *base* branch.

getversion.sh
    Used to determine the version numbers of the repositories of Gluon and the
    site configuration, to be included in the built firmware images as
    */lib/gluon/gluon-version* and */lib/gluon/site-version*.

    By default, this uses ``git describe`` to generate a version number based
    on the last git tag. This can be overridden by putting a file called
    *.scmversion* into the root of the respective repositories.

    A command like ``rm -f .scmversion; echo "$(./scripts/getversion.sh .)" > .scmversion``
    can be used before applying local patches to ensure that the reported
    version numbers refer to an upstream commit ID rather than an arbitrary
    local one after ``git am``.

docs/dev/debugging.rst

0 → 100644
+51 −0
Original line number Original line Diff line number Diff line
Debugging
=========


.. _dev-debugging-kernel-oops:

Kernel Oops
-----------

Sometimes a running Linux kernel detects an error during runtime that can't
be corrected.
This usually generates a stack trace that points to the location in the code
that caused the oops.

Linux kernels in Gluon (and OpenWrt) are stripped.
That means they do not contain any debug symbols.
On one hand this leads to a smaller binary and faster loading times on the
target.
On the other hand this means that in a case of a stack trace the unwinder
can only print memory locations and no further debugging information.

Gluon stores a compressed kernel with debug symbols for every target
in the directory `output/debug/`.
These kernels should be kept along with the images as long as the images
are in use.
This allows the developer to analyse a stack trace later.

Decoding Stacktraces
....................

The tooling is contained in the kernel source tree in the file
`decode_stacktrace.sh <https://github.com/torvalds/linux/blob/master/scripts/decode_stacktrace.sh>`__.
This file and the needed source tree are available in the directory: ::

  openwrt/build_dir/target-<architecture>/linux-<architecture>/linux-<version>/

.. note::
  Make sure to use a kernel tree that matches the version and patches
  that was used to build the kernel.
  If in doubt just re-build the images for the target.

Some more information on how to use this tool can be found at
`LWN <https://lwn.net/Articles/592724/>`__.

Obtaining Stacktraces
.....................

On many targets stack traces can be read from the following
location after reboot: ::

  /sys/kernel/debug/crashlog

docs/dev/feature-flags.rst

deleted100644 → 0
+0 −45
Original line number Original line Diff line number Diff line
Feature flags
=============

Feature flags provide a convenient way to define package selections without
making it necessary to list each package explicitly.

The main feature flag definition file is ``package/features``, but each package
feed can provide additional defintions in a file called ``features`` at the root
of the feed repository.

Each flag *$flag* without any explicit definition will simply include the package
with the name *gluon-$flag* by default. The feature definition file can modify
the package selection in two ways:

* The *nodefault* function suppresses default of including the *gluon-$flag*
  package
* The *packages* function adds a list of packages (or removes, when package
  names are prepended with minus signs) when a given logical expression
  is satisfied

Example::

    nodefault 'web-wizard'

    packages 'web-wizard' \
      'gluon-config-mode-hostname' \
      'gluon-config-mode-geo-location' \
      'gluon-config-mode-contact-info'

    packages 'web-wizard & (mesh-vpn-fastd | mesh-vpn-tunneldigger)' \
      'gluon-config-mode-mesh-vpn'

This will

* Disable the inclusion of a (non-existent) package called *gluon-web-wizard*
* Enable three config mode packages when the *web-wizard* feature is enabled
* Enable *gluon-config-mode-mesh-vpn* when both *web-wizard* and one
  of *mesh-vpn-fastd* and *mesh-vpn-tunneldigger* are enabled

Supported syntax elements of logical expressions are:

* \& (and)
* \| (or)
* \! (not)
* parentheses
+215 −117
Original line number Original line Diff line number Diff line
Adding support for new hardware
Adding hardware support
===============================
=======================
This page will give a short overview on how to add support
This page will give a short overview on how to add support
for new hardware to Gluon.
for new hardware to Gluon.


Hardware requirements
Hardware requirements
---------------------
---------------------
Having an ath9k (or ath10k) based WLAN adapter is highly recommended,
Having an ath9k, ath10k or mt76 based WLAN adapter is highly recommended,
although other chipsets may also work. VAP (multiple SSID) support
although other chipsets may also work. VAP (multiple SSID) support
is a requirement.
with simultaneous AP + Mesh Point (802.11s) operation is required.


Device checklist
----------------
The description of pull requests adding device support must include the
`device integration checklist
<https://github.com/freifunk-gluon/gluon/wiki/Device-Integration-checklist>`_.
The checklist ensures that core functionality of Gluon is well supported on the
device.


.. _hardware-adding-profiles:
.. _device-class-definition:


Adding profiles
Device classes
---------------
--------------
The vast majority of devices with ath9k WLAN is based on the ar71xx target of LEDE.
All supported hardware is categorized into "device classes". This allows to
If the hardware you want to add support for is ar71xx, adding a new profile
adjust the feature set of Gluon to the different hardware's capabilities via
is sufficient.
``site.mk`` without having to list individual devices.


Profiles are defined in ``targets/*`` in a shell-based DSL (so common shell
There are currently two devices classes defined: "standard" and "tiny". The
command syntax like ``if`` can be used).
"tiny" class contains all devices that do not meet the following requirements:


The ``device`` command is used to define an image build for a device. It takes
- At least 7 MiB of usable firmware space
two or three parameters.
- At least 64 MiB of RAM (128MiB for devices with ath10k radio)


The first parameter defines the Gluon profile name, which is used to refer to the
Target configuration
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
Gluon's hardware support is based on OpenWrt's. For each supported target,
can work::
a configuration file exists at ``targets/<target>-<subtarget>`` (or just
``target/<target>`` for targets without subtargets) that contains all
Gluon-specific settings for the target. The generic configuration
``targets/generic`` contains settings that affect all targets.


    lua -e 'print(require("platform_info").get_image_name())'
All targets must be listed in ``target/targets.mk``.


The second parameter defines the name of the image files generated by LEDE. Usually,
The target configuration language is based on Lua, so Lua's syntax for variables
it is also the LEDE profile name; for devices that still use the old image build
and control structures can be used.
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/<target>/image/Makefile``.


Examples::
Device definitions
~~~~~~~~~~~~~~~~~~
To configure a device to be built for Gluon, the ``device`` function is used.
In the simplest case, only two arguments are passed, for example:


    device tp-link-tl-wr1043n-nd-v1 tl-wr1043nd-v1
.. code-block:: lua
    device alfa-network-hornet-ub hornet-ub HORNETUB


Suffixes and extensions
  device('tp-link-tl-wdr3600-v1', 'tplink_tl-wdr3600-v1')
'''''''''''''''''''''''

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
The first argument is the device name in Gluon, which is part of the output
defines an additional package to include in the images in addition to the default
image filename, and must correspond to the model string looked up by the
package sets defined by LEDE. When a package name is prefixed by a minus sign, the
autoupdater. The second argument is the corresponding device profile name in
packages are excluded instead.
OpenWrt, as found in ``openwrt/target/linux/<target>/image/*``.


The ``packages`` command may be used at the top of a target definition to modify
A table of additional settings can be passed as a third argument:
the default package list for all images, or just for a single device (when the
target supports *per-default rootfs*).


.. code-block:: lua


Configuration
  device('ubiquiti-edgerouter-x', 'ubnt_edgerouter-x', {
'''''''''''''
    factory = false,
    packages = {'-hostapd-mini'},
    manifest_aliases = {
      'ubnt-erx',
    },
  })


The ``config`` command allows to add arbitary target-specific LEDE configuration
The supported additional settings are described in the following sections.
to be emitted to ``.config``.


Notes
Suffixes and extensions
'''''
~~~~~~~~~~~~~~~~~~~~~~~

For many targets, OpenWrt generates images with the suffixes
On devices with multiple WLAN adapters, care must also be taken that the primary MAC address is
``-squashfs-factory.bin`` and ``-squashfs-sysupgrade.bin``. For devices with
configured correctly. ``/lib/gluon/core/sysconfig/primary_mac`` should contain the MAC address which
different image names, is it possible to override the suffixes and extensions
can be found on a label on most hardware; if it does not, ``/lib/gluon/upgrade/010-primary-mac``
using the settings ``factory``, ``factory_ext``, ``sysupgrade`` and
in ``gluon-core`` might need a fix. (There have also been cases in which the address was incorrect
``sysupgrade_ext``, for example:
even on devices with only one WLAN adapter, in these cases a LEDE bug was the cause).


.. code-block:: lua


Adding support for new hardware targets
  {
---------------------------------------
    factory = '-squashfs-combined',

    factory_ext = '.img.gz',
Adding a new target is much more complex than adding a new profile. There are two basic steps
    sysupgrade = '-squashfs-combined',
required for adding a new target:
    sysupgrade_ext = '.img.gz',

  }
Package adjustments

'''''''''''''''''''
Only settings that differ from the defaults need to be passed. ``factory`` and

``sysupgrade`` can be set to ``false`` when no such images exist.
One package that may need adjustments for new targets is ``libplatforminfo`` (to be found in

`packages/gluon/libs/libplatforminfo <https://github.com/freifunk-gluon/packages/tree/master/libs/libplatforminfo>`_).
For some device types, there are multiple factory images with different
If the new platform works fine with the definitions found in ``default.c``, nothing needs to be done. Otherwise,
extensions. ``factory_ext`` can be set to a table of strings to account for this
create a definition for the added target or subtarget, either by symlinking one of the files in the ``templates``
case:
directory, or adding a new source file.


.. code-block:: lua
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).
    factory_ext = {'.img.gz', '.vmdk', '.vdi'},

  }
Build system support

''''''''''''''''''''
TODO: Extra images


A definition for the new target must be created under ``targets``, and it must be added
Aliases and manifest aliases
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
Sometimes multiple devices exist that use the same OpenWrt images. To make it
LEDE subtarget name (if it differs from the Gluon subtarget). The third argument
easier to find these images, the ``aliases`` setting can be used to define
can be used to define multiple Gluon targets with different configuration for the
additional device names. Gluon will create symlinks for these names in the
same LEDE target, like it is done for the ``ar71xx-tiny`` target.
image output directory.


After this, is should be sufficient to call ``make GLUON_TARGET=<target>`` to build the images for the new target.
.. code-block:: lua

  device('aruba-ap-303', 'aruba_ap-303', {
    factory = false,
    aliases = {'aruba-instant-on-ap11'},
  })

The aliased name will also be added to the autoupdater manifest, allowing upgrade
images to be found under the different name on targets that perform model name
detection at runtime.

It is also possible to add alternative names to the autoupdater manifest without
creating a symlink by using ``manifest_aliases`` instead of ``aliases``, which
should be done when the alternative name does not refer to a separate device.
This is particularly useful to allow the autoupdater to work when the model name
changed between Gluon versions.

Package lists
~~~~~~~~~~~~~
Gluon generates lists of packages that are installed in all images based on a
default list and the features and packages specified in the site configuration.

In addition, OpenWrt defines additional per-device package lists. These lists
may be modified in Gluon's device definitions, for example to include additional
drivers and firmware, or to remove unneeded software. Packages to remove are
prefixed with a ``-`` character.

For many ath10k-based devices, this is used to replace the "CT" variant of
ath10k with the mainline-based version:

.. code-block:: lua

  local ATH10K_PACKAGES_QCA9880 = {
    'kmod-ath10k',
    '-kmod-ath10k-ct',
    '-kmod-ath10k-ct-smallbuffers',
    'ath10k-firmware-qca988x',
    '-ath10k-firmware-qca988x-ct',
  }
  device('openmesh-a40', 'openmesh_a40', {
    packages = ATH10K_PACKAGES_QCA9880,
    factory = false,
  })

This example also shows how to define a local variable, allowing the package
list to be reused for multiple devices.

Device flags
~~~~~~~~~~~~

The settings ``class``, ``deprecated`` or ``broken`` should be set according to
the device support status. The default values are as follows:

.. code-block:: lua

  {
    class = 'standard',
    deprecated = false,
    broken = false,
  }

- Device classes are described in :ref:`device-class-definition`
- Broken devices are untested or do not meet our requirements as given by the
  device checklist
- Deprecated devices are slated for removal in a future Gluon version due to
  hardware constraints

Global settings
~~~~~~~~~~~~~~~
There is a number of directives that can be used outside of a ``device()``
definition:

- ``include('filename')``: Include another file with global settings
- ``config(key, value)``: Set a config symbol in OpenWrt's ``.config``. Value
  may be a string, number, boolean, or nil. Booleans and nil are used for
  tristate symbols, where nil sets the symbol to ``m``.
- ``try_config(key, value)``: Like ``config()``, but do not fail if setting
  the symbol is not possible (usually because its dependencies are not met)
- ``packages { 'package1', '-package2', ... }``: Define a list of packages to
  add or remove for all devices of a target. Package lists passed to multiple
  calls of ``packages`` will be aggregated.
- ``defaults { key = value, ... }``: Set default values for any of the
  additional settings that can be passed to ``device()``.

Helper functions
~~~~~~~~~~~~~~~~
The following helpers can be used in the target configuration:

- ``env.KEY`` allows to access environment variables
- ``istrue(value)`` returns true if the passed string is a positive number
  (often used with ``env``, for example ``if istrue(env.GLUON_DEBUG) then ...``)

Hardware support in packages
----------------------------
In addition to the target configuration files, some device-specific changes may
be required in packages.

gluon-core
~~~~~~~~~~
- ``/lib/gluon/upgrade/010-primary-mac``: Override primary MAC address selection

  Usually, the primary (label) MAC address is defined in OpenWrt's Device Trees.
  For devices or targets where this is not the case, it is possible to specify
  what interface to take the primary MAC address from in ``010-primary-mac``.

- ``/lib/gluon/upgrade/020-interfaces``: Override LAN/WAN interface assignment

  On PoE-powered devices, the PoE input port should be "WAN".

- ``/usr/lib/lua/gluon/platform.lua``: Contains a list of outdoor devices

gluon-setup-mode
~~~~~~~~~~~~~~~~
- ``/lib/gluon/upgrade/320-setup-ifname``: Contains a list of devices that use
  the WAN port for the config mode

  On PoE-powered devices, the PoE input port should be used for the config
  mode. This is handled correctly by default for outdoor devices listed in
  ``platform.lua``.

libplatforminfo
~~~~~~~~~~~~~~~
When adding support for a new target to Gluon, it may be necessary to adjust
libplatforminfo to define how autoupdater image names are derived from the
model name.
Original line number Original line Diff line number Diff line
@@ -10,9 +10,9 @@ Gluon tries to solve this issue by using a hash of the primary MAC address as a


* 0: client0; WAN
* 0: client0; WAN
* 1: mesh0
* 1: mesh0
* 2: ibss0
* 2: owe0
* 3: wan_radio0 (private WLAN); batman-adv primary address
* 3: wan_radio0 (private WLAN); batman-adv primary address
* 4: client1; LAN
* 4: client1; LAN
* 5: mesh1
* 5: mesh1
* 6: ibss1
* 6: owe1
* 7: wan_radio1 (private WLAN); mesh VPN
* 7: wan_radio1 (private WLAN); mesh VPN

docs/dev/packages.rst

0 → 100644
+215 −0
Original line number Original line Diff line number Diff line
Package development
###################

Gluon packages are OpenWrt packages and follow the same rules described at https://openwrt.org/docs/guide-developer/packages.

Development workflow
====================

When you are developing packages, it often happens that you iteratively want to deploy
and verify the state your development. There are two ways to verify your changes:

1)
  One way is to rebuild the complete firmware, flash it, configure it and verify your
  development then. This usually takes at least a few minutes to get your changes
  working so you can test them. Especially if you iterate a lot, this becomes tedious.

2)
  Another way is to rebuild only the package you are currently working on and
  to deploy this package to your test system. Here not even a reboot is required.
  This makes iterating relatively fast. Your test system could be real hardware or
  even a qemu in most cases.

Gluon provides scripts to enhance workflow 2). Here is an example illustrating
the workflow using these scripts:

.. code-block:: shell

  # start a local qemu instance
  contrib/run_qemu.sh output/images/factory/[...]-x86-64.img

  # apply changes to the desired package
  vi package/gluon-ebtables/files/etc/init.d/gluon-ebtables

  # rebuild and push the package to the qemu instance
  contrib/push_pkg.sh package/gluon-ebtables/

  # test your changes
  ...

  # do more changes
  ...

  # rebuild and push the package to the qemu instance
  contrib/push_pkg.sh package/gluon-ebtables/

  # test your changes
  ...

  (and so on...)

  # see help of the script for more information
  contrib/push_pkg.sh -h
  ...

Features of ``push_pkg.sh``:

* Works with compiled and non-compiled packages.

  * This means it can be used in the development of C-code, Lua-Code and mostly any other code.

* Works with native OpenWrt and Gluon packages.
* Pushes to remote machines or local qemu instances.
* Pushes multiple packages in one call if desired.
* Performs site.conf checks.

Implementation details of ``push_pkg.sh``:

* First, the script builds an opkg package using the OpenWrt build system.
* This package is pushed to a *target machine* using scp:

  * By default the *target machine* is a locally running x86 qemu started using ``run_qemu.sh``.
  * The *target machine* can also be remote machine. (See the cli switch ``-r``)
  * Remote machines are not limited to a specific architecture. All architectures supported by gluon can be used as remote machines.

* Finally opkg is used to install/update the packages in the target machine.

  * While doing this, it will not override ``/etc/config`` with package defaults by default. (See the cli switch ``-P``).
  * While doing this, opkg calls the ``check_site.lua`` from the package as post_install script to validate the ``site.conf``. This means that the ``site.conf`` of the target machine is used for this validation.

Note that:

* ``push_pkg.sh`` does neither build nor push dependencies of the packages automatically. If you want to update dependencies, you must explicitly specify them to be pushed.
* If you add new packages, you must run ``make update config GLUON_TARGET=...``.
* You can change the gluon target of the target machine via ``make config GLUON_TARGET=...``.
* If you want to update the ``site.conf`` of the target machine, use ``push_pkg.sh package/gluon-site/``.
* Sometimes when things break, you can heal them by compiling a package with its dependencies: ``cd openwrt; make package/gluon-ebtables/clean; make package/gluon-ebtables/compile; cd ..``.
* You can exit qemu by pressing ``CTRL + a`` and ``c`` afterwards.

Gluon package makefiles
=======================

As many packages share the same or a similar structure, Gluon provides a ``package/gluon.mk`` that
can be included for common definitions. This file replaces OpenWrt's ``$(INCLUDE_DIR)/package.mk``;
it is usually included as ``include ../gluon.mk`` from Gluon core packages, or as
``include $(TOPDIR)/../package/gluon.mk`` from feeds.

Provided macros
***************

* *GluonBuildI18N* (arguments: *<source directory>*)

  Converts the *.po* files for all enabled languages from the given source directory to
  the binary *.lmo* format and stores them in ``$(PKG_BUILD_DIR)/i18n``.

* *GluonInstallI18N*

  Install *.lmo* files from ``$(PKG_BUILD_DIR)/i18n`` to ``/lib/gluon/web/i18n`` in the
  package install directory.

* *GluonSrcDiet* (arguments: *<source directory>*, *<destination directory>*)

  Copies a directory tree, processing all files in it using *LuaSrcDiet*. The directory
  tree should only contain Lua files.

* *GluonCheckSite* (arguments: *<source file>*)

  Intended to be used in a package postinst script. It will use the passed Lua
  snippet to verify package-specific site configuration.

* *BuildPackageGluon* (replaces *BuildPackage*)

  Extends the *Package/<name>* definition with common defaults, sets the package
  install script to the common *Gluon/Build/Install*, and automatically creates
  a postinst script using *GluonCheckSite* if a ``check_site.lua`` is found in the
  package directory.

Default build steps
*******************

These defaults greatly reduce the boilerplate in each package, but they can also
be confusing because of the many implicit behaviors depending on files in the
package directory. If any part of *Gluon/Build/Compile* or *Gluon/Build/Install*
does not work as intended for a package, the compile and install steps can
always be replaced or extended.

*Build/Compile* is set to *Gluon/Build/Compile* by default, which will

* run OpenWrt standard default commands (*Build/Compile/Default*) if a ``src/Makefile``
  or ``src/CMakeLists.txt`` is found
* run *GluonSrcDiet* on all files in the ``luasrc`` directory
* run *GluonBuildI18N* if a ``i18n`` directory is found

*Package/<name>* defaults to *Gluon/Build/Install* for packages defined using
*BuildPackageGluon*, which will

* copy all files from ``$(PKG_INSTALL_DIR)`` into the package if ``$(PKG_INSTALL)`` is 1
* copy all files from ``files`` into the package
* copy all Lua files built from ``luasrc`` into the package
* installs ``$(PKG_BUILD_DIR)/respondd.so`` to ``/usr/lib/respondd/$(PKG_NAME).so`` if ``src/respondd.c`` exists
* installs compiled i18n *.lmo* files

Feature flags
=============

Feature flags provide a convenient way to define package selections without
making it necessary to list each package explicitly. The list of features to
enable for a Gluon build is determined by the evaluated image-customization.lua file
in the root-directory of the Site repository.

The main feature flag definition file is ``package/features``, but each package
feed can provide additional definitions in a file called ``features`` at the root
of the feed repository.

Each flag *$flag* will include the package the name *gluon-$flag* by default.
The feature definition file can modify the package selection by adding or removing
packages when certain combinations of flags are set.

Feature definitions use Lua syntax. Two basic functions are defined:

* *feature(name, pkgs)*: Defines a new feature. *feature()* expects a feature
  (flag) name and a list of packages to add or remove when the feature is
  enabled.

  * Defining a feature using *feature* replaces the default definition of
    just including *gluon-$flag*.
  * A package is removed when the package name is prefixed with a ``-`` (after
    the opening quotation mark).

* *when(expr, pkgs)*: Adds or removes packages when a given logical expression
  of feature flags is satisfied.

  * *expr* is a logical expression composed of feature flag names (each prefixed
    with an underscore before the opening quotation mark), logical operators
    (*and*, *or*, *not*) and parentheses.
  * Referencing a feature flag in *expr* has no effect on the default handling
    of the flag. When no *feature()* entry for a flag exists, it will still
    add *gluon-$flag* by default.
  * *pkgs* is handled as for *feature()*.

Example::

    feature('web-wizard', {
      'gluon-config-mode-hostname',
      'gluon-config-mode-geo-location',
      'gluon-config-mode-contact-info',
      'gluon-config-mode-outdoor',
    })

    when(_'web-wizard' and _'mesh-vpn-fastd' or _'mesh-vpn-wireguard'), {
      'gluon-config-mode-mesh-vpn',
    })

    feature('no-radvd', {
      '-gluon-radvd',
    })


This will

* disable the inclusion of the (non-existent) packages *gluon-web-wizard* and *gluon-no-radvd* when their
  corresponding feature flags are evaluated as selected in the image-customization.lua file
* enable four additional config mode packages when the *web-wizard* feature is enabled
* enable *gluon-config-mode-mesh-vpn* when both *web-wizard* and one
  of *mesh-vpn-fastd* and *mesh-vpn-wireguard* are enabled
* disable the *gluon-radvd* package when *gluon-no-radvd* is enabled
+36 −0
Original line number Original line Diff line number Diff line
gluon.site library
==================

The *gluon.site* library allows convenient access to the site configuration
from Lua scripts. Example:

.. code-block:: lua

  local site = require 'gluon.site'
  print(site.wifi24.ap.ssid())

The *site* object in this example does not directly represent the *site.conf* data structure;
instead, it is wrapped in a way that makes it more convenient to access deeply nested elements.
To access the underlying values, they must be unwrapped using the function call notation
(the ``()`` after ``site.wifi24.ap.ssid`` in the example).

The wrapper objects have two advantages over simple Lua tables:

* Accessing non-existing values is never an error: ``site.wifi24.ap.ssid()`` will simply
  return *nil* if ``site.wifi24`` or ``site.wifi24.ap`` do not exist
* Default values: A default value can be passed to the unwrapping function call:

  .. code-block:: lua

    print(site.wifi24.ap.ssid('Default'))

  will return *'Default'* instead of *nil* when the value is unset.

  Note that *nil* values and unset values are equivalent in Lua.

A simple way to access the whole site configuration as a simple table
is to unwrap the top-level site object:

.. code-block:: lua

  local site_table = site()
Original line number Original line Diff line number Diff line
@@ -23,7 +23,7 @@ Best practices
  This allows using the same code to create the initial configuration and upgrade configurations on upgrades.
  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
* If it is unavoidable to run different code during the initial installation, the ``sysconfig.gluon_version`` variable
  can be checked. This variable is ``nil`` during the initial installation and contains the previously install Gluon
  can be checked. This variable is ``nil`` during the initial installation and contains the previously installed Gluon
  version otherwise.
  version otherwise.


Script ordering
Script ordering
Original line number Original line Diff line number Diff line
WAN support
Uplink support
===========
==============


As the WAN port of a node will be connected to a user's private network, it
As the WAN port of a node will be connected to a user's private network, it
is essential that the node only uses the WAN when it is absolutely necessary.
is essential that the node only uses the WAN when it is absolutely necessary.
There are two cases in which the WAN port is used:
There are two cases in which the WAN port is used:


* Mesh VPN (package ``gluon-mesh-vpn-fastd``
* Mesh VPN (package ``gluon-mesh-vpn-fastd``)
* DNS to resolve the VPN servers' addresses (package ``gluon-wan-dnsmasq``)
* DNS to resolve the VPN servers' addresses (package ``gluon-wan-dnsmasq``)


After the VPN connection has been established, the node should be able to reach
After the VPN connection has been established, the node should be able to reach
the mesh's DNS servers and use these for all other name resolution.
the mesh's DNS servers and use these for all other name resolution.


If a device has only a single Ethernet port (or group of ports), it will be
used as an uplink port even when it is not labeled as "WAN" by default. This
behavior can be controlled using the ``interfaces.single.default_roles``
site.conf option. It is also possible to alter the interface assignment after
installation by modifying ``/etc/config/gluon`` and running
``gluon-reconfigure``.


Routing tables
Routing tables
~~~~~~~~~~~~~~
~~~~~~~~~~~~~~
Original line number Original line Diff line number Diff line
@@ -2,7 +2,7 @@ Config Mode
===========
===========


The `Config Mode` consists of several modules that provide a range of different
The `Config Mode` consists of several modules that provide a range of different
condiguration options:
configuration options:


gluon-config-mode-core
gluon-config-mode-core
    This modules provides the core functionality for the config mode.
    This modules provides the core functionality for the config mode.
@@ -11,18 +11,28 @@ gluon-config-mode-core
gluon-config-mode-hostname
gluon-config-mode-hostname
    Provides a hostname field.
    Provides a hostname field.


gluon-config-mode-autoupdater
:doc:`gluon-config-mode-autoupdater <../../features/autoupdater>`
    Informs whether the autoupdater is enabled.
    Informs whether the autoupdater is enabled.


gluon-config-mode-mesh-vpn
:doc:`gluon-config-mode-mesh-vpn <../../features/vpn>`
    Allows toggling of mesh-vpn-fastd and setting a bandwidth limit.
    Allows toggling of installed mesh-vpn technology and setting a bandwidth limit.


gluon-config-mode-geo-location
gluon-config-mode-geo-location
    Enables the user to set the geographical location of the node.
    Enables the user to set the geographical location of the node.


:doc:`../../package/gluon-config-mode-geo-location-osm`
    Lets the user click on a map to select the geographical location through a OSM map

gluon-config-mode-contact-info
gluon-config-mode-contact-info
    Adds a field where the user can provide contact information.
    Adds a field where the user can provide contact information.


:doc:`../../package/gluon-web-cellular`
    Adds advanced options to enter WWAN config.

:doc:`../../package/gluon-web-network`
    Adds option to configure used role on interfaces

Most of the configuration options are described in :ref:`user-site-config_mode`


Writing Config Mode modules
Writing Config Mode modules
~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Original line number Original line Diff line number Diff line
Controllers
Controllers
===========
===========


Controllers live in ``/lib/gluon/web/controller``. They define which pages ("routes")
Controllers live in the ``controller`` subdirectory of a gluon-web application
exist under the ``/cgi-bin/gluon`` path, and what code is run when these pages are requested.
(``/lib/gluon/config-mode/controller`` for the config mode,
``/lib/gluon/status-page/controller`` for the status page). They define which pages ("routes")
exist under the application base URL, and what code is run when these pages are requested.


Controller scripts mostly consist of calls of the `entry` function, which each define
Controller scripts usually start with a *package* declaration, followed by calls
one route:
to the *entry* function, which each define one route:


.. code-block:: lua
.. code-block:: lua


  package 'gluon-web-admin'

  entry({"admin"}, alias("admin", "info"), _("Advanced settings"), 10)
  entry({"admin"}, alias("admin", "info"), _("Advanced settings"), 10)
  entry({"admin", "info"}, template("admin/info"), _("Information"), 1)
  entry({"admin", "info"}, template("admin/info"), _("Information"), 1)


The entry function expects 4 arguments:
*package* defines the translation namespace for the titles of the defined
pages as well as the referenced views and models. The entry function expects 4
arguments:


  - `path`: Components of the path to define a route for.
  - `path`: Components of the path to define a route for.


@@ -20,6 +26,7 @@ The entry function expects 4 arguments:


  - `target`: Dispatcher for the route. See the following section for details.
  - `target`: Dispatcher for the route. See the following section for details.
  - `title`: Page title (also used in navigation). The underscore function is used
  - `title`: Page title (also used in navigation). The underscore function is used
    to mark the strings as translatable for ``i18n-scan.pl``.


  - `order`: Sort index in navigation (defaults to 100)
  - `order`: Sort index in navigation (defaults to 100)


@@ -64,11 +71,10 @@ Useful functions:
    values for the given key.
    values for the given key.
  - *status* (*code*, *message*): Writes the HTTP status to the reply. Has no effect
  - *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.
    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
  - *header* (*key*, *value*): Adds an HTTP header to the reply to be sent to
    the client. Has no effect when non-header data has already been written.
    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
  - *prepare_content* (*mime*): Sets the *Content-Type* header to the given MIME
    type, potentially setting additional headers or modifying the MIME type to
    type
    accommodate browser quirks
  - *write* (*data*, ...): Sends the given data to the client. If headers have not
  - *write* (*data*, ...): Sends the given data to the client. If headers have not
    been sent, it will be done before the data is written.
    been sent, it will be done before the data is written.


@@ -88,9 +94,10 @@ The template renderer
The template renderer allows to render templates (views). The most useful functions
The template renderer allows to render templates (views). The most useful functions
are:
are:


  - *render* (*view*, *scope*): Renders the given view, optionally passing a table
  - *render* (*view*, *scope*, *pkg*): Renders the given view, optionally passing a table
    with additional variables to make available in the template.
    with additional variables to make available in the template. The passed package
  - *render_string* (*str*, *scope*): Same as *render*, but the template is passed
    defines the translation namespace.
  - *render_string* (*str*, *scope*, *pkg*): Same as *render*, but the template is passed
    directly instead of being loaded from the view directory.
    directly instead of being loaded from the view directory.


The renderer functions are called in property syntax, for example:
The renderer functions are called in property syntax, for example:
Original line number Original line Diff line number Diff line
@@ -20,8 +20,9 @@ Internationalization support is available in all components (models, view and
controllers) of *gluon-web*-based packages. Strings are translated using the *translate*,
controllers) of *gluon-web*-based packages. Strings are translated using the *translate*,
*_translate* and *translatef* functions (*translate* for static strings, *translatef*
*_translate* and *translatef* functions (*translate* for static strings, *translatef*
for printf-like formatted string; *_translate* works the same as *translate*, but
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)
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.

In views, the special tags ``<%:...%>`` can be used to translate the contained string.


Example from the *gluon-config-mode-geo-location* package:
Example from the *gluon-config-mode-geo-location* package:


@@ -29,6 +30,18 @@ Example from the *gluon-config-mode-geo-location* package:


  local share_location = s:option(Flag, "location", translate("Show node on the map"))
  local share_location = s:option(Flag, "location", translate("Show node on the map"))


Note that translations are *namespaced*: each package will only use its own
translation strings by default. For this purpose, the package name must by
specified in a package's controller. It is possible to access a different
translation package using the *i18n* function from models and view, which is
necessary when strings from the site configuration are used, or packages do not
have their own controller (which is the case for config mode wizard components).

.. code-block:: lua

  local site_i18n = i18n 'gluon-site'
  local msg = site_i18n._translate('gluon-config-mode:welcome')

Adding translation templates to Gluon packages
Adding translation templates to Gluon packages
----------------------------------------------
----------------------------------------------


@@ -45,7 +58,7 @@ script in the ``contrib`` directory:


The same command can be run again to update the template.
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*,
In addition, the Makefile must be adjusted. Instead of OpenWrt's default *package.mk*,
the Gluon version (``../gluon.mk`` for core packages) must be used. The i18n files must be installed
the Gluon version (``../gluon.mk`` for core packages) must be used. The i18n files must be installed
and PKG_CONFIG_DEPENDS must be added::
and PKG_CONFIG_DEPENDS must be added::


@@ -92,5 +105,5 @@ Adding support for new languages
--------------------------------
--------------------------------


A list of all languages supported by *gluon-web* can be found in ``package/gluon.mk``.
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
New languages just need to be added to *GLUON_SUPPORTED_LANGS*, and a human-readable
language name has been defined in the same file.
language name must be defined.
Original line number Original line Diff line number Diff line
Models
Models
======
======


Models are defined in ``/lib/gluon/web/model``. Each model defines one or more
Models are defined in the ``model`` subdirectory of a gluon-web application
forms to display on a page, and how the submitted form data is handled.
(``/lib/gluon/config-mode/model`` for the config mode; the status
page does not use any models). Model support is not part of the gluon-web core
anymore, but is provided by the *gluon-web-model* package.

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:
Let's start with an example:


@@ -21,7 +26,7 @@ Let's start with an example:


  return f
  return f


The toplevel element of a model is always a *Form*, but it is also possible for
The top-level 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 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
A *Form* has one or more *Sections*, and each *Section* has different types
@@ -46,14 +51,14 @@ Classes and methods


    - *Form:write* ()
    - *Form:write* ()


      Is called after the form has beed submitted (but only if the data is valid). It
      Is called after the form has been submitted (but only if the data is valid). It
      is called last (after all options' *write* methods) and is usually used
      is called last (after all options' *write* methods) and is usually used
      to commit changed UCI packages.
      to commit changed UCI packages.


      The default implementation of *write* doesn't do anything, but it can be
      The default implementation of *write* doesn't do anything, but it can be
      overridden.
      overridden.


  - *Section* (usually instanciated through *Form:section*)
  - *Section* (usually instantiated through *Form:section*)


    - *Section:option* (*type*, *id*, *title*, *description*)
    - *Section:option* (*type*, *id*, *title*, *description*)


Original line number Original line Diff line number Diff line
Views
Views
=====
=====


The template parser reads views from ``/lib/gluon/web/view``. Writing own view
The template parser reads views from the ``view`` subdirectory of a
should be avoided in favour of using :doc:`model` with their predefined views.
gluon-web application (``/lib/gluon/config-mode/view`` for the config mode,
``lib/gluon/status-page/view`` for the status page).
Writing own views should usually be avoided in favour of using :doc:`model`
with their predefined views.


Views are partial HTML pages, with additional template tags that allow
Views are partial HTML pages, with additional template tags that allow
to embed Lua code and translation strings. The following tags are defined:
to embed Lua code and translation strings. The following tags are defined:


  - ``<%`` ... ``%>`` evaluates the enclosed Lua expression.
  - ``<%`` ... ``%>`` evaluates the enclosed Lua expression.
  - ``<%=`` ... ``%>`` evaluates the enclosed Lua expression and prints its value.
  - ``<%|`` ... ``%>`` evaluates the enclosed Lua expression and prints its value.
  - ``<%=`` ... ``%>`` evaluates the enclosed Lua expression and prints its value
    *without escaping HTML entities*. This is useful when the value contains HTML code.
  - ``<%+`` ... ``%>`` includes another template.
  - ``<%+`` ... ``%>`` includes another template.
  - ``<%:`` ... ``%>`` translates the enclosed string using the loaded i18n catalog.
  - ``<%:`` ... ``%>`` translates the enclosed string using the loaded i18n catalog.
  - ``<%_`` ... ``%>`` translates the enclosed string *without escaping HTML entities*
  - ``<%_`` ... ``%>`` translates the enclosed string *without escaping HTML entities*
@@ -52,4 +57,4 @@ variables and functions should always be available for the embedded Lua code:
    Use ``node(unpack(request))`` to get the node for the current page.
    Use ``node(unpack(request))`` to get the node for the current page.
  - *pcdata* (*str*): Escapes HTML entities in the passed string.
  - *pcdata* (*str*): Escapes HTML entities in the passed string.
  - *urlencode* (*str*): Escapes the passed string for use in an URL.
  - *urlencode* (*str*): Escapes the passed string for use in an URL.
  - *translate*, *_translate* and *translatef*: see :doc:`i18n`
  - *translate*, *_translate*, *translatef* and *i18n*: see :doc:`i18n`
Original line number Original line Diff line number Diff line
@@ -7,11 +7,14 @@ Building Images
---------------
---------------


By default, the autoupdater is disabled (as it is usually not helpful to have unexpected updates
By default, the autoupdater is disabled (as it is usually not helpful to have unexpected updates
during development), but it can be enabled by setting the variable GLUON_BRANCH when building
during development), but it can be enabled by setting the variable ``GLUON_AUTOUPDATER_ENABLED`` to ``1`` when building.
to override the default branch set in the set in the site configuration.
It is also possible to override the default branch during build using the variable ``GLUON_AUTOUPDATER_BRANCH``.

If a default branch is set neither in *site.conf* nor via ``GLUON_AUTOUPDATER_BRANCH``, the default branch is
implementation-defined. Currently, the branch with the first name in alphabetical order is chosen.


A manifest file for the updater can be generated with `make manifest`. A signing script (using
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, the
``ecdsautils``) can be 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``.
``PRIORITY`` value may be defined by setting ``GLUON_PRIORITY`` on the command line or in ``site.mk``.


``GLUON_PRIORITY`` defines the maximum number of days that may pass between releasing an update and installation
``GLUON_PRIORITY`` defines the maximum number of days that may pass between releasing an update and installation
@@ -27,20 +30,68 @@ in ``site.mk``, care must be taken to pass the same ``GLUON_RELEASE`` to ``make
as otherwise the generated manifest will be incomplete.
as otherwise the generated manifest will be incomplete.




Manifest format
---------------

The manifest starts with a short header, followed by the list of firmwares and signatures.
The header contains the following information:

.. code-block:: sh

    BRANCH=stable
    DATE=2020-10-07 00:00:00+02:00
    PRIORITY=7

- ``BRANCH`` is the autoupdater branch name that needs to match the nodes configuration.
- ``DATE`` specifies when the time period for the update begins. Nodes will do their regular update during a random minute
  between 4:00 and 4:59 am. Nodes might not always have a reliable NTP synchronization, which is why a fallback mechanism
  exists, that checks for an update, and will execute if ``DATE`` is at least 24h in the past.
- ``PRIORITY`` can be configured as ``GLUON_PRIORITY`` when generating the manifest or in ``site.mk``, and defines
  the number of days over which the update should be stretched out after ``DATE``. Nodes will calculate a probability
  based on the time left to determine when to update.

Signing images
--------------

As noted above, manifest files can be signed by an arbitrary amount of ECDSA keys.
The amount of valid signatures required to have the autoupdater accept an image is configured using the :ref:`site.conf <user-site-autoupdater>`.

A secret key (that like an SSH private key must never be shared) can be generated like this:

.. code-block:: sh

    mkdir ~/.ecdsa/
    ( umask 077 && ecdsautil generate-key > ~/.ecdsa/id_y25519 )

This is then used to derive a public key, meant to be placed in the ``site.conf``.

.. code-block:: sh

    ( umask 033 && ecdsautil show-key < ~/.ecdsa/id_y25519 > ~/.ecdsa/id_y25519.pub )

A manifest can then be signed using the helper in gluons `contrib` directory.

.. code-block:: sh

    ./contrib/sign.sh ~/.ecdsa/id_y25519 output/images/sysupgrade/stable.manifest

In the manifest file only the content above the three dashes is signed, not other signatures that might exist.

Automated nightly builds
Automated nightly builds
------------------------
------------------------


A fully automated nightly build could use the following commands:
A fully automated nightly build could use the following commands:


::
.. code-block:: sh


    git pull
    git pull
    (cd site && git pull)
    # git -C site pull
    make update
    make update
    make clean
    make clean GLUON_TARGET=ath79-generic
    NUM_CORES_PLUS_ONE=$(expr $(nproc) + 1)
    NUM_CORES_PLUS_ONE=$(expr $(nproc) + 1)
    make -j$NUM_CORES_PLUS_ONE GLUON_TARGET=ar71xx-generic GLUON_BRANCH=experimental
    make -j$NUM_CORES_PLUS_ONE GLUON_TARGET=ath79-generic GLUON_RELEASE=$GLUON_RELEASE \
    make manifest GLUON_BRANCH=$GLUON_BRANCH GLUON_RELEASE=$GLUON_RELEASE
        GLUON_AUTOUPDATER_BRANCH=experimental GLUON_AUTOUPDATER_ENABLED=1
    make manifest GLUON_RELEASE=$GLUON_RELEASE GLUON_AUTOUPDATER_BRANCH=experimental
    contrib/sign.sh $SECRETKEY output/images/sysupgrade/experimental.manifest
    contrib/sign.sh $SECRETKEY output/images/sysupgrade/experimental.manifest


    rm -rf /where/to/put/this/experimental
    rm -rf /where/to/put/this/experimental
Original line number Original line Diff line number Diff line
@@ -14,10 +14,13 @@ Activating Config Mode
----------------------
----------------------


Config Mode is automatically entered at the first boot. You can re-enter
Config Mode is automatically entered at the first boot. You can re-enter
Config Mode by pressing and holding the RESET/WPS button for about three
Config Mode by pressing and holding the RESET/WPS/DECT button for about three
seconds. The device should reboot (all LEDs will turn of briefly) and 
seconds. The device should reboot (all LEDs will turn off briefly) and
Config Mode will be available.
Config Mode will be available.


If you have access to the console of the node, there is the
``gluon-enter-setup-mode`` command, which reboots a node into Config Mode.



Port Configuration
Port Configuration
------------------
------------------
@@ -35,3 +38,17 @@ Accessing Config Mode
Config Mode can be accessed at http://192.168.1.1. The node will offer DHCP
Config Mode can be accessed at http://192.168.1.1. The node will offer DHCP
to clients. Should this fail, you may assign an IP from 192.168.1.0/24 to
to clients. Should this fail, you may assign an IP from 192.168.1.0/24 to
your computer manually.
your computer manually.

.. image:: configmode.png

Advanced Config Options
-----------------------

Depending on the installed packages, the advanced config mode allows to configure packages further.

* :doc:`gluon-web-wifi-config enable <wlan-configuration>` radios used for wifi and mesh as well as outdoor mode
* :doc:`../package/gluon-web-network` allows to configure the used roles (uplink, mesh, client) on each interface
* :doc:`../package/gluon-web-admin` allows to enter SSH keys or set a password in the `Remote access` section
* :doc:`../package/gluon-web-cellular` allows to configure SIM card / WWAN settings on supported cellular devices

The advanced config does also allow to upload a sysupgrade file to update the firmware to a different version.
Original line number Original line Diff line number Diff line
.. _dns-caching:

DNS caching
DNS caching
===========
===========


@@ -27,25 +29,25 @@ If these settings do not exist, the cache is not initialized and RAM usage will
not increase.
not increase.


When next_node.name is set, an A record and an AAAA record for the
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
next-node IP address are placed in the dnsmasq configuration. This means that
of next_node.name may be resolved even without upstream connectivity. It is suggested to use
the content of next_node.name may be resolved even without upstream connectivity.
the same name as the DNS server provides: e.g nextnode.yourdomain.net (This way the name also 
It is suggested to use the same name as the DNS server provides:
works if client uses static DNS Servers). Hint: If next_node.name does not contain a dot some 
e.g. nextnode.location.community.example.org (This way the name also works if a
browsers would open the searchpage instead.
client uses static DNS Servers). Hint: If next_node.name does not contain a dot
some browsers would open the searchpage instead.


::
::


  dns = {
  dns = {
    cacheentries = 5000,
    cacheentries = 5000,
    servers = { '2001:db8::1', },
    servers = { '2001:4860:4860::8888', '2001:4860:4860::8844' },
  },
  },


  next_node = {
  next_node = {
    name = 'nextnode.yourdomain.net',
    name = { 'nextnode.location.community.example.org', 'nextnode', 'nn' },
    ip6 = '2001:db8:8::1',
    ip6 = '2001:db8:8::1',
    ip4 = '198.51.100.1',
    ip4 = '198.51.100.1',
  }
  }




The cache will be initialized during startup.
Each cache entry will occupy about 90 bytes of RAM.
Each cache entry will occupy about 90 bytes of RAM.
Original line number Original line Diff line number Diff line
@@ -24,7 +24,7 @@ Information to be announced is currently split into three categories:
    interfaces. This data can be used to determine the network topology.
    interfaces. This data can be used to determine the network topology.


All categories will have a ``node_id`` key. It should be used to
All categories will have a ``node_id`` key. It should be used to
relate data of different catagories.
relate data of different categories.


Accessing Node Information
Accessing Node Information
--------------------------
--------------------------
@@ -33,7 +33,7 @@ There are two packages responsible for distribution of the information. For
one, information is distributed across the mesh using alfred_. Information
one, information is distributed across the mesh using alfred_. Information
between neighbouring nodes is exchanged using `gluon-respondd`.
between neighbouring nodes is exchanged using `gluon-respondd`.


.. _alfred: http://www.open-mesh.org/projects/alfred
.. _alfred: https://www.open-mesh.org/projects/alfred


alfred (mesh bound)
alfred (mesh bound)
~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~
@@ -97,14 +97,15 @@ In order to retrieve statistics data you could run:


You can find more information about alfred in its README_.
You can find more information about alfred in its README_.


.. _README: https://git.open-mesh.org/alfred.git/blob_plain/refs/heads/master:/README
.. _README: https://git.open-mesh.org/alfred.git/blob_plain/refs/heads/master:/README.rst


gluon-respondd
gluon-respondd
~~~~~~~~~~~~~~
~~~~~~~~~~~~~~


`gluon-respondd` allows querying neighbouring nodes for their information.
`gluon-respondd` allows querying neighbouring nodes for their information.
It is a daemon listening on the multicast address ``ff02::2:1001`` on
It is a daemon listening on the multicast address ``ff02::2:1001`` on
UDP port 1001 on both the bare mesh interfaces and `br-client`. Unicast
UDP port 1001 on the mesh interface and on the multicast address
``ff05::2:1001`` on the `br-client` interface. Unicast
requests are supported as well.
requests are supported as well.


The supported requests are:
The supported requests are:
@@ -117,13 +118,13 @@ The supported requests are:
gluon-neighbour-info
gluon-neighbour-info
~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~


The programm `gluon-neighbour-info` can be used to retrieve
The program `gluon-neighbour-info` can be used to retrieve
information from other nodes.
information from other nodes.


::
::


  gluon-neighbour-info -i wlan0 \
  gluon-neighbour-info -i bat0 \
  -p 1001 -d ff02:0:0:0:0:0:2:1001 \
  -p 1001 -d ff05:0:0:0:0:0:2:1001 \
  -r nodeinfo
  -r nodeinfo


An optional timeout may be specified, e.g. `-t 5` (default: 3 seconds). See
An optional timeout may be specified, e.g. `-t 5` (default: 3 seconds). See
@@ -134,5 +135,5 @@ Adding a data provider
----------------------
----------------------


To add a provider, you need to install a shared object into ``/lib/gluon/respondd``.
To add a provider, you need to install a shared object into ``/lib/gluon/respondd``.
For more information, refer to the `respondd README <https://github.com/freifunk-gluon/packages/blob/master/net/respondd/README.md>`_
For more information, refer to the `respondd README <https://github.com/freifunk-gluon/packages/blob/main/net/respondd/README.md>`_
and have a look the existing providers.
and have a look the existing providers.
+272 −0
Original line number Original line Diff line number Diff line
Multidomain Support
===================

Preamble
--------

There comes a time when a mesh network grows past sensible boundaries.
As broadcast traffic grows, mesh networks experience scaling issues and
using them becomes very unpleasant. An approach to solve this follows
the well-known “divide and conquer” paradigm and splits a large network
into multiple smaller networks. These smaller networks start with a
dedicated layer 2 network each, which are interconnected via their
gateways by layer 3 routing. Gluon is already field-tested handling a
single domain and the multidomain feature allows for the reconfiguration
of key parameters that decide which domain a node participates in,
without the need of a distinct set of firmware images for each mesh domain.

Overview
--------

Multidomain support allows to build a single firmware with multiple,
switchable domain configurations. The nomenclature is as follows:

- ``site``: an aggregate over multiple domains
- ``domain``: mesh network with connectivity parameters that prevent
  accidental bridging with other domains
- ``domain code``: unique domain identifier
- ``domain name``: pretty name for a domain code

By default Gluon builds firmware with a single domain embedded into
``site.conf``. To use multiple domains, enable it in ``site.mk``:

::

  GLUON_MULTIDOMAIN=1

In the site repository, create the ``domains/`` directory, which will
hold your domain configurations. Each domain configuration file is named
after its primary ``domain_code``, additional domain codes and names are
supported.

::

  site/
  |-- site.conf
  |-- site.mk
  |-- i18n/
  |-- domains/
    |-- alpha_centauri.conf
    |-- beta_centauri.conf
    |-- gamma_centauri.conf

The domain configuration ``alpha_centauri.conf`` could look like this.

::

  {
    domain_names = {
      alpha_centauri = 'Alpha Centauri'
    },

    -- more domain specific config follows below
  }

In this example “Alpha Centauri” is the user-visible ``domain_name`` for the
domain_code ``alpha_centauri``. Also note that the domain code
``alpha_centauri`` matches the filename ``alpha_centauri.conf``.

Additional domain codes/names can be added to ``domain_names``, which
are treated as aliases for the their domain configuration. Aliases can
be used to offer more fine-grained and well-recognizable domain choices
to users. Having multiple aliases on a single domain is a helpful
precursor to splitting the domain into even smaller blocks.

Furthermore you have to specify the ``default_domain`` in the ``site.conf``.
This domain is applied in following cases:

- When the config mode is skipped.
- When a domain is removed in a new firmware release, the default_domain
  will be chosen then.
- When a user selects a wrong domain code via uci.

Please note, that this value is saved to uci, so changing the `default_domain`
value in the `site.conf` in a new firmware release only affects the actual
domain of a router, if and only if one of the above conditions matches.


Switching the domain
--------------------

Via commandline
^^^^^^^^^^^^^^^

::

  gluon-switch-domain 'newdomaincode'

When the node is not in config mode, ``gluon-switch-domain`` will automatically
reboot the node by default. This can be suppressed by passing ``--no-reboot``::

  gluon-switch-domain --no-reboot 'newdomaincode'

Switching the domain without reboot is currently **experimental**.

Via config mode
^^^^^^^^^^^^^^^

To allow switching the domain via config mode, add ``config-mode-domain-select``
to the enabled features in the image-customization.lua file.

|image0|

Allowed site variables
----------------------

Internally the site variables are merged from the ``site.conf`` and the
selected ``domain.conf``, so the most variables are also allowed in
``site.conf`` and in ``domain.conf``. But there are some exceptions,
which do not make sense in a domain or site specific way. The following
sections give an overview over variables that are only usable in either
site or domain context.

site.conf only variables
^^^^^^^^^^^^^^^^^^^^^^^^

- Used in as initial default values, when the firmware was just flashed
  and/or the config mode is skipped, so they do not make sense in a
  domain specific way:

  - authorized_keys
  - default_domain
  - poe_passthrough
  - interfaces.*.default_roles
  - setup_mode.skip
  - autoupdater.branch
  - mesh_vpn.enabled
  - mesh_vpn.bandwidth_limit
  - mesh_vpn.bandwidth_limit.enabled
  - mesh_vpn.bandwidth_limit.ingress
  - mesh_vpn.bandwidth_limit.egress

- Variables that influence the appearance of the config mode,
  domain-independent because they are relevant before a domain was selected.

  - config_mode.geo_location.show_altitude
  - config_mode.hostname.optional
  - config_mode.remote_login
  - config_mode.remote_login.show_password_form
  - config_mode.remote_login.min_password_length
  - hostname_prefix
  - mesh_vpn.fastd.configurable
  - roles.default
  - roles.list

- Specific to a firmware build itself:

  - site_code
  - site_name
  - autoupdater.branches.*.name
  - autoupdater.branches.*.good_signatures
  - autoupdater.branches.*.pubkeys

- We simply do not see any reason, why these variables could be helpful
  in a domain specific way:

  - mesh_vpn.fastd.syslog_level
  - timezone
  - regdom

domain.conf only variables
^^^^^^^^^^^^^^^^^^^^^^^^^^

- Obviously:

  - domain_names

    - a table of domain codes to domain names
      ``domain_names = { foo = 'Foo Domain', bar = 'Bar Domain', baz = 'Baz Domain' }``

  - hide_domain

    - prevents a domain name(s) from appearing in config mode, either
      boolean or array of domain codes

      - ``true``, ``false``
      - ``{ 'foo', 'bar' }``

- Because each domain is considered a separate layer 2 network, these
  values should be different in each domain:

  - next_node.ip4
  - next_node.ip6
  - next_node.name
  - prefix6
  - prefix4
  - extra_prefixes6

- To prevent accidental bridging of different domains, all meshing
  technologies should be separated:

  - domain_seed (wired mesh)

    - must be a random value used to derive the vxlan id for wired meshing

  - wifi*.mesh.id
  - mesh_vpn.fastd.groups.*.peers.remotes
  - mesh_vpn.fastd.groups.*.peers.key

- Clients consider WiFi networks sharing the same ESSID as if they were
  the same L2 network and try to reconfirm and reuse previous
  addressing. If multiple neighbouring domains shared the same ESSID,
  the roaming experience of clients would degrade.

  - wifi*.ap.ssid

- Some values should be only set in legacy domains and not in new domains.

  - mesh.vxlan

    - By default, this value is `true`. It should be only set to `false`
      for one legacy domain, since vxlan prevents accidental wired
      merges of domains. For old domains this value is still available
      to keep compatibility between all nodes in one domain.

  - next_node.mac

    - For new domains, the default value should be used, since there is
      no need for a special mac (or domain specific mac). For old domains
      this value is still available to keep compatibility between all
      nodes in one domain.

Example config
--------------

site.mk
^^^^^^^

.. literalinclude:: ../multidomain-site-example/site.mk
  :language: makefile

site.conf
^^^^^^^^^

.. literalinclude:: ../multidomain-site-example/site.conf
  :language: lua

domains/alpha_centauri.conf
^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. literalinclude:: ../multidomain-site-example/domains/alpha_centauri.conf
  :language: lua

i18n/en.po
^^^^^^^^^^

.. literalinclude:: ../multidomain-site-example/i18n/en.po
  :language: po

i18n/de.po
^^^^^^^^^^

.. literalinclude:: ../multidomain-site-example/i18n/de.po
  :language: po

modules
^^^^^^^

.. literalinclude:: ../multidomain-site-example/modules
  :language: makefile


.. |image0| image:: multidomain_configmode.gif
Original line number Original line Diff line number Diff line
Private WLAN
Private WLAN
============
============


It is possible to set up a private WLAN that bridges the WAN port and is seperated from the mesh network.
It is possible to set up a private WLAN that bridges the uplink port and is separated from the mesh network.
Please note that you should not enable ``mesh_on_wan`` simultaneously.
Please note that you should not enable Wired Mesh on the uplink port at the same time.

The private WLAN is encrypted using WPA2 by default. On devices with enough flash and a supported radio,
WPA3 or WPA2/WPA3 mixed-mode can be used instead of WPA2. For this to work, the ``wireless-encryption-wpa3``
feature has to be enabled as a feature.

It is recommended to enable IEEE 802.11w management frame protection for WPA2/WPA3 networks, however this
can lead to connectivity problems for older clients. In this case, management frame protection can be
made optional or completely disabled in the advanced settings tab.


The private WLAN can be enabled through the config mode if the package ``gluon-web-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::
You may also enable a private WLAN using the command line::


  uci set wireless.wan_radio0=wifi-iface
  RID=0
  uci set wireless.wan_radio0.device=radio0
  SSID="privateWLANname"
  uci set wireless.wan_radio0.network=wan
  KEY="yoursecret1337password"
  uci set wireless.wan_radio0.mode=ap

  uci set wireless.wan_radio0.encryption=psk2
  uci set wireless.wan_radio$RID=wifi-iface
  uci set wireless.wan_radio0.ssid="$SSID"
  uci set wireless.wan_radio$RID.device=radio$RID
  uci set wireless.wan_radio0.key="$KEY"
  uci set wireless.wan_radio$RID.network=wan
  uci set wireless.wan_radio0.disabled=0
  uci set wireless.wan_radio$RID.mode=ap
  uci set wireless.wan_radio$RID.encryption=psk2
  uci set wireless.wan_radio$RID.ssid="$SSID"
  uci set wireless.wan_radio$RID.key="$KEY"
  uci set wireless.wan_radio$RID.disabled=0
  uci set wireless.wan_radio$RID.macaddr=$(lua -e "print(require('gluon.wireless').get_wlan_mac('wan_radio', $RID))")
  uci commit
  uci commit
  wifi
  wifi


Original line number Original line Diff line number Diff line
@@ -2,8 +2,8 @@ Roles
=====
=====


It is possible to define a set of roles you want to distinguish at backend side. One node can own one
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 respondd/announced 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
nodes when parsing respondd data. E.g to count only **normal** nodes and not the gateways
or servers (nodemap). A lot of things are possible.
or servers (nodemap). A lot of things are possible.


For this the section ``roles`` in ``site.conf`` is needed::
For this the section ``roles`` in ``site.conf`` is needed::
@@ -28,7 +28,7 @@ If you want node owners to change the defined roles via config-mode you can add


The role is saved in ``gluon-node-info.system.role``. To change the role using command line do::
The role is saved in ``gluon-node-info.system.role``. To change the role using command line do::


  uci set gluon-node-info.system.role="$ROLE"
  uci set gluon-node-info.@system[0].role="$ROLE"
  uci commit
  uci commit


Please replace ``$ROLE`` by the role you want the node to own.
Please replace ``$ROLE`` by the role you want the node to own.
+30 −0
Original line number Original line Diff line number Diff line
Status-Page
===========

When the feature ``gluon-status-page`` is enabled, Gluon nodes run a HTTP server with status information on all IP addresses of ``br-client``.
This makes it possible to check information of the node in realtime.

If the mesh protocol ``gluon-mesh-batman-adv`` is installed too, the package ``gluon-status-page-mesh-batman-adv`` is added too according to the :ref:`user-site-feature-flags`

.. _status-page-example-picture:

Example Picture
---------------

The left side of the status page contains Overview information.
In the middle, current monitoring information abut the system, number of clients, radios, amount of traffic and connected mesh-vpn if any are shown.
The right side of the Status-Page contains information about Neighbours to this node through :doc:`wired-mesh` as well as wireless mesh.

.. image:: status-page.png

Mesh Graphs
-----------

When wireless mesh is enabled, the mesh interfaces show realtime Graphs about the received signal strength (RSSI) in dBm.

Neighbours
----------

The list of neighbours at first shows the mac-address of the neighbour it sees.
The status-page sends a second request to ``http://[ipv6]/cgi-bin/dyn/neighbours-nodeinfo?mesh-vpn`` which triggers the lookup of neighbour information on the node itself.
Through this, the actual nodenames of the neighbours are shown on the status-page as can be seen in the :ref:`status-page-example-picture`.

docs/features/tls.rst

0 → 100644
+10 −0
Original line number Original line Diff line number Diff line
TLS support
===========

The generic TLS implementation which is currently used by OpenWRT can be installed or added as dependency through the package ``gluon-tls``.
This removes the need for community packages to depend on a specific TLS implementation (like mbedtls, OpenSSL or WolfSSL).

This package is an alias for the current TLS implementation used.
To allow for easy usage of communicating through HTTPS from the node, typical Certificate Authorities (CAs) are included through the package ``ca-bundle`` .

* Starting with OpenWRT 23.05, mbedtls is the default TLS layer - this is reflected in Gluon :ref:`v2023.2 <releases-v2023.2-minor-changes>`. HTTPS is used by default to communicate with OpenWRT opkg servers.

docs/features/vpn.rst

0 → 100644
+250 −0

File added.

Preview size limit exceeded, changes collapsed.

Original line number Original line Diff line number Diff line
@@ -2,10 +2,16 @@ WLAN configuration
==================
==================


Gluon allows to configure 2.4GHz and 5GHz radios independently. The 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
may include one or both of the two networks "client" (AP mode) and "mesh" (802.11s
mode) and "ibss" (adhoc mode), which can be used simultaneously (using "mesh" and
mode), which can be used simultaneously. See :doc:`../user/site` for details on the
"ibss" at same time should be avoided though as weaker hardware usually can't handle the additional
configuration.
load). See :doc:`../user/site` for details on the configuration.

Outdoor mode
------------

Configuring the node for outdoor use tunes the 5 GHz radio to a frequency and transmission power that conforms with the local regulatory requirements. 
It also enables dynamic frequency selection (DFS; radar detection).
At the same time, mesh functionality is disabled as it requires neighbouring nodes to stay on the same channel permanently.


Upgrade behaviour
Upgrade behaviour
-----------------
-----------------
@@ -16,19 +22,12 @@ on upgrades the existing setting is always retained (as this setting may have be
by the user). This means that it is not possible to enable or disable an existing network
by the user). This means that it is not possible to enable or disable an existing network
configurations during upgrades.
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
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
configured in the site.conf. The channel width will be reset to Gluon's default. If you need to preserve
you can configure this via the uci section ``gluon-core.wireless``::
these settings during upgrades you can configure this via the uci section ``gluon-core.wireless``::


  uci set gluon-core.@wireless[0].preserve_channels='1'
  uci set gluon.wireless.preserve_channels='1'


When channels should be preserved, toggling the outdoor mode will have no effect on the channel settings.
Therefore, the Outdoor mode settings won't be displayed in config mode.
Keep in mind that nodes running wifi interfaces on custom channels can't mesh with default nodes anymore!
Keep in mind that nodes running wifi interfaces on custom channels can't mesh with default nodes anymore!
+72 −284

File changed.

Preview size limit exceeded, changes collapsed.

Original line number Original line Diff line number Diff line
features {
	'autoupdater',
	'ebtables-filter-multicast',
	'ebtables-filter-ra-dhcp',
	'ebtables-limit-arp',
	'mesh-batman-adv-15',
	'mesh-vpn-fastd',
	'respondd',
	'status-page',
	'web-advanced',
	'web-wizard',
}

packages {
	'iwinfo',
}

if not device_class('tiny') then
	features {'wireless-encryption-wpa3'}
end
Original line number Original line Diff line number Diff line
.. _package-gluon-config-mode-geo-location-osm:

gluon-config-mode-geo-location-osm
==================================

When package *gluon-config-mode-geo-location-osm* is enabled, the configuration wizard will
try to load an OSM-based map to allow the user to specify the node location.
Loading the map requires a working internet connection, for example via WLAN
(while connected to the Gluon node via Ethernet).

.. image:: gluon-config-mode-geo-location-osm.png
+148 −0

File added.

Preview size limit exceeded, changes collapsed.

docs/requirements.txt

0 → 100644
+2 −0

File added.

Preview size limit exceeded, changes collapsed.

+36 −73

File changed.

Preview size limit exceeded, changes collapsed.

docs/user/mtu.rst

0 → 100644
+225 −0

File added.

Preview size limit exceeded, changes collapsed.

+749 −381

File changed.

Preview size limit exceeded, changes collapsed.

File changed.

Preview size limit exceeded, changes collapsed.

+11 −14

File changed.

Preview size limit exceeded, changes collapsed.

overlay/opkg.mk

deleted100644 → 0
+0 −10

File deleted.

Preview size limit exceeded, changes collapsed.

+48 −18

File changed.

Preview size limit exceeded, changes collapsed.

+85 −14

File changed.

Preview size limit exceeded, changes collapsed.