Compare commits

..

93 Commits

Author SHA1 Message Date
John Crispin
a4806f740d hostapd: track ratelimit config and reload wifi when state changes
Fixes: WIFI-5701
Signed-off-by: John Crispin <john@phrozen.org>
2021-11-11 13:41:11 +01:00
John Crispin
35740f321d ucentral-schema: fix wifi reload when using rate-limit
a78cad2 track if a ssid has rate-limiting enabled

Fixes: WIFI-5701
Signed-off-by: John Crispin <john@phrozen.org>
2021-11-11 13:40:43 +01:00
John Crispin
74c148e905 ucentral-schema: update to latest HEAD
5c3c572 airtime-fairness: add ATF to the data model

Fixes: WIFI-5703
Signed-off-by: John Crispin <john@phrozen.org>
2021-11-11 13:37:29 +01:00
John Crispin
a77d881147 atfpolicy: add package
Add a Airtime Scheduler that adjusts an UEs ATF weight based on its
WMM/TID usage.

Fixes: WIFI-5703
Signed-off-by: John Crispin <john@phrozen.org>
2021-11-11 02:22:02 +01:00
John Crispin
065539bbb3 ucentral-schema: update to latest HEAD
dd9708d openflow: add port property

Fixes: WIFI-5700
Signed-off-by: John Crispin <john@phrozen.org>
2021-11-10 17:06:35 +01:00
John Crispin
e2d90a7b06 procd: update to latest HEAD
fixes build on wifi-5 due to missing dependencies in last update

Signed-off-by: John Crispin <john@phrozen.org>
2021-11-10 10:42:17 +01:00
John Crispin
8bb9816e2b ipq807x: fix setting mac on cig wf-194c/4
Fixes: WIFI-3967
Signed-off-by: John Crispin <john@phrozen.org>
2021-11-09 17:34:16 +01:00
John Crispin
9673329c07 ucentral-schema: update to latest HEAD
c4e889c filter out _none, _4, _6 interfaces from state

Signed-off-by: John Crispin <john@phrozen.org>
2021-11-09 17:24:21 +01:00
John Crispin
2571ae5210 rpcd: add backport
Signed-off-by: John Crispin <john@phrozen.org>
2021-11-09 17:24:21 +01:00
John Crispin
8caffe46b4 procd: update to latest HEAD
Fixes: WIFI-5443
Signed-off-by: John Crispin <john@phrozen.org>
2021-11-09 15:39:10 +01:00
John Crispin
25641d5199 libubox: update to latest HEAD
Fixes: WIFI-5443
Signed-off-by: John Crispin <john@phrozen.org>
2021-11-09 15:39:10 +01:00
John Crispin
2b3cc2a5cf ucentral: add a dual-stack example config
Signed-off-by: John Crispin <john@phrozen.org>
2021-11-09 15:36:11 +01:00
John Crispin
12cc29265c ucentral-schema: update to latest HEAD
5a4cacb ipv6: default ipv6_prefix to 64 on downstream interfaces

Signed-off-by: John Crispin <john@phrozen.org>
2021-11-09 15:35:51 +01:00
Sharadanand Karanjkar
34a6f06bd9 hostapd: Added control for co-location enable and disable in config.
Re-enabling support for enabling configuring rnr_beacon and he_co_locate flag in hostapd config files.

Signed-off-by: Sharadanand Karanjkar <sk@simonwunderlich.de>
2021-11-09 15:35:51 +01:00
John Crispin
c343d5e629 docker: install clang-12 to speedup the build jobs
Signed-off-by: John Crispin <john@phrozen.org>
2021-11-09 13:10:09 +01:00
John Crispin
501907eeda ucentral-schema: update to latest HEAD
4caf81b renderer: setting the dns server was broken on static upstream interfaces

Signed-off-by: John Crispin <john@phrozen.org>
2021-11-09 12:54:39 +01:00
John Crispin
ba406fe01b hostapd: add radius based wispr/bandwidth control
Fixes: WIFI-4888
Signed-off-by: John Crispin <john@phrozen.org>
2021-11-09 12:50:31 +01:00
John Crispin
d61d5cd35e ucentral-client: update to latest HEAD
This adds a connection watchdog.

Signed-off-by: John Crispin <john@phrozen.org>
2021-11-08 09:15:42 +01:00
Paul Spooren
68d544c9af scripts: gen_config allow explicit warning message
Instead of generically mentioning a missing dependency the host
dependency can also be explained by defining a `warning`.

Warning messages are collected and printed at the end.

Signed-off-by: Paul Spooren <mail@aparcar.org>
2021-11-08 09:15:42 +01:00
Paul Spooren
5d86871253 profiles: qosify add explicit host dependency warning
If the host dependency is missing be explicit about the increasd build
time of more than an hour.

Signed-off-by: Paul Spooren <mail@aparcar.org>
2021-11-08 09:15:42 +01:00
John Crispin
460785cbe3 maverick: keep firstcontact and ucentral-client running while in maverick
Fixes: WIFI-5439
Signed-off-by: John Crispin <john@phrozen.org>
2021-11-05 14:46:32 +01:00
Paul Spooren
1cace058c5 profiles: swich ucentral ap's to qosify profile
Instead of installing the package directly use the qosify profile which
automatically handles the host dependency clang/llvm.

Signed-off-by: Paul Spooren <mail@aparcar.org>
2021-11-05 14:46:32 +01:00
Paul Spooren
5aaf734732 profiles: add qosify profile to use host toolchain
In case clang/llvm is available as a host dependency, modify the
configuration to use it. In case it is not available build clang/llvm
(takes ~30min).

Signed-off-by: Paul Spooren <mail@aparcar.org>
2021-11-05 14:46:32 +01:00
Paul Spooren
9d3768a68d scripts: gen_config add host_dependencies option
In case a package/image requres specific host dependencies it is
possible to define entries in the `host_dependencies` array. Each entry
is an object containing at least `name` and `which`. The `which` array
contains tools to be checked in the current `PATH`.

Optionally the two options `success_diffconfig` and
`fallback_diffconfig` can be set. The former is optionally added in case
the tool is found. The latter is added if the dependency is not
available.

If the dependecy is not available and no `fallback_diffconfig` is set,
the config generation is considered impossible and stopped.

Signed-off-by: Paul Spooren <mail@aparcar.org>
2021-11-05 10:47:41 +01:00
John Crispin
975aae507b llvm/clang: add support to build llvm/clang
Signed-off-by: John Crispin <john@phrozen.org>
2021-11-05 10:47:41 +01:00
John Crispin
cc0576886a ucentral-schema: update to latest HEAD
Signed-off-by: John Crispin <john@phrozen.org>
2021-11-04 16:33:04 +01:00
John Crispin
9c36b155f6 ucentral-schema: update to latest HEAD
dbb2aaf fix dns only classifiers and add missing class-selectors
4d2c297 qos: split class selector into its own yml
728c6f4 qos: add bulk detection support to data-model/renderer
f5a4651 wmm: fix qos_map_set generation
b958719 update qos/fqdn matching

Signed-off-by: John Crispin <john@phrozen.org>
2021-11-04 15:19:56 +01:00
John Crispin
28ac14ccc4 udnssnoop: add dns reply snooping package
Signed-off-by: John Crispin <john@phrozen.org>
2021-11-04 15:18:59 +01:00
John Crispin
e18e7fc8f6 hostapd: update qos_map_set code inside the script-foo
Signed-off-by: John Crispin <john@phrozen.org>
2021-11-04 15:18:59 +01:00
John Crispin
04d78d3334 qosify: update to latest HEAD
Signed-off-by: John Crispin <john@phrozen.org>
2021-11-04 15:18:59 +01:00
John Crispin
a9fd11ed8a ucentral-schema: update to latest HEAD
75c0a39 renderer: add wired interfaces to OVS bridge
5e42737 generate-reader.uc: rename ip to uc-ip

Signed-off-by: John Crispin <john@phrozen.org>
2021-11-02 17:39:49 +01:00
Stijn Tintel
839f43c010 openflow: sync pending change from openwrt-packages
c0daf3aaf openvswitch: bring up member ports

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
2021-11-02 17:35:28 +01:00
John Crispin
f599a42618 ucentral-client: update to latest HEAD
eabfeaa dynamically start event daemon when we need it

Signed-off-by: John Crispin <john@phrozen.org>
2021-11-02 17:30:46 +01:00
John Crispin
8bc7bee3bc ucentral-schema: update to latest HEAD
434f749 renderer: filter out HE160 and HE80+80

Signed-off-by: John Crispin <john@phrozen.org>
2021-11-01 16:04:35 +01:00
John Crispin
53004cc39c ubus: update to latest HEAD
Signed-off-by: John Crispin <john@phrozen.org>
2021-11-01 12:07:27 +01:00
John Crispin
9a1c8cff9f ucentral-schema: update to latest HEAD
9f8f80e renderer: fix wifi uci config in dual stack mode

Fixes: WIFI-5400
Signed-off-by: John Crispin <john@phrozen.org>
2021-11-01 11:49:50 +01:00
John Crispin
2d0e2bccbf netifd: remove NE dhcp hack
Fixes: WIFI-4949
Signed-off-by: John Crispin <john@phrozen.org>
2021-11-01 11:33:09 +01:00
John Crispin
70c2c36e0f qosify: update to latest version
This improves bulk traffic detection.

Signed-off-by: John Crispin <john@phrozen.org>
2021-11-01 11:32:13 +01:00
John Crispin
11ed0b089c ipq807x: update BPF backport
The patch broke kernel build with lockdep enabled

Signed-off-by: John Crispin <john@phrozen.org>
2021-11-01 11:30:55 +01:00
John Crispin
29058df59b luci-mod-ucentral: the continue button was grey when trying to flash an image
Fixes: WIFI-5072
Signed-off-by: John Crispin <john@phrozen.org>
2021-11-01 07:58:30 +01:00
John Crispin
e840bab8cc ucentral-schema: update to latest HEAD
17fefd3 pass-point: domain_name should be a ',' and not ':' seperated list

Fixes: WIFI-4869
Signed-off-by: John Crispin <john@phrozen.org>
2021-11-01 07:11:26 +01:00
John Crispin
e3e3c9ea72 qosify: disable automatic bulk detection until it is in the data-model
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-30 08:39:47 +02:00
John Crispin
a3125e6ab2 ipq807x: fix vlan offload support in v5.10 eBPF backport
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-30 08:39:39 +02:00
John Crispin
63e8b90656 qosify: update to latest bpf-headers ABI
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-29 19:49:34 +02:00
John Crispin
70f231d948 bpf-headers: more ABI fixes
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-29 19:48:56 +02:00
John Crispin
2983d9ca2b ath11k-wifi: add trailing '\' in Makefile
This caused image to pop up builds with no BDF in the image.

Fixes: 1a305421 (ipq807x: add support for wallystech dr6018)
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-29 08:36:21 +02:00
John Crispin
2283a64e57 ipq807x: backport eBPF layer from v5.10 kernel
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-28 19:40:05 +02:00
John Crispin
1a3054218f ipq807x: add support for wallystech dr6018
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-28 19:40:05 +02:00
John Crispin
7d26b55cb5 Dockerfile: install llvm/clang
This is required by the bpf-header compat package.

Signed-off-by: John Crispin <john@phrozen.org>
2021-10-28 19:40:05 +02:00
John Crispin
cd85723609 ipq807x: fix v4.4 kernel-headers for BPF
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-28 10:15:58 +02:00
John Crispin
6d922da9b8 backports: add iproute2 compile fix
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-28 10:15:58 +02:00
John Crispin
6b81555bb2 backports: add bpf-headers compat layer
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-28 10:15:58 +02:00
John Crispin
267157563e ucentral-schema: update to latest HEAD
1bdc8de update the qos scheme/renderer

Signed-off-by: John Crispin <john@phrozen.org>
2021-10-28 10:15:58 +02:00
John Crispin
6505ca0a8f hostapd: fix qos_map_set
The option was incorrectly masked by iw_enable.

Signed-off-by: John Crispin <john@phrozen.org>
2021-10-28 10:15:58 +02:00
John Crispin
5cafdaea60 profiles: add qosify to the ap profile
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-28 10:15:58 +02:00
John Crispin
4a3d4f5609 qosify: add new QoS package
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-28 10:15:58 +02:00
John Crispin
3085dc78ef ucode: update to latest HEAD
* adds resolv module

Signed-off-by: John Crispin <john@phrozen.org>
2021-10-27 18:21:02 +02:00
John Crispin
897ab17137 ucentral-schema: update to latest HEAD
6b3bdb1 force dnsmasq reload after applying a config

Fixes: WIFI-5025
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-22 18:05:38 +02:00
John Crispin
840319e24f udevmand: update to latest HEAD
b5a68ca fix wrap around glitch

Signed-off-by: John Crispin <john@phrozen.org>
2021-10-22 10:35:53 +02:00
John Crispin
00197d703e ath11k: fix regdb upload
Make ath11k honour latest regdb.

Fixes: WIFI-3256
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-22 10:27:47 +02:00
John Crispin
a290ad3764 ucentral-schema: update to latest HEAD
d59450b add bssid to radio stats

Signed-off-by: John Crispin <john@phrozen.org>
2021-10-22 08:18:50 +02:00
John Crispin
972eea34eb ucentral-client: update to latest HEAD
0179c0f Drop 60s socket timeout

Signed-off-by: John Crispin <john@phrozen.org>
2021-10-22 08:17:48 +02:00
John Crispin
851507921a hostapd: add wds fixes to AX hostapd
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-22 08:15:43 +02:00
John Crispin
b364ab3064 certificates: fix the file owner and permission of the certificates
This was breaking hostapd local-certificates support.

Signed-off-by: John Crispin <john@phrozen.org>
2021-10-22 07:58:20 +02:00
John Crispin
45143cc2c9 chilli-redirect: add uamsecret to list of possible options
Fixes: WIFI-4935
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-21 16:02:28 +02:00
John Crispin
895e501b93 hostapd: update to latest HEAD
This fixes an issue where WDS would not work reliably upon AP->STA transition.

Signed-off-by: John Crispin <john@phrozen.org>
2021-10-21 11:33:58 +02:00
John Crispin
7d9594c3c8 netifd: update to latest HEAD
This fixes an issue where WDS would not work reliably upon AP->STA transition.

Signed-off-by: John Crispin <john@phrozen.org>
2021-10-21 11:33:25 +02:00
John Crispin
485c689408 ipq807x: add support for wf194c4
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-20 08:23:04 +02:00
John Crispin
ec2e24e982 workflow: update wf-188 and ec-420 profile
This will let FMS properly pick the files up.

Fixes: WIFI-4929
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-18 10:10:07 +02:00
John Crispin
32f86e2d77 ucentral-event: update to latest HEAD
7b0d136 align event names

Signed-off-by: John Crispin <john@phrozen.org>
2021-10-18 09:32:50 +02:00
John Crispin
53e73b24de ucentral-schema: update metric example
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-18 08:58:36 +02:00
John Crispin
e57dad9009 ucentral-schema: update to latest HEAD
0456fc4 telemetry task was not getting enqueued in the correct runqueue

Signed-off-by: John Crispin <john@phrozen.org>
2021-10-18 08:58:17 +02:00
John Crispin
01c3ce4fc7 ucentral-wifi: update to latest HEAD
b6dd24f add bssid to wifi scan results

Signed-off-by: John Crispin <john@phrozen.org>
2021-10-18 07:01:16 +02:00
John Crispin
6b3d2b8059 ipq40xx: add spw2ac1200-lan-poe profile
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-14 16:22:24 +02:00
John Crispin
ba079bea9f linksys_ea6350-v4: make sure the image land in S3 with the correct name
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-14 12:39:38 +02:00
John Crispin
f971f3a4d4 luci-mod-ucentral: the unit was not correctly rebooting after "save & apply"
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-14 12:12:42 +02:00
Stijn Tintel
32524c19bd This is required for Express Wi-Fi in bridged mode
Fixes: WIFI-4639
Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
2021-10-13 18:17:52 +02:00
John Crispin
966353e747 ucentral-schema: update to latest HEAD
73e9fbc open-flow: support OpenFlow bridged mode
ac24d7f drop vlan-id from the gre tunnel definition

Fixes: WIFI-4639
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-13 18:17:46 +02:00
John Crispin
37f30d95f8 ucentral-schema: update to latest HEAD
7e59b14 only generate docs if the tool is installed
e440ced open-flow: fix controller property type
b85abaf generate-reader.uc: introduce ip format
288997c open-flow: update generated files
e9d7049 generate.sh: generate schemareader.uc before docs

Signed-off-by: John Crispin <john@phrozen.org>
2021-10-13 16:44:19 +02:00
John Crispin
e699bebac7 fbwifi: sync with latest HEAD
Fixes: WIFI-4910
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-13 14:08:12 +02:00
John Crispin
0e5ec91a12 luci: start using the upstream feed and move the maverick packages into the tree
Fixes: WIFI-4911
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-13 13:01:39 +02:00
John Crispin
3cad34e1b9 certififcates: reduce log noise when mounting the certificates partition
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-13 10:51:21 +02:00
Stijn Tintel
2c37a6983f openflow: sync changes from openwrt-packages
c05103da9 openvswitch: add option for OpenFlow datapath desc
 b2bfb572a openvswitch: fix build with libunbound
 9e45d4534 openvswitch: add option for failure mode

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
2021-10-13 07:37:16 +02:00
John Crispin
330eead632 ipq40xx: improve SPW2AC1200 sysupgrade
with this fix it does not matter if the unit is in primary or secondary boot mode.

Signed-off-by: John Crispin <john@phrozen.org>
2021-10-12 18:25:57 +02:00
John Crispin
f1456f321a ipq807x: update eap102 bdf
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-12 18:25:42 +02:00
John Crispin
9152942d93 ucentral-schema: update to latest HEAD
60549a8 open-flow: use mode ssl by default
70d8465 openflow: remove duplicate code
2718e30 schema: add property to set OpenFlow datapath description

Signed-off-by: John Crispin <john@phrozen.org>
2021-10-12 11:05:20 +02:00
John Crispin
f202250a68 ucentral-schema: update to latest HEAD
50d182c renderer: add missing support for hostapd_bss_raw and hostapd_iface_raw

Signed-off-by: John Crispin <john@phrozen.org>
2021-10-12 10:53:49 +02:00
John Crispin
fad14af474 ipq40xx: improve EdgeCore-SPW2AC1200 sysupgrade
Make sure to always flash into the primary partition.

Signed-off-by: John Crispin <john@phrozen.org>
2021-10-12 08:13:11 +02:00
John Crispin
5a7bafede0 ucentral-schema: update to latest HEAD
8eb586b 11u domain operator name was a singleton but should be an array
4eb1560 iw_nai_realm was being written to uci using set and not add_list
a35a0ea add support for hs20_wan_metrics

Fixes: WIFI-4868
Fixes: WIFI-4869
Fixes: WIFI-4870
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-11 11:51:39 +02:00
John Crispin
6738a933ab ucentral-schema: add example vlan config for switches
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-09 08:11:16 +02:00
John Crispin
a46262aaaa hostapd: fix wpa3-eap modes
wpa3 was not setup correctly and wpa3-192 was missing

Fixes: WIFI-4281
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-07 14:08:17 +02:00
John Crispin
2988180211 maverick: fix feature on single port devices
On single port devices no logical lan interface was setup resulting in
clients associating not being provided with DHCP.

Fixes: WIFI-4641
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-07 09:07:37 +02:00
John Crispin
ec0d693d12 ath79: add certificates partition for indio device
Signed-off-by: John Crispin <john@phrozen.org>
2021-10-05 16:38:32 +02:00
136 changed files with 57877 additions and 609 deletions

View File

@@ -11,7 +11,7 @@ jobs:
strategy:
fail-fast: false
matrix:
target: ['cig_wf188', 'cig_wf194c', 'cig_wf160d', 'edgecore_eap101', 'edgecore_eap102', 'edgecore_ecs4100-12ph', 'edgecore_ecw5211', 'edgecore_ecw5410', 'edgecore_oap100', 'edgecore_ssw2ac2600', 'edgecore_spw2ac1200', 'hfcl_ion4.yml', 'indio_um-305ac', 'linksys_ea6350', 'linksys_e8450-ubi', 'linksys_ea8300', 'tplink_ec420', 'tplink_ex227', 'tplink_ex228', 'tplink_ex447', 'wallys_dr40x9' ]
target: ['cig_wf188n', 'cig_wf194c', 'cig_wf194c4', 'cig_wf160d', 'edgecore_eap101', 'edgecore_eap102', 'edgecore_ecs4100-12ph', 'edgecore_ecw5211', 'edgecore_ecw5410', 'edgecore_oap100', 'edgecore_ssw2ac2600', 'edgecore_spw2ac1200', 'edgecore_spw2ac1200-lan-poe', 'hfcl_ion4.yml', 'indio_um-305ac', 'linksys_ea6350-v4', 'linksys_e8450-ubi', 'linksys_ea8300', 'tp-link_ec420-g1', 'tplink_ex227', 'tplink_ex228', 'tplink_ex447', 'wallys_dr40x9' ]
steps:
- uses: actions/checkout@v2

View File

@@ -1,7 +1,7 @@
From 2af08d2e85ee946de5f53bbd0ddf239de9b78f6d Mon Sep 17 00:00:00 2001
From bb797fc82f8ade2a1c0b7a68dd7c920eae2f531f Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Tue, 18 May 2021 10:46:43 +0200
Subject: [PATCH 12/27] libubox: update to latest HEAD
Subject: [PATCH 01/74] libubox: update to latest HEAD
Signed-off-by: John Crispin <john@phrozen.org>
---
@@ -9,7 +9,7 @@ Signed-off-by: John Crispin <john@phrozen.org>
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/package/libs/libubox/Makefile b/package/libs/libubox/Makefile
index d2c07783e1..33aa73eef7 100644
index d2c07783e1..3b01930d6c 100644
--- a/package/libs/libubox/Makefile
+++ b/package/libs/libubox/Makefile
@@ -5,9 +5,9 @@ PKG_RELEASE=2
@@ -19,9 +19,9 @@ index d2c07783e1..33aa73eef7 100644
-PKG_MIRROR_HASH:=7dd1db1e0074a9c7c722db654cce3111b3bd3cff0bfd791c4497cb0f6c22d3ca
-PKG_SOURCE_DATE:=2021-05-16
-PKG_SOURCE_VERSION:=b14c4688612c05c78ce984d7bde633bce8703b1e
+PKG_MIRROR_HASH:=1cdb91ac0ee925f133ee9f70eac131a99def312fe7cf0aed44df84eb1762e30b
+PKG_MIRROR_HASH:=82d84fb97e725b0a18ceac639cae0c17d922754bb648ff58c62069d92798a6cd
+PKG_SOURCE_DATE:=2021-08-19
+PKG_SOURCE_VERSION:=d716ac4bc4236031d4c3cc1ed362b502e20e3787
+PKG_SOURCE_VERSION:=c86a894ec63d83ecf2c373bbf9dc8fba9713d942
PKG_ABI_VERSION:=$(call abi_version_str,$(PKG_SOURCE_DATE))
CMAKE_INSTALL:=1

View File

@@ -1,17 +1,19 @@
From 39af14f6e40bcb97772dcc0c03849fbf6aa0032b Mon Sep 17 00:00:00 2001
From 1496ca5ceb941ba725311c6c0366193092035f32 Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Thu, 27 May 2021 13:24:47 +0200
Subject: [PATCH 01/58] netifd: update to latest HEAD
Subject: [PATCH 01/60] netifd: update to latest HEAD
Signed-off-by: John Crispin <john@phrozen.org>
---
package/network/config/netifd/Makefile | 8 +++-----
.../netifd/patches/002-fix-dhcp-issue.patch | 17 +++++++++++++++++
2 files changed, 20 insertions(+), 5 deletions(-)
create mode 100644 package/network/config/netifd/patches/002-fix-dhcp-issue.patch
package/network/config/netifd/Makefile | 8 ++--
.../config/netifd/patches/100-script.patch | 21 +++++++++++
.../config/netifd/patches/hairpin.patch | 37 +++++++++++++++++++
3 files changed, 61 insertions(+), 5 deletions(-)
create mode 100644 package/network/config/netifd/patches/100-script.patch
create mode 100644 package/network/config/netifd/patches/hairpin.patch
diff --git a/package/network/config/netifd/Makefile b/package/network/config/netifd/Makefile
index 4b5f110da2..d0ddec8f61 100644
index 4b5f110da2..d41bddfd56 100644
--- a/package/network/config/netifd/Makefile
+++ b/package/network/config/netifd/Makefile
@@ -5,16 +5,14 @@ PKG_RELEASE:=1
@@ -21,9 +23,9 @@ index 4b5f110da2..d0ddec8f61 100644
-PKG_SOURCE_DATE:=2021-07-26
-PKG_SOURCE_VERSION:=440eb0647708274cc8d7d9e7c2bb0cfdfba90023
-PKG_MIRROR_HASH:=eed957036ab608fdc49bdf801fc5b4405fcd2a3a5e5d3343ec39898e156c10e9
+PKG_SOURCE_DATE:=2021-09-01
+PKG_SOURCE_VERSION:=e467e0ff44c00cdd722e7149baaa8706d44e657e
+PKG_MIRROR_HASH:=cde5c1c1609c29f24171dcd97d2264e28a6dfb724e25f4bd3c2be351b6dd4f10
+PKG_SOURCE_DATE:=2021-10-20
+PKG_SOURCE_VERSION:=c61a1d432b34babe230e49a82712608b07410fc3
+PKG_MIRROR_HASH:=2b040d039c560cbc04dfe1e496aa81f714a032db88986803728dd6b724c11cd2
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_LICENSE:=GPL-2.0
@@ -34,29 +36,76 @@ index 4b5f110da2..d0ddec8f61 100644
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
diff --git a/package/network/config/netifd/patches/002-fix-dhcp-issue.patch b/package/network/config/netifd/patches/002-fix-dhcp-issue.patch
diff --git a/package/network/config/netifd/patches/100-script.patch b/package/network/config/netifd/patches/100-script.patch
new file mode 100644
index 0000000000..6f1d2e708e
index 0000000000..e7ba83f4bb
--- /dev/null
+++ b/package/network/config/netifd/patches/002-fix-dhcp-issue.patch
@@ -0,0 +1,17 @@
+Index: netifd-2019-08-05-5e02f944/interface.c
+++ b/package/network/config/netifd/patches/100-script.patch
@@ -0,0 +1,21 @@
+Index: a/scripts/netifd-wireless.sh
+===================================================================
+--- netifd-2019-08-05-5e02f944.orig/interface.c
++++ netifd-2019-08-05-5e02f944/interface.c
+@@ -424,7 +424,11 @@ interface_main_dev_cb(struct device_user
+ interface_set_link_state(iface, false);
+ break;
+ case DEV_EVENT_TOPO_CHANGE:
+- interface_proto_event(iface->proto, PROTO_CMD_RENEW, false);
++ /* This renews the dhcp lease when the bridge adds/deletes a
++ * new interface. It causes some dhcp servers to fail in
++ * case where there are many interfaces being added to the
++ * bridge frequently. Disabling this for now. */
++ /* interface_proto_event(iface->proto, PROTO_CMD_RENEW, false); */
+ return;
+ default:
+ break;
+--- a/scripts/netifd-wireless.sh
++++ b/scripts/netifd-wireless.sh
+@@ -252,11 +252,14 @@ wireless_vif_parse_encryption() {
+ auth_type=owe
+ ;;
+ wpa3-mixed*)
+- auth_type=eap-eap192
++ auth_type=eap-eap256
+ ;;
+- wpa3*)
++ wpa3-192*)
+ auth_type=eap192
+ ;;
++ wpa3*)
++ auth_type=eap256
++ ;;
+ psk3-mixed*|sae-mixed*)
+ auth_type=psk-sae
+ ;;
diff --git a/package/network/config/netifd/patches/hairpin.patch b/package/network/config/netifd/patches/hairpin.patch
new file mode 100644
index 0000000000..25515d75d4
--- /dev/null
+++ b/package/network/config/netifd/patches/hairpin.patch
@@ -0,0 +1,37 @@
+diff --git a/wireless.c b/wireless.c
+index b26c4e8c8f0b..bd847e72ab40 100644
+--- a/wireless.c
++++ b/wireless.c
+@@ -804,20 +804,13 @@ wireless_interface_init_config(struct wireless_interface *vif)
+ vif->network = cur;
+
+ cur = tb[VIF_ATTR_MODE];
+- if (cur)
+- vif->ap_mode = !strcmp(blobmsg_get_string(cur), "ap");
+-
+- if (!vif->ap_mode)
+- return;
++ vif->ap_mode = cur && !strcmp(blobmsg_get_string(cur), "ap");
+
+ cur = tb[VIF_ATTR_ISOLATE];
+- if (cur)
+- vif->isolate = blobmsg_get_bool(cur);
++ vif->isolate = vif->ap_mode && cur && blobmsg_get_bool(cur);
+
+ cur = tb[VIF_ATTR_PROXYARP];
+- if (cur)
+- vif->proxyarp = blobmsg_get_bool(cur);
+-
++ vif->proxyarp = vif->ap_mode && cur && blobmsg_get_bool(cur);
+ }
+
+ /* vlist update call for wireless interface list */
+@@ -846,8 +839,6 @@ vif_update(struct vlist_tree *tree, struct vlist_node *node_new,
+ wireless_interface_handle_link(vif_old, NULL, false);
+ free(vif_old->config);
+ vif_old->config = blob_memdup(vif_new->config);
+- vif_old->isolate = vif_new->isolate;
+- vif_old->ap_mode = vif_new->ap_mode;
+ wireless_interface_init_config(vif_old);
+ free(vif_new);
+ } else if (vif_new) {
--
2.25.1

View File

@@ -1,14 +1,14 @@
From c51842eff4bcbc1def57e54d5eab0e5df2046d7e Mon Sep 17 00:00:00 2001
From 6e3370a4c785c2c245b77832960f1dbed2736192 Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Sat, 4 Sep 2021 05:48:27 +0200
Subject: [PATCH 01/56] hostapd: update to latest HEAD
Subject: [PATCH 01/70] hostapd: update to latest HEAD
Signed-off-by: John Crispin <john@phrozen.org>
---
package/network/services/hostapd/Makefile | 15 +-
.../hostapd/files/hostapd-basic.config | 2 +-
.../hostapd/files/hostapd-full.config | 4 +-
.../network/services/hostapd/files/hostapd.sh | 145 +++++++--
.../network/services/hostapd/files/hostapd.sh | 188 +++++++++---
...-fix-frequency-setup-with-HE-enabled.patch | 196 -------------
...> 001-wolfssl-init-RNG-with-ECC-key.patch} | 11 +-
...-init-order-disable-pri-sec-channel-.patch | 126 --------
@@ -63,16 +63,17 @@ Signed-off-by: John Crispin <john@phrozen.org>
.../hostapd/patches/600-ubus_support.patch | 166 ++++++++---
.../hostapd/patches/700-wifi-reload.patch | 51 ++--
.../hostapd/patches/710-vlan_no_bridge.patch | 41 +++
.../patches/711-wds_bridge_force.patch | 26 ++
.../720-ACS-fix-channel-100-frequency.patch | 30 ++
.../patches/720-iface_max_num_sta.patch | 82 ++++++
.../hostapd/patches/730-ft_iface.patch | 38 +++
.../hostapd/patches/740-snoop_iface.patch | 66 +++++
.../hostapd/patches/740-snoop_iface.patch | 72 +++++
...ate-if-no-available-channel-is-found.patch | 37 ---
...of-secondary-device-types-for-P2P-gr.patch | 33 ---
.../services/hostapd/src/src/ap/ubus.c | 214 +++++++++++++-
.../services/hostapd/src/src/ap/ubus.h | 16 +
.../hostapd/src/src/utils/build_features.h | 2 -
67 files changed, 1280 insertions(+), 2335 deletions(-)
68 files changed, 1343 insertions(+), 2347 deletions(-)
delete mode 100644 package/network/services/hostapd/patches/001-HE-VHT-fix-frequency-setup-with-HE-enabled.patch
rename package/network/services/hostapd/patches/{802-wolfssl-init-RNG-with-ECC-key.patch => 001-wolfssl-init-RNG-with-ECC-key.patch} (76%)
delete mode 100644 package/network/services/hostapd/patches/002-mesh-fix-channel-init-order-disable-pri-sec-channel-.patch
@@ -103,6 +104,7 @@ Signed-off-by: John Crispin <john@phrozen.org>
delete mode 100644 package/network/services/hostapd/patches/110-wolfssl-compile-fix.patch
delete mode 100644 package/network/services/hostapd/patches/120-reconfigure-wps-credentials.patch
create mode 100644 package/network/services/hostapd/patches/710-vlan_no_bridge.patch
create mode 100644 package/network/services/hostapd/patches/711-wds_bridge_force.patch
create mode 100644 package/network/services/hostapd/patches/720-ACS-fix-channel-100-frequency.patch
create mode 100644 package/network/services/hostapd/patches/720-iface_max_num_sta.patch
create mode 100644 package/network/services/hostapd/patches/730-ft_iface.patch
@@ -179,18 +181,31 @@ index df272e443a..61b6daf861 100644
# EAP-SAKE for the integrated EAP server
#CONFIG_EAP_SAKE=y
diff --git a/package/network/services/hostapd/files/hostapd.sh b/package/network/services/hostapd/files/hostapd.sh
index aa72e09eba..c1f48326fa 100644
index aa72e09eba..fe6af98f4d 100644
--- a/package/network/services/hostapd/files/hostapd.sh
+++ b/package/network/services/hostapd/files/hostapd.sh
@@ -49,6 +49,7 @@ hostapd_append_wpa_key_mgmt() {
@@ -48,13 +48,17 @@ hostapd_append_wpa_key_mgmt() {
;;
eap192)
append wpa_key_mgmt "WPA-EAP-SUITE-B-192"
+ append wpa_key_mgmt "WPA-EAP-SHA256"
[ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt "FT-EAP"
+ [ "${ieee80211w:-0}" -gt 0 ] && append wpa_key_mgmt "WPA-EAP-SHA256"
;;
eap-eap192)
append wpa_key_mgmt "WPA-EAP-SUITE-B-192"
@@ -91,6 +92,7 @@ hostapd_add_log_config() {
- eap-eap192)
- append wpa_key_mgmt "WPA-EAP-SUITE-B-192"
+ eap-eap256)
append wpa_key_mgmt "WPA-EAP"
+ append wpa_key_mgmt "WPA-EAP-SHA256"
+ [ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt "FT-EAP"
+ ;;
+ eap256)
+ append wpa_key_mgmt "WPA-EAP-SHA256"
[ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt "FT-EAP"
- [ "${ieee80211w:-0}" -gt 0 ] && append wpa_key_mgmt "WPA-EAP-SHA256"
;;
sae)
append wpa_key_mgmt "SAE"
@@ -91,6 +95,7 @@ hostapd_add_log_config() {
hostapd_common_add_device_config() {
config_add_array basic_rate
config_add_array supported_rates
@@ -198,7 +213,7 @@ index aa72e09eba..c1f48326fa 100644
config_add_string country country3
config_add_boolean country_ie doth
@@ -99,6 +101,10 @@ hostapd_common_add_device_config() {
@@ -99,6 +104,10 @@ hostapd_common_add_device_config() {
config_add_string require_mode
config_add_boolean legacy_rates
config_add_int cell_density
@@ -209,7 +224,7 @@ index aa72e09eba..c1f48326fa 100644
config_add_string acs_chan_bias
config_add_array hostapd_options
@@ -115,7 +121,8 @@ hostapd_prepare_device_config() {
@@ -115,7 +124,8 @@ hostapd_prepare_device_config() {
local base_cfg=
json_get_vars country country3 country_ie beacon_int:100 dtim_period:2 doth require_mode legacy_rates \
@@ -219,7 +234,7 @@ index aa72e09eba..c1f48326fa 100644
hostapd_set_log_options base_cfg
@@ -207,11 +214,16 @@ hostapd_prepare_device_config() {
@@ -207,11 +217,16 @@ hostapd_prepare_device_config() {
hostapd_add_rate brlist "$br"
done
@@ -236,7 +251,7 @@ index aa72e09eba..c1f48326fa 100644
json_get_values opts hostapd_options
for val in $opts; do
@@ -269,7 +281,7 @@ hostapd_common_add_bss_config() {
@@ -269,7 +284,7 @@ hostapd_common_add_bss_config() {
config_add_array domain_match domain_match2 domain_suffix_match domain_suffix_match2
config_add_string ieee80211w_mgmt_cipher
@@ -245,7 +260,7 @@ index aa72e09eba..c1f48326fa 100644
config_add_string vlan_tagged_interface vlan_bridge
config_add_string vlan_file
@@ -287,6 +299,7 @@ hostapd_common_add_bss_config() {
@@ -287,6 +302,7 @@ hostapd_common_add_bss_config() {
config_add_boolean wnm_sleep_mode wnm_sleep_mode_no_keys bss_transition
config_add_int time_advertisement
config_add_string time_zone
@@ -253,7 +268,7 @@ index aa72e09eba..c1f48326fa 100644
config_add_boolean ieee80211k rrm_neighbor_report rrm_beacon_report
@@ -311,6 +324,7 @@ hostapd_common_add_bss_config() {
@@ -311,6 +327,7 @@ hostapd_common_add_bss_config() {
config_add_array supported_rates
config_add_boolean sae_require_mfp
@@ -261,7 +276,7 @@ index aa72e09eba..c1f48326fa 100644
config_add_string 'owe_transition_bssid:macaddr' 'owe_transition_ssid:string'
@@ -319,23 +333,33 @@ hostapd_common_add_bss_config() {
@@ -319,23 +336,35 @@ hostapd_common_add_bss_config() {
config_add_int iw_ipaddr_type_availability iw_gas_address3
config_add_string iw_hessid iw_network_auth_type iw_qos_map_set
config_add_array iw_roaming_consortium iw_domain_name iw_anqp_3gpp_cell_net iw_nai_realm
@@ -295,10 +310,12 @@ index aa72e09eba..c1f48326fa 100644
+
+ config_add_int eap_server
+ config_add_string eap_user_file ca_cert server_cert private_key private_key_passwd server_id
+
+ config_add_boolean ratelimit
}
hostapd_set_vlan_file() {
@@ -387,7 +411,7 @@ append_iw_anqp_3gpp_cell_net() {
@@ -387,7 +416,7 @@ append_iw_anqp_3gpp_cell_net() {
if [ -z "$iw_anqp_3gpp_cell_net_conf" ]; then
iw_anqp_3gpp_cell_net_conf="$1"
else
@@ -307,7 +324,7 @@ index aa72e09eba..c1f48326fa 100644
fi
}
@@ -399,10 +423,22 @@ append_iw_nai_realm() {
@@ -399,10 +428,22 @@ append_iw_nai_realm() {
[ -n "$1" ] && append bss_conf "nai_realm=$1" "$N"
}
@@ -330,7 +347,7 @@ index aa72e09eba..c1f48326fa 100644
append_osu_provider_service_desc() {
append bss_conf "osu_service_desc=$1" "$N"
}
@@ -450,6 +486,7 @@ append_osu_provider() {
@@ -450,6 +491,7 @@ append_osu_provider() {
append bss_conf "osu_method_list=$osu_method_list" "$N"
config_list_foreach "$1" osu_service_desc append_osu_provider_service_desc
@@ -338,7 +355,7 @@ index aa72e09eba..c1f48326fa 100644
config_list_foreach "$1" osu_icon append_osu_icon
append bss_conf "$N"
@@ -459,6 +496,14 @@ append_hs20_conn_capab() {
@@ -459,6 +501,14 @@ append_hs20_conn_capab() {
[ -n "$1" ] && append bss_conf "hs20_conn_capab=$1" "$N"
}
@@ -353,7 +370,7 @@ index aa72e09eba..c1f48326fa 100644
append_airtime_sta_weight() {
[ -n "$1" ] && append bss_conf "airtime_sta_weight=$1" "$N"
}
@@ -482,10 +527,12 @@ hostapd_set_bss_options() {
@@ -482,10 +532,12 @@ hostapd_set_bss_options() {
macfilter ssid utf8_ssid wmm uapsd hidden short_preamble rsn_preauth \
iapp_interface eapol_version dynamic_vlan ieee80211w nasid \
acct_server acct_secret acct_port acct_interval \
@@ -368,7 +385,7 @@ index aa72e09eba..c1f48326fa 100644
set_default isolate 0
set_default maxassoc 0
@@ -506,6 +553,7 @@ hostapd_set_bss_options() {
@@ -506,6 +558,7 @@ hostapd_set_bss_options() {
set_default multi_ap 0
set_default airtime_bss_weight 0
set_default airtime_bss_limit 0
@@ -376,7 +393,7 @@ index aa72e09eba..c1f48326fa 100644
append bss_conf "ctrl_interface=/var/run/hostapd"
if [ "$isolate" -gt 0 ]; then
@@ -532,6 +580,7 @@ hostapd_set_bss_options() {
@@ -532,6 +585,7 @@ hostapd_set_bss_options() {
append bss_conf "uapsd_advertisement_enabled=$uapsd" "$N"
append bss_conf "utf8_ssid=$utf8_ssid" "$N"
append bss_conf "multi_ap=$multi_ap" "$N"
@@ -384,7 +401,7 @@ index aa72e09eba..c1f48326fa 100644
[ "$tdls_prohibit" -gt 0 ] && append bss_conf "tdls_prohibit=$tdls_prohibit" "$N"
@@ -550,6 +599,7 @@ hostapd_set_bss_options() {
@@ -550,19 +604,21 @@ hostapd_set_bss_options() {
append bss_conf "acct_server_shared_secret=$acct_secret" "$N"
[ -n "$acct_interval" ] && \
append bss_conf "radius_acct_interim_interval=$acct_interval" "$N"
@@ -392,7 +409,15 @@ index aa72e09eba..c1f48326fa 100644
}
case "$auth_type" in
@@ -563,6 +613,7 @@ hostapd_set_bss_options() {
- sae|owe|eap192|eap-eap192)
+ sae|owe|eap192|eap256)
set_default ieee80211w 2
set_default sae_require_mfp 1
;;
- psk-sae)
+ psk-sae|eap-eap256)
set_default ieee80211w 1
set_default sae_require_mfp 1
;;
esac
[ -n "$sae_require_mfp" ] && append bss_conf "sae_require_mfp=$sae_require_mfp" "$N"
@@ -400,7 +425,13 @@ index aa72e09eba..c1f48326fa 100644
local vlan_possible=""
@@ -604,7 +655,7 @@ hostapd_set_bss_options() {
@@ -599,12 +655,12 @@ hostapd_set_bss_options() {
vlan_possible=1
wps_possible=1
;;
- eap|eap192|eap-eap192)
+ eap|eap192|eap-eap256|eap256)
json_get_vars \
auth_server auth_secret auth_port \
dae_client dae_secret dae_port \
ownip radius_client_addr \
@@ -409,7 +440,7 @@ index aa72e09eba..c1f48326fa 100644
# radius can provide VLAN ID for clients
vlan_possible=1
@@ -616,18 +667,22 @@ hostapd_set_bss_options() {
@@ -616,18 +672,22 @@ hostapd_set_bss_options() {
set_default auth_port 1812
set_default dae_port 3799
@@ -436,15 +467,17 @@ index aa72e09eba..c1f48326fa 100644
[ -n "$ownip" ] && append bss_conf "own_ip_addr=$ownip" "$N"
[ -n "$radius_client_addr" ] && append bss_conf "radius_client_addr=$radius_client_addr" "$N"
@@ -700,6 +755,7 @@ hostapd_set_bss_options() {
@@ -699,7 +759,8 @@ hostapd_set_bss_options() {
}
append bss_conf "ssid=$ssid" "$N"
[ -n "$network_bridge" ] && append bss_conf "bridge=$network_bridge" "$N"
- [ -n "$network_bridge" ] && append bss_conf "bridge=$network_bridge" "$N"
+ [ -n "$network_bridge" ] && append bss_conf "bridge=$network_bridge${N}wds_bridge=" "$N"
+ [ -n "$network_ifname" ] && append bss_conf "snoop_iface=$network_ifname" "$N"
[ -n "$iapp_interface" ] && {
local ifname
network_get_device ifname "$iapp_interface" || ifname="$iapp_interface"
@@ -740,7 +796,7 @@ hostapd_set_bss_options() {
@@ -740,7 +801,7 @@ hostapd_set_bss_options() {
append bss_conf "ftm_responder=1" "$N"
[ "$stationary_ap" -eq "1" ] && append bss_conf "stationary_ap=1" "$N"
[ -n "$lci" ] && append bss_conf "lci=$lci" "$N"
@@ -453,7 +486,7 @@ index aa72e09eba..c1f48326fa 100644
}
fi
@@ -764,6 +820,7 @@ hostapd_set_bss_options() {
@@ -764,6 +825,7 @@ hostapd_set_bss_options() {
;;
esac
@@ -461,7 +494,7 @@ index aa72e09eba..c1f48326fa 100644
append bss_conf "mobility_domain=$mobility_domain" "$N"
append bss_conf "ft_psk_generate_local=$ft_psk_generate_local" "$N"
append bss_conf "ft_over_ds=$ft_over_ds" "$N"
@@ -778,6 +835,13 @@ hostapd_set_bss_options() {
@@ -778,6 +840,13 @@ hostapd_set_bss_options() {
set_default r0_key_lifetime 10000
set_default pmk_r1_push 0
@@ -475,7 +508,25 @@ index aa72e09eba..c1f48326fa 100644
[ -n "$r1_key_holder" ] && append bss_conf "r1_key_holder=$r1_key_holder" "$N"
append bss_conf "r0_key_lifetime=$r0_key_lifetime" "$N"
append bss_conf "pmk_r1_push=$pmk_r1_push" "$N"
@@ -863,13 +927,17 @@ hostapd_set_bss_options() {
@@ -822,7 +891,16 @@ hostapd_set_bss_options() {
json_get_vars ieee80211w_mgmt_cipher ieee80211w_max_timeout ieee80211w_retry_timeout
append bss_conf "ieee80211w=$ieee80211w" "$N"
[ "$ieee80211w" -gt "0" ] && {
- append bss_conf "group_mgmt_cipher=${ieee80211w_mgmt_cipher:-AES-128-CMAC}" "$N"
+ case "$auth_type" in
+ eap192)
+ append bss_conf "group_mgmt_cipher=BIP-GMAC-256" "$N"
+ append bss_conf "group_cipher=GCMP-256" "$N"
+ ;;
+ *)
+ append bss_conf "group_mgmt_cipher=${ieee80211w_mgmt_cipher:-AES-128-CMAC}" "$N"
+ ;;
+ esac
+
[ -n "$ieee80211w_max_timeout" ] && \
append bss_conf "assoc_sa_query_max_timeout=$ieee80211w_max_timeout" "$N"
[ -n "$ieee80211w_retry_timeout" ] && \
@@ -863,13 +941,17 @@ hostapd_set_bss_options() {
}
[ -n "$vlan_possible" -a -n "$dynamic_vlan" ] && {
@@ -495,7 +546,7 @@ index aa72e09eba..c1f48326fa 100644
[ -n "$vlan_tagged_interface" ] && \
append bss_conf "vlan_tagged_interface=$vlan_tagged_interface" "$N"
[ -n "$vlan_file" ] && {
@@ -882,6 +950,7 @@ hostapd_set_bss_options() {
@@ -882,6 +964,7 @@ hostapd_set_bss_options() {
json_get_vars iw_hessid iw_venue_group iw_venue_type iw_network_auth_type
json_get_vars iw_roaming_consortium iw_domain_name iw_anqp_3gpp_cell_net iw_nai_realm
json_get_vars iw_anqp_elem iw_qos_map_set iw_ipaddr_type_availability iw_gas_address3
@@ -503,7 +554,12 @@ index aa72e09eba..c1f48326fa 100644
set_default iw_enabled 0
if [ "$iw_enabled" = "1" ]; then
@@ -910,6 +979,8 @@ hostapd_set_bss_options() {
@@ -905,11 +988,12 @@ hostapd_set_bss_options() {
[ -n "$iw_network_auth_type" ] && \
append bss_conf "network_auth_type=$iw_network_auth_type" "$N"
[ -n "$iw_gas_address3" ] && append bss_conf "gas_address3=$iw_gas_address3" "$N"
- [ -n "$iw_qos_map_set" ] && append bss_conf "qos_map_set=$iw_qos_map_set" "$N"
json_for_each_item append_iw_roaming_consortium iw_roaming_consortium
json_for_each_item append_iw_anqp_elem iw_anqp_elem
json_for_each_item append_iw_nai_realm iw_nai_realm
@@ -512,8 +568,16 @@ index aa72e09eba..c1f48326fa 100644
iw_domain_name_conf=
json_for_each_item append_iw_domain_name iw_domain_name
@@ -924,11 +995,14 @@ hostapd_set_bss_options() {
@@ -922,13 +1006,22 @@ hostapd_set_bss_options() {
append bss_conf "anqp_3gpp_cell_net=$iw_anqp_3gpp_cell_net_conf" "$N"
fi
+ set_default iw_qos_map_set 0,0,2,16,1,1,255,255,18,22,24,38,40,40,44,46,48,56
+ case "$iw_qos_map_set" in
+ *,*);;
+ *) iw_qos_map_set="";;
+ esac
+ [ -n "$iw_qos_map_set" ] && append bss_conf "qos_map_set=$iw_qos_map_set" "$N"
local hs20 disable_dgaf osen anqp_domain_id hs20_deauth_req_timeout \
- osu_ssid hs20_wan_metrics hs20_operating_class hs20_t_c_filename hs20_t_c_timestamp
@@ -529,7 +593,7 @@ index aa72e09eba..c1f48326fa 100644
set_default disable_dgaf $hs20
set_default osen 0
set_default anqp_domain_id 0
@@ -936,6 +1010,7 @@ hostapd_set_bss_options() {
@@ -936,6 +1029,7 @@ hostapd_set_bss_options() {
if [ "$hs20" = "1" ]; then
append bss_conf "hs20=1" "$N"
append_hs20_icons
@@ -537,7 +601,7 @@ index aa72e09eba..c1f48326fa 100644
append bss_conf "disable_dgaf=$disable_dgaf" "$N"
append bss_conf "osen=$osen" "$N"
append bss_conf "anqp_domain_id=$anqp_domain_id" "$N"
@@ -945,16 +1020,31 @@ hostapd_set_bss_options() {
@@ -945,16 +1039,31 @@ hostapd_set_bss_options() {
[ -n "$hs20_operating_class" ] && append bss_conf "hs20_operating_class=$hs20_operating_class" "$N"
[ -n "$hs20_t_c_filename" ] && append bss_conf "hs20_t_c_filename=$hs20_t_c_filename" "$N"
[ -n "$hs20_t_c_timestamp" ] && append bss_conf "hs20_t_c_timestamp=$hs20_t_c_timestamp" "$N"
@@ -570,7 +634,7 @@ index aa72e09eba..c1f48326fa 100644
set_default per_sta_vif 0
if [ "$per_sta_vif" -gt 0 ]; then
@@ -1079,16 +1169,16 @@ wpa_supplicant_set_fixed_freq() {
@@ -1079,16 +1188,16 @@ wpa_supplicant_set_fixed_freq() {
append network_data "frequency=$freq" "$N$T"
case "$htmode" in
NOHT) append network_data "disable_ht=1" "$N$T";;
@@ -591,7 +655,7 @@ index aa72e09eba..c1f48326fa 100644
*) append network_data "disable_vht=1" "$N$T";;
esac
}
@@ -1106,7 +1196,8 @@ wpa_supplicant_add_network() {
@@ -1106,19 +1215,21 @@ wpa_supplicant_add_network() {
ssid bssid key \
basic_rate mcast_rate \
ieee80211w ieee80211r \
@@ -600,8 +664,15 @@ index aa72e09eba..c1f48326fa 100644
+ default_disabled
case "$auth_type" in
sae|owe|eap192|eap-eap192)
@@ -1119,6 +1210,7 @@ wpa_supplicant_add_network() {
- sae|owe|eap192|eap-eap192)
+ sae|owe|eap-eap256)
set_default ieee80211w 2
;;
- psk-sae)
+ psk-sae|eap192|eap256)
set_default ieee80211w 1
;;
esac
set_default ieee80211r 0
set_default multi_ap 0
@@ -609,7 +680,7 @@ index aa72e09eba..c1f48326fa 100644
local key_mgmt='NONE'
local network_data=
@@ -1150,7 +1242,10 @@ wpa_supplicant_add_network() {
@@ -1150,7 +1261,10 @@ wpa_supplicant_add_network() {
scan_ssid=""
}
@@ -621,6 +692,15 @@ index aa72e09eba..c1f48326fa 100644
case "$auth_type" in
none) ;;
@@ -1186,7 +1300,7 @@ wpa_supplicant_add_network() {
fi
append network_data "$passphrase" "$N$T"
;;
- eap|eap192|eap-eap192)
+ eap|eap192|eap-eap256|eap256)
hostapd_append_wpa_key_mgmt
key_mgmt="$wpa_key_mgmt"
diff --git a/package/network/services/hostapd/patches/001-HE-VHT-fix-frequency-setup-with-HE-enabled.patch b/package/network/services/hostapd/patches/001-HE-VHT-fix-frequency-setup-with-HE-enabled.patch
deleted file mode 100644
index 37c17c50af..0000000000
@@ -5122,6 +5202,38 @@ index 0000000000..73db32e54a
+ } else if (os_strcmp(buf, "per_sta_vif") == 0) {
+ bss->ssid.per_sta_vif = atoi(pos);
+ } else if (os_strcmp(buf, "vlan_file") == 0) {
diff --git a/package/network/services/hostapd/patches/711-wds_bridge_force.patch b/package/network/services/hostapd/patches/711-wds_bridge_force.patch
new file mode 100644
index 0000000000..76a3547805
--- /dev/null
+++ b/package/network/services/hostapd/patches/711-wds_bridge_force.patch
@@ -0,0 +1,26 @@
+Index: hostapd-2021-05-22-b102f19b/hostapd/config_file.c
+===================================================================
+--- hostapd-2021-05-22-b102f19b.orig/hostapd/config_file.c
++++ hostapd-2021-05-22-b102f19b/hostapd/config_file.c
+@@ -2357,6 +2357,8 @@ static int hostapd_config_fill(struct ho
+ sizeof(conf->bss[0]->iface));
+ } else if (os_strcmp(buf, "bridge") == 0) {
+ os_strlcpy(bss->bridge, pos, sizeof(bss->bridge));
++ if (!bss->wds_bridge[0])
++ os_strlcpy(bss->wds_bridge, pos, sizeof(bss->wds_bridge));
+ } else if (os_strcmp(buf, "vlan_bridge") == 0) {
+ os_strlcpy(bss->vlan_bridge, pos, sizeof(bss->vlan_bridge));
+ } else if (os_strcmp(buf, "wds_bridge") == 0) {
+Index: hostapd-2021-05-22-b102f19b/src/ap/ap_drv_ops.c
+===================================================================
+--- hostapd-2021-05-22-b102f19b.orig/src/ap/ap_drv_ops.c
++++ hostapd-2021-05-22-b102f19b/src/ap/ap_drv_ops.c
+@@ -340,8 +340,6 @@ int hostapd_set_wds_sta(struct hostapd_d
+ return -1;
+ if (hapd->conf->wds_bridge[0])
+ bridge = hapd->conf->wds_bridge;
+- else if (hapd->conf->bridge[0])
+- bridge = hapd->conf->bridge;
+ return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val,
+ bridge, ifname_wds);
+ }
diff --git a/package/network/services/hostapd/patches/720-ACS-fix-channel-100-frequency.patch b/package/network/services/hostapd/patches/720-ACS-fix-channel-100-frequency.patch
new file mode 100644
index 0000000000..3ef19e5298
@@ -5292,12 +5404,14 @@ index 0000000000..793e8e0194
+ if (!hapd->l2) {
diff --git a/package/network/services/hostapd/patches/740-snoop_iface.patch b/package/network/services/hostapd/patches/740-snoop_iface.patch
new file mode 100644
index 0000000000..8d928f8505
index 0000000000..6e60cde844
--- /dev/null
+++ b/package/network/services/hostapd/patches/740-snoop_iface.patch
@@ -0,0 +1,66 @@
+--- a/src/ap/ap_config.h
++++ b/src/ap/ap_config.h
@@ -0,0 +1,72 @@
+Index: hostapd-2021-05-22-b102f19b/src/ap/ap_config.h
+===================================================================
+--- hostapd-2021-05-22-b102f19b.orig/src/ap/ap_config.h
++++ hostapd-2021-05-22-b102f19b/src/ap/ap_config.h
+@@ -278,6 +278,7 @@ struct hostapd_bss_config {
+ char iface[IFNAMSIZ + 1];
+ char bridge[IFNAMSIZ + 1];
@@ -5306,8 +5420,10 @@ index 0000000000..8d928f8505
+ char vlan_bridge[IFNAMSIZ + 1];
+ char wds_bridge[IFNAMSIZ + 1];
+
+--- a/src/ap/x_snoop.c
++++ b/src/ap/x_snoop.c
+Index: hostapd-2021-05-22-b102f19b/src/ap/x_snoop.c
+===================================================================
+--- hostapd-2021-05-22-b102f19b.orig/src/ap/x_snoop.c
++++ hostapd-2021-05-22-b102f19b/src/ap/x_snoop.c
+@@ -31,14 +31,16 @@ int x_snoop_init(struct hostapd_data *ha
+ return -1;
+ }
@@ -5351,12 +5467,14 @@ index 0000000000..8d928f8505
+ if (l2 == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: Failed to initialize L2 packet processing %s",
+--- a/hostapd/config_file.c
++++ b/hostapd/config_file.c
+@@ -2357,6 +2357,8 @@ static int hostapd_config_fill(struct ho
+ sizeof(conf->bss[0]->iface));
+ } else if (os_strcmp(buf, "bridge") == 0) {
+Index: hostapd-2021-05-22-b102f19b/hostapd/config_file.c
+===================================================================
+--- hostapd-2021-05-22-b102f19b.orig/hostapd/config_file.c
++++ hostapd-2021-05-22-b102f19b/hostapd/config_file.c
+@@ -2359,6 +2359,8 @@ static int hostapd_config_fill(struct ho
+ os_strlcpy(bss->bridge, pos, sizeof(bss->bridge));
+ if (!bss->wds_bridge[0])
+ os_strlcpy(bss->wds_bridge, pos, sizeof(bss->wds_bridge));
++ } else if (os_strcmp(buf, "snoop_iface") == 0) {
++ os_strlcpy(bss->snoop_iface, pos, sizeof(bss->snoop_iface));
+ } else if (os_strcmp(buf, "vlan_bridge") == 0) {

View File

@@ -1,17 +1,17 @@
From aab305d662fa77ef4495574c096cb1e065c1908a Mon Sep 17 00:00:00 2001
From 006abf1773051ad355b52d70095f63f44a496b13 Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Sun, 25 Jul 2021 13:32:37 +0200
Subject: [PATCH 20/27] procd: add uxc support
Subject: [PATCH 02/70] procd: add uxc support
Signed-off-by: John Crispin <john@phrozen.org>
---
package/system/procd/Makefile | 12 ++---
package/system/procd/Makefile | 15 +++---
package/system/procd/files/procd.sh | 79 +++++++++++++++++++++++++++++
package/system/procd/files/uxc.init | 4 ++
3 files changed, 89 insertions(+), 6 deletions(-)
3 files changed, 90 insertions(+), 8 deletions(-)
diff --git a/package/system/procd/Makefile b/package/system/procd/Makefile
index 30d5adf427..98f1ed1775 100644
index 30d5adf427..b831f86639 100644
--- a/package/system/procd/Makefile
+++ b/package/system/procd/Makefile
@@ -12,9 +12,9 @@ PKG_RELEASE:=$(AUTORELEASE)
@@ -21,9 +21,9 @@ index 30d5adf427..98f1ed1775 100644
-PKG_SOURCE_DATE:=2021-02-23
-PKG_SOURCE_VERSION:=37eed131e9967a35f47bacb3437a9d3c8a57b3f4
-PKG_MIRROR_HASH:=2b0131ff9055ccf987cbeb5f36c2c2585dc780999df6be312fbbbcd61ce676d4
+PKG_SOURCE_DATE:=2021-08-15
+PKG_SOURCE_VERSION:=104b49d6ab25a8cf067e6d8d1f2da7defb9876d4
+PKG_MIRROR_HASH:=d13b566a14e84f6babe8b7d3dfb88e34c3dff0e97d7770d6fe71174685bca628
+PKG_MIRROR_HASH:=0d51642d82d7bb4150355a6986e54504dce171c6fcb7eeff312d20a5d106bad8
+PKG_SOURCE_DATE:=2021-11-04
+PKG_SOURCE_VERSION:=0ee8e734a7f67220cf4a3412b60ff674b5fb20dd
CMAKE_INSTALL:=1
PKG_LICENSE:=GPL-2.0
@@ -36,21 +36,30 @@ index 30d5adf427..98f1ed1775 100644
endif
CMAKE_OPTIONS += -DEARLY_PATH="$(TARGET_INIT_PATH)"
@@ -82,7 +82,7 @@ endef
@@ -68,7 +68,7 @@ define Package/procd-ujail
SECTION:=base
CATEGORY:=Base system
DEPENDS:=@KERNEL_NAMESPACES +@KERNEL_UTS_NS +@KERNEL_IPC_NS +@KERNEL_PID_NS \
- +libubox +libubus +libblobmsg-json
+ +libubox +libubus +libuci +libblobmsg-json
TITLE:=OpenWrt process jail helper
endef
@@ -82,15 +82,14 @@ endef
define Package/procd-seccomp
SECTION:=base
CATEGORY:=Base system
- DEPENDS:=@(arm||armeb||mips||mipsel||i386||powerpc||x86_64) @!TARGET_uml \
+ DEPENDS:=@(aarch64||arm||armeb||mips||mipsel||i386||powerpc||x86_64) @!TARGET_uml \
@KERNEL_SECCOMP +libubox +libblobmsg-json
- @KERNEL_SECCOMP +libubox +libblobmsg-json
+ DEPENDS:=@SECCOMP +libubox +libblobmsg-json
TITLE:=OpenWrt process seccomp helper + utrace
endef
@@ -90,7 +90,7 @@ endef
define Package/uxc
SECTION:=base
CATEGORY:=Base system
- DEPENDS:=+procd-ujail +libubus +libubox +libblobmsg-json
+ DEPENDS:=+procd-ujail +libubus +libubox +libblobmsg-json +blockd +rpcd
+ DEPENDS:=+procd-ujail +libubus +libubox +libblobmsg-json +blockd +PACKAGE_uxc:rpcd
TITLE:=OpenWrt container management
MAINTAINER:=Daniel Golle <daniel@makrotopia.org>
endef

View File

@@ -0,0 +1,47 @@
From 4b2e6bb352b400e244646a7bc59bc5ca3ca6f5df Mon Sep 17 00:00:00 2001
From: Roman Yeryomin <roman@advem.lv>
Date: Fri, 3 Sep 2021 17:31:11 +0300
Subject: [PATCH 32/32] iproute2: m_xt.so depends on dynsyms.list
When doing parallel build on a fast machine with bottleneck in i/o,
m_xt.so may start linking faster than dynsyms.list gets populated,
resulting in error:
ld:dynsyms.list:0: syntax error in dynamic list
Fix this by adding dynsyms.list as make dependency to m_xt.so
Described also here:
https://bugs.openwrt.org/index.php?do=details&task_id=3353
Change from v1:
- add dynsysms.list dependancy only when shared libs are enabled
Signed-off-by: Roman Yeryomin <roman@advem.lv>
Fixes: FS#3353
---
.../utils/iproute2/patches/175-reduce-dynamic-syms.patch | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/package/network/utils/iproute2/patches/175-reduce-dynamic-syms.patch b/package/network/utils/iproute2/patches/175-reduce-dynamic-syms.patch
index da961a183b..c3892e5a0e 100644
--- a/package/network/utils/iproute2/patches/175-reduce-dynamic-syms.patch
+++ b/package/network/utils/iproute2/patches/175-reduce-dynamic-syms.patch
@@ -26,13 +26,14 @@
q_atm.so: q_atm.c
$(QUIET_CC)$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -shared -fpic -o q_atm.so q_atm.c -latm
-@@ -205,4 +206,15 @@ static-syms.h: $(wildcard *.c)
+@@ -205,4 +206,16 @@ static-syms.h: $(wildcard *.c)
sed -n '/'$$s'[^ ]* =/{s:.* \([^ ]*'$$s'[^ ]*\) .*:extern char \1[] __attribute__((weak)); if (!strcmp(sym, "\1")) return \1;:;p}' $$files ; \
done > $@
+else
+
+tc: dynsyms.list
++m_xt.so: dynsyms.list
+dynsyms.list: $(wildcard *.c)
+ files="$(filter-out $(patsubst %.so,%.c,$(TCSO)), $^)" ; \
+ echo "{" > $@ ; \
--
2.25.1

View File

@@ -0,0 +1,35 @@
From d4e24006e05474b6dbe582f7c56a505cc0c45e81 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Mon, 1 Nov 2021 11:59:41 +0100
Subject: [PATCH] ubus: update to the latest version
b743a331421d ubusd: log ACL init errors
2099bb3ad997 libubus: use list_empty/list_first_entry in ubus_process_pending_msg
ef038488edc3 libubus: process pending messages in data handler if stack depth is 0
a72457b61df0 libubus: increase stack depth for processing obj msgs
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
package/system/ubus/Makefile | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/package/system/ubus/Makefile b/package/system/ubus/Makefile
index 8a3fd1de7b..d5f86b6850 100644
--- a/package/system/ubus/Makefile
+++ b/package/system/ubus/Makefile
@@ -5,9 +5,9 @@ PKG_RELEASE:=2
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/ubus.git
-PKG_SOURCE_DATE:=2021-06-30
-PKG_SOURCE_VERSION:=4fc532c8a55ba8217ad67d7fd47c5eb9a8aba044
-PKG_MIRROR_HASH:=a5c8205f2e2b2f1f9ad687592e66a6e2bf8900dc54cfe3ceefe6c297d18971a8
+PKG_SOURCE_DATE:=2021-08-09
+PKG_SOURCE_VERSION:=a72457b61df045d3c499a6211362b751710590d7
+PKG_MIRROR_HASH:=ac617577bcb2ff3dbc3039ad67200afcce910840223a2de15977d3224e6557fd
PKG_ABI_VERSION:=$(call abi_version_str,$(PKG_SOURCE_DATE))
CMAKE_INSTALL:=1
--
2.25.1

View File

@@ -0,0 +1,34 @@
From 49ceb8a8d7009e5c81599c68b8aacc16d17d2e62 Mon Sep 17 00:00:00 2001
From: Stijn Tintel <stijn@linux-ipv6.be>
Date: Tue, 9 Nov 2021 17:20:41 +0100
Subject: [PATCH] rpcd: bump to git HEAD
20bf958 session: use uloop_timeout_remaining64
d11ffe9 session: use blobmsg_get_u64 for RPC_DUMP_EXPIRES
Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
---
package/system/rpcd/Makefile | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/package/system/rpcd/Makefile b/package/system/rpcd/Makefile
index 0896a7dada..af788dcfaa 100644
--- a/package/system/rpcd/Makefile
+++ b/package/system/rpcd/Makefile
@@ -12,10 +12,10 @@ PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/rpcd.git
-PKG_SOURCE_DATE:=2021-03-11
-PKG_SOURCE_VERSION:=ccb75178cf6a726896729c6904bd623636aa0b29
+PKG_MIRROR_HASH:=98071b4a1ce983a0e738d7e4a2f6e52b7f6db19f99510ddef430093314134ca4
+PKG_SOURCE_DATE:=2021-11-04
+PKG_SOURCE_VERSION:=d11ffe9383ae0ec34836421926364b24c1d891ca
PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
-PKG_MIRROR_HASH:=87b1839275c209f9767057d6da5272cae973a064767fa28f380a37fb65e2e643
PKG_LICENSE:=ISC
PKG_LICENSE_FILES:=
--
2.25.1

View File

@@ -0,0 +1,221 @@
From 3937223beab0c3e4284fd916c0c3b6548c287e03 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Tue, 26 Oct 2021 20:41:22 +0200
Subject: [PATCH 050/102] bpf-headers: add a package with kernel headers for
ebpf
In order to genererate suitable kernel headers, a 5.10 kernel tree is
prepared with a default config for mips. The arch is forced to mips in
order to avoid issues with inline asm on various architectures in a way
that doesn't involve relying on the host toolchain/headers.
It also has the advantage of supporting both endian types
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
include/bpf.mk | 65 ++++++++++++
package/kernel/bpf-headers/Makefile | 99 +++++++++++++++++++
.../src/include/generated/bounds.h | 14 +++
3 files changed, 178 insertions(+)
create mode 100644 include/bpf.mk
create mode 100644 package/kernel/bpf-headers/Makefile
create mode 100644 package/kernel/bpf-headers/src/include/generated/bounds.h
diff --git a/include/bpf.mk b/include/bpf.mk
new file mode 100644
index 0000000000..3dc65c7685
--- /dev/null
+++ b/include/bpf.mk
@@ -0,0 +1,65 @@
+ifneq ($(CONFIG_BPF_TOOLCHAIN_HOST),)
+ BPF_TOOLCHAIN_HOST_PATH:=$(call qstrip,$(CONFIG_BPF_TOOLCHAIN_HOST_PATH))
+ ifneq ($(BPF_TOOLCHAIN_HOST_PATH),)
+ BPF_PATH:=$(BPF_TOOLCHAIN_HOST_PATH)/bin:$(PATH)
+ else
+ BPF_PATH:=$(BPF_PATH)
+ endif
+ CLANG:=$(firstword $(shell PATH='$(BPF_PATH)' which clang clang-13 clang-12 clang-11))
+ LLVM_VER:=$(subst clang,,$(notdir $(CLANG)))
+else
+ CLANG:=$(STAGING_DIR_HOST)/bin/clang
+ LLVM_VER:=
+endif
+
+LLVM_PATH:=$(dir $(CLANG))
+LLVM_LLC:=$(LLVM_PATH)/llc$(LLVM_VER)
+LLVM_DIS:=$(LLVM_PATH)/llvm-dis$(LLVM_VER)
+LLVM_OPT:=$(LLVM_PATH)/opt$(LLVM_VER)
+LLVM_STRIP:=$(LLVM_PATH)/llvm-strip$(LLVM_VER)
+
+BPF_KARCH:=mips
+BPF_ARCH:=mips$(if $(CONFIG_BIG_ENDIAN),,el)
+
+BPF_HEADERS_DIR:=$(STAGING_DIR)/bpf-headers
+
+BPF_KERNEL_INCLUDE := \
+ -nostdinc -isystem $(TOOLCHAIN_DIR)/include \
+ -I$(BPF_HEADERS_DIR)/arch/$(BPF_KARCH)/include \
+ -I$(BPF_HEADERS_DIR)/arch/$(BPF_KARCH)/include/asm/mach-generic \
+ -I$(BPF_HEADERS_DIR)/arch/$(BPF_KARCH)/include/generated \
+ -I$(BPF_HEADERS_DIR)/include \
+ -I$(BPF_HEADERS_DIR)/arch/$(BPF_KARCH)/include/uapi \
+ -I$(BPF_HEADERS_DIR)/arch/$(BPF_KARCH)/include/generated/uapi \
+ -I$(BPF_HEADERS_DIR)/include/uapi \
+ -I$(BPF_HEADERS_DIR)/include/generated/uapi \
+ -I$(BPF_HEADERS_DIR)/tools/lib \
+ -I$(BPF_HEADERS_DIR)/tools/testing/selftests \
+ -I$(BPF_HEADERS_DIR)/samples/bpf \
+ -include linux/kconfig.h -include asm_goto_workaround.h
+
+BPF_CFLAGS := \
+ $(BPF_KERNEL_INCLUDE) -I$(PKG_BUILD_DIR) \
+ -D__KERNEL__ -D__BPF_TRACING__ \
+ -D__TARGET_ARCH_${BPF_KARCH} \
+ -m$(if $(CONFIG_BIG_ENDIAN),big,little)-endian \
+ -fno-stack-protector -Wall \
+ -Wno-unused-value -Wno-pointer-sign \
+ -Wno-compare-distinct-pointer-types \
+ -Wno-gnu-variable-sized-type-not-at-end \
+ -Wno-address-of-packed-member -Wno-tautological-compare \
+ -Wno-unknown-warning-option \
+ -fno-asynchronous-unwind-tables \
+ -Wno-uninitialized -Wno-unused-variable \
+ -Wno-unused-label \
+ -O2 -emit-llvm -Xclang -disable-llvm-passes
+
+define CompileBPF
+ $(CLANG) -g -target $(BPF_ARCH)-linux-gnu $(BPF_CFLAGS) $(2) \
+ -c $(1) -o $(patsubst %.c,%.bc,$(1))
+ $(LLVM_OPT) -O2 -mtriple=bpf-pc-linux < $(patsubst %.c,%.bc,$(1)) > $(patsubst %.c,%.opt,$(1))
+ $(LLVM_DIS) < $(patsubst %.c,%.opt,$(1)) > $(patsubst %.c,%.S,$(1))
+ $(LLVM_LLC) -march=bpf -filetype=obj -o $(patsubst %.c,%.o,$(1)) < $(patsubst %.c,%.S,$(1))
+ $(LLVM_STRIP) --strip-debug $(patsubst %.c,%.o,$(1))
+endef
+
diff --git a/package/kernel/bpf-headers/Makefile b/package/kernel/bpf-headers/Makefile
new file mode 100644
index 0000000000..5f5b89370d
--- /dev/null
+++ b/package/kernel/bpf-headers/Makefile
@@ -0,0 +1,99 @@
+#
+# Copyright (C) 2006-2009 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+override QUILT:=
+override HOST_QUILT:=
+
+include $(INCLUDE_DIR)/kernel.mk
+
+
+PKG_NAME:=linux
+PKG_PATCHVER:=5.10
+PKG_VERSION:=$(PKG_PATCHVER)$(strip $(LINUX_VERSION-$(PKG_PATCHVER)))
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=$(LINUX_SITE)
+PKG_HASH:=$(LINUX_KERNEL_HASH-$(strip $(PKG_VERSION)))
+PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/bpf-headers/$(PKG_NAME)-$(PKG_VERSION)
+
+GENERIC_BACKPORT_DIR := $(GENERIC_PLATFORM_DIR)/backport$(if $(wildcard $(GENERIC_PLATFORM_DIR)/backport-$(PKG_PATCHVER)),-$(PKG_PATCHVER))
+GENERIC_PATCH_DIR := $(GENERIC_PLATFORM_DIR)/pending$(if $(wildcard $(GENERIC_PLATFORM_DIR)/pending-$(PKG_PATCHVER)),-$(PKG_PATCHVER))
+GENERIC_HACK_DIR := $(GENERIC_PLATFORM_DIR)/hack$(if $(wildcard $(GENERIC_PLATFORM_DIR)/hack-$(PKG_PATCHVER)),-$(PKG_PATCHVER))
+GENERIC_FILES_DIR := $(foreach dir,$(wildcard $(GENERIC_PLATFORM_DIR)/files $(GENERIC_PLATFORM_DIR)/files-$(PKG_PATCHVER)),"$(dir)")
+PATCH_DIR := $(CURDIR)/patches
+FILES_DIR :=
+
+REAL_LINUX_DIR := $(LINUX_DIR)
+LINUX_DIR := $(PKG_BUILD_DIR)
+
+include $(INCLUDE_DIR)/bpf.mk
+include $(INCLUDE_DIR)/package.mk
+
+define Package/bpf-headers
+ SECTION:=kernel
+ CATEGORY:=Kernel
+ TITLE:=eBPF kernel headers
+ BUILDONLY:=1
+ HIDDEN:=1
+endef
+
+export HOST_EXTRACFLAGS=-I$(STAGING_DIR_HOST)/include
+
+KERNEL_MAKE := \
+ $(MAKE) -C $(PKG_BUILD_DIR) \
+ ARCH=$(BPF_KARCH) \
+ CROSS_COMPILE=$(BPF_ARCH)-linux- \
+ LLVM=1 CC="$(CLANG)" LD="$(TARGET_CROSS)ld" \
+ HOSTCC="$(HOSTCC)" \
+ HOSTCXX="$(HOSTCXX)" \
+ HOST_LOADLIBES="-L$(STAGING_DIR_HOST)/lib" \
+ KBUILD_HOSTLDLIBS="-L$(STAGING_DIR_HOST)/lib" \
+ CONFIG_SHELL="$(BASH)" \
+ INSTALL_HDR_PATH="$(PKG_BUILD_DIR)/user_headers"
+
+define Build/Patch
+ $(Kernel/Patch/Default)
+endef
+
+BPF_DOC = $(PKG_BUILD_DIR)/scripts/bpf_helpers_doc.py
+
+define Build/Configure
+ grep -vE 'CONFIG_(CPU_.*ENDIAN|HZ)' $(PKG_BUILD_DIR)/arch/mips/configs/generic_defconfig > $(PKG_BUILD_DIR)/.config
+ echo 'CONFIG_CPU_$(if $(CONFIG_BIG_ENDIAN),BIG,LITTLE)_ENDIAN=y' >> $(PKG_BUILD_DIR)/.config
+ grep CONFIG_HZ $(REAL_LINUX_DIR)/.config >> $(PKG_BUILD_DIR)/.config
+ yes '' | $(KERNEL_MAKE) oldconfig
+ grep 'CONFIG_HZ=' $(REAL_LINUX_DIR)/.config | \
+ cut -d= -f2 | \
+ bc -q $(LINUX_DIR)/kernel/time/timeconst.bc \
+ > $(LINUX_DIR)/include/generated/timeconst.h
+ $(BPF_DOC) --header \
+ --file $(LINUX_DIR)/tools/include/uapi/linux/bpf.h \
+ > $(PKG_BUILD_DIR)/tools/lib/bpf/bpf_helper_defs.h
+endef
+
+define Build/Compile
+ $(KERNEL_MAKE) archprepare headers_install
+endef
+
+define Build/InstallDev
+ mkdir -p $(1)/bpf-headers/arch $(1)/bpf-headers/tools
+ $(CP) \
+ $(PKG_BUILD_DIR)/arch/$(BPF_KARCH) \
+ $(1)/bpf-headers/arch/
+ $(CP) \
+ $(PKG_BUILD_DIR)/tools/lib \
+ $(PKG_BUILD_DIR)/tools/testing \
+ $(1)/bpf-headers/tools/
+ $(CP) \
+ $(PKG_BUILD_DIR)/include \
+ $(PKG_BUILD_DIR)/samples \
+ $(PKG_BUILD_DIR)/scripts \
+ $(PKG_BUILD_DIR)/user_headers \
+ $(1)/bpf-headers
+endef
+
+$(eval $(call BuildPackage,bpf-headers))
diff --git a/package/kernel/bpf-headers/src/include/generated/bounds.h b/package/kernel/bpf-headers/src/include/generated/bounds.h
new file mode 100644
index 0000000000..82ff01043c
--- /dev/null
+++ b/package/kernel/bpf-headers/src/include/generated/bounds.h
@@ -0,0 +1,14 @@
+#ifndef __LINUX_BOUNDS_H__
+#define __LINUX_BOUNDS_H__
+/*
+ * DO NOT MODIFY.
+ *
+ * This file was generated by Kbuild
+ */
+
+#define NR_PAGEFLAGS 23 /* __NR_PAGEFLAGS */
+#define MAX_NR_ZONES 4 /* __MAX_NR_ZONES */
+#define NR_CPUS_BITS 1 /* ilog2(CONFIG_NR_CPUS) */
+#define SPINLOCK_SIZE 64 /* sizeof(spinlock_t) */
+
+#endif
--
2.25.1

View File

@@ -0,0 +1,29 @@
From 32243b2148fd0dacd0630affaea59345c64df79a Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Tue, 2 Nov 2021 10:36:14 +0100
Subject: [PATCH 051/102] bpf-headers: unset PKG_CONFIG_PATH
This fixes an issue where the kernel would pick up an incompatible target
libyaml for building host tools
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
package/kernel/bpf-headers/Makefile | 2 ++
1 file changed, 2 insertions(+)
diff --git a/package/kernel/bpf-headers/Makefile b/package/kernel/bpf-headers/Makefile
index 5f5b89370d..df24bfa13f 100644
--- a/package/kernel/bpf-headers/Makefile
+++ b/package/kernel/bpf-headers/Makefile
@@ -41,6 +41,8 @@ define Package/bpf-headers
HIDDEN:=1
endef
+PKG_CONFIG_PATH:=
+
export HOST_EXTRACFLAGS=-I$(STAGING_DIR_HOST)/include
KERNEL_MAKE := \
--
2.25.1

View File

@@ -0,0 +1,99 @@
From 1eb36bc2be4b54e4e4e4ceffc01be78d996205f0 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Sun, 17 Oct 2021 17:50:53 +0200
Subject: [PATCH 052/102] tools/llvm-bpf: add llvm+clang build suitable for
compiling code to eBPF
Preparation for building packages that ship eBPF code
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
toolchain/Config.in | 7 +++++++
tools/Makefile | 2 ++
tools/llvm-bpf/Makefile | 36 ++++++++++++++++++++++++++++++++++++
3 files changed, 45 insertions(+)
create mode 100644 tools/llvm-bpf/Makefile
diff --git a/toolchain/Config.in b/toolchain/Config.in
index 6dda9af92d..9062d6f65e 100644
--- a/toolchain/Config.in
+++ b/toolchain/Config.in
@@ -37,6 +37,13 @@ menuconfig TARGET_OPTIONS
Most people will answer N.
+config BUILD_LLVM_BPF
+ bool "Build LLVM toolchain for eBPF" if DEVEL
+ help
+ If enabled, a LLVM toolchain for building eBPF binaries will be built.
+ If this is not enabled, eBPF packages can only be built if the host
+ has a suitable toolchain
+
menuconfig EXTERNAL_TOOLCHAIN
bool
diff --git a/tools/Makefile b/tools/Makefile
index a2665dbc9a..83147014c6 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -35,6 +35,7 @@ tools-$(CONFIG_TARGET_mxs) += elftosb sdimage
tools-$(CONFIG_TARGET_tegra) += cbootimage cbootimage-configs
tools-$(CONFIG_USES_MINOR) += kernel2minor
tools-$(CONFIG_USE_SPARSE) += sparse
+tools-$(CONFIG_BUILD_LLVM_BPF) += llvm-bpf
# builddir dependencies
$(curdir)/autoconf/compile := $(curdir)/m4/compile
@@ -57,6 +58,7 @@ $(curdir)/libelf/compile := $(curdir)/libtool/compile
$(curdir)/libressl/compile := $(curdir)/pkgconf/compile
$(curdir)/libtool/compile := $(curdir)/m4/compile $(curdir)/autoconf/compile $(curdir)/automake/compile $(curdir)/missing-macros/compile
$(curdir)/lzma-old/compile := $(curdir)/zlib/compile
+$(curdir)/llvm-bpf/compile := $(curdir)/cmake/compile
$(curdir)/make-ext4fs/compile := $(curdir)/zlib/compile
$(curdir)/missing-macros/compile := $(curdir)/autoconf/compile
$(curdir)/mkimage/compile += $(curdir)/libressl/compile
diff --git a/tools/llvm-bpf/Makefile b/tools/llvm-bpf/Makefile
new file mode 100644
index 0000000000..a5ba2a4cb7
--- /dev/null
+++ b/tools/llvm-bpf/Makefile
@@ -0,0 +1,36 @@
+#
+# Copyright (C) 2006-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=llvm-project
+PKG_VERSION:=13.0.0
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).src.tar.xz
+PKG_SOURCE_URL:=https://github.com/llvm/llvm-project/releases/download/llvmorg-$(PKG_VERSION)
+PKG_HASH:=6075ad30f1ac0e15f07c1bf062c1e1268c241d674f11bd32cdf0e040c71f2bf3
+
+HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/$(PKG_NAME)-$(PKG_VERSION).src
+
+HOST_BUILD_PARALLEL:=1
+
+CMAKE_BINARY_SUBDIR := build
+CMAKE_SOURCE_SUBDIR := llvm
+
+include $(INCLUDE_DIR)/host-build.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+CMAKE_HOST_OPTIONS += \
+ -DLLVM_ENABLE_BINDINGS=OFF \
+ -DLLVM_INCLUDE_DOCS=OFF \
+ -DLLVM_INCLUDE_EXAMPLES=OFF \
+ -DLLVM_INCLUDE_TESTS=OFF \
+ -DLLVM_ENABLE_PROJECTS="clang;lld" \
+ -DLLVM_TARGETS_TO_BUILD=BPF \
+ -DCLANG_BUILD_EXAMPLES=OFF
+
+$(eval $(call HostBuild))
--
2.25.1

View File

@@ -0,0 +1,40 @@
From 103a743e7ca4a2e98969d0f60d8aeb6cc7641f67 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Tue, 2 Nov 2021 19:38:12 +0100
Subject: [PATCH 053/102] llvm-bpf: move to staging_dir/host/llvm-bpf
This makes it easier to package it up for the download server
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
tools/llvm-bpf/Makefile | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/tools/llvm-bpf/Makefile b/tools/llvm-bpf/Makefile
index a5ba2a4cb7..ae279d26d2 100644
--- a/tools/llvm-bpf/Makefile
+++ b/tools/llvm-bpf/Makefile
@@ -24,6 +24,8 @@ CMAKE_SOURCE_SUBDIR := llvm
include $(INCLUDE_DIR)/host-build.mk
include $(INCLUDE_DIR)/cmake.mk
+CMAKE_HOST_INSTALL_PREFIX = $(STAGING_DIR_HOST)/llvm-bpf
+
CMAKE_HOST_OPTIONS += \
-DLLVM_ENABLE_BINDINGS=OFF \
-DLLVM_INCLUDE_DOCS=OFF \
@@ -31,6 +33,10 @@ CMAKE_HOST_OPTIONS += \
-DLLVM_INCLUDE_TESTS=OFF \
-DLLVM_ENABLE_PROJECTS="clang;lld" \
-DLLVM_TARGETS_TO_BUILD=BPF \
- -DCLANG_BUILD_EXAMPLES=OFF
+ -DCLANG_BUILD_EXAMPLES=OFF \
+ -DLLVM_INSTALL_TOOLCHAIN_ONLY=ON \
+ -DLLVM_LINK_LLVM_DYLIB=ON \
+ -DLLVM_TOOLCHAIN_TOOLS="llvm-objcopy;llvm-objdump;llvm-readelf;llvm-strip;llvm-ar;llvm-as;llvm-dis;llvm-link;llvm-nm;llvm-ranlib;llc;opt" \
+ -DCMAKE_SKIP_RPATH=OFF
$(eval $(call HostBuild))
--
2.25.1

View File

@@ -0,0 +1,103 @@
From a368d456ba1e9198fd8f473b7e82c0e066e4eb82 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Mon, 1 Nov 2021 18:40:03 +0100
Subject: [PATCH 054/102] build: fix bpf toolchain dependency for qosify
Add hidden symbols to fix defaults with CONFIG_DEVEL unset
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
include/bpf.mk | 2 ++
toolchain/Config.in | 45 +++++++++++++++++++++++++++++++++++++++++++++
tools/Makefile | 2 +-
3 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/include/bpf.mk b/include/bpf.mk
index 3dc65c7685..5211ec4434 100644
--- a/include/bpf.mk
+++ b/include/bpf.mk
@@ -1,3 +1,5 @@
+BPF_DEPENDS := @HAS_BPF_TOOLCHAIN
+
ifneq ($(CONFIG_BPF_TOOLCHAIN_HOST),)
BPF_TOOLCHAIN_HOST_PATH:=$(call qstrip,$(CONFIG_BPF_TOOLCHAIN_HOST_PATH))
ifneq ($(BPF_TOOLCHAIN_HOST_PATH),)
diff --git a/toolchain/Config.in b/toolchain/Config.in
index 9062d6f65e..997cff59e4 100644
--- a/toolchain/Config.in
+++ b/toolchain/Config.in
@@ -44,6 +44,32 @@ config BUILD_LLVM_BPF
If this is not enabled, eBPF packages can only be built if the host
has a suitable toolchain
+ choice BPF_TOOLCHAIN
+ prompt "BPF toolchain" if DEVEL
+ default BPF_TOOLCHAIN_NONE
+
+ config BPF_TOOLCHAIN_NONE
+ bool "None"
+
+ config BPF_TOOLCHAIN_HOST
+ select USE_LLVM_HOST
+ bool "Use host LLVM toolchain"
+
+ config BPF_TOOLCHAIN_BUILD_LLVM
+ select USE_LLVM_BUILD
+ bool "Build LLVM toolchain for eBPF"
+ help
+ If enabled, a LLVM toolchain for building eBPF binaries will be built.
+ If this is not enabled, eBPF packages can only be built if the host
+ has a suitable toolchain
+ endchoice
+
+ config BPF_TOOLCHAIN_HOST_PATH
+ string
+ depends on BPF_TOOLCHAIN_HOST
+ prompt "Host LLVM toolchain path (prefix)" if DEVEL
+ default "/usr/local/opt/llvm" if HOST_OS_MACOS
+ default ""
menuconfig EXTERNAL_TOOLCHAIN
bool
@@ -266,6 +292,25 @@ config GDB
help
Enable if you want to build the gdb.
+config GDB_PYTHON
+ bool
+ depends on GDB
+ prompt "Build gdb with python binding"
+
+ help
+ Enable the python bindings for GDB to allow using python in the gdb shell.
+
+config HAS_BPF_TOOLCHAIN
+ bool
+
+config USE_LLVM_HOST
+ select HAS_BPF_TOOLCHAIN
+ bool
+
+config USE_LLVM_BUILD
+ select HAS_BPF_TOOLCHAIN
+ bool
+
config USE_GLIBC
default y if !TOOLCHAINOPTS && !EXTERNAL_TOOLCHAIN && !NATIVE_TOOLCHAIN && (arc)
bool
diff --git a/tools/Makefile b/tools/Makefile
index 83147014c6..ae3cc5dfd6 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -35,7 +35,7 @@ tools-$(CONFIG_TARGET_mxs) += elftosb sdimage
tools-$(CONFIG_TARGET_tegra) += cbootimage cbootimage-configs
tools-$(CONFIG_USES_MINOR) += kernel2minor
tools-$(CONFIG_USE_SPARSE) += sparse
-tools-$(CONFIG_BUILD_LLVM_BPF) += llvm-bpf
+tools-$(CONFIG_USE_LLVM_BUILD) += llvm-bpf
# builddir dependencies
$(curdir)/autoconf/compile := $(curdir)/m4/compile
--
2.25.1

View File

@@ -0,0 +1,26 @@
From 2ae5b19a52da190ea342ec4210523407837c58ea Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Tue, 2 Nov 2021 09:56:10 +0100
Subject: [PATCH 055/102] include/bpf.mk: fix typo
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
include/bpf.mk | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/bpf.mk b/include/bpf.mk
index 5211ec4434..6223648c5d 100644
--- a/include/bpf.mk
+++ b/include/bpf.mk
@@ -5,7 +5,7 @@ ifneq ($(CONFIG_BPF_TOOLCHAIN_HOST),)
ifneq ($(BPF_TOOLCHAIN_HOST_PATH),)
BPF_PATH:=$(BPF_TOOLCHAIN_HOST_PATH)/bin:$(PATH)
else
- BPF_PATH:=$(BPF_PATH)
+ BPF_PATH:=$(PATH)
endif
CLANG:=$(firstword $(shell PATH='$(BPF_PATH)' which clang clang-13 clang-12 clang-11))
LLVM_VER:=$(subst clang,,$(notdir $(CLANG)))
--
2.25.1

View File

@@ -0,0 +1,39 @@
From aff796bf3e60d7f09e5ca500cbf59221211dd218 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Tue, 2 Nov 2021 10:39:35 +0100
Subject: [PATCH 056/102] include/bpf.mk: fix compile for big-endian targets
llvm-opt and llc need endian flags in the target as well
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
include/bpf.mk | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/include/bpf.mk b/include/bpf.mk
index 6223648c5d..9636ad5165 100644
--- a/include/bpf.mk
+++ b/include/bpf.mk
@@ -22,6 +22,7 @@ LLVM_STRIP:=$(LLVM_PATH)/llvm-strip$(LLVM_VER)
BPF_KARCH:=mips
BPF_ARCH:=mips$(if $(CONFIG_BIG_ENDIAN),,el)
+BPF_TARGET:=bpf$(if $(CONFIG_BIG_ENDIAN),eb,el)
BPF_HEADERS_DIR:=$(STAGING_DIR)/bpf-headers
@@ -59,9 +60,9 @@ BPF_CFLAGS := \
define CompileBPF
$(CLANG) -g -target $(BPF_ARCH)-linux-gnu $(BPF_CFLAGS) $(2) \
-c $(1) -o $(patsubst %.c,%.bc,$(1))
- $(LLVM_OPT) -O2 -mtriple=bpf-pc-linux < $(patsubst %.c,%.bc,$(1)) > $(patsubst %.c,%.opt,$(1))
+ $(LLVM_OPT) -O2 -mtriple=$(BPF_TARGET) < $(patsubst %.c,%.bc,$(1)) > $(patsubst %.c,%.opt,$(1))
$(LLVM_DIS) < $(patsubst %.c,%.opt,$(1)) > $(patsubst %.c,%.S,$(1))
- $(LLVM_LLC) -march=bpf -filetype=obj -o $(patsubst %.c,%.o,$(1)) < $(patsubst %.c,%.S,$(1))
+ $(LLVM_LLC) -march=$(BPF_TARGET) -filetype=obj -o $(patsubst %.c,%.o,$(1)) < $(patsubst %.c,%.S,$(1))
$(LLVM_STRIP) --strip-debug $(patsubst %.c,%.o,$(1))
endef
--
2.25.1

View File

@@ -0,0 +1,34 @@
From d05fae42794c5fe76509935b1e8f900e1d17d9f0 Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Fri, 5 Nov 2021 10:46:00 +0100
Subject: [PATCH] include/bpf.mk: add LD_LIBRARY_PATH
Signed-off-by: John Crispin <john@phrozen.org>
---
include/bpf.mk | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/include/bpf.mk b/include/bpf.mk
index 9636ad5165..2f797625b6 100644
--- a/include/bpf.mk
+++ b/include/bpf.mk
@@ -58,11 +58,16 @@ BPF_CFLAGS := \
-O2 -emit-llvm -Xclang -disable-llvm-passes
define CompileBPF
+ LD_LIBRARY_PATH=$(LD_LIBRARY_PATH):$(STAGING_DIR_HOST)/lib \
$(CLANG) -g -target $(BPF_ARCH)-linux-gnu $(BPF_CFLAGS) $(2) \
-c $(1) -o $(patsubst %.c,%.bc,$(1))
+ LD_LIBRARY_PATH=$(LD_LIBRARY_PATH):$(STAGING_DIR_HOST)/lib \
$(LLVM_OPT) -O2 -mtriple=$(BPF_TARGET) < $(patsubst %.c,%.bc,$(1)) > $(patsubst %.c,%.opt,$(1))
+ LD_LIBRARY_PATH=$(LD_LIBRARY_PATH):$(STAGING_DIR_HOST)/lib \
$(LLVM_DIS) < $(patsubst %.c,%.opt,$(1)) > $(patsubst %.c,%.S,$(1))
+ LD_LIBRARY_PATH=$(LD_LIBRARY_PATH):$(STAGING_DIR_HOST)/lib \
$(LLVM_LLC) -march=$(BPF_TARGET) -filetype=obj -o $(patsubst %.c,%.o,$(1)) < $(patsubst %.c,%.S,$(1))
+ LD_LIBRARY_PATH=$(LD_LIBRARY_PATH):$(STAGING_DIR_HOST)/lib \
$(LLVM_STRIP) --strip-debug $(patsubst %.c,%.o,$(1))
endef
--
2.25.1

View File

@@ -3,9 +3,10 @@ FROM ubuntu:20.04
RUN apt-get update \
&& DEBIAN_FRONTEND="noninteractive" apt-get -y install tzdata \
&& apt-get install -y \
time git-core build-essential gcc-multilib \
time git-core build-essential gcc-multilib clang \
libncurses5-dev zlib1g-dev gawk flex gettext wget unzip python \
python3 python3-pip python3-yaml libssl-dev rsync \
python3 python3-pip python3-yaml libssl-dev rsync llvm llvm-12 \
clang-12 \
&& apt-get clean
RUN git config --global user.email "you@example.com"
RUN git config --global user.name "Your Name"

View File

@@ -24,8 +24,7 @@ define Package/fbwifi
SECTION:=net
CATEGORY:=Network
DEPENDS:=+iptables +luasec +luasocket \
+luci-base +libuci-lua +luaposix \
+luci-mod-network +luci-mod-status +luci-theme-bootstrap \
+libuci-lua +luaposix \
+lua-cjson +uhttpd
TITLE:=Facebook Wi-Fi
PKGARCH:=all
@@ -35,6 +34,22 @@ define Package/fbwifi/description
Facebook Wi-Fi, an AP authorisation solution
endef
define Package/luci-app-fbwifi
SUBMENU:=3. Applications
SECTION:=luci
CATEGORY:=LuCI
TITLE:=LuCI support for Facebook Wi-Fi
DEPENDS:= \
+fbwifi \
+luci-base +luci-mod-network +luci-mod-status +luci-theme-bootstrap
endef
define Package/luci-app-fbwifi/description
LuCI support for Facebook Wi-Fi
endef
define Package/fbwifi/conffiles
/etc/config/fbwifi
endef
@@ -50,7 +65,13 @@ endef
define Package/fbwifi/install
$(INSTALL_DIR) $(1)
$(CP) ./files/* $(1)/
$(CP) ./files/fbwifi/* $(1)/
endef
define Package/luci-app-fbwifi/install
$(INSTALL_DIR) $(1)
$(CP) ./files/luci-app-fbwifi/* $(1)
endef
$(eval $(call BuildPackage,fbwifi))
$(eval $(call BuildPackage,luci-app-fbwifi))

View File

@@ -11,48 +11,12 @@ To disable Facebook Wi-Fi, run `fbwifi disable`.
## Contents
The 'files' subdirectory contains all the configuration, script and code
that implements the Facebook Wi-Fi v2.0 standard for OpenWrt.
The 'files' subdirectory contains two subdirectories, one for the fbwifi
package that implements the Facebook Wi-Fi v2.0 standard for OpenWrt, and
another one containing a LuCI application to configure Facebook Wi-Fi.
The folder structure follows *nix conventions :
The folder structures follow *nix conventions:
- 'etc' is the boot time scripts and configuration
- 'usr' contains procedural scripts, lua common code module and GUI prototype for luci
- 'www' contains the HTTP endpoints as CGI handlers
```
files/
├── etc
│   ├── config
│   │   └── fbwifi
│   ├── hotplug.d
│   │   └── iface
│   │   └── 50-fbwifi
│   ├── init.d
│   │   └── fbwifi
├── usr
│   ├── lib
│   │   └── lua
│   │   ├── fbwifi.lua
│   │   └── luci
│   │   ├── controller
│   │   │   └── fbwifi.lua
│   │   └── view
│   │   └── fbwifi.htm
│   ├── sbin
│   │ ├── fbwifi
│   │ ├── fbwifi_debug_dump
│   │ ├── fbwifi_gateway_info_update
│   │ ├── fbwifi_get_config
│   │ └── fbwifi_validate_token_db
│ └── share
│ └── fbwifi
│ ├── firewall.include
│ └── uhttpd.json
└── www
└── cgi-bin
└── fbwifi
└── v2.0
├── auth
├── capport
└── info
```

View File

@@ -17,7 +17,7 @@ include ./openvswitch.mk
#
PKG_NAME:=openvswitch
PKG_VERSION:=$(ovs_version)
PKG_RELEASE:=6
PKG_RELEASE:=10
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://www.openvswitch.org/releases/
PKG_HASH:=5c7baed537364d43af36c15dde298c95d35cb2cb3204b4d3fe9b0fc73c97f16d
@@ -155,7 +155,7 @@ ovs_libopenvswitch_title:=Open vSwitch (libopenvswitch.so)
ovs_libopenvswitch_hidden:=1
ovs_libopenvswitch_depends:=+libopenssl +!(arc||arceb):libunwind
ovs_libopenvswitch_depends+=+libatomic
ifeq ($(CONFIG_KEEPALIVED_ROUTES),y)
ifeq ($(CONFIG_OPENVSWITCH_WITH_LIBUNBOUND),y)
ovs_libopenvswitch_depends+=+libunbound
endif
ovs_libopenvswitch_files:=usr/lib/libopenvswitch*.so*

View File

@@ -85,12 +85,14 @@ after adding or changing these options.
The ovs_bridge section also supports the options below,
for initialising a virtual bridge with an OpenFlow controller.
| Name | Type | Required | Default | Description |
|-------------|---------|----------|--------------------------------|------------------------------------------------------------|
| disabled | boolean | no | 0 | If set to true, disable initialisation of the named bridge |
| name | string | no | Inherits UCI config block name | The name of the switch in the OVS daemon |
| controller | string | no | (none) | The endpoint of an OpenFlow controller for this bridge |
| datapath_id | string | no | (none) | The OpenFlow datapath ID for this bridge |
| Name | Type | Required | Default | Description |
|---------------|---------|----------|--------------------------------|------------------------------------------------------------|
| disabled | boolean | no | 0 | If set to true, disable initialisation of the named bridge |
| name | string | no | Inherits UCI config block name | The name of the switch in the OVS daemon |
| controller | string | no | (none) | The endpoint of an OpenFlow controller for this bridge |
| datapath_id | string | no | (none) | The OpenFlow datapath ID for this bridge |
| datapath_desc | string | no | (none) | The OpenFlow datapath description for this bridge |
| fail_mode | string | no | standalone | The bridge failure mode |
The ovs_port section can be used to add ports to a bridge. It supports the options below.

View File

@@ -14,7 +14,9 @@ config ovs_bridge
option disabled 1
option name 'my-bridge'
option controller 'tcp:192.168.0.1'
option datapath_desc ''
option datapath_id ''
option fail_mode 'standalone'
config ovs_port
option disabled 1

View File

@@ -121,6 +121,7 @@ ovs_bridge_port_add() {
}
ovs-vsctl --may-exist add-port "$name" "$port" ${type:+ -- set interface "$port" type="$type"}
ovs_bridge_port_up "$port"
__port_list="$__port_list ${port} "
}
@@ -162,6 +163,7 @@ ovs_bridge_port_add_complex() {
ovs-vsctl --may-exist add-port "$bridge" "$port" ${tag:+tag="$tag"} \
${ofport:+ -- set interface "$port" ofport_request="$ofport"} \
${type:+ -- set interface "$port" type="$type"}
ovs_bridge_port_up "$port"
__port_list="$__port_list ${port} "
}
@@ -174,6 +176,12 @@ ovs_bridge_port_cleanup() {
done
}
ovs_bridge_port_up() {
local port="$1"
ip link set dev "$port" up
}
ovs_bridge_validate_datapath_id() {
local dpid="$1"
@@ -187,6 +195,31 @@ ovs_bridge_validate_datapath_id() {
fi
}
ovs_bridge_validate_datapath_desc() {
local dpdesc="$1"
if [ "$(echo $dpdesc | wc -c)" -le 255 ]; then
return 0
else
logger -t openvswitch "invalid datapath_desc: $dpdesc"
return 1
fi
}
ovs_bridge_validate_fail_mode() {
local fail_mode="$1"
case "$fail_mode" in
secure|standalone)
return 0
;;
*)
logger -t openvswitch "invalid fail_mode: $fail_mode"
return 1
;;
esac
}
ovs_bridge_init() {
local cfg="$1"
@@ -208,6 +241,24 @@ ovs_bridge_init() {
}
}
config_get datapath_desc "$cfg" datapath_desc
[ -n "$datapath_desc" ] && {
ovs_bridge_validate_datapath_desc "$datapath_desc" && {
ovs-vsctl --if-exists set bridge "$name" other-config:dp-desc="$datapath_desc"
}
}
config_get fail_mode "$cfg" fail_mode
[ -n "$fail_mode" ] && {
ovs_bridge_validate_fail_mode "$fail_mode" && {
ovs-vsctl set-fail-mode "$name" "$fail_mode" 2> /dev/null
} || {
ovs-vsctl del-fail-mode "$name" 2> /dev/null
}
} || {
ovs-vsctl del-fail-mode "$name" 2> /dev/null
}
config_list_foreach "$cfg" "ports" ovs_bridge_port_add
config_foreach ovs_bridge_port_add_complex ovs_port "$name"
config_get_bool drop "$cfg" "drop_unknown_ports" 0

View File

@@ -22,6 +22,7 @@ let keys = {
nasmac: false,
macauth: false,
macpassword: false,
uamsecret: false,
};
function get_value(key, value) {

View File

@@ -9,13 +9,16 @@ boot() {
local mtd=$(find_mtd_index certificates)
[ -n "$mtd" -a -f /sys/class/mtd/mtd$mtd/oobsize ] && ubiattach -p /dev/mtd$mtd
if [ -n "$(ubinfo -a | grep certificates)" ]; then
mount -t ubifs ubi0:certificates /certificates
mount -t ubifs ubi1:certificates /certificates
[ -e /dev/ubi0 ] && mount -t ubifs ubi0:certificates /certificates
[ -e /dev/ubi1 ] && mount -t ubifs ubi1:certificates /certificates
else
mount -t squashfs /dev/mtdblock$mtd /certificates
fi
[ -f /certificates/dev-id ] && {
cp /certificates/*.pem /etc/ucentral/
cp /certificates/dev-id /etc/ucentral/
chown root.network /etc/ucentral/*.pem
chmod 0440 root.network /etc/ucentral/*.pem
chmod 0400 /etc/ucentral/dev-id
}
}

View File

@@ -0,0 +1,17 @@
#
# Copyright (C) 2021 Jo-Philipp Wich <jo@mein.io>
#
# This is free software, licensed under the Apache License, Version 2.0 .
#
include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI uCentral Configuration
LUCI_DEPENDS:=+luci-base
PKG_LICENSE:=Apache-2.0
include ../luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@@ -0,0 +1,98 @@
'use strict';
'require fs';
'require ui';
'require dom';
'require rpc';
'require session';
'require baseclass';
var callReboot = rpc.declare({
object: 'system',
method: 'reboot',
expect: { result: 0 }
});
function handleReboot(ev) {
return callReboot().then(function(res) {
if (res != 0) {
showError(_('The reboot command failed with code %d').format(res));
L.raise('Error', 'Reboot failed');
}
showProgress(_('The system is rebooting in order to attempt applying the remote configuration profile now. If not successful, the device will revert back into the initial provisioning state.'));
ui.awaitReconnect();
}).catch(function(e) { showError(e.message) });
}
function setDirty(isDirty) {
if (isDirty) {
session.setLocalData('ucentral-dirty', true);
ui.showIndicator('ucentral-dirty', _('Reboot required'), showApplySettings);
}
else {
session.setLocalData('ucentral-dirty', null);
ui.hideIndicator('ucentral-dirty');
}
}
function handleContinue(ev) {
setDirty(true);
ui.hideModal();
}
function showApplySettings() {
ui.showModal(_('Apply Settings'), [
E('p', _('The device must be rebooted in order to apply the changed settings. Once the uCentral agent successfully connects to the controller, the remote configuration profile will be applied and the initial provisioning web interface is disabled.')),
E('div', { 'class': 'right' }, [
E('button', { 'click': handleReboot, 'class': 'btn primary' }, [ _('Apply settings and reboot device now') ]),
'\xa0',
E('button', { 'click': handleContinue, 'class': 'btn' }, [ _('Continue configuration') ])
])
]);
}
function showProgress(text, timeout) {
var dlg = ui.showModal(null, [
E('p', { 'class': (timeout > 0) ? null : 'spinning' }, text)
]);
dlg.removeChild(dlg.firstElementChild);
if (timeout > 0)
window.setTimeout(ui.hideModal, timeout);
return dlg;
}
function showError(text) {
ui.showModal(_('Error'), [
E('p', [ text ]),
E('div', { 'class': 'right' }, [
E('button', { 'class': 'btn', 'click': ui.hideModal }, _('OK'))
])
]);
}
if (session.getLocalData('ucentral-dirty'))
setDirty(true);
return baseclass.extend({
save: function(serializeFn, ev) {
var m = dom.findClassInstance(document.querySelector('.cbi-map'));
return m.save().then(function() {
return fs.write('/etc/ucentral/profile.json', serializeFn(m.data.data));
}).then(function() {
return fs.exec('/sbin/profileupdate');
}).then(function() {
showApplySettings();
}).catch(function(err) {
showError(_('Unable to save settings: %s').format(err));
});
},
setDirty: setDirty,
showError: showError,
showProgress: showProgress,
});

View File

@@ -0,0 +1,70 @@
'use strict';
'require view';
'require form';
'require fs';
'require ui';
'require tools.ucentral as uctool';
var profile = null;
function serialize(data) {
if (!L.isObject(profile.unit))
profile.unit = {};
profile.redirector = data.local.redirector;
profile.unit.location = data.local.location;
return JSON.stringify(profile, null, '\t');
}
return view.extend({
load: function() {
return L.resolveDefault(fs.read('/etc/ucentral/profile.json'), '').then(function(data) {
try { profile = JSON.parse(data); }
catch(e) { profile = {}; };
});
},
render: function() {
var m, s, o, data = { local: {
redirector: profile.redirector,
location: L.isObject(profile.unit) ? profile.unit.location : ''
} };
m = new form.JSONMap(data);
m.readonly = !L.hasViewPermission();
s = m.section(form.NamedSection, 'local', 'local', _('Local settings'),
_('The settings on this page specify how the local uCentral client connects to the controller server.'));
s.option(form.Value, 'redirector', _('Redirector URL'));
s.option(form.Value, 'location', _('Unit location'));
o = s.option(form.Button, '_certs', _('Certificates'));
o.inputtitle = _('Upload certificate bundle…');
o.onclick = function(ev) {
return ui.uploadFile('/tmp/certs.tar').then(function(res) {
uctool.showProgress(_('Verifying certificates…'));
return fs.exec('/sbin/certupdate').then(function(res) {
if (res.code) {
uctool.showError(_('Certificate validation failed: %s').format(res.stderr || res.stdout));
}
else {
uctool.showProgress(_('Certificates updated.'), 1500);
uctool.setDirty(true);
}
}, function(err) {
uctool.showError(_('Unable to verify certificates: %s').format(err));
});
});
};
return m.render();
},
handleSave: uctool.save.bind(uctool, serialize),
handleSaveApply: null,
handleReset: null
});

View File

@@ -0,0 +1,121 @@
'use strict';
'require rpc';
'require view';
'require tools.ucentral as uctool';
var callSystemBoard = rpc.declare({
object: 'system',
method: 'board'
});
var callSystemInfo = rpc.declare({
object: 'system',
method: 'info'
});
function progressbar(value, max, byte) {
var vn = parseInt(value) || 0,
mn = parseInt(max) || 100,
fv = byte ? String.format('%1024.2mB', value) : value,
fm = byte ? String.format('%1024.2mB', max) : max,
pc = Math.floor((100 / mn) * vn);
return E('div', {
'class': 'cbi-progressbar',
'title': '%s / %s (%d%%)'.format(fv, fm, pc)
}, E('div', { 'style': 'width:%.2f%%'.format(pc) }));
}
return view.extend({
load: function() {
return Promise.all([
L.resolveDefault(callSystemBoard(), {}),
L.resolveDefault(callSystemInfo(), {})
]);
},
render: function(data) {
var boardinfo = data[0],
systeminfo = data[1],
mem = L.isObject(systeminfo.memory) ? systeminfo.memory : {},
swap = L.isObject(systeminfo.swap) ? systeminfo.swap : {},
datestr = null;
if (systeminfo.localtime) {
var date = new Date(systeminfo.localtime * 1000);
datestr = '%04d-%02d-%02d %02d:%02d:%02d'.format(
date.getUTCFullYear(),
date.getUTCMonth() + 1,
date.getUTCDate(),
date.getUTCHours(),
date.getUTCMinutes(),
date.getUTCSeconds()
);
}
var sysfields = [
_('Hostname'), boardinfo.hostname,
_('Model'), boardinfo.model,
_('Architecture'), boardinfo.system,
_('Firmware Version'), (L.isObject(boardinfo.release) ? boardinfo.release.description : '?'),
_('Kernel Version'), boardinfo.kernel,
_('Local Time'), datestr,
_('Uptime'), systeminfo.uptime ? '%t'.format(systeminfo.uptime) : null,
_('Load Average'), Array.isArray(systeminfo.load) ? '%.2f, %.2f, %.2f'.format(
systeminfo.load[0] / 65535.0,
systeminfo.load[1] / 65535.0,
systeminfo.load[2] / 65535.0
) : null
];
var systable = E('table', { 'class': 'table' });
for (var i = 0; i < sysfields.length; i += 2) {
systable.appendChild(E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'width': '33%' }, [ sysfields[i] ]),
E('td', { 'class': 'td left' }, [ (sysfields[i + 1] != null) ? sysfields[i + 1] : '?' ])
]));
}
var memfields = [
_('Total Available'), (mem.available) ? mem.available : (mem.total && mem.free && mem.buffered) ? mem.free + mem.buffered : null, mem.total,
_('Used'), (mem.total && mem.free) ? (mem.total - mem.free) : null, mem.total,
_('Buffered'), (mem.total && mem.buffered) ? mem.buffered : null, mem.total
];
if (mem.cached)
memfields.push(_('Cached'), mem.cached, mem.total);
if (swap.total > 0)
memfields.push(_('Swap free'), swap.free, swap.total);
var memtable = E('table', { 'class': 'table' });
for (var i = 0; i < memfields.length; i += 3) {
memtable.appendChild(E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'width': '33%' }, [ memfields[i] ]),
E('td', { 'class': 'td left' }, [
(memfields[i + 1] != null) ? progressbar(memfields[i + 1], memfields[i + 2], true) : '?'
])
]));
}
return E([], [
E('div', { 'class': 'cbi-section' }, [
E('h3', _('System')),
systable
]),
E('div', { 'class': 'cbi-section' }, [
E('h3', _('Memory')),
memtable
]),
]);
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});

View File

@@ -0,0 +1,181 @@
'use strict';
'require view';
'require dom';
'require form';
'require rpc';
'require fs';
'require ui';
'require tools.ucentral as uctool';
var callSystemValidateFirmwareImage = rpc.declare({
object: 'system',
method: 'validate_firmware_image',
params: [ 'path' ],
expect: { '': { valid: false, forcable: true } }
});
var callReboot = rpc.declare({
object: 'system',
method: 'reboot',
expect: { result: 0 }
});
var mapdata = { actions: {}, config: {} };
return view.extend({
load: function() {
var tasks = [
fs.trimmed('/proc/mtd'),
fs.trimmed('/proc/mounts')
];
return Promise.all(tasks);
},
handleFirstboot: function(ev) {
if (!confirm(_('Do you really want to erase all settings?')))
return;
uctool.showProgress(_('The system is erasing the configuration partition now and will reboot itself when finished.'));
/* Currently the sysupgrade rpc call will not return, hence no promise handling */
fs.exec('/sbin/firstboot', [ '-r', '-y' ]);
ui.awaitReconnect('192.168.1.1', 'openwrt.lan');
},
handleSysupgrade: function(ev) {
return ui.uploadFile('/tmp/firmware.bin', ev.target.firstChild)
.then(L.bind(function(btn, reply) {
btn.firstChild.data = _('Checking image…');
uctool.showProgress(_('Verifying the uploaded image file.'));
return callSystemValidateFirmwareImage('/tmp/firmware.bin')
.then(function(res) { return [ reply, res ]; });
}, this, ev.target))
.then(L.bind(function(btn, reply) {
return fs.exec('/sbin/sysupgrade', [ '--test', '/tmp/firmware.bin' ])
.then(function(res) { reply.push(res); return reply; });
}, this, ev.target))
.then(L.bind(function(btn, res) {
var is_valid = res[1].valid,
body = [];
if (is_valid) {
body.push(E('p', _("The firmware image was uploaded. Compare the checksum and file size listed below with the original file to ensure data integrity. <br /> Click 'Continue' below to start the flash procedure.")));
body.push(E('ul', {}, [
res[0].size ? E('li', {}, '%s: %1024.2mB'.format(_('Size'), res[0].size)) : '',
res[0].checksum ? E('li', {}, '%s: %s'.format(_('MD5'), res[0].checksum)) : '',
res[0].sha256sum ? E('li', {}, '%s: %s'.format(_('SHA256'), res[0].sha256sum)) : ''
]));
}
else {
body.push(E('p', _("The firmware image is invalid and cannot be flashed. Check the diagnostics below for further details.")));
if (res[2].stderr)
body.push(E('pre', { 'class': 'alert-message' }, [ res[2].stderr ]));
}
var cntbtn = E('button', {
'class': 'btn cbi-button-action important',
'click': ui.createHandlerFn(this, 'handleSysupgradeConfirm', btn)
}, [ _('Continue') ]);
if (!is_valid)
cntbtn.disabled = true;
body.push(E('div', { 'class': 'right' }, [
E('button', {
'class': 'btn',
'click': ui.createHandlerFn(this, function(ev) {
return fs.remove('/tmp/firmware.bin').finally(ui.hideModal);
})
}, [ _('Cancel') ]), ' ', cntbtn
]));
ui.showModal(is_valid ? _('Flash image?') : _('Invalid image'), body);
}, this, ev.target))
.catch(function(e) { uctool.showError(e.message) })
.finally(L.bind(function(btn) {
btn.firstChild.data = _('Flash image…');
}, this, ev.target));
},
handleSysupgradeConfirm: function(btn, ev) {
btn.firstChild.data = _('Flashing…');
uctool.showProgress(_('The system is flashing now.<br /> DO NOT POWER OFF THE DEVICE!<br /> Wait a few minutes before you try to reconnect. It might be necessary to renew the address of your computer to reach the device again, depending on your settings.'));
/* Currently the sysupgrade rpc call will not return, hence no promise handling */
fs.exec('/sbin/sysupgrade', [ '-n', '/tmp/firmware.bin' ]);
ui.awaitReconnect('192.168.1.1', 'openwrt.lan');
},
handleReboot: function(ev) {
return callReboot().then(function(res) {
if (res != 0) {
uctool.showError(_('The reboot command failed with code %d').format(res));
L.raise('Error', 'Reboot failed');
}
uctool.showProgress(_('The device is rebooting now. This page will try to reconnect automatically once the device is fully booted.'));
ui.awaitReconnect();
})
.catch(function(e) { uctool.showError(e.message) });
},
render: function(rpc_replies) {
var procmtd = rpc_replies[0],
procmounts = rpc_replies[1],
has_rootfs_data = (procmtd.match(/"rootfs_data"/) != null) || (procmounts.match("overlayfs:\/overlay \/ ") != null),
m, s, o, ss;
m = new form.JSONMap(mapdata);
m.readonly = !L.hasViewPermission();
s = m.section(form.NamedSection, 'actions');
o = s.option(form.SectionValue, 'actions', form.NamedSection, 'actions', 'actions', _('Reboot device'),
_('Issue a reboot and restart the operating system on this device.'));
ss = o.subsection;
o = ss.option(form.Button, 'reboot');
o.inputstyle = 'action important';
o.inputtitle = _('Reboot');
o.onclick = L.bind(this.handleReboot, this);
o = s.option(form.SectionValue, 'actions', form.NamedSection, 'actions', 'actions', _('Reset to defaults'),
_('Reset the system to its initial state and discard any configuration changes.'));
ss = o.subsection;
if (has_rootfs_data) {
o = ss.option(form.Button, 'reset');
o.inputstyle = 'negative important';
o.inputtitle = _('Perform reset');
o.onclick = this.handleFirstboot;
}
o = s.option(form.SectionValue, 'actions', form.NamedSection, 'actions', 'actions', _('Firmware upgrade'),
_('Upload a compatible firmware image here to upgrade the running system.'));
ss = o.subsection;
o = ss.option(form.Button, 'sysupgrade');
o.inputstyle = 'action important';
o.inputtitle = _('Flash image…');
o.onclick = L.bind(this.handleSysupgrade, this);
return m.render();
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});

View File

@@ -0,0 +1,118 @@
'use strict';
'require view';
'require form';
'require fs';
'require tools.ucentral as uctool';
var profile = null;
function serialize(data) {
if (data.broadband.protocol != 'default')
profile.broadband = Object.assign({}, data.broadband);
else
delete profile.broadband;
return JSON.stringify(profile, function(key, val) {
return (key.charAt(0) != '.') ? val : undefined;
}, '\t');
}
return view.extend({
load: function() {
return L.resolveDefault(fs.read('/etc/ucentral/profile.json'), '').then(function(data) {
try { profile = JSON.parse(data); }
catch(e) { profile = {}; };
if (!L.isObject(profile.broadband))
profile.broadband = { protocol: 'default' };
});
},
render: function() {
var m, s, o, data = { broadband: {} };
m = new form.JSONMap(data);
m.readonly = !L.hasViewPermission();
s = m.section(form.NamedSection, 'broadband', 'broadband', _('Uplink configuration'),
_('The uplink settings allow overriding the WAN connection properties of the local device.'));
o = s.option(form.ListValue, 'protocol', _('Connection'));
o.value('default', _('Use default cloud settings'));
o.value('static', _('Static address configuration'));
o.value('dhcp', _('Address configuration via DHCP'));
o.value('pppoe', _('Address configuration via PPPoE'));
o.value('wwan', _('Cellular network connection'));
o = s.option(form.ListValue, 'modem-type', _('Modem type'));
o.depends('protocol', 'wwan');
o.value('wwan', _('Automatic', 'Automatic modem type selection'));
o.value('mbim', 'MBIM');
o.value('qmi', 'QMI');
o = s.option(form.Value, 'access-point-name', _('APN', 'Cellular access point name'));
o.depends('protocol', 'wwan');
o.validate = function(section_id, value) {
if (!/^[a-zA-Z0-9\-.]*[a-zA-Z0-9]$/.test(value))
return _('Invalid APN provided');
return true;
};
o = s.option(form.Value, 'pin-code', _('PIN'));
o.depends('protocol', 'wwan');
o.datatype = 'and(uinteger,minlength(4),maxlength(8))';
o = s.option(form.ListValue, 'authentication-type', _('Authentication'));
o.depends('protocol', 'wwan');
o.value('', _('No authentication'));
o.value('pap-chap', 'PAP/CHAP');
o.value('chap', 'CHAP');
o.value('pap', 'PAP');
o = s.option(form.Value, 'user-name', _('Username'));
o.depends('authentication-type', 'pap-chap');
o.depends('authentication-type', 'chap');
o.depends('authentication-type', 'pap');
o.depends('protocol', 'pppoe');
o = s.option(form.Value, 'password', _('Password'));
o.depends('authentication-type', 'pap-chap');
o.depends('authentication-type', 'chap');
o.depends('authentication-type', 'pap');
o.depends('protocol', 'pppoe');
o.password = true;
o = s.option(form.Value, 'ipv4-address', _('IPv4 Address'), _('Address and mask in CIDR notation.'));
o.depends('protocol', 'static');
o.datatype = 'or(cidr4,ipnet4)';
o.rmempty = false;
o = s.option(form.Value, 'ipv4-gateway', _('IPv4 Gateway'));
o.depends('protocol', 'static');
o.datatype = 'ip4addr("nomask")';
o.rmempty = false;
o = s.option(form.Value, 'ipv6-address', _('IPv6 Address'), _('Address and mask in CIDR notation.'));
o.depends('protocol', 'static');
o.datatype = 'or(cidr6,ipnet6)';
o = s.option(form.Value, 'ipv6-gateway', _('IPv6 Gateway'));
o.depends('protocol', 'static');
o.datatype = 'ip6addr("nomask")';
o = s.option(form.DynamicList, 'use-dns', _('DNS Servers'));
o.depends('protocol', 'static');
o.datatype = 'ipaddr("nomask")';
for (var i = 0; i < s.children.length; i++)
data.broadband[s.children[i].option] = profile.broadband[s.children[i].option];
return m.render();
},
handleSave: uctool.save.bind(uctool, serialize),
handleSaveApply: null,
handleReset: null
});

View File

@@ -0,0 +1,426 @@
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Project-Id-Version: \n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"X-Generator: Poedit 2.4.2\n"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:53
msgctxt "Cellular access point name"
msgid "APN"
msgstr "APN"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:86
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:96
msgid "Address and mask in CIDR notation."
msgstr "Adresse und Netzmaske in CIDR-Notation."
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:43
msgid "Address configuration via DHCP"
msgstr "Adresskonfiguration mittels DHCP"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:44
msgid "Address configuration via PPPoE"
msgstr "Adresskonfiguration mittels PPPoE"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/tools/ucentral.js:49
msgid "Apply Settings"
msgstr "Einstellungen anwenden"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/tools/ucentral.js:52
msgid "Apply settings and reboot device now"
msgstr "Anwenden und Gerät jetzt neu starten"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:60
msgid "Architecture"
msgstr "Architektur"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:66
msgid "Authentication"
msgstr "Authentifizierung"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:49
msgctxt "Automatic modem type selection"
msgid "Automatic"
msgstr "automatisch"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:85
msgid "Buffered"
msgstr "Gepuffert"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:89
msgid "Cached"
msgstr "Gecached"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:92
msgid "Cancel"
msgstr "Abbrechen"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:45
msgid "Cellular network connection"
msgstr "Mobilfunkverbindung"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/settings.js:51
msgid "Certificate validation failed: %s"
msgstr "Validierung der Zertifikate fehlgeschlagen: %s"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/settings.js:43
msgid "Certificates"
msgstr "Zertifikate"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/settings.js:54
msgid "Certificates updated."
msgstr "Zertifikate aktualisiert."
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:51
msgid "Checking image…"
msgstr "Prüfe Imagedatei…"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:40
msgid "Connection"
msgstr "Verbindung"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:84
msgid "Continue"
msgstr "Fortfahren"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/tools/ucentral.js:54
msgid "Continue configuration"
msgstr "Konfiguration fortsetzen"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:104
msgid "DNS Servers"
msgstr "DNS-Server"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:37
msgid "Do you really want to erase all settings?"
msgstr "Sollen wirklich alle Systemeinstellungen zurückgesetzt werden?"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/tools/ucentral.js:73
msgid "Error"
msgstr "Fehler"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:61
msgid "Firmware Version"
msgstr "Firmware-Version"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:163
msgid "Firmware upgrade"
msgstr "Firmware Update"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:95
msgid "Flash image?"
msgstr "Image flashen?"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:99
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:170
msgid "Flash image…"
msgstr "Image flashen…"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:104
msgid "Flashing…"
msgstr "Schreibt…"
#: modules/luci-mod-ucentral/root/usr/share/rpcd/acl.d/luci-mod-ucentral.json:3
msgid "Grant access to ucentral configuration"
msgstr "Zugriff auf uCentral-Konfigurationseinstellungen ermöglichen"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:58
msgid "Hostname"
msgstr "Hostname"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:86
msgid "IPv4 Address"
msgstr "IPv4-Adresse"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:91
msgid "IPv4 Gateway"
msgstr "IPv4-Gateway"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:96
msgid "IPv6 Address"
msgstr "IPv6-Adresse"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:100
msgid "IPv6 Gateway"
msgstr "IPv6-Gateway"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:57
msgid "Invalid APN provided"
msgstr "Ungültige APN angegeben"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:95
msgid "Invalid image"
msgstr "Ungültige Image-Datei"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:141
msgid "Issue a reboot and restart the operating system on this device."
msgstr "Einen Reboot auslösen und das Betriebssystem des Gerätes neu starten."
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:62
msgid "Kernel Version"
msgstr "Kernel-Version"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:65
msgid "Load Average"
msgstr "Systemlast"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:63
msgid "Local Time"
msgstr "Lokalzeit"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/settings.js:37
msgid "Local settings"
msgstr "Lokale Einstellungen"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:69
msgid "MD5"
msgstr "MD5"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:112
msgid "Memory"
msgstr "Arbeitsspeicher"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:59
msgid "Model"
msgstr "Modell"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:47
msgid "Modem type"
msgstr "Modemtyp"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:68
msgid "No authentication"
msgstr "keine Authentifizierung"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/tools/ucentral.js:76
msgid "OK"
msgstr "OK"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:62
msgid "PIN"
msgstr "OIN"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:79
msgid "Password"
msgstr "Passwort"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:158
msgid "Perform reset"
msgstr "System zurücksetzen"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:147
msgid "Reboot"
msgstr "Reboot"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:140
msgid "Reboot device"
msgstr "Gerät neu starten"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/tools/ucentral.js:35
msgid "Reboot required"
msgstr "Neustart erforderlich"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/settings.js:40
msgid "Redirector URL"
msgstr "Redirector-URL"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:152
msgid ""
"Reset the system to its initial state and discard any configuration changes."
msgstr ""
"Das System auf Grundeinstellungen zurücksetzen und sämtliche "
"Konfigurationsänderungen verwerfen."
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:151
msgid "Reset to defaults"
msgstr "Grundeinstellungen wiederherstellen"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:70
msgid "SHA256"
msgstr "SHA256"
#: modules/luci-mod-ucentral/root/usr/share/luci/menu.d/luci-mod-ucentral.json:40
msgid "Settings"
msgstr "Einstellungen"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:68
msgid "Size"
msgstr "Größe"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:42
msgid "Static address configuration"
msgstr "Statische Adresskonfiguration"
#: modules/luci-mod-ucentral/root/usr/share/luci/menu.d/luci-mod-ucentral.json:16
msgid "Status"
msgstr "Status"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:92
msgid "Swap free"
msgstr "Freier Auslagerungsspeicher"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:108
#: modules/luci-mod-ucentral/root/usr/share/luci/menu.d/luci-mod-ucentral.json:52
msgid "System"
msgstr "System"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:121
msgid ""
"The device is rebooting now. This page will try to reconnect automatically "
"once the device is fully booted."
msgstr ""
"Das Gerät startet jetzt neu. Diese Seite wird versuchen sich automatisch neu "
"zu verbinden sobald das Gerät wieder voll hochgefahren ist."
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/tools/ucentral.js:50
msgid ""
"The device must be rebooted in order to apply the changed settings. Once the "
"uCentral agent successfully connects to the controller, the remote "
"configuration profile will be applied and the initial provisioning web "
"interface is disabled."
msgstr ""
"Das Gerät muss neu gestartet werden um die geänderten Einstellungen "
"anzuwenden. Sobald sich der uCentral-Client nach dem Neustart erfolgreich "
"mit dem Controller verbindet, wird das entfernte Konfigurationsprofil für "
"dieses Gerät angewendet und das initiale Provisionierungs-Webinterface "
"deaktiviert."
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:74
msgid ""
"The firmware image is invalid and cannot be flashed. Check the diagnostics "
"below for further details."
msgstr ""
"Die Firmware-Datei ist ungültig und kann nicht geflasht werden. Die "
"nachfolgenden Diagnosemeldungen enthalten weitere Details."
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:66
msgid ""
"The firmware image was uploaded. Compare the checksum and file size listed "
"below with the original file to ensure data integrity. <br /> Click "
"'Continue' below to start the flash procedure."
msgstr ""
"Die Firmware-Datei wurde hochgeladen. Die Prüfsummen und Dateigröße mit der "
"Originaldatei vergleichen um die Integrität des Images sicherzustellen.<br /"
"> \"Fortfahren\" anklicken um die Upgrade-Prozedur zu starten."
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/tools/ucentral.js:22
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:117
msgid "The reboot command failed with code %d"
msgstr "Das Reboot-Kommando wurde mit Fehlercode %d abgebrochen"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/settings.js:38
msgid ""
"The settings on this page specify how the local uCentral client connects to "
"the controller server."
msgstr ""
"Die Einstellungen auf dieser Seite beeinflussen die Verbindung des uCentral "
"Clients zum Controller-Server."
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:40
msgid ""
"The system is erasing the configuration partition now and will reboot itself "
"when finished."
msgstr ""
"Das System löscht nun die Konfigurationspartition und startet das Gerät neu "
"sobald die Prozedur abgeschlossen ist."
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:106
msgid ""
"The system is flashing now.<br /> DO NOT POWER OFF THE DEVICE!<br /> Wait a "
"few minutes before you try to reconnect. It might be necessary to renew the "
"address of your computer to reach the device again, depending on your "
"settings."
msgstr ""
"Das System-Upgrade läuft jetzt.<br />DAS GERÄT NICHT AUSSCHALTEN!<br /"
">Einige Minuten warten, bevor ein Verbindungsversuch unternommen wird. Ja "
"nach Netzwerktopologie kann es nötig sein, die lokalen Adresseinstellungen "
"des Computers zu verändern bevor wieder eine Verbindung zum Gerät möglich "
"ist."
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/tools/ucentral.js:26
msgid ""
"The system is rebooting in order to attempt applying the remote "
"configuration profile now. If not successful, the device will revert back "
"into the initial provisioning state."
msgstr ""
"Das System startet jetzt neu um zu versuchen das entfernte "
"Konfigurationsprofil anzuwenden. Im Fehlerfall wird das Gerät in den "
"initialen Provisionierungs-Zustand zurückversetzt."
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:38
msgid ""
"The uplink settings allow overriding the WAN connection properties of the "
"local device."
msgstr ""
"Die Uplink-Einstellungen ermöglichen es die WAN-Verbindungseigenschaften des "
"lokalen Gerätes zu überschreiben."
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:83
msgid "Total Available"
msgstr "Gesamt verfügbar"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/tools/ucentral.js:95
msgid "Unable to save settings: %s"
msgstr "Einstellungen konnten nicht gespeichert werden: %s"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/settings.js:58
msgid "Unable to verify certificates: %s"
msgstr "Zertifikate konnten nicht verifiziert werden: %s"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/settings.js:41
msgid "Unit location"
msgstr "Gerätestandort"
#: modules/luci-mod-ucentral/root/usr/share/luci/menu.d/luci-mod-ucentral.json:28
msgid "Uplink"
msgstr "Uplink"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:37
msgid "Uplink configuration"
msgstr "Uplink-Einstellungen"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:164
msgid "Upload a compatible firmware image here to upgrade the running system."
msgstr ""
"Kompatible Firmware-Datei hier hochladen um das laufende System zu "
"aktualisieren."
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/settings.js:44
msgid "Upload certificate bundle…"
msgstr "Zertifikatsarchiv hochladen…"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:64
msgid "Uptime"
msgstr "Laufzeit"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:41
msgid "Use default cloud settings"
msgstr "Cloud-Einstellungen nutzen"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:84
msgid "Used"
msgstr "In Benutzung"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:73
msgid "Username"
msgstr "Benutzername"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/settings.js:47
msgid "Verifying certificates…"
msgstr "Überprüfe Zertifikate…"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:52
msgid "Verifying the uploaded image file."
msgstr "Überprüfe die hochgeladene Image-Datei."
#: modules/luci-mod-ucentral/root/usr/share/luci/menu.d/luci-mod-ucentral.json:3
msgid "uCentral"
msgstr "uCentral"

View File

@@ -0,0 +1,385 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:53
msgctxt "Cellular access point name"
msgid "APN"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:86
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:96
msgid "Address and mask in CIDR notation."
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:43
msgid "Address configuration via DHCP"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:44
msgid "Address configuration via PPPoE"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/tools/ucentral.js:49
msgid "Apply Settings"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/tools/ucentral.js:52
msgid "Apply settings and reboot device now"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:60
msgid "Architecture"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:66
msgid "Authentication"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:49
msgctxt "Automatic modem type selection"
msgid "Automatic"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:85
msgid "Buffered"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:89
msgid "Cached"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:92
msgid "Cancel"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:45
msgid "Cellular network connection"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/settings.js:51
msgid "Certificate validation failed: %s"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/settings.js:43
msgid "Certificates"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/settings.js:54
msgid "Certificates updated."
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:51
msgid "Checking image…"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:40
msgid "Connection"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:84
msgid "Continue"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/tools/ucentral.js:54
msgid "Continue configuration"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:104
msgid "DNS Servers"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:37
msgid "Do you really want to erase all settings?"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/tools/ucentral.js:73
msgid "Error"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:61
msgid "Firmware Version"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:163
msgid "Firmware upgrade"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:95
msgid "Flash image?"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:99
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:170
msgid "Flash image…"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:104
msgid "Flashing…"
msgstr ""
#: modules/luci-mod-ucentral/root/usr/share/rpcd/acl.d/luci-mod-ucentral.json:3
msgid "Grant access to ucentral configuration"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:58
msgid "Hostname"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:86
msgid "IPv4 Address"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:91
msgid "IPv4 Gateway"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:96
msgid "IPv6 Address"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:100
msgid "IPv6 Gateway"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:57
msgid "Invalid APN provided"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:95
msgid "Invalid image"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:141
msgid "Issue a reboot and restart the operating system on this device."
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:62
msgid "Kernel Version"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:65
msgid "Load Average"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:63
msgid "Local Time"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/settings.js:37
msgid "Local settings"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:69
msgid "MD5"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:112
msgid "Memory"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:59
msgid "Model"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:47
msgid "Modem type"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:68
msgid "No authentication"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/tools/ucentral.js:76
msgid "OK"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:62
msgid "PIN"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:79
msgid "Password"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:158
msgid "Perform reset"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:147
msgid "Reboot"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:140
msgid "Reboot device"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/tools/ucentral.js:35
msgid "Reboot required"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/settings.js:40
msgid "Redirector URL"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:152
msgid ""
"Reset the system to its initial state and discard any configuration changes."
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:151
msgid "Reset to defaults"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:70
msgid "SHA256"
msgstr ""
#: modules/luci-mod-ucentral/root/usr/share/luci/menu.d/luci-mod-ucentral.json:40
msgid "Settings"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:68
msgid "Size"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:42
msgid "Static address configuration"
msgstr ""
#: modules/luci-mod-ucentral/root/usr/share/luci/menu.d/luci-mod-ucentral.json:16
msgid "Status"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:92
msgid "Swap free"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:108
#: modules/luci-mod-ucentral/root/usr/share/luci/menu.d/luci-mod-ucentral.json:52
msgid "System"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:121
msgid ""
"The device is rebooting now. This page will try to reconnect automatically "
"once the device is fully booted."
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/tools/ucentral.js:50
msgid ""
"The device must be rebooted in order to apply the changed settings. Once the "
"uCentral agent successfully connects to the controller, the remote "
"configuration profile will be applied and the initial provisioning web "
"interface is disabled."
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:74
msgid ""
"The firmware image is invalid and cannot be flashed. Check the diagnostics "
"below for further details."
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:66
msgid ""
"The firmware image was uploaded. Compare the checksum and file size listed "
"below with the original file to ensure data integrity. <br /> Click "
"'Continue' below to start the flash procedure."
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/tools/ucentral.js:22
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:117
msgid "The reboot command failed with code %d"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/settings.js:38
msgid ""
"The settings on this page specify how the local uCentral client connects to "
"the controller server."
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:40
msgid ""
"The system is erasing the configuration partition now and will reboot itself "
"when finished."
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:106
msgid ""
"The system is flashing now.<br /> DO NOT POWER OFF THE DEVICE!<br /> Wait a "
"few minutes before you try to reconnect. It might be necessary to renew the "
"address of your computer to reach the device again, depending on your "
"settings."
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/tools/ucentral.js:26
msgid ""
"The system is rebooting in order to attempt applying the remote "
"configuration profile now. If not successful, the device will revert back "
"into the initial provisioning state."
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:38
msgid ""
"The uplink settings allow overriding the WAN connection properties of the "
"local device."
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:83
msgid "Total Available"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/tools/ucentral.js:95
msgid "Unable to save settings: %s"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/settings.js:58
msgid "Unable to verify certificates: %s"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/settings.js:41
msgid "Unit location"
msgstr ""
#: modules/luci-mod-ucentral/root/usr/share/luci/menu.d/luci-mod-ucentral.json:28
msgid "Uplink"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:37
msgid "Uplink configuration"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:164
msgid "Upload a compatible firmware image here to upgrade the running system."
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/settings.js:44
msgid "Upload certificate bundle…"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:64
msgid "Uptime"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:41
msgid "Use default cloud settings"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/status.js:84
msgid "Used"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/uplink.js:73
msgid "Username"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/settings.js:47
msgid "Verifying certificates…"
msgstr ""
#: modules/luci-mod-ucentral/htdocs/luci-static/resources/view/ucentral/system.js:52
msgid "Verifying the uploaded image file."
msgstr ""
#: modules/luci-mod-ucentral/root/usr/share/luci/menu.d/luci-mod-ucentral.json:3
msgid "uCentral"
msgstr ""

View File

@@ -0,0 +1,33 @@
#!/bin/sh
# make sure we have a tar file
[ -f /tmp/certs.tar ] || exit 1
# check if there is a certificates partition
. /lib/functions.sh
mtd="$(find_mtd_index certificates)"
[ -z "$mtd" ] && exit 1
# check if this is ubi or squashfs
ubi="$(ubinfo -a | grep certificates)"
# extract the certificates
mkdir /tmp/certs
cd /tmp/certs
tar xf /tmp/certs.tar
# copy the certificates to /etc
cp *.pem dev-id /etc/ucentral/
# persistently store the certificates
if [ -z "$ubi" ]; then
# squashfs
mtd write /tmp/certs/squashfs /dev/mtd$mtd
else
# ubi
[ -e /dev/ubi0 ] && mount -t ubifs ubi0:certificates /certificates
[ -e /dev/ubi1 ] && mount -t ubifs ubi1:certificates /certificates
cp *.pem dev-id /certificates/
fi
exit 0

View File

@@ -0,0 +1,15 @@
#!/bin/sh
REDIRECTOR=$(cat /etc/ucentral/profile.json | jsonfilter -e '@.redirector')
if [ -n "$REDIRECTOR" ]; then
uci -c /etc/config-shadow/ set ucentral.config.server="$REDIRECTOR"
uci -c /etc/config-shadow/ commit ucentral
/etc/init.d/firstcontact disable
/etc/init.d/ucentral enable
else
rm /etc/ucentral/redirector.json
/etc/init.d/firstcontact enable
/etc/init.d/ucentral disable
fi
exit 0

View File

@@ -0,0 +1,62 @@
{
"ucentral": {
"title": "uCentral",
"order": 20,
"action": {
"type": "firstchild",
"recurse": true
},
"auth": {
"methods": [ "cookie:sysauth" ],
"login": true
}
},
"ucentral/status": {
"title": "Status",
"order": 1,
"action": {
"type": "view",
"path": "ucentral/status"
},
"depends": {
"acl": [ "luci-mod-ucentral" ]
}
},
"ucentral/uplink": {
"title": "Uplink",
"order": 2,
"action": {
"type": "view",
"path": "ucentral/uplink"
},
"depends": {
"acl": [ "luci-mod-ucentral" ]
}
},
"ucentral/settings": {
"title": "Settings",
"order": 3,
"action": {
"type": "view",
"path": "ucentral/settings"
},
"depends": {
"acl": [ "luci-mod-ucentral" ]
}
},
"ucentral/system": {
"title": "System",
"order": 4,
"action": {
"type": "view",
"path": "ucentral/system"
},
"depends": {
"acl": [ "luci-mod-ucentral" ]
}
}
}

View File

@@ -0,0 +1,33 @@
{
"luci-mod-ucentral": {
"description": "Grant access to ucentral configuration",
"read": {
"file": {
"/etc/ucentral/profile.json": [ "read" ],
"/proc/mounts": [ "read" ],
"/proc/mtd": [ "read" ]
},
"ubus": {
"file": [ "read" ],
"system": [ "board", "info" ]
}
},
"write": {
"cgi-io": [ "upload" ],
"file": {
"/etc/ucentral/profile.json": [ "write" ],
"/sbin/certupdate": [ "exec" ],
"/sbin/firstboot -r -y": [ "exec" ],
"/sbin/profileupdate": [ "exec" ],
"/sbin/sysupgrade -n /tmp/firmware.bin": [ "exec" ],
"/sbin/sysupgrade --test /tmp/firmware.bin": [ "exec" ],
"/tmp/certs.tar": [ "write" ],
"/tmp/firmware.bin": [ "write" ]
},
"ubus": {
"file": [ "exec", "remove", "write" ],
"system": [ "reboot", "validate_firmware_image" ]
}
}
}
}

View File

@@ -0,0 +1,14 @@
#
# Copyright (C) 2021 Jo-Philipp Wich <jo@mein.io>
#
# This is free software, licensed under the Apache License, Version 2.0 .
#
include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI theme for uCentral
LUCI_DEPENDS:=
include ../luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@@ -0,0 +1,152 @@
'use strict';
'require baseclass';
'require ui';
return baseclass.extend({
__init__: function() {
ui.menu.load().then(L.bind(this.render, this));
},
render: function(tree) {
var menu = document.querySelector('#mainmenu'),
nav = document.querySelector('#menubar > .navigation'),
node = tree,
url = '';
this.renderModeMenu(node);
if (L.env.dispatchpath.length >= 3) {
for (var i = 0; i < 3 && node; i++) {
node = node.children[L.env.dispatchpath[i]];
url = url + (url ? '/' : '') + L.env.dispatchpath[i];
}
if (node)
this.renderTabMenu(node, url);
}
if (menu.firstElementChild) {
nav.addEventListener('click', ui.createHandlerFn(this, 'handleSidebarToggle'));
nav.style.visibility = 'visible';
}
},
handleMenuExpand: function(ev) {
var a = ev.target, ul1 = a.parentNode.parentNode, ul2 = a.nextElementSibling;
document.querySelectorAll('ul.mainmenu.l1 > li.active').forEach(function(li) {
if (li !== a.parentNode)
li.classList.remove('active');
});
if (!ul2)
return;
if (ul2.parentNode.offsetLeft + ul2.offsetWidth <= ul1.offsetLeft + ul1.offsetWidth)
ul2.classList.add('align-left');
ul1.classList.add('active');
a.parentNode.classList.add('active');
a.blur();
ev.preventDefault();
ev.stopPropagation();
},
renderMainMenu: function(tree, url, level) {
var l = (level || 0) + 1,
ul = E('ul', { 'class': 'mainmenu l%d'.format(l) }),
children = ui.menu.getChildren(tree);
if (children.length == 0 || l > 2)
return E([]);
for (var i = 0; i < children.length; i++) {
var isActive = (L.env.dispatchpath[l] == children[i].name),
isReadonly = children[i].readonly,
activeClass = 'mainmenu-item-%s%s'.format(children[i].name, isActive ? ' selected' : '');
ul.appendChild(E('li', { 'class': activeClass }, [
E('a', {
'href': L.url(url, children[i].name),
'click': (l == 1) ? ui.createHandlerFn(this, 'handleMenuExpand') : null
}, [ _(children[i].title) ]),
this.renderMainMenu(children[i], url + '/' + children[i].name, l)
]));
}
if (l == 1)
document.querySelector('#mainmenu').appendChild(E('div', [ ul ]));
return ul;
},
renderModeMenu: function(tree, root) {
var menu = document.querySelector('#modemenu'),
children = ui.menu.getChildren(tree);
for (var i = 0; i < children.length; i++) {
var isActive = (L.env.requestpath.length ? children[i].name == L.env.requestpath[+!!root] : i == 0),
isUcentral = (!root && children[i].name == 'ucentral');
if (root || children.length > 1)
menu.appendChild(E('div', { 'class': isActive ? 'active' : null }, [
E('a', { 'href': root ? L.url(root, children[i].name) : L.url(children[i].name) }, [ _(children[i].title) ])
]));
if (isUcentral && isActive)
this.renderModeMenu(children[i], children[i].name);
else if (isActive)
this.renderMainMenu(children[i], children[i].name);
}
if (menu.children.length > 1)
menu.style.display = '';
},
renderTabMenu: function(tree, url, level) {
var container = document.querySelector('#tabmenu'),
l = (level || 0) + 1,
ul = E('ul', { 'class': 'cbi-tabmenu' }),
children = ui.menu.getChildren(tree),
activeNode = null;
if (children.length == 0)
return E([]);
for (var i = 0; i < children.length; i++) {
var isActive = (L.env.dispatchpath[l + 2] == children[i].name),
activeClass = isActive ? ' cbi-tab' : '',
className = 'tabmenu-item-%s %s'.format(children[i].name, activeClass);
ul.appendChild(E('li', { 'class': className }, [
E('a', { 'href': L.url(url, children[i].name) }, [ _(children[i].title) ] )
]));
if (isActive)
activeNode = children[i];
}
container.appendChild(ul);
container.style.display = '';
if (activeNode)
container.appendChild(this.renderTabMenu(activeNode, url + '/' + activeNode.name, l));
return ul;
},
handleSidebarToggle: function(ev) {
var btn = ev.currentTarget,
bar = document.querySelector('#mainmenu');
if (btn.classList.contains('active')) {
btn.classList.remove('active');
bar.classList.remove('active');
}
else {
btn.classList.add('active');
bar.classList.add('active');
}
}
});

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,140 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 251.2 114.2" style="enable-background:new 0 0 251.2 114.2;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FED206;}
.st1{fill:#EB6F53;}
.st2{fill:#3BA9B6;}
.st3{fill:#414141;}
</style>
<g>
<path class="st0" d="M219.6,43.3C219.5,43.3,219.5,43.3,219.6,43.3c-1.3,0-2.2-1-2.2-2.2c0-0.2,0-0.4,0-0.6
c0-11.9-9.7-21.6-21.6-21.6c-0.2,0-0.4,0-0.6,0c-1.2,0-2.2-0.9-2.2-2.1c0-1.2,0.9-2.2,2.1-2.2c0.2,0,0.5,0,0.7,0
c14.3,0,25.9,11.6,25.9,25.9c0,0.2,0,0.5,0,0.7C221.7,42.4,220.7,43.3,219.6,43.3z"/>
<path class="st1" d="M212.1,43.3C212,43.3,212,43.3,212.1,43.3c-1.3-0.1-2.2-1.1-2.2-2.3c0-0.2,0-0.4,0-0.6
c0-7.7-6.3-14.1-14.1-14.1c-0.2,0-0.4,0-0.6,0c-1.2,0.1-2.2-0.9-2.3-2.1c0-1.2,0.9-2.2,2.1-2.3c0.3,0,0.5,0,0.8,0
c10.2,0,18.4,8.3,18.4,18.4c0,0.2,0,0.5,0,0.8C214.2,42.4,213.2,43.3,212.1,43.3z"/>
<path class="st2" d="M204.3,43.3c-0.1,0-0.1,0-0.2,0c-1.2-0.1-2.1-1.1-2-2.3c0-0.2,0-0.4,0-0.5c0-3.5-2.8-6.3-6.3-6.3
c-0.1,0-0.3,0-0.5,0c-1.2,0.1-2.3-0.8-2.3-2c-0.1-1.2,0.8-2.3,2-2.3c0.3,0,0.6,0,0.9,0c5.9,0,10.7,4.8,10.7,10.7c0,0.3,0,0.5,0,0.9
C206.4,42.4,205.4,43.3,204.3,43.3z"/>
<g>
<g>
<g>
<path class="st3" d="M61.9,89.9v-4.7h-1.7v-0.9h4.4v0.9h-1.7v4.7H61.9z"/>
</g>
<g>
<path class="st3" d="M65.6,89.9v-5.6h3.8v0.9h-2.9v1.4h2.8v0.9h-2.8V89h2.9v0.9H65.6z"/>
</g>
<g>
<path class="st3" d="M70.7,89.9v-5.6h1V89h2.5v0.9H70.7z"/>
</g>
<g>
<path class="st3" d="M74.9,89.9v-5.6h3.8v0.9h-2.9v1.4h2.8v0.9h-2.8V89h2.9v0.9H74.9z"/>
</g>
<g>
<path class="st3" d="M79.8,87.1c0-1.7,1.3-2.9,2.9-2.9c1.1,0,1.8,0.6,2.2,1.3l-0.8,0.4c-0.3-0.5-0.8-0.8-1.4-0.8
c-1.1,0-1.9,0.8-1.9,2c0,1.2,0.8,2,1.9,2c0.6,0,1.1-0.4,1.4-0.8l0.8,0.4c-0.4,0.7-1.1,1.3-2.2,1.3C81.1,90,79.8,88.8,79.8,87.1z
"/>
</g>
<g>
<path class="st3" d="M85.5,87.1c0-1.7,1.2-2.9,2.9-2.9c1.7,0,2.9,1.2,2.9,2.9S90,90,88.3,90C86.7,90,85.5,88.8,85.5,87.1z
M90.2,87.1c0-1.2-0.7-2-1.9-2c-1.1,0-1.9,0.9-1.9,2c0,1.1,0.7,2,1.9,2C89.5,89.1,90.2,88.3,90.2,87.1z"/>
</g>
<g>
<path class="st3" d="M96.9,89.9v-4.3l-1.7,4.3h-0.4l-1.7-4.3v4.3h-1v-5.6h1.4l1.5,3.8l1.5-3.8h1.4v5.6H96.9z"/>
</g>
<g>
<path class="st3" d="M103,89.9v-5.6h1v5.6H103z"/>
</g>
<g>
<path class="st3" d="M109.7,89.9l-2.9-4v4h-1v-5.6h1l2.9,3.9v-3.9h1v5.6H109.7z"/>
</g>
<g>
<path class="st3" d="M112.4,89.9v-5.6h3.8v0.9h-2.9v1.4h2.8v0.9h-2.8v2.4H112.4z"/>
</g>
<g>
<path class="st3" d="M120.3,89.9l-1.2-2.1h-1v2.1h-1v-5.6h2.5c1.1,0,1.8,0.7,1.8,1.8c0,1-0.7,1.5-1.3,1.6l1.4,2.2H120.3z
M120.4,86.1c0-0.5-0.4-0.9-1-0.9h-1.4V87h1.4C120,87,120.4,86.6,120.4,86.1z"/>
</g>
<g>
<path class="st3" d="M126.6,89.9l-0.4-1.1h-2.6l-0.4,1.1h-1.1l2.2-5.6h1.2l2.2,5.6H126.6z M124.9,85.3l-1,2.7h2L124.9,85.3z"/>
</g>
<g>
<path class="st3" d="M131.4,89.9v-5.6h2.1c1.1,0,1.7,0.8,1.7,1.6c0,0.9-0.6,1.6-1.7,1.6h-1.6v2.3H131.4z M134.7,86
c0-0.7-0.5-1.2-1.2-1.2h-1.6v2.4h1.6C134.2,87.2,134.7,86.6,134.7,86z"/>
</g>
<g>
<path class="st3" d="M139.4,89.9l-1.6-2.3h-1.2v2.3h-0.5v-5.6h2.1c1,0,1.7,0.6,1.7,1.6c0,1-0.7,1.6-1.6,1.6l1.6,2.3H139.4z
M139.4,86c0-0.7-0.5-1.2-1.2-1.2h-1.6v2.4h1.6C138.9,87.2,139.4,86.7,139.4,86z"/>
</g>
<g>
<path class="st3" d="M141.2,87.1c0-1.6,1.1-2.9,2.7-2.9c1.6,0,2.7,1.3,2.7,2.9c0,1.6-1.1,2.9-2.7,2.9
C142.3,90,141.2,88.8,141.2,87.1z M146.1,87.1c0-1.4-0.9-2.5-2.2-2.5c-1.4,0-2.2,1-2.2,2.5c0,1.4,0.9,2.5,2.2,2.5
C145.2,89.6,146.1,88.5,146.1,87.1z"/>
</g>
<g>
<path class="st3" d="M147,89.3l0.3-0.4c0.3,0.3,0.6,0.6,1.1,0.6c0.8,0,1.2-0.5,1.2-1.3v-4h0.5v4c0,1.2-0.8,1.7-1.7,1.7
C147.9,90,147.4,89.8,147,89.3z"/>
</g>
<g>
<path class="st3" d="M151.8,89.9v-5.6h3.5v0.4h-3.1v2.1h3v0.4h-3v2.2h3.1v0.4H151.8z"/>
</g>
<g>
<path class="st3" d="M156.3,87.1c0-1.7,1.3-2.9,2.8-2.9c0.9,0,1.6,0.4,2,1l-0.4,0.3c-0.4-0.5-1-0.8-1.6-0.8
c-1.3,0-2.3,1-2.3,2.5c0,1.4,1,2.5,2.3,2.5c0.7,0,1.3-0.3,1.6-0.8l0.4,0.3c-0.5,0.6-1.2,1-2,1C157.5,90,156.3,88.8,156.3,87.1z"
/>
</g>
<g>
<path class="st3" d="M163.5,89.9v-5.2h-1.8v-0.4h4.1v0.4H164v5.2H163.5z"/>
</g>
</g>
<g>
<polygon class="st3" points="33.7,86.5 41.2,79 48.6,86.5 49.8,86.5 41.2,77.9 32.6,86.5 "/>
<polygon class="st3" points="48.6,87.8 41.2,95.2 33.7,87.8 32.6,87.8 41.2,96.4 49.8,87.8 "/>
<polygon class="st3" points="40.3,86.5 47.8,79 55.3,86.5 56.4,86.5 47.8,77.9 39.2,86.5 "/>
<polygon class="st3" points="55.3,87.8 47.8,95.2 40.3,87.8 39.2,87.8 47.8,96.4 56.4,87.8 "/>
</g>
</g>
</g>
<g>
<path class="st3" d="M51.2,41.3c2,1.1,3.6,2.6,4.7,4.5c1.1,1.9,1.7,4,1.7,6.4c0,2.3-0.6,4.5-1.7,6.4c-1.1,1.9-2.7,3.4-4.7,4.6
c-2,1.1-4.2,1.7-6.6,1.7c-2.4,0-4.6-0.6-6.6-1.7c-2-1.1-3.6-2.6-4.7-4.6c-1.1-1.9-1.7-4.1-1.7-6.4c0-2.3,0.6-4.5,1.7-6.4
c1.1-1.9,2.7-3.4,4.7-4.5c2-1.1,4.2-1.6,6.6-1.6C47,39.6,49.2,40.2,51.2,41.3z M40.5,44.9c-1.3,0.7-2.3,1.7-3,3
c-0.7,1.3-1.1,2.7-1.1,4.2s0.4,3,1.1,4.2c0.8,1.3,1.8,2.3,3,3c1.3,0.7,2.7,1.1,4.1,1.1c1.5,0,2.8-0.4,4.1-1.1c1.3-0.7,2.3-1.8,3-3
c0.7-1.3,1.1-2.7,1.1-4.2s-0.4-2.9-1.1-4.2c-0.7-1.3-1.7-2.3-3-3c-1.3-0.7-2.6-1.1-4.1-1.1C43.2,43.8,41.8,44.2,40.5,44.9z"/>
<path class="st3" d="M76.9,46.8c1.3,0.8,2.4,1.9,3.1,3.4c0.7,1.4,1.1,3.1,1.1,5c0,1.9-0.4,3.5-1.1,4.9c-0.7,1.4-1.8,2.5-3.1,3.3
c-1.3,0.8-2.9,1.2-4.6,1.2c-1.4,0-2.6-0.3-3.7-0.8c-1.1-0.5-2-1.3-2.7-2.4v9.8h-4.6V45.7H66v3.1c0.7-1.1,1.5-1.8,2.6-2.4
c1.1-0.5,2.3-0.8,3.7-0.8C74,45.6,75.6,46,76.9,46.8z M75.1,59.1c1-1.1,1.5-2.4,1.5-4.1c0-1.7-0.5-3-1.5-4.1
c-1-1.1-2.2-1.6-3.8-1.6c-1.6,0-2.8,0.5-3.8,1.6c-1,1-1.5,2.4-1.5,4.1c0,1.7,0.5,3,1.5,4.1c1,1.1,2.3,1.6,3.8,1.6
C72.8,60.7,74.1,60.2,75.1,59.1z"/>
<path class="st3" d="M99.3,48.1c1.5,1.7,2.3,4.1,2.3,7.2c0,0.6,0,1.1,0,1.4H87.7c0.3,1.3,0.9,2.4,1.9,3.1c0.9,0.8,2.1,1.1,3.5,1.1
c1,0,1.9-0.2,2.7-0.5c0.9-0.4,1.6-0.9,2.3-1.6l2.5,2.6c-0.9,1-2.1,1.8-3.4,2.4c-1.3,0.6-2.8,0.8-4.5,0.8c-1.9,0-3.6-0.4-5.1-1.2
c-1.5-0.8-2.6-1.9-3.4-3.3c-0.8-1.4-1.2-3.1-1.2-5c0-1.9,0.4-3.5,1.2-5c0.8-1.4,1.9-2.6,3.4-3.4c1.4-0.8,3.1-1.2,4.9-1.2
C95.5,45.6,97.8,46.4,99.3,48.1z M97.4,53.6c0-1.4-0.5-2.5-1.4-3.3c-0.9-0.8-2-1.2-3.4-1.2c-1.3,0-2.4,0.4-3.3,1.2
c-0.9,0.8-1.5,1.9-1.7,3.3H97.4z"/>
<path class="st3" d="M121.5,47.5c1.2,1.3,1.9,3.1,1.9,5.3v11.7h-4.6V54.1c0-1.3-0.4-2.3-1.1-3.1c-0.7-0.8-1.8-1.1-3-1.1
c-1.5,0-2.7,0.5-3.6,1.5s-1.3,2.3-1.3,3.8v9.2h-4.5V45.7h4.5v3.5c1.3-2.4,3.5-3.6,6.7-3.7C118.5,45.5,120.2,46.2,121.5,47.5z"/>
<path class="st3" d="M156.5,39.9h4.9l-8.3,24.5h-4.9l-5.6-18.6l-5.7,18.6h-4.8l-8.3-24.5h5l5.8,19.4l5.7-19.4h4.6l5.8,19.5
L156.5,39.9z"/>
<path class="st3" d="M168,38.4c0.5,0.5,0.7,1.2,0.7,2c0,0.8-0.2,1.4-0.7,1.9c-0.5,0.5-1.1,0.8-1.9,0.8c-0.7,0-1.4-0.3-1.9-0.8
c-0.5-0.5-0.7-1.2-0.7-1.9c0-0.8,0.2-1.4,0.7-2c0.5-0.5,1.1-0.8,1.9-0.8C166.9,37.7,167.6,37.9,168,38.4z M164,45.7h4.5v18.7H164
V45.7z"/>
<path class="st3" d="M174,39.9h16.9l0,4.1h-12.2v6.6h11.1v4.1h-11.1v9.7H174V39.9z"/>
<path class="st3" d="M197.9,38.4c0.5,0.5,0.7,1.2,0.7,2c0,0.8-0.2,1.4-0.7,1.9c-0.5,0.5-1.1,0.8-1.9,0.8c-0.7,0-1.4-0.3-1.9-0.8
c-0.5-0.5-0.7-1.2-0.7-1.9c0-0.8,0.2-1.4,0.7-2c0.5-0.5,1.1-0.8,1.9-0.8C196.8,37.7,197.4,37.9,197.9,38.4z M193.8,45.7h4.5v18.7
h-4.5V45.7z"/>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="132 132 264 264">
<defs>
<radialGradient id="g" cx="0%" cy="0%" r="60%">
<stop offset=".8" style="stop-opacity:1" />
<stop offset="1" style="stop-opacity:.5" />
</radialGradient>
</defs>
<g>
<path style="fill:url(#g)" d="M 264 132 A 132 132 0 0 0 132 264 A 132 132 0 0 0 264 396 A 132 132 0 0 0 396 264 A 132 132 0 0 0 264 132 z M 264 170 A 94 94 0 0 1 359 264 A 94 94 0 0 1 264 359 A 94 94 0 0 1 170 264 A 94 94 0 0 1 264 170 z " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 582 B

View File

@@ -0,0 +1,13 @@
<%#
Copyright 2021 Jo-Philipp Wich <jo@mein.io>
Licensed to the public under the Apache License 2.0.
-%>
</div>
</div>
</div>
<script type="text/javascript">L.require('menu-ucentral')</script>
</body>
</html>

View File

@@ -0,0 +1,67 @@
<%#
Copyright 2021 Jo-Philipp Wich <jo@mein.io>
Licensed to the public under the Apache License 2.0.
-%>
<%
local sys = require "luci.sys"
local util = require "luci.util"
local http = require "luci.http"
local disp = require "luci.dispatcher"
local ver = require "luci.version"
local boardinfo = util.ubus("system", "board") or { }
local node = disp.context.dispatched
local path = table.concat(disp.context.path, "-")
http.prepare_content("text/html; charset=UTF-8")
-%>
<!DOCTYPE html>
<html lang="<%=luci.i18n.context.lang%>">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" type="text/css" media="screen" href="<%=media%>/cascade.css" />
<link rel="icon" href="<%=media%>/logo.svg" type="image/svg+xml" />
<script type="text/javascript" src="<%=url('admin/translations', luci.i18n.context.lang)%><%# ?v=PKG_VERSION %>"></script>
<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
<title><%=striptags( (boardinfo.hostname or "?") .. ( (node and node.title) and ' - ' .. translate(node.title) or '')) %> - LuCI</title>
<% if css then %><style title="text/css">
<%= css %>
</style>
<% end -%>
</head>
<body class="lang_<%=luci.i18n.context.lang%>" data-page="<%= pcdata(path) %>">
<p class="skiplink">
<span id="skiplink1"><a href="#navigation"><%:Skip to navigation%></a></span>
<span id="skiplink2"><a href="#content"><%:Skip to content%></a></span>
</p>
<div id="page">
<div id="menubar">
<h2 class="navigation" style="visibility:hidden"><a id="navigation" name="navigation"><%:Navigation%></a></h2>
<img src="<%=media%>/logo.svg" />
<span id="indicators"></span>
</div>
<div id="modemenu" style="display:none"></div>
<div id="maincontainer">
<div id="mainmenu"></div>
<div id="maincontent">
<%- if luci.sys.process.info("uid") == 0 and luci.sys.user.getuser("root") and not luci.sys.user.getpasswd("root") and path ~= "admin-system-admin-password" then -%>
<div class="alert-message warning">
<h4><%:No password set!%></h4>
<p><%:There is no password set on this router. Please configure a root password to protect the web interface.%></p>
<% if disp.lookup("admin/system/admin") then %>
<div class="right"><a class="btn" href="<%=url("admin/system/admin")%>"><%:Go to password configuration...%></a></div>
<% end %>
</div>
<%- end -%>
<div id="tabmenu" style="display:none"></div>

View File

@@ -0,0 +1,12 @@
#!/bin/sh
if [ "$PKG_UPGRADE" != 1 ]; then
uci get luci.themes.uCentral >/dev/null 2>&1 || \
uci batch <<-EOF
set luci.themes.uCentral=/luci-static/ucentral
set luci.main.mediaurlbase=/luci-static/ucentral
commit luci
EOF
fi
exit 0

294
feeds/tip/luci/luci.mk Normal file
View File

@@ -0,0 +1,294 @@
#
# Copyright (C) 2008-2015 The LuCI Team <luci@lists.subsignal.org>
#
# This is free software, licensed under the Apache License, Version 2.0 .
#
LUCI_NAME?=$(notdir ${CURDIR})
LUCI_TYPE?=$(word 2,$(subst -, ,$(LUCI_NAME)))
LUCI_BASENAME?=$(patsubst luci-$(LUCI_TYPE)-%,%,$(LUCI_NAME))
LUCI_LANGUAGES:=$(sort $(filter-out templates,$(notdir $(wildcard ${CURDIR}/po/*))))
LUCI_DEFAULTS:=$(notdir $(wildcard ${CURDIR}/root/etc/uci-defaults/*))
LUCI_PKGARCH?=$(if $(realpath src/Makefile),,all)
# Language code titles
LUCI_LANG.bg=български (Bulgarian)
LUCI_LANG.bn_BD=বাংলা (Bengali)
LUCI_LANG.ca=Català (Catalan)
LUCI_LANG.cs=Čeština (Czech)
LUCI_LANG.de=Deutsch (German)
LUCI_LANG.el=Ελληνικά (Greek)
LUCI_LANG.en=English
LUCI_LANG.es=Español (Spanish)
LUCI_LANG.fr=Français (French)
LUCI_LANG.he=עִבְרִית (Hebrew)
LUCI_LANG.hi=हिंदी (Hindi)
LUCI_LANG.hu=Magyar (Hungarian)
LUCI_LANG.it=Italiano (Italian)
LUCI_LANG.ja=日本語 (Japanese)
LUCI_LANG.ko=한국어 (Korean)
LUCI_LANG.mr=Marāṭhī (Marathi)
LUCI_LANG.ms=Bahasa Melayu (Malay)
LUCI_LANG.nb_NO=Norsk (Norwegian)
LUCI_LANG.pl=Polski (Polish)
LUCI_LANG.pt_BR=Português do Brasil (Brazilian Portuguese)
LUCI_LANG.pt=Português (Portuguese)
LUCI_LANG.ro=Română (Romanian)
LUCI_LANG.ru=Русский (Russian)
LUCI_LANG.sk=Slovenčina (Slovak)
LUCI_LANG.sv=Svenska (Swedish)
LUCI_LANG.tr=Türkçe (Turkish)
LUCI_LANG.uk=Українська (Ukrainian)
LUCI_LANG.vi=Tiếng Việt (Vietnamese)
LUCI_LANG.zh_Hans=简体中文 (Chinese Simplified)
LUCI_LANG.zh_Hant=繁體中文 (Chinese Traditional)
# Submenu titles
LUCI_MENU.col=1. Collections
LUCI_MENU.mod=2. Modules
LUCI_MENU.app=3. Applications
LUCI_MENU.theme=4. Themes
LUCI_MENU.proto=5. Protocols
LUCI_MENU.lib=6. Libraries
# Language aliases
LUCI_LC_ALIAS.bn_BD=bn
LUCI_LC_ALIAS.nb_NO=no
LUCI_LC_ALIAS.pt_BR=pt-br
LUCI_LC_ALIAS.zh_Hans=zh-cn
LUCI_LC_ALIAS.zh_Hant=zh-tw
PKG_NAME?=$(LUCI_NAME)
# 1: everything expect po subdir or only po subdir
define findrev
$(shell \
if git log -1 >/dev/null 2>/dev/null; then \
set -- $$(git log -1 --format="%ct %h" --abbrev=7 -- $(if $(1),. ':(exclude)po',po)); \
if [ -n "$$1" ]; then
secs="$$(($$1 % 86400))"; \
yday="$$(date --utc --date="@$$1" "+%y.%j")"; \
printf 'git-%s.%05d-%s' "$$yday" "$$secs" "$$2"; \
else \
echo "unknown"; \
fi; \
else \
ts=$$(find . -type f $(if $(1),-not) -path './po/*' -printf '%T@\n' 2>/dev/null | sort -rn | head -n1 | cut -d. -f1); \
if [ -n "$$ts" ]; then \
secs="$$(($$ts % 86400))"; \
date="$$(date --utc --date="@$$ts" "+%y%m%d")"; \
printf '%s.%05d' "$$date" "$$secs"; \
else \
echo "unknown"; \
fi; \
fi \
)
endef
PKG_PO_VERSION?=$(if $(DUMP),x,$(strip $(call findrev)))
PKG_SRC_VERSION?=$(if $(DUMP),x,$(strip $(call findrev,1)))
PKG_GITBRANCH?=$(if $(DUMP),x,$(strip $(shell \
variant="LuCI"; \
if git log -1 >/dev/null 2>/dev/null; then \
branch="$$(git branch --remote --verbose --no-abbrev --contains 2>/dev/null | \
sed -rne 's|^[^/]+/([^ ]+) [a-f0-9]{40} .+$$|\1|p' | head -n1)"; \
if [ "$$branch" != "master" ]; then \
variant="LuCI $$branch branch"; \
else \
variant="LuCI Master"; \
fi; \
fi; \
echo "$$variant" \
)))
PKG_RELEASE?=1
PKG_INSTALL:=$(if $(realpath src/Makefile),1)
PKG_BUILD_DEPENDS += lua/host luci-base/host LUCI_CSSTIDY:csstidy/host LUCI_SRCDIET:luasrcdiet/host $(LUCI_BUILD_DEPENDS)
PKG_CONFIG_DEPENDS += CONFIG_LUCI_SRCDIET CONFIG_LUCI_JSMIN CONFIG_LUCI_CSSTIDY
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)/package.mk
define Package/$(PKG_NAME)
SECTION:=luci
CATEGORY:=LuCI
SUBMENU:=$(if $(LUCI_MENU.$(LUCI_TYPE)),$(LUCI_MENU.$(LUCI_TYPE)),$(LUCI_MENU.app))
TITLE:=$(if $(LUCI_TITLE),$(LUCI_TITLE),LuCI $(LUCI_NAME) $(LUCI_TYPE))
DEPENDS:=$(LUCI_DEPENDS)
VERSION:=$(if $(PKG_VERSION),$(PKG_VERSION),$(PKG_SRC_VERSION))
$(if $(LUCI_EXTRA_DEPENDS),EXTRA_DEPENDS:=$(LUCI_EXTRA_DEPENDS))
$(if $(LUCI_PKGARCH),PKGARCH:=$(LUCI_PKGARCH))
endef
ifneq ($(LUCI_DESCRIPTION),)
define Package/$(PKG_NAME)/description
$(strip $(LUCI_DESCRIPTION))
endef
endif
# Language selection for luci-base
ifeq ($(PKG_NAME),luci-base)
define Package/luci-base/config
config LUCI_SRCDIET
bool "Minify Lua sources"
default n
config LUCI_JSMIN
bool "Minify JavaScript sources"
default y
config LUCI_CSSTIDY
bool "Minify CSS files"
default y
menu "Translations"$(foreach lang,$(LUCI_LANGUAGES),
config LUCI_LANG_$(lang)
tristate "$(shell echo '$(LUCI_LANG.$(lang))' | sed -e 's/^.* (\(.*\))$$/\1/') ($(lang))")
endmenu
endef
endif
define Build/Prepare
for d in luasrc htdocs root src; do \
if [ -d ./$$$$d ]; then \
mkdir -p $(PKG_BUILD_DIR)/$$$$d; \
$(CP) ./$$$$d/* $(PKG_BUILD_DIR)/$$$$d/; \
fi; \
done
$(call Build/Prepare/Default)
endef
define Build/Configure
endef
ifneq ($(wildcard ${CURDIR}/src/Makefile),)
MAKE_PATH := src/
MAKE_VARS += FPIC="$(FPIC)" LUCI_VERSION="$(PKG_SRC_VERSION)" LUCI_GITBRANCH="$(PKG_GITBRANCH)"
define Build/Compile
$(call Build/Compile/Default,clean compile)
endef
else
define Build/Compile
endef
endif
HTDOCS = /www
LUA_LIBRARYDIR = /usr/lib/lua
LUCI_LIBRARYDIR = $(LUA_LIBRARYDIR)/luci
define SrcDiet
$(FIND) $(1) -type f -name '*.lua' | while read src; do \
if LUA_PATH="$(STAGING_DIR_HOSTPKG)/lib/lua/5.1/?.lua" luasrcdiet --noopt-binequiv -o "$$$$src.o" "$$$$src"; \
then mv "$$$$src.o" "$$$$src"; fi; \
done
endef
define JsMin
$(FIND) $(1) -type f -name '*.js' | while read src; do \
if jsmin < "$$$$src" > "$$$$src.o"; \
then mv "$$$$src.o" "$$$$src"; fi; \
done
endef
define CssTidy
$(FIND) $(1) -type f -name '*.css' | while read src; do \
if csstidy "$$$$src" --template=highest --remove_last_semicolon=true "$$$$src.o"; \
then mv "$$$$src.o" "$$$$src"; fi; \
done
endef
define SubstituteVersion
$(FIND) $(1) -type f -name '*.htm' | while read src; do \
$(SED) 's/<%# *\([^ ]*\)PKG_VERSION *%>/\1$(if $(PKG_VERSION),$(PKG_VERSION),$(PKG_SRC_VERSION))/g' \
-e 's/"\(<%= *\(media\|resource\) *%>[^"]*\.\(js\|css\)\)"/"\1?v=$(if $(PKG_VERSION),$(PKG_VERSION),$(PKG_SRC_VERSION))"/g' \
"$$$$src"; \
done
endef
define Package/$(PKG_NAME)/install
if [ -d $(PKG_BUILD_DIR)/luasrc ]; then \
$(INSTALL_DIR) $(1)$(LUCI_LIBRARYDIR); \
cp -pR $(PKG_BUILD_DIR)/luasrc/* $(1)$(LUCI_LIBRARYDIR)/; \
$(FIND) $(1)$(LUCI_LIBRARYDIR)/ -type f -name '*.luadoc' | $(XARGS) rm; \
$(if $(CONFIG_LUCI_SRCDIET),$(call SrcDiet,$(1)$(LUCI_LIBRARYDIR)/),true); \
$(call SubstituteVersion,$(1)$(LUCI_LIBRARYDIR)/); \
else true; fi
if [ -d $(PKG_BUILD_DIR)/htdocs ]; then \
$(INSTALL_DIR) $(1)$(HTDOCS); \
cp -pR $(PKG_BUILD_DIR)/htdocs/* $(1)$(HTDOCS)/; \
$(if $(CONFIG_LUCI_JSMIN),$(call JsMin,$(1)$(HTDOCS)/),true); \
$(if $(CONFIG_LUCI_CSSTIDY),$(call CssTidy,$(1)$(HTDOCS)/),true); \
else true; fi
if [ -d $(PKG_BUILD_DIR)/root ]; then \
$(INSTALL_DIR) $(1)/; \
cp -pR $(PKG_BUILD_DIR)/root/* $(1)/; \
else true; fi
if [ -d $(PKG_BUILD_DIR)/src ]; then \
$(call Build/Install/Default) \
$(CP) $(PKG_INSTALL_DIR)/* $(1)/; \
else true; fi
endef
ifndef Package/$(PKG_NAME)/postinst
define Package/$(PKG_NAME)/postinst
[ -n "$${IPKG_INSTROOT}" ] || {$(foreach script,$(LUCI_DEFAULTS),
(. /etc/uci-defaults/$(script)) && rm -f /etc/uci-defaults/$(script))
rm -f /tmp/luci-indexcache
rm -rf /tmp/luci-modulecache/
killall -HUP rpcd 2>/dev/null
exit 0
}
endef
endif
LUCI_BUILD_PACKAGES := $(PKG_NAME)
# 1: LuCI language code
# 2: BCP 47 language tag
define LuciTranslation
define Package/luci-i18n-$(LUCI_BASENAME)-$(1)
SECTION:=luci
CATEGORY:=LuCI
TITLE:=$(PKG_NAME) - $(1) translation
HIDDEN:=1
DEFAULT:=LUCI_LANG_$(2)||(ALL&&m)
DEPENDS:=$(PKG_NAME)
VERSION:=$(PKG_PO_VERSION)
PKGARCH:=all
endef
define Package/luci-i18n-$(LUCI_BASENAME)-$(1)/description
Translation for $(PKG_NAME) - $(LUCI_LANG.$(2))
endef
define Package/luci-i18n-$(LUCI_BASENAME)-$(1)/install
$$(INSTALL_DIR) $$(1)/etc/uci-defaults
echo "uci set luci.languages.$(subst -,_,$(1))='$(LUCI_LANG.$(2))'; uci commit luci" \
> $$(1)/etc/uci-defaults/luci-i18n-$(LUCI_BASENAME)-$(1)
$$(INSTALL_DIR) $$(1)$(LUCI_LIBRARYDIR)/i18n
$(foreach po,$(wildcard ${CURDIR}/po/$(2)/*.po), \
po2lmo $(po) \
$$(1)$(LUCI_LIBRARYDIR)/i18n/$(basename $(notdir $(po))).$(1).lmo;)
endef
define Package/luci-i18n-$(LUCI_BASENAME)-$(1)/postinst
[ -n "$$$${IPKG_INSTROOT}" ] || {
(. /etc/uci-defaults/luci-i18n-$(LUCI_BASENAME)-$(1)) && rm -f /etc/uci-defaults/luci-i18n-$(LUCI_BASENAME)-$(1)
exit 0
}
endef
LUCI_BUILD_PACKAGES += luci-i18n-$(LUCI_BASENAME)-$(1)
endef
$(foreach lang,$(LUCI_LANGUAGES),$(eval $(call LuciTranslation,$(firstword $(LUCI_LC_ALIAS.$(lang)) $(lang)),$(lang))))
$(foreach pkg,$(LUCI_BUILD_PACKAGES),$(eval $(call BuildPackage,$(pkg))))

View File

@@ -34,10 +34,17 @@ config_foreach ssid_set wifi-iface
config_load firewall
config_foreach delete_forwarding forwarding
[ -z "$(uci get network.lan)" ] && {
# single port devices wont bring up a lan interface by default
uci set network.lan=interface
uci set network.lan.type=bridge
uci set network.lan.proto=static
uci set network.lan.ipaddr=192.168.1.1
uci set network.lan.netmask=255.255.255.0
}
uci commit
/etc/init.d/uhttpd enable
/etc/init.d/uhttpd start
/etc/init.d/ucentral stop
reload_config

View File

@@ -0,0 +1,36 @@
#
# Copyright (C) 2021 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=atfpolicy
PKG_VERSION:=1
PKG_LICENSE:=GPL-2.0
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
define Package/atfpolicy
SECTION:=net
CATEGORY:=Network
TITLE:=A simple daemon for handling airtime fairness prioritization
DEPENDS:=+libubox +libubus +libnl-tiny
endef
TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include/libnl-tiny
define Package/atfpolicy/install
$(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/init.d $(1)/etc/config
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/atfpolicy $(1)/usr/sbin/
$(INSTALL_BIN) ./files/atfpolicy.init $(1)/etc/init.d/atfpolicy
$(INSTALL_DATA) ./files/atfpolicy.conf $(1)/etc/config/atfpolicy
endef
$(eval $(call BuildPackage,atfpolicy))

View File

@@ -0,0 +1,8 @@
config defaults
option vo_queue_weight 4
option update_pkt_threshold 100
option bulk_percent_thresh 50
option prio_percent_thresh 30
option weight_normal 256
option weight_prio 512
option weight_bulk 128

View File

@@ -0,0 +1,57 @@
#!/bin/sh /etc/rc.common
# Copyright (c) 2021 OpenWrt.org
START=50
USE_PROCD=1
PROG=/usr/sbin/atfpolicy
add_option() {
local type="$1"
local name="$2"
config_get val "$cfg" "$name"
[ -n "$val" ] && json_add_$type "$name" "$val"
}
add_defaults() {
cfg="$1"
json_add_boolean reset 1
add_option int vo_queue_weight
add_option int update_pkt_threshold
add_option int bulk_percent_thresh
add_option int prio_percent_thresh
add_option int weight_normal
add_option int weight_prio
add_option int weight_bulk
}
reload_service() {
json_init
config_load atfpolicy
config_foreach add_defaults defaults
ubus call atfpolicy config "$(json_dump)"
}
service_triggers() {
procd_add_reload_trigger atfpolicy
}
start_service() {
procd_open_instance
procd_set_param command "$PROG"
procd_set_param respawn
procd_close_instance
}
service_started() {
ubus -t 10 wait_for atfpolicy
[ $? = 0 ] && reload_service
}

View File

@@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.10)
PROJECT(atfpolicy C)
ADD_DEFINITIONS(-Os -Wall -Wno-unknown-warning-option -Wno-array-bounds -Wno-format-truncation -Werror --std=gnu99)
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
find_library(nl NAMES nl-tiny)
ADD_EXECUTABLE(atfpolicy main.c ubus.c interface.c nl80211.c)
TARGET_LINK_LIBRARIES(atfpolicy ${nl} ubox ubus)
INSTALL(TARGETS atfpolicy
RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}
)

View File

@@ -0,0 +1,90 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
*/
#ifndef __ATF_H
#define __ATF_H
#include <net/if.h>
#include <stdint.h>
#include <libubox/avl.h>
#define ATF_AVG_SCALE 12
#define ATF_AVG_WEIGHT_FACTOR 3
#define ATF_AVG_WEIGHT_DIV 4
#define MAC_ADDR_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
#define MAC_ADDR_DATA(_a) \
((const uint8_t *)(_a))[0], \
((const uint8_t *)(_a))[1], \
((const uint8_t *)(_a))[2], \
((const uint8_t *)(_a))[3], \
((const uint8_t *)(_a))[4], \
((const uint8_t *)(_a))[5]
#define D(format, ...) do { \
if (debug_flag) \
fprintf(stderr, "DEBUG: %s(%d) " format "\n", __func__, __LINE__, ## __VA_ARGS__); \
} while (0)
struct atf_config {
int voice_queue_weight;
int min_pkt_thresh;
int bulk_percent_thresh;
int prio_percent_thresh;
int weight_normal;
int weight_prio;
int weight_bulk;
};
struct atf_interface {
struct avl_node avl;
char ifname[IFNAMSIZ + 1];
uint32_t ubus_obj;
struct avl_tree stations;
};
struct atf_stats {
uint64_t bulk, normal, prio;
};
struct atf_station {
struct avl_node avl;
uint8_t macaddr[6];
bool present;
uint8_t stats_idx;
struct atf_stats stats[2];
uint16_t avg_bulk;
uint16_t avg_prio;
int weight;
};
extern struct atf_config config;
extern int debug_flag;
void reset_config(void);
struct atf_interface *atf_interface_get(const char *ifname);
void atf_interface_sta_update(struct atf_interface *iface);
struct atf_station *atf_interface_sta_get(struct atf_interface *iface, uint8_t *macaddr);
void atf_interface_sta_changed(struct atf_interface *iface, struct atf_station *sta);
void atf_interface_sta_flush(struct atf_interface *iface);
void atf_interface_update_all(void);
int atf_ubus_init(void);
void atf_ubus_stop(void);
void atf_ubus_set_sta_weight(struct atf_interface *iface, struct atf_station *sta);
int atf_nl80211_init(void);
int atf_nl80211_interface_update(struct atf_interface *iface);
#endif

View File

@@ -0,0 +1,108 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
*/
#include <string.h>
#include <stdlib.h>
#include <libubox/avl-cmp.h>
#include "atf.h"
static AVL_TREE(interfaces, avl_strcmp, false, NULL);
#ifndef container_of_safe
#define container_of_safe(ptr, type, member) \
(ptr ? container_of(ptr, type, member) : NULL)
#endif
static int avl_macaddr_cmp(const void *k1, const void *k2, void *ptr)
{
return memcmp(k1, k2, 6);
}
void atf_interface_sta_update(struct atf_interface *iface)
{
struct atf_station *sta;
avl_for_each_element(&iface->stations, sta, avl)
sta->present = false;
}
struct atf_station *atf_interface_sta_get(struct atf_interface *iface, uint8_t *macaddr)
{
struct atf_station *sta;
sta = avl_find_element(&iface->stations, macaddr, sta, avl);
if (sta)
goto out;
sta = calloc(1, sizeof(*sta));
memcpy(sta->macaddr, macaddr, sizeof(sta->macaddr));
sta->avl.key = sta->macaddr;
sta->weight = -1;
avl_insert(&iface->stations, &sta->avl);
out:
sta->present = true;
return sta;
}
void atf_interface_sta_flush(struct atf_interface *iface)
{
struct atf_station *sta, *tmp;
avl_for_each_element_safe(&iface->stations, sta, avl, tmp) {
if (sta->present)
continue;
avl_delete(&iface->stations, &sta->avl);
free(sta);
}
}
void atf_interface_sta_changed(struct atf_interface *iface, struct atf_station *sta)
{
int weight;
if (sta->avg_prio > config.prio_percent_thresh)
weight = config.weight_prio;
else if (sta->avg_prio > config.bulk_percent_thresh)
weight = config.weight_bulk;
else
weight = config.weight_normal;
if (sta->weight == weight)
return;
sta->weight = weight;
atf_ubus_set_sta_weight(iface, sta);
}
struct atf_interface *atf_interface_get(const char *ifname)
{
struct atf_interface *iface;
iface = avl_find_element(&interfaces, ifname, iface, avl);
if (iface)
return iface;
if (strlen(ifname) + 1 > sizeof(iface->ifname))
return NULL;
iface = calloc(1, sizeof(*iface));
strcpy(iface->ifname, ifname);
iface->avl.key = iface->ifname;
avl_init(&iface->stations, avl_macaddr_cmp, false, NULL);
avl_insert(&interfaces, &iface->avl);
return iface;
}
void atf_interface_update_all(void)
{
struct atf_interface *iface, *tmp;
avl_for_each_element_safe(&interfaces, iface, avl, tmp)
atf_nl80211_interface_update(iface);
}

View File

@@ -0,0 +1,62 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
*/
#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <libubox/uloop.h>
#include "atf.h"
struct atf_config config;
int debug_flag;
void reset_config(void)
{
memset(&config, 0, sizeof(config));
config.voice_queue_weight = 4;
config.min_pkt_thresh = 100;
config.bulk_percent_thresh = (50 << ATF_AVG_SCALE) / 100;
config.prio_percent_thresh = (30 << ATF_AVG_SCALE) / 100;
config.weight_normal = 256;
config.weight_bulk = 128;
config.weight_prio = 512;
}
static void atf_update_cb(struct uloop_timeout *t)
{
atf_interface_update_all();
uloop_timeout_set(t, 1000);
}
int main(int argc, char **argv)
{
static struct uloop_timeout update_timer = {
.cb = atf_update_cb,
};
int ch;
while ((ch = getopt(argc, argv, "d")) != -1) {
switch (ch) {
case 'd':
debug_flag = 1;
break;
}
}
reset_config();
uloop_init();
atf_ubus_init();
atf_nl80211_init();
atf_update_cb(&update_timer);
uloop_run();
atf_ubus_stop();
uloop_done();
return 0;
}

View File

@@ -0,0 +1,174 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
*/
#define _GNU_SOURCE
#include <linux/nl80211.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <unl.h>
#include "atf.h"
static struct unl unl;
static void
atf_parse_tid_stats(struct atf_interface *iface, struct atf_stats *stats,
int tid, struct nlattr *attr)
{
struct nlattr *tb[NL80211_TID_STATS_MAX + 1];
uint64_t msdu;
if (nla_parse_nested(tb, NL80211_TID_STATS_MAX, attr, NULL))
return;
if (!tb[NL80211_TID_STATS_TX_MSDU])
return;
msdu = nla_get_u64(tb[NL80211_TID_STATS_TX_MSDU]);
switch (tid) {
case 0:
case 3:
/* BE */
stats->normal += msdu;
break;
case 1:
case 2:
/* BK */
stats->bulk += msdu;
break;
case 4:
case 5:
/* VI */
stats->prio += msdu;
break;
case 6:
case 7:
stats->prio += msdu * config.voice_queue_weight;
/* VO */
break;
default:
break;
}
}
static uint64_t atf_stats_total(struct atf_stats *stats)
{
return stats->normal + stats->prio + stats->bulk;
}
static void atf_stats_diff(struct atf_stats *dest, struct atf_stats *cur, struct atf_stats *prev)
{
dest->normal = cur->normal - prev->normal;
dest->prio = cur->prio - prev->prio;
dest->bulk = cur->bulk - prev->bulk;
}
static uint16_t atf_stats_avg(uint16_t avg, uint64_t cur, uint32_t total)
{
cur <<= ATF_AVG_SCALE;
cur /= total;
if (!avg)
return (uint16_t)cur;
avg *= ATF_AVG_WEIGHT_FACTOR;
avg += cur * (ATF_AVG_WEIGHT_DIV - ATF_AVG_WEIGHT_FACTOR);
avg /= ATF_AVG_WEIGHT_DIV;
if (!avg)
avg = 1;
return avg;
}
static void atf_sta_update_avg(struct atf_station *sta, struct atf_stats *cur)
{
uint64_t total = atf_stats_total(cur);
D("sta "MAC_ADDR_FMT" total pkts: total=%d bulk=%d normal=%d prio=%d",
MAC_ADDR_DATA(sta->macaddr), (uint32_t)total,
(uint32_t)cur->bulk, (uint32_t)cur->normal, (uint32_t)cur->prio);
if (total < config.min_pkt_thresh)
return;
sta->avg_bulk = atf_stats_avg(sta->avg_bulk, cur->bulk, total);
sta->avg_prio = atf_stats_avg(sta->avg_prio, cur->prio, total);
D("avg bulk=%d prio=%d",
(sta->avg_bulk * 100) >> ATF_AVG_SCALE,
(sta->avg_prio * 100) >> ATF_AVG_SCALE);
sta->stats_idx = !sta->stats_idx;
}
static int
atf_sta_cb(struct nl_msg *msg, void *arg)
{
struct atf_interface *iface = arg;
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
struct nlattr *tb[NL80211_ATTR_MAX + 1];
struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
struct atf_station *sta;
struct atf_stats *stats, diff = {};
struct nlattr *cur;
int idx = 0;
int rem;
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
if (!tb[NL80211_ATTR_STA_INFO] || !tb[NL80211_ATTR_MAC])
return NL_SKIP;
if (nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
tb[NL80211_ATTR_STA_INFO], NULL))
return NL_SKIP;
if (!sinfo[NL80211_STA_INFO_TID_STATS])
return NL_SKIP;
sta = atf_interface_sta_get(iface, nla_data(tb[NL80211_ATTR_MAC]));
if (!sta)
return NL_SKIP;
stats = &sta->stats[sta->stats_idx];
memset(stats, 0, sizeof(*stats));
nla_for_each_nested(cur, sinfo[NL80211_STA_INFO_TID_STATS], rem)
atf_parse_tid_stats(iface, stats, idx++, cur);
atf_stats_diff(&diff, stats, &sta->stats[!sta->stats_idx]);
atf_sta_update_avg(sta, &diff);
atf_interface_sta_changed(iface, sta);
return NL_SKIP;
}
int atf_nl80211_interface_update(struct atf_interface *iface)
{
struct nl_msg *msg;
int ifindex;
ifindex = if_nametoindex(iface->ifname);
if (!ifindex)
return -1;
atf_interface_sta_update(iface);
msg = unl_genl_msg(&unl, NL80211_CMD_GET_STATION, true);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
unl_genl_request(&unl, msg, atf_sta_cb, iface);
atf_interface_sta_flush(iface);
return 0;
nla_put_failure:
nlmsg_free(msg);
return -1;
}
int atf_nl80211_init(void)
{
return unl_genl_init(&unl, "nl80211");
}

View File

@@ -0,0 +1,164 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
*/
#include <libubus.h>
#include "atf.h"
#define HOSTAPD_PREFIX "hostapd."
static struct ubus_auto_conn conn;
static struct blob_buf b;
enum {
ATF_CONFIG_RESET,
ATF_CONFIG_VO_Q_WEIGHT,
ATF_CONFIG_MIN_PKT_THRESH,
ATF_CONFIG_BULK_PERCENT_THR,
ATF_CONFIG_PRIO_PERCENT_THR,
ATF_CONFIG_WEIGHT_NORMAL,
ATF_CONFIG_WEIGHT_PRIO,
ATF_CONFIG_WEIGHT_BULK,
__ATF_CONFIG_MAX
};
static const struct blobmsg_policy atf_config_policy[__ATF_CONFIG_MAX] = {
[ATF_CONFIG_VO_Q_WEIGHT] = { "vo_queue_weight", BLOBMSG_TYPE_INT32 },
[ATF_CONFIG_MIN_PKT_THRESH] = { "update_pkt_threshold", BLOBMSG_TYPE_INT32 },
[ATF_CONFIG_BULK_PERCENT_THR] = { "bulk_percent_thresh", BLOBMSG_TYPE_INT32 },
[ATF_CONFIG_PRIO_PERCENT_THR] = { "prio_percent_thresh", BLOBMSG_TYPE_INT32 },
[ATF_CONFIG_WEIGHT_NORMAL] = { "weight_normal", BLOBMSG_TYPE_INT32 },
[ATF_CONFIG_WEIGHT_PRIO] = { "weight_prio", BLOBMSG_TYPE_INT32 },
[ATF_CONFIG_WEIGHT_BULK] = { "weight_bulk", BLOBMSG_TYPE_INT32 },
};
static int
atf_ubus_config(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_attr *tb[__ATF_CONFIG_MAX];
struct blob_attr *cur;
static const struct {
int id;
int *field;
} field_map[] = {
{ ATF_CONFIG_VO_Q_WEIGHT, &config.voice_queue_weight },
{ ATF_CONFIG_MIN_PKT_THRESH, &config.min_pkt_thresh },
{ ATF_CONFIG_BULK_PERCENT_THR, &config.bulk_percent_thresh },
{ ATF_CONFIG_PRIO_PERCENT_THR, &config.prio_percent_thresh },
{ ATF_CONFIG_WEIGHT_NORMAL, &config.weight_normal },
{ ATF_CONFIG_WEIGHT_PRIO, &config.weight_prio },
{ ATF_CONFIG_WEIGHT_BULK, &config.weight_bulk },
};
bool reset = false;
int i;
blobmsg_parse(atf_config_policy, __ATF_CONFIG_MAX, tb,
blobmsg_data(msg), blobmsg_len(msg));
if ((cur = tb[ATF_CONFIG_RESET]) != NULL)
reset = blobmsg_get_bool(cur);
if (reset)
reset_config();
for (i = 0; i < ARRAY_SIZE(field_map); i++) {
if ((cur = tb[field_map[i].id]) != NULL)
*(field_map[i].field) = blobmsg_get_u32(cur);
}
return 0;
}
static const struct ubus_method atf_methods[] = {
UBUS_METHOD("config", atf_ubus_config, atf_config_policy),
};
static struct ubus_object_type atf_object_type =
UBUS_OBJECT_TYPE("atfpolicy", atf_methods);
static struct ubus_object atf_object = {
.name = "atfpolicy",
.type = &atf_object_type,
.methods = atf_methods,
.n_methods = ARRAY_SIZE(atf_methods),
};
static void
atf_ubus_add_interface(struct ubus_context *ctx, const char *name)
{
struct atf_interface *iface;
iface = atf_interface_get(name + strlen(HOSTAPD_PREFIX));
if (!iface)
return;
iface->ubus_obj = 0;
ubus_lookup_id(ctx, name, &iface->ubus_obj);
D("add interface %s", name + strlen(HOSTAPD_PREFIX));
}
static void
atf_ubus_lookup_cb(struct ubus_context *ctx, struct ubus_object_data *obj,
void *priv)
{
if (!strncmp(obj->path, HOSTAPD_PREFIX, strlen(HOSTAPD_PREFIX)))
atf_ubus_add_interface(ctx, obj->path);
}
void atf_ubus_set_sta_weight(struct atf_interface *iface, struct atf_station *sta)
{
D("set sta "MAC_ADDR_FMT" weight=%d", MAC_ADDR_DATA(sta->macaddr), sta->weight);
blob_buf_init(&b, 0);
blobmsg_printf(&b, "sta", MAC_ADDR_FMT, MAC_ADDR_DATA(sta->macaddr));
blobmsg_add_u32(&b, "weight", sta->weight);
if (ubus_invoke(&conn.ctx, iface->ubus_obj, "update_airtime", b.head, NULL, NULL, 100))
D("set airtime weight failed");
}
static void
atf_ubus_event_cb(struct ubus_context *ctx, struct ubus_event_handler *ev,
const char *type, struct blob_attr *msg)
{
static const struct blobmsg_policy policy =
{ "path", BLOBMSG_TYPE_STRING };
struct ubus_object_data obj;
struct blob_attr *attr;
blobmsg_parse(&policy, 1, &attr, blobmsg_data(msg), blobmsg_len(msg));
if (!attr)
return;
obj.path = blobmsg_get_string(attr);
atf_ubus_lookup_cb(ctx, &obj, NULL);
}
static void
ubus_connect_handler(struct ubus_context *ctx)
{
static struct ubus_event_handler ev = {
.cb = atf_ubus_event_cb
};
ubus_add_object(ctx, &atf_object);
ubus_register_event_handler(ctx, &ev, "ubus.object.add");
ubus_lookup(ctx, "hostapd.*", atf_ubus_lookup_cb, NULL);
}
int atf_ubus_init(void)
{
conn.cb = ubus_connect_handler;
ubus_auto_connect(&conn);
return 0;
}
void atf_ubus_stop(void)
{
ubus_auto_shutdown(&conn);
}

View File

@@ -0,0 +1,52 @@
#
# Copyright (C) 2008-2012 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=qosify
PKG_RELEASE:=1
PKG_LICENSE:=GPL-2.0
PKG_BUILD_DEPENDS:=bpf-headers
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
include $(INCLUDE_DIR)/bpf.mk
define Package/qosify
SECTION:=kernel
CATEGORY:=Kernel modules
SUBMENU:=Network Support
TITLE:=QoS classifier eBPF module
DEPENDS:=+libbpf +libubox +libubus +kmod-sched-cake +tc-full
PKGFLAGS+=nonshared
endef
BPF_DOC = $(wildcard $(patsubst %,$(BPF_HEADERS_DIR)/scripts/%.py,bpf_doc bpf_helpers_doc))
define Build/Compile
$(call CompileBPF,$(PKG_BUILD_DIR)/qosify-bpf.c)
$(Build/Compile/Default)
endef
define Package/qosify/conffiles
/etc/config/qosify
/etc/qosify-defaults.conf
endef
define Package/qosify/install
$(INSTALL_DIR) $(1)/lib/bpf $(1)/usr/sbin $(1)/etc/init.d $(1)/etc/config $(1)/etc/hotplug.d/net
$(INSTALL_DATA) $(PKG_BUILD_DIR)/qosify-bpf.o $(1)/lib/bpf
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/qosify $(1)/usr/sbin/
$(INSTALL_BIN) ./files/qosify.init $(1)/etc/init.d/qosify
$(INSTALL_DATA) ./files/qosify-defaults.conf $(1)/etc/qosify-defaults.conf
$(INSTALL_DATA) ./files/qosify.conf $(1)/etc/config/qosify
$(INSTALL_DATA) ./files/qosify.hotplug $(1)/etc/hotplug.d/net/10-qosify
endef
$(eval $(call BuildPackage,qosify))

Binary file not shown.

View File

@@ -0,0 +1,17 @@
# DNS
tcp:53 CS5
tcp:5353 CS5
udp:53 CS5
udp:5353 CS5
# NTP
udp:123 CS6
# SSH
tcp:22 +CS4
# HTTP/QUIC
tcp:80 +CS3
tcp:443 +CS3
udp:80 +CS3
udp:443 +CS3

View File

@@ -0,0 +1,30 @@
config defaults
list defaults /etc/qosify-defaults.conf
option dscp_prio CS5
option dscp_icmp CS6
option dscp_bulk CS0
option dscp_default_udp CS4
option bulk_trigger_timeout 5
option bulk_trigger_pps 100
option prio_max_avg_pkt_len 500
config interface wan
option name wan
option disabled 1
option bandwidth_up 100mbit
option bandwidth_down 100mbit
# defaults:
option ingress 1
option egress 1
option mode diffserv4
option host_isolate 1
option autorate_ingress 1
option ingress_options ""
option egress_options ""
option options ""
config device wandev
option disabled 1
option name wan
option bandwidth 100mbit

View File

@@ -0,0 +1,2 @@
#!/bin/sh
ubus call qosify check_devices

View File

@@ -0,0 +1,105 @@
#!/bin/sh /etc/rc.common
# Copyright (c) 2014 OpenWrt.org
START=19
USE_PROCD=1
PROG=/usr/sbin/qosify
add_option() {
local type="$1"
local name="$2"
config_get val "$cfg" "$name"
[ -n "$val" ] && json_add_$type "$name" "$val"
}
add_defaults() {
cfg="$1"
json_add_boolean reset 1
config_get files "$cfg" defaults
json_add_array files
for i in $files; do
json_add_string "" "$i"
done
json_close_array
add_option int timeout
add_option string dscp_prio
add_option string dscp_bulk
add_option string dscp_icmp
add_option string dscp_default_udp
add_option string dscp_default_tcp
add_option int bulk_trigger_timeout
add_option int bulk_trigger_pps
add_option int prio_max_avg_pkt_len
}
add_interface() {
local cfg="$1"
config_get_bool disabled "$cfg" disabled 0
[ "$disabled" -gt 0 ] && return
config_get name "$cfg" name
json_add_object "$name"
config_get bw "$cfg" bandwidth
config_get bw_up "$cfg" bandwidth_up
bw_up="${bw_up:-$bw}"
[ -n "$bw_up" ] && json_add_string bandwidth_up "$bw_up"
config_get bw_down "$cfg" bandwidth_down
bw_down="${bw_down:-$bw}"
[ -n "$bw_down" ] && json_add_string bandwidth_down "$bw_down"
add_option string bandwidth
add_option boolean ingress
add_option boolean egress
add_option string mode
add_option boolean host_isolate
add_option boolean autorate_ingress
add_option string ingress_options
add_option string egress_options
add_option string options
json_close_object
}
reload_service() {
json_init
config_load qosify
config_foreach add_defaults defaults
json_add_object interfaces
config_foreach add_interface interface
json_close_object
json_add_object devices
config_foreach add_interface device
json_close_object
ubus call qosify config "$(json_dump)"
}
service_triggers() {
procd_add_reload_trigger qosify
}
start_service() {
procd_open_instance
procd_set_param command "$PROG"
procd_set_param respawn
procd_close_instance
}
service_started() {
ubus -t 10 wait_for qosify
[ $? = 0 ] && reload_service
}

View File

@@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.10)
PROJECT(qosify C)
ADD_DEFINITIONS(-Os -Wall -Wno-unknown-warning-option -Wno-array-bounds -Wno-format-truncation -Werror --std=gnu99)
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
find_library(bpf NAMES bpf)
ADD_EXECUTABLE(qosify main.c loader.c map.c ubus.c interface.c)
TARGET_LINK_LIBRARIES(qosify ${bpf} ubox ubus)
INSTALL(TARGETS qosify
RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}
)

View File

@@ -0,0 +1,112 @@
QoSify is simple daemon for setting up and managing CAKE along with a custom
eBPF based classifier that sets DSCP fields of packets.
It supports the following features:
- simple TCP/UDP port based mapping
- IP address based mapping
- priority boosting based on average packet size
- bulk flow detection based on number of packets per second
- dynamically add IP entries with timeout
- dns regex entries and ubus api for providing dns lookup results
It can be configured via ubus call qosify config.
This call supports the following parameters:
- "reset": BOOL
Reset the config to defaults instead of only updating supplied values
- "files": ARRAY of STRING
List of files with port/IP/host mappings
- "timeout": INT32
Default timeout for dynamically added entries
- "dscp_default_udp": STRING
Default DSCP value for UDP packets
- "dscp_default_tcp": STRING
Default DSCP value for TCP packets
- "dscp_prio": STRING
DSCP value for priority-marked packets
- "dscp_bulk": STRING
DSCP value for bulk-marked packets
- "dscp_icmp": STRING
DSCP value for ICMP packets
- "bulk_trigger_pps": INT32
Number of packets per second to trigger bulk flow detection
- "bulk_trigger_timeout": INT32
Time below bulk_trigger_pps threshold until a bulk flow mark is removed
- "prio_max_avg_pkt_len": INT32
Maximum average packet length for marking a flow as priority
- "interfaces": TABLE of TABLE
netifd interfaces to enable QoS on
- "devices": TABLE of TABLE
netdevs to enable QoS on
interface/device properties:
- "bandwidth_up": STRING
Uplink bandwidth (same format as tc)
- "bandwidth_down": STRING
Downlink bandwidth (same format as tc)
- "ingress": BOOL
Enable ingress shaping
- "egress": BOOL
Enable egress shaping
- "mode": STRING
CAKE diffserv mode
- "nat": BOOL
Enable CAKE NAT host detection via conntrack
- "host_isolate": BOOL
Enable CAKE host isolation
- "autorate_ingress": BOOL
Enable CAKE automatic rate estimation for ingress
- "ingress_options": STRING
CAKE ingress options
- "egress_options": STRING
CAKE egress options
- "options": STRING
CAKE options for ingress + egress
Mapping file syntax:
Each line has two whitespace separated fields, match and dscp
match is one of:
- tcp:<port>[-<endport>]
TCP single port, or range from <port> to <endport>
- udp:<port>[-<endport>]
UDP single port, or range from <port> to <endport>
- <ipaddr>
IPv4 address, e.g. 1.1.1.1
- <ipv6addr>
IPv6 address, e.g. ff01::1
- dns:<regex>
POSIX.2 extended regular expression for matching hostnames
Only works, if dns lookups are passed to qosify via the add_dns_host ubus call.
dscp can be a raw value, or a codepoint like CS0
Adding a + in front of the value tells qosify to only override the DSCP value if it is zero
Planned features:
- Integration with dnsmasq to support hostname pattern based DSCP marking
- Support for LAN host based priority

View File

@@ -0,0 +1,563 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <net/if_arp.h>
#include <net/if.h>
#include <unistd.h>
#include <errno.h>
#include <libubox/vlist.h>
#include <libubox/avl-cmp.h>
#include <libubox/uloop.h>
#include "qosify.h"
static void interface_update_cb(struct vlist_tree *tree,
struct vlist_node *node_new,
struct vlist_node *node_old);
static VLIST_TREE(devices, avl_strcmp, interface_update_cb, true, false);
static VLIST_TREE(interfaces, avl_strcmp, interface_update_cb, true, false);
static int socket_fd;
#define APPEND(_buf, _ofs, _format, ...) _ofs += snprintf(_buf + _ofs, sizeof(_buf) - _ofs, _format, ##__VA_ARGS__)
struct qosify_iface_config {
struct blob_attr *data;
bool ingress;
bool egress;
bool nat;
bool host_isolate;
bool autorate_ingress;
const char *bandwidth_up;
const char *bandwidth_down;
const char *mode;
const char *common_opts;
const char *ingress_opts;
const char *egress_opts;
};
struct qosify_iface {
struct vlist_node node;
char ifname[IFNAMSIZ];
bool active;
bool device;
struct blob_attr *config_data;
struct qosify_iface_config config;
};
enum {
IFACE_ATTR_BW_UP,
IFACE_ATTR_BW_DOWN,
IFACE_ATTR_INGRESS,
IFACE_ATTR_EGRESS,
IFACE_ATTR_MODE,
IFACE_ATTR_NAT,
IFACE_ATTR_HOST_ISOLATE,
IFACE_ATTR_AUTORATE_IN,
IFACE_ATTR_INGRESS_OPTS,
IFACE_ATTR_EGRESS_OPTS,
IFACE_ATTR_OPTS,
__IFACE_ATTR_MAX
};
static inline const char *qosify_iface_name(struct qosify_iface *iface)
{
return iface->node.avl.key;
}
static void
iface_config_parse(struct blob_attr *attr, struct blob_attr **tb)
{
static const struct blobmsg_policy policy[__IFACE_ATTR_MAX] = {
[IFACE_ATTR_BW_UP] = { "bandwidth_up", BLOBMSG_TYPE_STRING },
[IFACE_ATTR_BW_DOWN] = { "bandwidth_down", BLOBMSG_TYPE_STRING },
[IFACE_ATTR_INGRESS] = { "ingress", BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_EGRESS] = { "egress", BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_MODE] = { "mode", BLOBMSG_TYPE_STRING },
[IFACE_ATTR_NAT] = { "nat", BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_HOST_ISOLATE] = { "host_isolate", BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_AUTORATE_IN] = { "autorate_ingress", BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_INGRESS_OPTS] = { "ingress_options", BLOBMSG_TYPE_STRING },
[IFACE_ATTR_EGRESS_OPTS] = { "egress_options", BLOBMSG_TYPE_STRING },
[IFACE_ATTR_OPTS] = { "options", BLOBMSG_TYPE_STRING },
};
blobmsg_parse(policy, __IFACE_ATTR_MAX, tb, blobmsg_data(attr), blobmsg_len(attr));
}
static bool
iface_config_equal(struct qosify_iface *if1, struct qosify_iface *if2)
{
struct blob_attr *tb1[__IFACE_ATTR_MAX], *tb2[__IFACE_ATTR_MAX];
int i;
iface_config_parse(if1->config_data, tb1);
iface_config_parse(if2->config_data, tb2);
for (i = 0; i < __IFACE_ATTR_MAX; i++) {
if (!!tb1[i] != !!tb2[i])
return false;
if (!tb1[i])
continue;
if (blob_raw_len(tb1[i]) != blob_raw_len(tb2[i]))
return false;
if (memcmp(tb1[i], tb2[i], blob_raw_len(tb1[i])) != 0)
return false;
}
return true;
}
static const char *check_str(struct blob_attr *attr)
{
const char *str = blobmsg_get_string(attr);
if (strchr(str, '\''))
return NULL;
return str;
}
static void
iface_config_set(struct qosify_iface *iface, struct blob_attr *attr)
{
struct qosify_iface_config *cfg = &iface->config;
struct blob_attr *tb[__IFACE_ATTR_MAX];
struct blob_attr *cur;
iface_config_parse(attr, tb);
memset(cfg, 0, sizeof(*cfg));
/* defaults */
cfg->mode = "diffserv4";
cfg->ingress = true;
cfg->egress = true;
cfg->host_isolate = true;
cfg->autorate_ingress = true;
cfg->nat = !iface->device;
if ((cur = tb[IFACE_ATTR_BW_UP]) != NULL)
cfg->bandwidth_up = check_str(cur);
if ((cur = tb[IFACE_ATTR_BW_DOWN]) != NULL)
cfg->bandwidth_down = check_str(cur);
if ((cur = tb[IFACE_ATTR_MODE]) != NULL)
cfg->mode = check_str(cur);
if ((cur = tb[IFACE_ATTR_OPTS]) != NULL)
cfg->common_opts = check_str(cur);
if ((cur = tb[IFACE_ATTR_EGRESS_OPTS]) != NULL)
cfg->egress_opts = check_str(cur);
if ((cur = tb[IFACE_ATTR_INGRESS_OPTS]) != NULL)
cfg->ingress_opts = check_str(cur);
if ((cur = tb[IFACE_ATTR_INGRESS]) != NULL)
cfg->ingress = blobmsg_get_bool(cur);
if ((cur = tb[IFACE_ATTR_EGRESS]) != NULL)
cfg->egress = blobmsg_get_bool(cur);
if ((cur = tb[IFACE_ATTR_NAT]) != NULL)
cfg->nat = blobmsg_get_bool(cur);
if ((cur = tb[IFACE_ATTR_HOST_ISOLATE]) != NULL)
cfg->host_isolate = blobmsg_get_bool(cur);
if ((cur = tb[IFACE_ATTR_AUTORATE_IN]) != NULL)
cfg->autorate_ingress = blobmsg_get_bool(cur);
}
static const char *
interface_ifb_name(struct qosify_iface *iface)
{
static char ifname[IFNAMSIZ + 1] = "ifb-";
int len = strlen(iface->ifname);
if (len + 4 < IFNAMSIZ) {
snprintf(ifname + 4, IFNAMSIZ - 4, "%s", iface->ifname);
return ifname;
}
ifname[4] = iface->ifname[0];
ifname[5] = iface->ifname[1];
snprintf(ifname + 6, IFNAMSIZ - 6, "%s", iface->ifname + len - (IFNAMSIZ + 6) - 1);
return ifname;
}
static int run_cmd(char *cmd, bool ignore)
{
char *argv[] = { "sh", "-c", cmd, NULL };
bool first = true;
int status = -1;
char buf[512];
int fds[2];
FILE *f;
int pid;
if (pipe(fds))
return -1;
pid = fork();
if (!pid) {
close(fds[0]);
if (fds[1] != STDOUT_FILENO)
dup2(fds[1], STDOUT_FILENO);
if (fds[1] != STDERR_FILENO)
dup2(fds[1], STDERR_FILENO);
if (fds[1] > STDERR_FILENO)
close(fds[1]);
execv("/bin/sh", argv);
exit(1);
}
if (pid < 0)
return -1;
close(fds[1]);
f = fdopen(fds[0], "r");
if (!f) {
close(fds[0]);
goto out;
}
while (fgets(buf, sizeof(buf), f) != NULL) {
if (!strlen(buf))
break;
if (ignore)
continue;
if (first) {
ULOG_WARN("Command: %s\n", cmd);
first = false;
}
ULOG_WARN("%s%s", buf, strchr(buf, '\n') ? "" : "\n");
}
fclose(f);
out:
while (waitpid(pid, &status, 0) < 0)
if (errno != EINTR)
break;
return status;
}
static int
prepare_tc_cmd(char *buf, int len, const char *type, const char *cmd,
const char *dev, const char *extra)
{
return snprintf(buf, len, "tc %s %s dev '%s' %s", type, cmd, dev, extra);
}
static int
cmd_del_qdisc(const char *ifname, const char *type)
{
char buf[64];
prepare_tc_cmd(buf, sizeof(buf), "qdisc", "del", ifname, type);
return run_cmd(buf, true);
}
static int
cmd_add_qdisc(struct qosify_iface *iface, const char *ifname, bool egress, bool eth)
{
struct qosify_iface_config *cfg = &iface->config;
const char *bw = egress ? cfg->bandwidth_up : cfg->bandwidth_down;
const char *dir_opts = egress ? cfg->egress_opts : cfg->ingress_opts;
char buf[512];
int ofs;
cmd_del_qdisc(ifname, "root");
ofs = prepare_tc_cmd(buf, sizeof(buf), "qdisc", "add", ifname, "root handle 1: cake");
if (bw)
APPEND(buf, ofs, " bandwidth %s", bw);
APPEND(buf, ofs, " %s %sgress", cfg->mode, egress ? "e" : "in");
if (cfg->host_isolate)
APPEND(buf, ofs, " %snat dual-%shost",
cfg->nat ? "" : "no",
egress ? "src" : "dst");
else
APPEND(buf, ofs, " flows");
APPEND(buf, ofs, " %s %s",
cfg->common_opts ? cfg->common_opts : "",
dir_opts ? dir_opts : "");
run_cmd(buf, false);
ofs = prepare_tc_cmd(buf, sizeof(buf), "filter", "add", ifname, "parent 1: bpf");
APPEND(buf, ofs, " object-pinned /sys/fs/bpf/qosify_%sgress_%s verbose direct-action",
egress ? "e" : "in",
eth ? "eth" : "ip");
return run_cmd(buf, false);
}
static int
cmd_del_ingress(struct qosify_iface *iface)
{
char buf[256];
cmd_del_qdisc(iface->ifname, "handle ffff: ingress");
snprintf(buf, sizeof(buf), "ip link del '%s'", interface_ifb_name(iface));
return run_cmd(buf, true);
}
static int
cmd_add_ingress(struct qosify_iface *iface, bool eth)
{
const char *ifbdev = interface_ifb_name(iface);
char buf[256];
int ofs;
cmd_del_ingress(iface);
ofs = prepare_tc_cmd(buf, sizeof(buf), "qdisc", "add", iface->ifname, " handle ffff: ingress");
run_cmd(buf, false);
snprintf(buf, sizeof(buf), "ip link add '%s' type ifb", ifbdev);
run_cmd(buf, false);
cmd_add_qdisc(iface, ifbdev, false, eth);
snprintf(buf, sizeof(buf), "ip link set dev '%s' up", ifbdev);
run_cmd(buf, false);
ofs = prepare_tc_cmd(buf, sizeof(buf), "filter", "add", iface->ifname, " parent ffff:");
APPEND(buf, ofs, " protocol all prio 10 u32 match u32 0 0 "
"flowid 1:1 action mirred egress redirect dev '%s'", ifbdev);
return run_cmd(buf, false);
}
static void
interface_start(struct qosify_iface *iface)
{
struct ifreq ifr = {};
bool eth;
if (!iface->ifname[0] || iface->active)
return;
ULOG_INFO("start interface %s\n", iface->ifname);
strncpy(ifr.ifr_name, iface->ifname, sizeof(ifr.ifr_name));
if (ioctl(socket_fd, SIOCGIFHWADDR, &ifr) < 0) {
ULOG_ERR("ioctl(SIOCGIFHWADDR, %s) failed: %s\n", iface->ifname, strerror(errno));
return;
}
eth = ifr.ifr_hwaddr.sa_family == ARPHRD_ETHER;
if (iface->config.egress)
cmd_add_qdisc(iface, iface->ifname, true, eth);
if (iface->config.ingress)
cmd_add_ingress(iface, eth);
iface->active = true;
}
static void
interface_stop(struct qosify_iface *iface)
{
if (!iface->ifname[0] || !iface->active)
return;
ULOG_INFO("stop interface %s\n", iface->ifname);
iface->active = false;
if (iface->config.egress)
cmd_del_qdisc(iface->ifname, "root");
if (iface->config.ingress)
cmd_del_ingress(iface);
}
static void
interface_set_config(struct qosify_iface *iface, struct blob_attr *config)
{
iface->config_data = blob_memdup(config);
iface_config_set(iface, iface->config_data);
interface_start(iface);
}
static void
interface_update_cb(struct vlist_tree *tree,
struct vlist_node *node_new, struct vlist_node *node_old)
{
struct qosify_iface *if_new = NULL, *if_old = NULL;
if (node_new)
if_new = container_of(node_new, struct qosify_iface, node);
if (node_old)
if_old = container_of(node_old, struct qosify_iface, node);
if (if_new && if_old) {
if (!iface_config_equal(if_old, if_new)) {
interface_stop(if_old);
free(if_old->config_data);
interface_set_config(if_old, if_new->config_data);
}
free(if_new);
return;
}
if (if_old) {
interface_stop(if_old);
free(if_old->config_data);
free(if_old);
}
if (if_new)
interface_set_config(if_new, if_new->config_data);
}
static void
interface_create(struct blob_attr *attr, bool device)
{
struct qosify_iface *iface;
const char *name = blobmsg_name(attr);
int name_len = strlen(name);
char *name_buf;
if (strchr(name, '\''))
return;
if (name_len >= IFNAMSIZ)
return;
if (blobmsg_type(attr) != BLOBMSG_TYPE_TABLE)
return;
iface = calloc_a(sizeof(*iface), &name_buf, name_len + 1);
strcpy(name_buf, blobmsg_name(attr));
iface->config_data = attr;
iface->device = device;
vlist_add(device ? &devices : &interfaces, &iface->node, name_buf);
}
void qosify_iface_config_update(struct blob_attr *ifaces, struct blob_attr *devs)
{
struct blob_attr *cur;
int rem;
vlist_update(&devices);
blobmsg_for_each_attr(cur, devs, rem)
interface_create(cur, true);
vlist_flush(&devices);
vlist_update(&interfaces);
blobmsg_for_each_attr(cur, ifaces, rem)
interface_create(cur, false);
vlist_flush(&interfaces);
}
static void
qosify_iface_check_device(struct qosify_iface *iface)
{
const char *name = qosify_iface_name(iface);
int ifindex;
ifindex = if_nametoindex(name);
if (!ifindex) {
interface_stop(iface);
iface->ifname[0] = 0;
} else {
snprintf(iface->ifname, sizeof(iface->ifname), "%s", name);
interface_start(iface);
}
}
static void
qosify_iface_check_interface(struct qosify_iface *iface)
{
const char *name = qosify_iface_name(iface);
char ifname[IFNAMSIZ];
if (qosify_ubus_check_interface(name, ifname, sizeof(ifname)) == 0) {
snprintf(iface->ifname, sizeof(iface->ifname), "%s", ifname);
interface_start(iface);
} else {
interface_stop(iface);
iface->ifname[0] = 0;
}
}
static void qos_iface_check_cb(struct uloop_timeout *t)
{
struct qosify_iface *iface;
vlist_for_each_element(&devices, iface, node)
qosify_iface_check_device(iface);
vlist_for_each_element(&interfaces, iface, node)
qosify_iface_check_interface(iface);
}
void qosify_iface_check(void)
{
static struct uloop_timeout timer = {
.cb = qos_iface_check_cb,
};
uloop_timeout_set(&timer, 10);
}
void qosify_iface_status(struct blob_buf *b)
{
struct qosify_iface *iface;
void *c, *i;
c = blobmsg_open_table(b, "devices");
vlist_for_each_element(&devices, iface, node) {
i = blobmsg_open_table(b, qosify_iface_name(iface));
blobmsg_add_u8(b, "active", iface->active);
blobmsg_close_table(b, i);
}
blobmsg_close_table(b, c);
c = blobmsg_open_table(b, "interfaces");
vlist_for_each_element(&interfaces, iface, node) {
i = blobmsg_open_table(b, qosify_iface_name(iface));
blobmsg_add_u8(b, "active", iface->active);
if (iface->ifname)
blobmsg_add_string(b, "ifname", iface->ifname);
blobmsg_close_table(b, i);
}
blobmsg_close_table(b, c);
}
int qosify_iface_init(void)
{
socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (socket < 0)
return -1;
return 0;
}
void qosify_iface_stop(void)
{
struct qosify_iface *iface;
vlist_for_each_element(&interfaces, iface, node)
interface_stop(iface);
vlist_for_each_element(&devices, iface, node)
interface_stop(iface);
}

View File

@@ -0,0 +1,121 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
*/
#include <sys/resource.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <glob.h>
#include <unistd.h>
#include "qosify.h"
static int qosify_bpf_pr(enum libbpf_print_level level, const char *format,
va_list args)
{
return vfprintf(stderr, format, args);
}
static void qosify_init_env(void)
{
struct rlimit limit = {
.rlim_cur = RLIM_INFINITY,
.rlim_max = RLIM_INFINITY,
};
setrlimit(RLIMIT_MEMLOCK, &limit);
}
static void qosify_fill_rodata(struct bpf_object *obj, uint32_t flags)
{
struct bpf_map *map = NULL;
while ((map = bpf_map__next(map, obj)) != NULL) {
if (!strstr(bpf_map__name(map), ".rodata"))
continue;
bpf_map__set_initial_value(map, &flags, sizeof(flags));
}
}
static int
qosify_create_program(const char *suffix, uint32_t flags)
{
DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts,
.pin_root_path = CLASSIFY_DATA_PATH,
);
struct bpf_program *prog;
struct bpf_object *obj;
char path[256];
int err;
snprintf(path, sizeof(path), CLASSIFY_PIN_PATH "_" "%s", suffix);
obj = bpf_object__open_file(CLASSIFY_PROG_PATH, &opts);
err = libbpf_get_error(obj);
if (err) {
perror("bpf_object__open_file");
return -1;
}
prog = bpf_object__find_program_by_title(obj, "classifier");
if (!prog) {
fprintf(stderr, "Can't find classifier prog\n");
return -1;
}
bpf_program__set_type(prog, BPF_PROG_TYPE_SCHED_CLS);
qosify_fill_rodata(obj, flags);
err = bpf_object__load(obj);
if (err) {
perror("bpf_object__load");
return -1;
}
libbpf_set_print(NULL);
unlink(path);
err = bpf_program__pin(prog, path);
if (err) {
fprintf(stderr, "Failed to pin program to %s: %s\n",
path, strerror(-err));
}
bpf_object__close(obj);
return 0;
}
int qosify_loader_init(void)
{
static const struct {
const char *suffix;
uint32_t flags;
} progs[] = {
{ "egress_eth", 0 },
{ "egress_ip", QOSIFY_IP_ONLY },
{ "ingress_eth", QOSIFY_INGRESS },
{ "ingress_ip", QOSIFY_INGRESS | QOSIFY_IP_ONLY },
};
glob_t g;
int i;
if (glob(CLASSIFY_DATA_PATH "/*", 0, NULL, &g) == 0) {
for (i = 0; i < g.gl_pathc; i++)
unlink(g.gl_pathv[i]);
}
libbpf_set_print(qosify_bpf_pr);
qosify_init_env();
for (i = 0; i < ARRAY_SIZE(progs); i++) {
if (qosify_create_program(progs[i].suffix, progs[i].flags))
return -1;
}
return 0;
}

View File

@@ -0,0 +1,72 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
*/
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <libubox/uloop.h>
#include "qosify.h"
static int usage(const char *progname)
{
fprintf(stderr, "Usage: %s [options]\n"
"Options:\n"
" -l <file> Load defaults from <file>\n"
" -o only load program/maps without running as daemon\n"
"\n", progname);
return 1;
}
int main(int argc, char **argv)
{
const char *load_file = NULL;
bool oneshot = false;
int ch;
while ((ch = getopt(argc, argv, "fl:o")) != -1) {
switch (ch) {
case 'f':
break;
case 'l':
load_file = optarg;
break;
case 'o':
oneshot = true;
break;
default:
return usage(argv[0]);
}
}
if (qosify_loader_init())
return 2;
if (qosify_map_init())
return 2;
if (qosify_map_load_file(load_file))
return 2;
if (oneshot)
return 0;
ulog_open(ULOG_SYSLOG, LOG_DAEMON, "qosify");
uloop_init();
if (qosify_ubus_init() ||
qosify_iface_init())
return 2;
uloop_run();
qosify_ubus_stop();
qosify_iface_stop();
uloop_done();
return 0;
}

View File

@@ -0,0 +1,735 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
*/
#include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <time.h>
#include <libubox/uloop.h>
#include "qosify.h"
static int qosify_map_entry_cmp(const void *k1, const void *k2, void *ptr);
static int qosify_map_fds[__CL_MAP_MAX];
static AVL_TREE(map_data, qosify_map_entry_cmp, false, NULL);
static LIST_HEAD(map_files);
static uint32_t next_timeout;
static uint8_t qosify_dscp_default[2] = { 0xff, 0xff };
int qosify_map_timeout;
int qosify_active_timeout;
struct qosify_config config;
struct qosify_map_file {
struct list_head list;
char filename[];
};
static const struct {
const char *name;
const char *type_name;
} qosify_map_info[] = {
[CL_MAP_TCP_PORTS] = { "tcp_ports", "tcp_port" },
[CL_MAP_UDP_PORTS] = { "udp_ports", "udp_port" },
[CL_MAP_IPV4_ADDR] = { "ipv4_map", "ipv4_addr" },
[CL_MAP_IPV6_ADDR] = { "ipv6_map", "ipv6_addr" },
[CL_MAP_CONFIG] = { "config", "config" },
[CL_MAP_DNS] = { "dns", "dns" },
};
static const struct {
const char name[5];
uint8_t val;
} codepoints[] = {
{ "CS0", 0 },
{ "CS1", 8 },
{ "CS2", 16 },
{ "CS3", 24 },
{ "CS4", 32 },
{ "CS5", 40 },
{ "CS6", 48 },
{ "CS7", 56 },
{ "AF11", 10 },
{ "AF12", 12 },
{ "AF13", 14 },
{ "AF21", 18 },
{ "AF22", 20 },
{ "AF22", 22 },
{ "AF31", 26 },
{ "AF32", 28 },
{ "AF33", 30 },
{ "AF41", 34 },
{ "AF42", 36 },
{ "AF43", 38 },
{ "EF", 46 },
{ "VA", 44 },
{ "LE", 1 },
{ "DF", 0 },
};
static void qosify_map_timer_cb(struct uloop_timeout *t)
{
qosify_map_gc();
}
static struct uloop_timeout qosify_map_timer = {
.cb = qosify_map_timer_cb,
};
static uint32_t qosify_gettime(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec;
}
static const char *
qosify_map_path(enum qosify_map_id id)
{
static char path[128];
const char *name;
if (id >= ARRAY_SIZE(qosify_map_info))
return NULL;
name = qosify_map_info[id].name;
if (!name)
return NULL;
snprintf(path, sizeof(path), "%s/%s", CLASSIFY_DATA_PATH, name);
return path;
}
static int qosify_map_get_fd(enum qosify_map_id id)
{
const char *path = qosify_map_path(id);
int fd;
if (!path)
return -1;
fd = bpf_obj_get(path);
if (fd < 0)
fprintf(stderr, "Failed to open map %s: %s\n", path, strerror(errno));
return fd;
}
static void qosify_map_clear_list(enum qosify_map_id id)
{
int fd = qosify_map_fds[id];
__u32 key[4] = {};
while (bpf_map_get_next_key(fd, &key, &key) != -1)
bpf_map_delete_elem(fd, &key);
}
static void __qosify_map_set_dscp_default(enum qosify_map_id id, uint8_t val)
{
struct qosify_map_data data = {
.id = id,
};
int fd = qosify_map_fds[id];
int i;
val |= QOSIFY_DSCP_DEFAULT_FLAG;
for (i = 0; i < (1 << 16); i++) {
data.addr.port = htons(i);
if (avl_find(&map_data, &data))
continue;
bpf_map_update_elem(fd, &data.addr, &val, BPF_ANY);
}
}
void qosify_map_set_dscp_default(enum qosify_map_id id, uint8_t val)
{
bool udp;
if (id == CL_MAP_TCP_PORTS)
udp = false;
else if (id == CL_MAP_UDP_PORTS)
udp = true;
else
return;
if (qosify_dscp_default[udp] == val)
return;
qosify_dscp_default[udp] = val;
__qosify_map_set_dscp_default(id, val);
}
int qosify_map_init(void)
{
int i;
for (i = 0; i < CL_MAP_DNS; i++) {
qosify_map_fds[i] = qosify_map_get_fd(i);
if (qosify_map_fds[i] < 0)
return -1;
}
qosify_map_clear_list(CL_MAP_IPV4_ADDR);
qosify_map_clear_list(CL_MAP_IPV6_ADDR);
qosify_map_reset_config();
return 0;
}
static char *str_skip(char *str, bool space)
{
while (*str && isspace(*str) == space)
str++;
return str;
}
static int
qosify_map_codepoint(const char *val)
{
int i;
for (i = 0; i < ARRAY_SIZE(codepoints); i++)
if (!strcmp(codepoints[i].name, val))
return codepoints[i].val;
return 0xff;
}
static int qosify_map_entry_cmp(const void *k1, const void *k2, void *ptr)
{
const struct qosify_map_data *d1 = k1;
const struct qosify_map_data *d2 = k2;
if (d1->id != d2->id)
return d2->id - d1->id;
if (d1->id == CL_MAP_DNS)
return strcmp(d1->addr.dns.pattern, d2->addr.dns.pattern);
return memcmp(&d1->addr, &d2->addr, sizeof(d1->addr));
}
static struct qosify_map_entry *
__qosify_map_alloc_entry(struct qosify_map_data *data)
{
struct qosify_map_entry *e;
char *pattern;
if (data->id < CL_MAP_DNS) {
e = calloc(1, sizeof(*e));
memcpy(&e->data.addr, &data->addr, sizeof(e->data.addr));
return e;
}
e = calloc_a(sizeof(*e), &pattern, strlen(data->addr.dns.pattern) + 1);
strcpy(pattern, data->addr.dns.pattern);
e->data.addr.dns.pattern = pattern;
if (regcomp(&e->data.addr.dns.regex, pattern,
REG_EXTENDED | REG_ICASE | REG_NOSUB)) {
free(e);
return NULL;
}
return e;
}
static void __qosify_map_set_entry(struct qosify_map_data *data)
{
int fd = qosify_map_fds[data->id];
struct qosify_map_entry *e;
bool file = data->file;
int32_t delta = 0;
bool add = data->dscp != 0xff;
uint8_t prev_dscp = 0xff;
e = avl_find_element(&map_data, data, e, avl);
if (!e) {
if (!add)
return;
e = __qosify_map_alloc_entry(data);
if (!e)
return;
e->avl.key = &e->data;
e->data.id = data->id;
avl_insert(&map_data, &e->avl);
} else {
prev_dscp = e->data.dscp;
}
if (file)
e->data.file = add;
else
e->data.user = add;
if (add) {
if (file)
e->data.file_dscp = data->dscp;
if (!e->data.user || !file)
e->data.dscp = data->dscp;
} else if (e->data.file && !file) {
e->data.dscp = e->data.file_dscp;
}
if (e->data.dscp != prev_dscp && data->id < CL_MAP_DNS) {
struct qosify_ip_map_val val = {
.dscp = e->data.dscp,
.seen = 1,
};
bpf_map_update_elem(fd, &data->addr, &val, BPF_ANY);
}
if (add) {
if (qosify_map_timeout == ~0 || file) {
e->timeout = ~0;
return;
}
e->timeout = qosify_gettime() + qosify_map_timeout;
delta = e->timeout - next_timeout;
if (next_timeout && delta >= 0)
return;
}
uloop_timeout_set(&qosify_map_timer, 1);
}
static int
qosify_map_set_port(struct qosify_map_data *data, const char *str)
{
unsigned long start_port, end_port;
char *err;
int i;
start_port = end_port = strtoul(str, &err, 0);
if (err && *err) {
if (*err == '-')
end_port = strtoul(err + 1, &err, 0);
if (*err)
return -1;
}
if (!start_port || end_port < start_port ||
end_port >= 65535)
return -1;
for (i = start_port; i <= end_port; i++) {
data->addr.port = htons(i);
__qosify_map_set_entry(data);
}
return 0;
}
static int
qosify_map_fill_ip(struct qosify_map_data *data, const char *str)
{
int af;
if (data->id == CL_MAP_IPV6_ADDR)
af = AF_INET6;
else
af = AF_INET;
if (inet_pton(af, str, &data->addr) != 1)
return -1;
return 0;
}
int qosify_map_set_entry(enum qosify_map_id id, bool file, const char *str, uint8_t dscp)
{
struct qosify_map_data data = {
.id = id,
.file = file,
.dscp = dscp,
};
switch (id) {
case CL_MAP_DNS:
data.addr.dns.pattern = str;
break;
case CL_MAP_TCP_PORTS:
case CL_MAP_UDP_PORTS:
return qosify_map_set_port(&data, str);
case CL_MAP_IPV4_ADDR:
case CL_MAP_IPV6_ADDR:
if (qosify_map_fill_ip(&data, str))
return -1;
break;
default:
return -1;
}
__qosify_map_set_entry(&data);
return 0;
}
int qosify_map_dscp_value(const char *val)
{
unsigned long dscp;
char *err;
bool fallback = false;
if (*val == '+') {
fallback = true;
val++;
}
dscp = strtoul(val, &err, 0);
if (err && *err)
dscp = qosify_map_codepoint(val);
if (dscp >= 64)
return -1;
return dscp + (fallback << 6);
}
static void
qosify_map_dscp_codepoint_str(char *dest, int len, uint8_t dscp)
{
int i;
if (dscp & QOSIFY_DSCP_FALLBACK_FLAG) {
*(dest++) = '+';
len--;
dscp &= ~QOSIFY_DSCP_FALLBACK_FLAG;
}
for (i = 0; i < ARRAY_SIZE(codepoints); i++) {
if (codepoints[i].val != dscp)
continue;
snprintf(dest, len, "%s", codepoints[i].name);
return;
}
snprintf(dest, len, "0x%x", dscp);
}
static void
qosify_map_parse_line(char *str)
{
const char *key, *value;
int dscp;
str = str_skip(str, true);
key = str;
str = str_skip(str, false);
if (!*str)
return;
*(str++) = 0;
str = str_skip(str, true);
value = str;
dscp = qosify_map_dscp_value(value);
if (dscp < 0)
return;
if (!strncmp(key, "dns:", 4))
qosify_map_set_entry(CL_MAP_DNS, true, key + 4, dscp);
if (!strncmp(key, "tcp:", 4))
qosify_map_set_entry(CL_MAP_TCP_PORTS, true, key + 4, dscp);
else if (!strncmp(key, "udp:", 4))
qosify_map_set_entry(CL_MAP_UDP_PORTS, true, key + 4, dscp);
else if (strchr(key, ':'))
qosify_map_set_entry(CL_MAP_IPV6_ADDR, true, key, dscp);
else if (strchr(key, '.'))
qosify_map_set_entry(CL_MAP_IPV4_ADDR, true, key, dscp);
}
static int __qosify_map_load_file(const char *file)
{
char line[1024];
char *cur;
FILE *f;
if (!file)
return 0;
f = fopen(file, "r");
if (!f) {
fprintf(stderr, "Can't open data file %s\n", file);
return -1;
}
while (fgets(line, sizeof(line), f)) {
cur = strchr(line, '#');
if (cur)
*cur = 0;
cur = line + strlen(line);
if (cur == line)
continue;
while (cur > line && isspace(cur[-1]))
cur--;
*cur = 0;
qosify_map_parse_line(line);
}
fclose(f);
return 0;
}
int qosify_map_load_file(const char *file)
{
struct qosify_map_file *f;
if (!file)
return 0;
f = calloc(1, sizeof(*f) + strlen(file) + 1);
strcpy(f->filename, file);
list_add_tail(&f->list, &map_files);
return __qosify_map_load_file(file);
}
static void qosify_map_reset_file_entries(void)
{
struct qosify_map_entry *e;
avl_for_each_element(&map_data, e, avl)
e->data.file = false;
}
void qosify_map_clear_files(void)
{
struct qosify_map_file *f, *tmp;
qosify_map_reset_file_entries();
list_for_each_entry_safe(f, tmp, &map_files, list) {
list_del(&f->list);
free(f);
}
}
void qosify_map_reset_config(void)
{
qosify_map_clear_files();
qosify_map_set_dscp_default(CL_MAP_TCP_PORTS, 0);
qosify_map_set_dscp_default(CL_MAP_UDP_PORTS, 0);
qosify_map_timeout = 3600;
qosify_active_timeout = 300;
memset(&config, 0, sizeof(config));
config.dscp_prio = 0xff;
config.dscp_bulk = 0xff;
config.dscp_icmp = 0xff;
}
void qosify_map_reload(void)
{
struct qosify_map_file *f;
qosify_map_reset_file_entries();
list_for_each_entry(f, &map_files, list)
__qosify_map_load_file(f->filename);
qosify_map_gc();
}
static void qosify_map_free_entry(struct qosify_map_entry *e)
{
int fd = qosify_map_fds[e->data.id];
avl_delete(&map_data, &e->avl);
if (e->data.id < CL_MAP_DNS)
bpf_map_delete_elem(fd, &e->data.addr);
free(e);
}
static bool
qosify_map_entry_refresh_timeout(struct qosify_map_entry *e)
{
struct qosify_ip_map_val val;
int fd = qosify_map_fds[e->data.id];
if (e->data.id != CL_MAP_IPV4_ADDR &&
e->data.id != CL_MAP_IPV6_ADDR)
return false;
if (bpf_map_lookup_elem(fd, &e->data.addr, &val))
return false;
if (!val.seen)
return false;
e->timeout = qosify_gettime() + qosify_active_timeout;
val.seen = 0;
bpf_map_update_elem(fd, &e->data.addr, &val, BPF_ANY);
return true;
}
void qosify_map_gc(void)
{
struct qosify_map_entry *e, *tmp;
int32_t timeout = 0;
uint32_t cur_time = qosify_gettime();
next_timeout = 0;
avl_for_each_element_safe(&map_data, e, avl, tmp) {
int32_t cur_timeout;
if (e->data.user && e->timeout != ~0) {
cur_timeout = e->timeout - cur_time;
if (cur_timeout <= 0 &&
qosify_map_entry_refresh_timeout(e))
cur_timeout = e->timeout - cur_time;
if (cur_timeout <= 0) {
e->data.user = false;
e->data.dscp = e->data.file_dscp;
} else if (!timeout || cur_timeout < timeout) {
timeout = cur_timeout;
next_timeout = e->timeout;
}
}
if (e->data.file || e->data.user)
continue;
qosify_map_free_entry(e);
}
if (!timeout)
return;
uloop_timeout_set(&qosify_map_timer, timeout * 1000);
}
int qosify_map_add_dns_host(const char *host, const char *addr, const char *type, int ttl)
{
struct qosify_map_data data = {
.id = CL_MAP_DNS,
.addr.dns.pattern = "",
};
struct qosify_map_entry *e;
int prev_timeout = qosify_map_timeout;
e = avl_find_ge_element(&map_data, &data, e, avl);
if (!e)
return 0;
memset(&data, 0, sizeof(data));
data.user = true;
if (!strcmp(type, "A"))
data.id = CL_MAP_IPV4_ADDR;
else if (!strcmp(type, "AAAA"))
data.id = CL_MAP_IPV6_ADDR;
else
return 0;
if (qosify_map_fill_ip(&data, addr))
return -1;
avl_for_element_to_last(&map_data, e, e, avl) {
regex_t *regex = &e->data.addr.dns.regex;
if (e->data.id != CL_MAP_DNS)
return 0;
if (regexec(regex, host, 0, NULL, 0) != 0)
continue;
if (ttl)
qosify_map_timeout = ttl;
data.dscp = e->data.dscp;
__qosify_map_set_entry(&data);
qosify_map_timeout = prev_timeout;
}
return 0;
}
void qosify_map_dump(struct blob_buf *b)
{
struct qosify_map_entry *e;
uint32_t cur_time = qosify_gettime();
int buf_len = INET6_ADDRSTRLEN + 1;
char *buf;
void *a;
int af;
a = blobmsg_open_array(b, "entries");
avl_for_each_element(&map_data, e, avl) {
void *c;
if (!e->data.file && !e->data.user)
continue;
c = blobmsg_open_table(b, NULL);
if (e->data.user && e->timeout != ~0) {
int32_t cur_timeout = e->timeout - cur_time;
if (cur_timeout < 0)
cur_timeout = 0;
blobmsg_add_u32(b, "timeout", cur_timeout);
}
blobmsg_add_u8(b, "file", e->data.file);
blobmsg_add_u8(b, "user", e->data.user);
buf = blobmsg_alloc_string_buffer(b, "dscp", buf_len);
qosify_map_dscp_codepoint_str(buf, buf_len, e->data.dscp);
blobmsg_add_string_buffer(b);
blobmsg_add_string(b, "type", qosify_map_info[e->data.id].type_name);
switch (e->data.id) {
case CL_MAP_TCP_PORTS:
case CL_MAP_UDP_PORTS:
blobmsg_printf(b, "addr", "%d", ntohs(e->data.addr.port));
break;
case CL_MAP_IPV4_ADDR:
case CL_MAP_IPV6_ADDR:
buf = blobmsg_alloc_string_buffer(b, "addr", buf_len);
af = e->data.id == CL_MAP_IPV6_ADDR ? AF_INET6 : AF_INET;
inet_ntop(af, &e->data.addr, buf, buf_len);
blobmsg_add_string_buffer(b);
break;
case CL_MAP_DNS:
blobmsg_add_string(b, "addr", e->data.addr.dns.pattern);
break;
default:
*buf = 0;
break;
}
blobmsg_close_table(b, c);
}
blobmsg_close_array(b, a);
}
void qosify_map_update_config(void)
{
int fd = qosify_map_fds[CL_MAP_CONFIG];
uint32_t key = 0;
bpf_map_update_elem(fd, &key, &config, BPF_ANY);
}

View File

@@ -0,0 +1,464 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
*/
#define KBUILD_MODNAME "foo"
#include <uapi/linux/bpf.h>
#include <uapi/linux/if_ether.h>
#include <uapi/linux/if_packet.h>
#include <uapi/linux/ip.h>
#include <uapi/linux/ipv6.h>
#include <uapi/linux/in.h>
#include <uapi/linux/tcp.h>
#include <uapi/linux/udp.h>
#include <uapi/linux/filter.h>
#include <uapi/linux/pkt_cls.h>
#include <linux/ip.h>
#include <net/ipv6.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>
#include "qosify-bpf.h"
#define INET_ECN_MASK 3
#define FLOW_CHECK_INTERVAL ((u32)((1000000000ULL) >> 24))
#define FLOW_TIMEOUT ((u32)((30ULL * 1000000000ULL) >> 24))
#define FLOW_BULK_TIMEOUT 5
#define EWMA_SHIFT 12
const volatile static uint32_t module_flags = 0;
struct flow_bucket {
__u32 last_update;
__u32 pkt_len_avg;
__u16 pkt_count;
__u8 dscp;
__u8 bulk_timeout;
};
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(pinning, 1);
__type(key, __u32);
__type(value, struct qosify_config);
__uint(max_entries, 1);
} config SEC(".maps");
typedef struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(pinning, 1);
__type(key, __u32);
__type(value, __u8);
__uint(max_entries, 1 << 16);
} port_array_t;
struct {
__uint(type, BPF_MAP_TYPE_LRU_HASH);
__uint(pinning, 1);
__type(key, __u32);
__uint(value_size, sizeof(struct flow_bucket));
__uint(max_entries, QOSIFY_FLOW_BUCKETS);
} flow_map SEC(".maps");
port_array_t tcp_ports SEC(".maps");
port_array_t udp_ports SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(pinning, 1);
__uint(key_size, sizeof(struct in_addr));
__type(value, struct qosify_ip_map_val);
__uint(max_entries, 100000);
__uint(map_flags, BPF_F_NO_PREALLOC);
} ipv4_map SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(pinning, 1);
__uint(key_size, sizeof(struct in6_addr));
__type(value, struct qosify_ip_map_val);
__uint(max_entries, 100000);
__uint(map_flags, BPF_F_NO_PREALLOC);
} ipv6_map SEC(".maps");
static struct qosify_config *get_config(void)
{
__u32 key = 0;
return bpf_map_lookup_elem(&config, &key);
}
static __always_inline int proto_is_vlan(__u16 h_proto)
{
return !!(h_proto == bpf_htons(ETH_P_8021Q) ||
h_proto == bpf_htons(ETH_P_8021AD));
}
static __always_inline int proto_is_ip(__u16 h_proto)
{
return !!(h_proto == bpf_htons(ETH_P_IP) ||
h_proto == bpf_htons(ETH_P_IPV6));
}
static __always_inline void *skb_ptr(struct __sk_buff *skb, __u32 offset)
{
void *start = (void *)(unsigned long long)skb->data;
return start + offset;
}
static __always_inline void *skb_end_ptr(struct __sk_buff *skb)
{
return (void *)(unsigned long long)skb->data_end;
}
static __always_inline int skb_check(struct __sk_buff *skb, void *ptr)
{
if (ptr > skb_end_ptr(skb))
return -1;
return 0;
}
static __always_inline __u32 cur_time(void)
{
__u32 val = bpf_ktime_get_ns() >> 24;
if (!val)
val = 1;
return val;
}
static __always_inline __u32 ewma(__u32 *avg, __u32 val)
{
if (*avg)
*avg = (*avg * 3) / 4 + (val << EWMA_SHIFT) / 4;
else
*avg = val << EWMA_SHIFT;
return *avg >> EWMA_SHIFT;
}
static __always_inline void
ipv4_change_dsfield(struct iphdr *iph, __u8 mask, __u8 value, bool force)
{
__u32 check = bpf_ntohs(iph->check);
__u8 dsfield;
if ((iph->tos & mask) && !force)
return;
dsfield = (iph->tos & mask) | value;
if (iph->tos == dsfield)
return;
check += iph->tos;
if ((check + 1) >> 16)
check = (check + 1) & 0xffff;
check -= dsfield;
check += check >> 16;
iph->check = bpf_htons(check);
iph->tos = dsfield;
}
static __always_inline void
ipv6_change_dsfield(struct ipv6hdr *ipv6h, __u8 mask, __u8 value, bool force)
{
__u16 *p = (__u16 *)ipv6h;
__u16 val;
if (((*p >> 4) & mask) && !force)
return;
val = (*p & bpf_htons((((__u16)mask << 4) | 0xf00f))) | bpf_htons((__u16)value << 4);
if (val == *p)
return;
*p = val;
}
static __always_inline int
parse_ethernet(struct __sk_buff *skb, __u32 *offset)
{
struct ethhdr *eth;
__u16 h_proto;
int i;
eth = skb_ptr(skb, *offset);
if (skb_check(skb, eth + 1))
return -1;
h_proto = eth->h_proto;
*offset += sizeof(*eth);
#pragma unroll
for (i = 0; i < 2; i++) {
struct vlan_hdr *vlh = skb_ptr(skb, *offset);
if (!proto_is_vlan(h_proto))
break;
if (skb_check(skb, vlh + 1))
return -1;
h_proto = vlh->h_vlan_encapsulated_proto;
*offset += sizeof(*vlh);
}
return h_proto;
}
static void
parse_l4proto(struct qosify_config *config, struct __sk_buff *skb,
__u32 offset, __u8 proto, __u8 *dscp_out)
{
struct udphdr *udp;
__u32 src, dest, key;
__u8 *value;
udp = skb_ptr(skb, offset);
if (skb_check(skb, &udp->len))
return;
if (config && (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6)) {
*dscp_out = config->dscp_icmp;
return;
}
src = udp->source;
dest = udp->dest;
if (module_flags & QOSIFY_INGRESS)
key = src;
else
key = dest;
if (proto == IPPROTO_TCP) {
value = bpf_map_lookup_elem(&tcp_ports, &key);
} else {
if (proto != IPPROTO_UDP)
key = 0;
value = bpf_map_lookup_elem(&udp_ports, &key);
}
if (!value)
return;
*dscp_out = *value;
}
static void
check_flow(struct qosify_config *config, struct __sk_buff *skb,
uint8_t *dscp)
{
struct flow_bucket flow_data;
struct flow_bucket *flow;
__s32 delta;
__u32 hash;
__u32 time;
if (!(*dscp & QOSIFY_DSCP_DEFAULT_FLAG))
return;
if (!config)
return;
if (!config->bulk_trigger_pps &&
!config->prio_max_avg_pkt_len)
return;
time = cur_time();
hash = bpf_get_hash_recalc(skb);
flow = bpf_map_lookup_elem(&flow_map, &hash);
if (!flow) {
memset(&flow_data, 0, sizeof(flow_data));
bpf_map_update_elem(&flow_map, &hash, &flow_data, BPF_ANY);
flow = bpf_map_lookup_elem(&flow_map, &hash);
if (!flow)
return;
}
if (!flow->last_update)
goto reset;
delta = time - flow->last_update;
if ((u32)delta > FLOW_TIMEOUT)
goto reset;
if (delta >= FLOW_CHECK_INTERVAL) {
if (flow->bulk_timeout) {
flow->bulk_timeout--;
if (!flow->bulk_timeout)
flow->dscp = 0xff;
}
goto clear;
}
if (flow->pkt_count < 0xffff)
flow->pkt_count++;
if (config->bulk_trigger_pps &&
flow->pkt_count > config->bulk_trigger_pps) {
flow->dscp = config->dscp_bulk;
flow->bulk_timeout = config->bulk_trigger_timeout;
}
out:
if (config->prio_max_avg_pkt_len &&
flow->dscp != config->dscp_bulk) {
if (ewma(&flow->pkt_len_avg, skb->len) <
config->prio_max_avg_pkt_len)
flow->dscp = config->dscp_prio;
else
flow->dscp = 0xff;
}
if (flow->dscp != 0xff)
*dscp = flow->dscp;
return;
reset:
flow->dscp = 0xff;
flow->pkt_len_avg = 0;
clear:
flow->pkt_count = 1;
flow->last_update = time;
goto out;
}
static __always_inline void
parse_ipv4(struct __sk_buff *skb, __u32 *offset)
{
struct qosify_config *config;
struct qosify_ip_map_val *ip_val;
const __u32 zero_port = 0;
struct iphdr *iph;
__u8 dscp = 0xff;
__u8 *value;
__u8 ipproto;
int hdr_len;
void *key;
bool force;
config = get_config();
iph = skb_ptr(skb, *offset);
if (skb_check(skb, iph + 1))
return;
hdr_len = iph->ihl * 4;
if (bpf_skb_pull_data(skb, *offset + hdr_len + sizeof(struct udphdr)))
return;
iph = skb_ptr(skb, *offset);
*offset += hdr_len;
if (skb_check(skb, (void *)(iph + 1)))
return;
ipproto = iph->protocol;
parse_l4proto(config, skb, *offset, ipproto, &dscp);
if (module_flags & QOSIFY_INGRESS)
key = &iph->saddr;
else
key = &iph->daddr;
ip_val = bpf_map_lookup_elem(&ipv4_map, key);
if (ip_val) {
if (!ip_val->seen)
ip_val->seen = 1;
dscp = ip_val->dscp;
} else if (dscp == 0xff) {
/* use udp port 0 entry as fallback for non-tcp/udp */
value = bpf_map_lookup_elem(&udp_ports, &zero_port);
if (value)
dscp = *value;
}
check_flow(config, skb, &dscp);
force = !(dscp & QOSIFY_DSCP_FALLBACK_FLAG);
dscp &= GENMASK(5, 0);
ipv4_change_dsfield(iph, INET_ECN_MASK, dscp << 2, force);
}
static __always_inline void
parse_ipv6(struct __sk_buff *skb, __u32 *offset)
{
struct qosify_config *config;
struct qosify_ip_map_val *ip_val;
const __u32 zero_port = 0;
struct ipv6hdr *iph;
__u8 dscp = 0;
__u8 *value;
__u8 ipproto;
void *key;
bool force;
config = get_config();
if (bpf_skb_pull_data(skb, *offset + sizeof(*iph) + sizeof(struct udphdr)))
return;
iph = skb_ptr(skb, *offset);
*offset += sizeof(*iph);
if (skb_check(skb, (void *)(iph + 1)))
return;
ipproto = iph->nexthdr;
if (module_flags & QOSIFY_INGRESS)
key = &iph->saddr;
else
key = &iph->daddr;
parse_l4proto(config, skb, *offset, ipproto, &dscp);
ip_val = bpf_map_lookup_elem(&ipv6_map, key);
if (ip_val) {
if (!ip_val->seen)
ip_val->seen = 1;
dscp = ip_val->dscp;
} else if (dscp == 0xff) {
/* use udp port 0 entry as fallback for non-tcp/udp */
value = bpf_map_lookup_elem(&udp_ports, &zero_port);
if (value)
dscp = *value;
}
check_flow(config, skb, &dscp);
force = !(dscp & QOSIFY_DSCP_FALLBACK_FLAG);
dscp &= GENMASK(5, 0);
ipv6_change_dsfield(iph, INET_ECN_MASK, dscp << 2, force);
}
SEC("classifier")
int classify(struct __sk_buff *skb)
{
__u32 offset = 0;
int type;
if (module_flags & QOSIFY_IP_ONLY)
type = skb->protocol;
else
type = parse_ethernet(skb, &offset);
if (type == bpf_htons(ETH_P_IP))
parse_ipv4(skb, &offset);
else if (type == bpf_htons(ETH_P_IPV6))
parse_ipv6(skb, &offset);
return TC_ACT_OK;
}
char _license[] SEC("license") = "GPL";

View File

@@ -0,0 +1,39 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
*/
#ifndef __BPF_QOSIFY_H
#define __BPF_QOSIFY_H
#ifndef QOSIFY_FLOW_BUCKET_SHIFT
#define QOSIFY_FLOW_BUCKET_SHIFT 13
#endif
#define QOSIFY_FLOW_BUCKETS (1 << QOSIFY_FLOW_BUCKET_SHIFT)
/* rodata per-instance flags */
#define QOSIFY_INGRESS (1 << 0)
#define QOSIFY_IP_ONLY (1 << 1)
#define QOSIFY_DSCP_FALLBACK_FLAG (1 << 6)
#define QOSIFY_DSCP_DEFAULT_FLAG (1 << 7)
/* global config data */
struct qosify_config {
uint8_t dscp_prio;
uint8_t dscp_bulk;
uint8_t dscp_icmp;
uint8_t bulk_trigger_timeout;
uint16_t bulk_trigger_pps;
uint16_t prio_max_avg_pkt_len;
};
struct qosify_ip_map_val {
uint8_t dscp; /* must be first */
uint8_t seen;
};
#endif

View File

@@ -0,0 +1,95 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
*/
#ifndef __QOS_CLASSIFY_H
#define __QOS_CLASSIFY_H
#include <stdbool.h>
#include <regex.h>
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include "qosify-bpf.h"
#include <libubox/utils.h>
#include <libubox/avl.h>
#include <libubox/blobmsg.h>
#include <libubox/ulog.h>
#include <netinet/in.h>
#define CLASSIFY_PROG_PATH "/lib/bpf/qosify-bpf.o"
#define CLASSIFY_PIN_PATH "/sys/fs/bpf/qosify"
#define CLASSIFY_DATA_PATH "/sys/fs/bpf/qosify_data"
enum qosify_map_id {
CL_MAP_TCP_PORTS,
CL_MAP_UDP_PORTS,
CL_MAP_IPV4_ADDR,
CL_MAP_IPV6_ADDR,
CL_MAP_CONFIG,
CL_MAP_DNS,
__CL_MAP_MAX,
};
struct qosify_map_data {
enum qosify_map_id id;
bool file : 1;
bool user : 1;
uint8_t dscp;
uint8_t file_dscp;
union {
uint32_t port;
struct in_addr ip;
struct in6_addr ip6;
struct {
const char *pattern;
regex_t regex;
} dns;
} addr;
};
struct qosify_map_entry {
struct avl_node avl;
uint32_t timeout;
struct qosify_map_data data;
};
extern int qosify_map_timeout;
extern int qosify_active_timeout;
extern struct qosify_config config;
int qosify_loader_init(void);
int qosify_map_init(void);
int qosify_map_dscp_value(const char *val);
int qosify_map_load_file(const char *file);
int qosify_map_set_entry(enum qosify_map_id id, bool file, const char *str, uint8_t dscp);
void qosify_map_reload(void);
void qosify_map_clear_files(void);
void qosify_map_gc(void);
void qosify_map_dump(struct blob_buf *b);
void qosify_map_set_dscp_default(enum qosify_map_id id, uint8_t val);
void qosify_map_reset_config(void);
void qosify_map_update_config(void);
int qosify_map_add_dns_host(const char *host, const char *addr, const char *type, int ttl);
int qosify_iface_init(void);
void qosify_iface_config_update(struct blob_attr *ifaces, struct blob_attr *devs);
void qosify_iface_check(void);
void qosify_iface_status(struct blob_buf *b);
void qosify_iface_stop(void);
int qosify_ubus_init(void);
void qosify_ubus_stop(void);
int qosify_ubus_check_interface(const char *name, char *ifname, int ifname_len);
#endif

View File

@@ -0,0 +1,416 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
*/
#include <libubus.h>
#include "qosify.h"
static struct blob_buf b;
static int
qosify_ubus_add_array(struct blob_attr *attr, uint8_t val, enum qosify_map_id id)
{
struct blob_attr *cur;
int rem;
if (blobmsg_check_array(attr, BLOBMSG_TYPE_STRING) < 0)
return UBUS_STATUS_INVALID_ARGUMENT;
blobmsg_for_each_attr(cur, attr, rem)
qosify_map_set_entry(id, false, blobmsg_get_string(cur), val);
return 0;
}
static int
qosify_ubus_set_files(struct blob_attr *attr)
{
struct blob_attr *cur;
int rem;
if (blobmsg_check_array(attr, BLOBMSG_TYPE_STRING) < 0)
return UBUS_STATUS_INVALID_ARGUMENT;
qosify_map_clear_files();
blobmsg_for_each_attr(cur, attr, rem)
qosify_map_load_file(blobmsg_get_string(cur));
qosify_map_gc();
return 0;
}
enum {
CL_ADD_DSCP,
CL_ADD_TIMEOUT,
CL_ADD_IPV4,
CL_ADD_IPV6,
CL_ADD_TCP_PORT,
CL_ADD_UDP_PORT,
CL_ADD_DNS,
__CL_ADD_MAX
};
static const struct blobmsg_policy qosify_add_policy[__CL_ADD_MAX] = {
[CL_ADD_DSCP] = { "dscp", BLOBMSG_TYPE_STRING },
[CL_ADD_TIMEOUT] = { "timeout", BLOBMSG_TYPE_INT32 },
[CL_ADD_IPV4] = { "ipv4", BLOBMSG_TYPE_ARRAY },
[CL_ADD_IPV6] = { "ipv6", BLOBMSG_TYPE_ARRAY },
[CL_ADD_TCP_PORT] = { "tcp_port", BLOBMSG_TYPE_ARRAY },
[CL_ADD_UDP_PORT] = { "udp_port", BLOBMSG_TYPE_ARRAY },
[CL_ADD_DNS] = { "dns", BLOBMSG_TYPE_ARRAY },
};
static int
qosify_ubus_reload(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
qosify_map_reload();
return 0;
}
static int
qosify_ubus_add(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
int prev_timemout = qosify_map_timeout;
struct blob_attr *tb[__CL_ADD_MAX];
struct blob_attr *cur;
int dscp = -1;
int ret;
blobmsg_parse(qosify_add_policy, __CL_ADD_MAX, tb,
blobmsg_data(msg), blobmsg_len(msg));
if (!strcmp(method, "add")) {
if ((cur = tb[CL_ADD_DSCP]) != NULL)
dscp = qosify_map_dscp_value(blobmsg_get_string(cur));
else
return UBUS_STATUS_INVALID_ARGUMENT;
if (dscp < 0)
return UBUS_STATUS_INVALID_ARGUMENT;
if ((cur = tb[CL_ADD_TIMEOUT]) != NULL)
qosify_map_timeout = blobmsg_get_u32(cur);
} else {
dscp = 0xff;
}
if ((cur = tb[CL_ADD_IPV4]) != NULL &&
(ret = qosify_ubus_add_array(cur, dscp, CL_MAP_IPV4_ADDR) != 0))
return ret;
if ((cur = tb[CL_ADD_IPV6]) != NULL &&
(ret = qosify_ubus_add_array(cur, dscp, CL_MAP_IPV6_ADDR) != 0))
return ret;
if ((cur = tb[CL_ADD_TCP_PORT]) != NULL &&
(ret = qosify_ubus_add_array(cur, dscp, CL_MAP_TCP_PORTS) != 0))
return ret;
if ((cur = tb[CL_ADD_UDP_PORT]) != NULL &&
(ret = qosify_ubus_add_array(cur, dscp, CL_MAP_UDP_PORTS) != 0))
return ret;
if ((cur = tb[CL_ADD_DNS]) != NULL &&
(ret = qosify_ubus_add_array(cur, dscp, CL_MAP_DNS) != 0))
return ret;
qosify_map_timeout = prev_timemout;
return 0;
}
enum {
CL_CONFIG_RESET,
CL_CONFIG_FILES,
CL_CONFIG_TIMEOUT,
CL_CONFIG_DSCP_UDP,
CL_CONFIG_DSCP_TCP,
CL_CONFIG_DSCP_PRIO,
CL_CONFIG_DSCP_BULK,
CL_CONFIG_DSCP_ICMP,
CL_CONFIG_BULK_TIMEOUT,
CL_CONFIG_BULK_PPS,
CL_CONFIG_PRIO_PKT_LEN,
CL_CONFIG_INTERFACES,
CL_CONFIG_DEVICES,
__CL_CONFIG_MAX
};
static const struct blobmsg_policy qosify_config_policy[__CL_CONFIG_MAX] = {
[CL_CONFIG_RESET] = { "reset", BLOBMSG_TYPE_BOOL },
[CL_CONFIG_FILES] = { "files", BLOBMSG_TYPE_ARRAY },
[CL_CONFIG_TIMEOUT] = { "timeout", BLOBMSG_TYPE_INT32 },
[CL_CONFIG_DSCP_UDP] = { "dscp_default_udp", BLOBMSG_TYPE_STRING },
[CL_CONFIG_DSCP_TCP] = { "dscp_default_tcp", BLOBMSG_TYPE_STRING },
[CL_CONFIG_DSCP_PRIO] = { "dscp_prio", BLOBMSG_TYPE_STRING },
[CL_CONFIG_DSCP_BULK] = { "dscp_bulk", BLOBMSG_TYPE_STRING },
[CL_CONFIG_DSCP_ICMP] = { "dscp_icmp", BLOBMSG_TYPE_STRING },
[CL_CONFIG_BULK_TIMEOUT] = { "bulk_trigger_timeout", BLOBMSG_TYPE_INT32 },
[CL_CONFIG_BULK_PPS] = { "bulk_trigger_pps", BLOBMSG_TYPE_INT32 },
[CL_CONFIG_PRIO_PKT_LEN] = { "prio_max_avg_pkt_len", BLOBMSG_TYPE_INT32 },
[CL_CONFIG_INTERFACES] = { "interfaces", BLOBMSG_TYPE_TABLE },
[CL_CONFIG_DEVICES] = { "devices", BLOBMSG_TYPE_TABLE },
};
static int __set_dscp(uint8_t *dest, struct blob_attr *attr, bool reset)
{
int dscp;
if (reset)
*dest = 0xff;
if (!attr)
return 0;
dscp = qosify_map_dscp_value(blobmsg_get_string(attr));
if (dscp < 0)
return -1;
*dest = dscp;
return 0;
}
static int
qosify_ubus_config(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_attr *tb[__CL_CONFIG_MAX];
struct blob_attr *cur;
uint8_t dscp;
bool reset = false;
int ret;
blobmsg_parse(qosify_config_policy, __CL_CONFIG_MAX, tb,
blobmsg_data(msg), blobmsg_len(msg));
if ((cur = tb[CL_CONFIG_RESET]) != NULL)
reset = blobmsg_get_bool(cur);
if (reset)
qosify_map_reset_config();
if ((cur = tb[CL_CONFIG_TIMEOUT]) != NULL)
qosify_map_timeout = blobmsg_get_u32(cur);
if ((cur = tb[CL_CONFIG_FILES]) != NULL &&
(ret = qosify_ubus_set_files(cur) != 0))
return ret;
__set_dscp(&dscp, tb[CL_CONFIG_DSCP_UDP], true);
if (dscp != 0xff)
qosify_map_set_dscp_default(CL_MAP_UDP_PORTS, dscp);
__set_dscp(&dscp, tb[CL_CONFIG_DSCP_TCP], true);
if (dscp != 0xff)
qosify_map_set_dscp_default(CL_MAP_TCP_PORTS, dscp);
__set_dscp(&config.dscp_prio, tb[CL_CONFIG_DSCP_PRIO], reset);
__set_dscp(&config.dscp_bulk, tb[CL_CONFIG_DSCP_BULK], reset);
__set_dscp(&config.dscp_icmp, tb[CL_CONFIG_DSCP_ICMP], reset);
if ((cur = tb[CL_CONFIG_BULK_TIMEOUT]) != NULL)
config.bulk_trigger_timeout = blobmsg_get_u32(cur);
if ((cur = tb[CL_CONFIG_BULK_PPS]) != NULL)
config.bulk_trigger_pps = blobmsg_get_u32(cur);
if ((cur = tb[CL_CONFIG_PRIO_PKT_LEN]) != NULL)
config.prio_max_avg_pkt_len = blobmsg_get_u32(cur);
qosify_map_update_config();
qosify_iface_config_update(tb[CL_CONFIG_INTERFACES], tb[CL_CONFIG_DEVICES]);
qosify_iface_check();
return 0;
}
static int
qosify_ubus_dump(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
blob_buf_init(&b, 0);
qosify_map_dump(&b);
ubus_send_reply(ctx, req, b.head);
blob_buf_free(&b);
return 0;
}
static int
qosify_ubus_status(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
blob_buf_init(&b, 0);
qosify_iface_status(&b);
ubus_send_reply(ctx, req, b.head);
blob_buf_free(&b);
return 0;
}
static int
qosify_ubus_check_devices(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
qosify_iface_check();
return 0;
}
enum {
CL_DNS_HOST_NAME,
CL_DNS_HOST_TYPE,
CL_DNS_HOST_ADDR,
CL_DNS_HOST_TTL,
__CL_DNS_HOST_MAX
};
static const struct blobmsg_policy qosify_dns_policy[__CL_DNS_HOST_MAX] = {
[CL_DNS_HOST_NAME] = { "name", BLOBMSG_TYPE_STRING },
[CL_DNS_HOST_TYPE] = { "type", BLOBMSG_TYPE_STRING },
[CL_DNS_HOST_ADDR] = { "address", BLOBMSG_TYPE_STRING },
[CL_DNS_HOST_TTL] = { "ttl", BLOBMSG_TYPE_INT32 },
};
static int
qosify_ubus_add_dns_host(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_attr *tb[__CL_DNS_HOST_MAX];
struct blob_attr *cur;
uint32_t ttl = 0;
blobmsg_parse(qosify_dns_policy, __CL_DNS_HOST_MAX, tb,
blobmsg_data(msg), blobmsg_len(msg));
if (!tb[CL_DNS_HOST_NAME] || !tb[CL_DNS_HOST_TYPE] ||
!tb[CL_DNS_HOST_ADDR])
return UBUS_STATUS_INVALID_ARGUMENT;
if ((cur = tb[CL_DNS_HOST_TTL]) != NULL)
ttl = blobmsg_get_u32(cur);
if (qosify_map_add_dns_host(blobmsg_get_string(tb[CL_DNS_HOST_NAME]),
blobmsg_get_string(tb[CL_DNS_HOST_ADDR]),
blobmsg_get_string(tb[CL_DNS_HOST_TYPE]),
ttl))
return UBUS_STATUS_INVALID_ARGUMENT;
return 0;
}
static const struct ubus_method qosify_methods[] = {
UBUS_METHOD_NOARG("reload", qosify_ubus_reload),
UBUS_METHOD("add", qosify_ubus_add, qosify_add_policy),
UBUS_METHOD_MASK("remove", qosify_ubus_add, qosify_add_policy,
((1 << __CL_ADD_MAX) - 1) & ~(1 << CL_ADD_DSCP)),
UBUS_METHOD("config", qosify_ubus_config, qosify_config_policy),
UBUS_METHOD_NOARG("dump", qosify_ubus_dump),
UBUS_METHOD_NOARG("status", qosify_ubus_status),
UBUS_METHOD("add_dns_host", qosify_ubus_add_dns_host, qosify_dns_policy),
UBUS_METHOD_NOARG("check_devices", qosify_ubus_check_devices),
};
static struct ubus_object_type qosify_object_type =
UBUS_OBJECT_TYPE("qosify", qosify_methods);
static struct ubus_object qosify_object = {
.name = "qosify",
.type = &qosify_object_type,
.methods = qosify_methods,
.n_methods = ARRAY_SIZE(qosify_methods),
};
static void
ubus_connect_handler(struct ubus_context *ctx)
{
ubus_add_object(ctx, &qosify_object);
}
static struct ubus_auto_conn conn;
int qosify_ubus_init(void)
{
conn.cb = ubus_connect_handler;
ubus_auto_connect(&conn);
return 0;
}
void qosify_ubus_stop(void)
{
ubus_auto_shutdown(&conn);
}
struct iface_req {
char *name;
int len;
};
static void
netifd_if_cb(struct ubus_request *req, int type, struct blob_attr *msg)
{
struct iface_req *ifr = req->priv;
enum {
IFS_ATTR_UP,
IFS_ATTR_DEV,
__IFS_ATTR_MAX
};
static const struct blobmsg_policy policy[__IFS_ATTR_MAX] = {
[IFS_ATTR_UP] = { "up", BLOBMSG_TYPE_BOOL },
[IFS_ATTR_DEV] = { "l3_device", BLOBMSG_TYPE_STRING },
};
struct blob_attr *tb[__IFS_ATTR_MAX];
blobmsg_parse(policy, __IFS_ATTR_MAX, tb, blobmsg_data(msg), blobmsg_len(msg));
if (!tb[IFS_ATTR_UP] || !tb[IFS_ATTR_DEV])
return;
if (!blobmsg_get_bool(tb[IFS_ATTR_UP]))
return;
snprintf(ifr->name, ifr->len, "%s", blobmsg_get_string(tb[IFS_ATTR_DEV]));
}
int qosify_ubus_check_interface(const char *name, char *ifname, int ifname_len)
{
struct iface_req req = { ifname, ifname_len };
char *obj_name = "network.interface.";
uint32_t id;
#define PREFIX "network.interface."
obj_name = alloca(sizeof(PREFIX) + strlen(name) + 1);
sprintf(obj_name, PREFIX "%s", name);
#undef PREFIX
ifname[0] = 0;
if (ubus_lookup_id(&conn.ctx, obj_name, &id))
return -1;
ubus_invoke(&conn.ctx, id, "status", b.head, netifd_if_cb, &req, 1000);
if (!ifname[0])
return -1;
return 0;
}

View File

@@ -39,8 +39,8 @@ delclient() {
TC class del dev $ifb parent 1:1 classid 1:$id
}
ingress=
egress=
ingress=0
egress=0
getrate() {
config_get ssid $1 ssid
@@ -55,12 +55,17 @@ addclient() {
local mac=$2
local ssid=$(cat /tmp/ratelimit.$iface)
egress=$3
ingress=$4
logger "ratelimit: adding client"
config_load ratelimit
config_foreach getrate rate $ssid
[ "$egress" -eq 0 -o $ingress -eq 0 ] && {
config_load ratelimit
config_foreach getrate rate $ssid
}
[ -z "$egress" -o -z $ingress ] && {
[ "$egress" -eq 0 -o $ingress -eq 0 ] && {
logger "ratelimit: no valid rates"
exit 1
}

View File

@@ -2,7 +2,7 @@
case $2 in
AP-STA-CONNECTED)
ratelimit addclient $1 $3
ratelimit addclient $1 $3 $4 $5
;;
AP-STA-DISCONNECTED)
ratelimit delclient $1 $3

View File

@@ -6,7 +6,7 @@ PKG_RELEASE:=1
PKG_SOURCE_URL=https://github.com/blogic/ucentral-client.git
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2021-02-15
PKG_SOURCE_VERSION:=06704453bec36baf96919021507627b1f1d4e6e4
PKG_SOURCE_VERSION:=e27356216c6baecda9424b81ad90242505e16f08
PKG_LICENSE:=BSD-3-Clause
PKG_MAINTAINER:=John Crispin <john@phrozen.org>
@@ -18,7 +18,7 @@ define Package/ucentral-client
SECTION:=ucentral
CATEGORY:=uCentral
TITLE:=OpenWrt uCentral websocket client
DEPENDS:=+ucode +ucode-mod-fs +ucode-mod-ubus +ucode-mod-uci +ucode-mod-math \
DEPENDS:=+ucode +ucode-mod-fs +ucode-mod-ubus +ucode-mod-uci +ucode-mod-math +ucode-mod-resolv \
+libubox +libwebsockets-openssl +libblobmsg-json +libubus
endef

View File

@@ -0,0 +1,14 @@
#!/bin/sh /etc/rc.common
START=99
USE_PROCD=1
PROG=/usr/libexec/ucentral-wdt.sh
start_service() {
active=$(readlink /etc/ucentral/ucentral.active)
[ -n "$active" -a "$active" != "/etc/ucentral/ucentral.cfg.0000000001" ] && return 0
procd_open_instance
procd_set_param command "$PROG"
procd_close_instance
}

View File

@@ -0,0 +1,16 @@
#!/bin/sh
sleep 60
[ -f /etc/ucentral/redirector.json ] || return 0
active=$(ubus call ucentral status | jsonfilter -e '@.active')
[ -n "$active" -a ! "$active" -eq 1 ] && {
logger ucentral-wdt: all good
exit 0
}
logger ucentral-wdt: restarting client
/etc/init.d/ucentral restart

View File

@@ -6,7 +6,7 @@ PKG_RELEASE:=1
PKG_SOURCE_URL=https://github.com/blogic/ucentral-event.git
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2021-04-13
PKG_SOURCE_VERSION:=863be47d264ea3fefccadfcfa53c1af53f54dd3b
PKG_SOURCE_VERSION:=7b0d136e8556bb099d7032823139d275448714cb
PKG_MAINTAINER:=John Crispin <john@phrozen.org>
PKG_LICENSE:=BSD-3-Clause

View File

@@ -6,7 +6,7 @@ PKG_RELEASE:=1
PKG_SOURCE_URL=https://github.com/blogic/ucentral-schema.git
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2021-02-15
PKG_SOURCE_VERSION:=224042e57012b72231c5d402816a83fab5bbf54f
PKG_SOURCE_VERSION:=a78cad29ffd3635d80d2dfc414051ec8a9dbb6b0
PKG_MAINTAINER:=John Crispin <john@phrozen.org>
PKG_LICENSE:=BSD-3-Clause

View File

@@ -0,0 +1,107 @@
{
"uuid": 2,
"radios": [
{
"band": "2G",
"country": "CA",
"channel-mode": "HE",
"channel-width": 80,
"channel": 32
}
],
"interfaces": [
{
"name": "WAN",
"role": "upstream",
"services": [ "lldp" ],
"ethernet": [
{
"select-ports": [
"WAN*"
]
}
],
"ipv4": {
"addressing": "dynamic"
},
"ipv6": {
"addressing": "dynamic"
},
"ssids": [
{
"name": "OpenWifi",
"wifi-bands": [
"2G"
],
"bss-mode": "ap",
"encryption": {
"proto": "psk2",
"key": "OpenWifi",
"ieee80211w": "optional"
}
}
]
},
{
"name": "LAN",
"role": "downstream",
"services": [ "ssh", "lldp" ],
"ethernet": [
{
"select-ports": [
"LAN*"
]
}
],
"ipv4": {
"addressing": "static",
"subnet": "192.168.1.1/24",
"dhcp": {
"lease-first": 10,
"lease-count": 100,
"lease-time": "6h"
}
},
"ipv6": {
"addressing": "static",
"dhcpv6": {
"mode": "hybrid"
}
},
"ssids": [
{
"name": "OpenWifi",
"wifi-bands": [
"2G"
],
"bss-mode": "ap",
"encryption": {
"proto": "psk2",
"key": "OpenWifi",
"ieee80211w": "optional"
}
}
]
}
],
"metrics": {
"statistics": {
"interval": 120,
"types": [ "ssids", "lldp", "clients" ]
},
"health": {
"interval": 120
}
},
"services": {
"lldp": {
"describe": "uCentral",
"location": "universe"
},
"ssh": {
"port": 22
}
}
}

View File

@@ -1,5 +1,14 @@
{
"uuid": 2,
"radios": [
{
"band": "2G",
"country": "CA",
"channel-mode": "HE",
"channel-width": 80,
"channel": 32
}
],
"interfaces": [
{
"name": "WAN",
@@ -34,7 +43,21 @@
"lease-count": 100,
"lease-time": "6h"
}
}
},
"ssids": [
{
"name": "Metric",
"wifi-bands": [
"2G"
],
"bss-mode": "ap",
"encryption": {
"proto": "psk2",
"key": "OpenWifi",
"ieee80211w": "optional"
}
}
]
}
],
"metrics": {

View File

@@ -0,0 +1,138 @@
{
"uuid": 2,
"globals": {
"wireless-multimedia": {
"profile": "rfc8325"
}
},
"radios": [
{
"band": "2G",
"country": "CA",
"channel-mode": "HE",
"channel-width": 80,
"channel": 32
}
],
"interfaces": [
{
"name": "WAN",
"role": "upstream",
"services": [ "lldp" ],
"ethernet": [
{
"select-ports": [
"WAN*"
]
}
],
"ipv4": {
"addressing": "dynamic"
},
"ssids": [
{
"name": "OpenWifi",
"wifi-bands": [
"2G"
],
"bss-mode": "ap",
"encryption": {
"proto": "psk2",
"key": "OpenWifi",
"ieee80211w": "optional"
}
}
]
},
{
"name": "LAN",
"role": "downstream",
"services": [ "ssh", "lldp" ],
"ethernet": [
{
"select-ports": [
"LAN*"
]
}
],
"ipv4": {
"addressing": "static",
"subnet": "192.168.1.1/24",
"dhcp": {
"lease-first": 10,
"lease-count": 100,
"lease-time": "6h"
}
},
"ssids": [
{
"name": "OpenWifi",
"wifi-bands": [
"2G"
],
"bss-mode": "ap",
"encryption": {
"proto": "psk2",
"key": "OpenWifi",
"ieee80211w": "optional"
}
}
]
}
],
"metrics": {
"statistics": {
"interval": 120,
"types": [ "ssids", "lldp", "clients" ]
},
"health": {
"interval": 120
}
},
"services": {
"lldp": {
"describe": "uCentral",
"location": "universe"
},
"ssh": {
"port": 22
},
"quality-of-service": {
"select-ports": [ "WAN" ],
"bandwidth_up": 1000,
"bandwidth_down": 1000,
"bulk-detection": {
"dscp": "CS1",
"packets-per-second": 500
},
"classifier": [
{
"dscp": "CS1",
"ports": [
{ "protocol": "any", "port": 53 },
{ "protocol": "tcp", "port": 80 }
],
"dns": [
{ "fqdn": "telecominfraproject.com", "suffix-matching": false }
]
}, {
"dscp": "AF41",
"dns": [
{ "fqdn": "zoom.us" }
]
}
]
},
"airtime-fairness": {
"voice-weight": 4,
"packet-threshold": 100,
"bulk-threshold": 50,
"priority-threshold": 30,
"weight-normal": 256,
"weight-priority": 384,
"weight-bulk": 128
}
}
}

View File

@@ -0,0 +1,94 @@
{
"uuid": 2,
"ethernet": [
{
"select-ports": [
"WAN1"
],
"speed": 100,
"duplex": "half"
},
{
"select-ports": [
"WAN2"
],
"speed": 1000,
"duplex": "full"
},
{
"select-ports": [
"WAN3"
],
"speed": 100,
"duplex": "half"
}
],
"interfaces": [
{
"name": "WAN100",
"role": "upstream",
"services": [ "lldp", "ssh" ],
"ethernet": [
{
"select-ports": [
"WAN1", "WAN2", "WAN3"
],
"vlan-tag": "un-tagged"
}, {
"select-ports": [
"WAN7", "WAN8"
]
}
],
"vlan": {
"id": 100
},
"ipv4": {
"addressing": "dynamic"
}
},
{
"name": "WAN200",
"role": "upstream",
"services": [ "lldp", "ssh" ],
"ethernet": [
{
"select-ports": [
"WAN4", "WAN5", "WAN6"
],
"vlan-tag": "un-tagged"
}, {
"select-ports": [
"WAN7", "WAN8"
]
}
],
"vlan": {
"id": 101
},
"ipv4": {
"addressing": "dynamic"
}
}
],
"metrics": {
"statistics": {
"interval": 120,
"types": [ "ssids", "lldp", "clients" ]
},
"health": {
"interval": 120
}
},
"services": {
"lldp": {
"describe": "uCentral",
"location": "universe"
},
"ssh": {
"port": 22
}
}
}

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