mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-10-29 09:32:34 +00:00
Compare commits
127 Commits
v2.2.0-rc1
...
v2.4.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02c0af4bb4 | ||
|
|
8c987c4949 | ||
|
|
a686beebbb | ||
|
|
ec8d056cc8 | ||
|
|
1d4b8ab7ff | ||
|
|
f87960eadc | ||
|
|
769e8c5c0b | ||
|
|
04c3325710 | ||
|
|
7c1fd79ceb | ||
|
|
1e950be127 | ||
|
|
5fc7ac166a | ||
|
|
87be030169 | ||
|
|
b0688f097b | ||
|
|
ae77be4e5c | ||
|
|
efac512c90 | ||
|
|
bcde3ee6d7 | ||
|
|
7b0ef7f265 | ||
|
|
670f9fee14 | ||
|
|
4c7ee4bf6d | ||
|
|
90868338c7 | ||
|
|
7a20f558e1 | ||
|
|
9b8c1f8449 | ||
|
|
002880c3fa | ||
|
|
3de5c91e6c | ||
|
|
679e20af39 | ||
|
|
191081e46f | ||
|
|
8f7a66f1ac | ||
|
|
c93b14ca7a | ||
|
|
16176a1cc3 | ||
|
|
a4806f740d | ||
|
|
35740f321d | ||
|
|
74c148e905 | ||
|
|
a77d881147 | ||
|
|
065539bbb3 | ||
|
|
e2d90a7b06 | ||
|
|
8bb9816e2b | ||
|
|
9673329c07 | ||
|
|
2571ae5210 | ||
|
|
8caffe46b4 | ||
|
|
25641d5199 | ||
|
|
2b3cc2a5cf | ||
|
|
12cc29265c | ||
|
|
34a6f06bd9 | ||
|
|
c343d5e629 | ||
|
|
501907eeda | ||
|
|
ba406fe01b | ||
|
|
d61d5cd35e | ||
|
|
68d544c9af | ||
|
|
5d86871253 | ||
|
|
460785cbe3 | ||
|
|
1cace058c5 | ||
|
|
5aaf734732 | ||
|
|
9d3768a68d | ||
|
|
975aae507b | ||
|
|
cc0576886a | ||
|
|
9c36b155f6 | ||
|
|
28ac14ccc4 | ||
|
|
e18e7fc8f6 | ||
|
|
04d78d3334 | ||
|
|
a9fd11ed8a | ||
|
|
839f43c010 | ||
|
|
f599a42618 | ||
|
|
8bc7bee3bc | ||
|
|
53004cc39c | ||
|
|
9a1c8cff9f | ||
|
|
2d0e2bccbf | ||
|
|
70c2c36e0f | ||
|
|
11ed0b089c | ||
|
|
29058df59b | ||
|
|
e840bab8cc | ||
|
|
e3e3c9ea72 | ||
|
|
a3125e6ab2 | ||
|
|
63e8b90656 | ||
|
|
70f231d948 | ||
|
|
2983d9ca2b | ||
|
|
2283a64e57 | ||
|
|
1a3054218f | ||
|
|
7d26b55cb5 | ||
|
|
cd85723609 | ||
|
|
6d922da9b8 | ||
|
|
6b81555bb2 | ||
|
|
267157563e | ||
|
|
6505ca0a8f | ||
|
|
5cafdaea60 | ||
|
|
4a3d4f5609 | ||
|
|
3085dc78ef | ||
|
|
897ab17137 | ||
|
|
840319e24f | ||
|
|
00197d703e | ||
|
|
a290ad3764 | ||
|
|
972eea34eb | ||
|
|
851507921a | ||
|
|
b364ab3064 | ||
|
|
45143cc2c9 | ||
|
|
895e501b93 | ||
|
|
7d9594c3c8 | ||
|
|
485c689408 | ||
|
|
ec2e24e982 | ||
|
|
32f86e2d77 | ||
|
|
53e73b24de | ||
|
|
e57dad9009 | ||
|
|
01c3ce4fc7 | ||
|
|
6b3d2b8059 | ||
|
|
ba079bea9f | ||
|
|
f971f3a4d4 | ||
|
|
32524c19bd | ||
|
|
966353e747 | ||
|
|
37f30d95f8 | ||
|
|
e699bebac7 | ||
|
|
0e5ec91a12 | ||
|
|
3cad34e1b9 | ||
|
|
2c37a6983f | ||
|
|
330eead632 | ||
|
|
f1456f321a | ||
|
|
9152942d93 | ||
|
|
f202250a68 | ||
|
|
fad14af474 | ||
|
|
5a7bafede0 | ||
|
|
6738a933ab | ||
|
|
a46262aaaa | ||
|
|
2988180211 | ||
|
|
ec0d693d12 | ||
|
|
406dad6604 | ||
|
|
b31b236646 | ||
|
|
0c379ed26c | ||
|
|
647d5c8a33 | ||
|
|
7baf962bb8 |
15
.github/workflows/build-dev.yml
vendored
15
.github/workflows/build-dev.yml
vendored
@@ -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', 'indio_um-305ac', 'linksys_ea6350-v4', 'linksys_e8450-ubi', 'linksys_ea8300', 'tp-link_ec420-g1', 'tplink_ex227', 'tplink_ex228', 'tplink_ex447', 'wallys_dr40x9', 'wallys_dr6018', 'wallys_dr6018_v4' ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@@ -61,3 +61,16 @@ jobs:
|
||||
|
||||
[ -f openwrt/tmp/image-file ] && aws s3 cp --acl public-read --content-type "application/octet-stream" "openwrt/$(cat openwrt/tmp/image-file)" "s3://$AWS_S3_BUCKET_NAME/$IMG_NAME"
|
||||
[ -f openwrt/tmp/image-file ] && aws s3 cp --acl public-read --content-type "application/json" "latest-upgrade.json" "s3://$AWS_S3_BUCKET_NAME/$JSON_NAME"
|
||||
|
||||
trigger-testing:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
steps:
|
||||
- name: Trigger testing of release
|
||||
uses: peter-evans/repository-dispatch@v1
|
||||
with:
|
||||
token: ${{ secrets.WLAN_TESTING_PAT }}
|
||||
repository: Telecominfraproject/wlan-testing
|
||||
event-type: new-ap-release
|
||||
client-payload: '{"ref": "${GITHUB_REF#refs/tags/}", "sha": "${{ github.sha }}"}'
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
From 85aa45ef0dc90e50e9ac0931fd2a8c99c764e101 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..276633cfa7 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..276633cfa7 100644
|
||||
-PKG_SOURCE_DATE:=2021-07-26
|
||||
-PKG_SOURCE_VERSION:=440eb0647708274cc8d7d9e7c2bb0cfdfba90023
|
||||
-PKG_MIRROR_HASH:=eed957036ab608fdc49bdf801fc5b4405fcd2a3a5e5d3343ec39898e156c10e9
|
||||
+PKG_SOURCE_DATE:=2021-09-01
|
||||
+PKG_SOURCE_VERSION:=5a4ac30c7a15712d01110befec1acfe86c2cbed0
|
||||
+PKG_MIRROR_HASH:=888d40c88997a628be2a6d7f7a1de1c7fed742f4c19312c52cdf5a72b26a96af
|
||||
+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..276633cfa7 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
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
From 4381103753770dab05cb94045a60573e4863fca5 Mon Sep 17 00:00:00 2001
|
||||
From 3feca6da7b0571cf17afc9f0e40d0ede9059c271 Mon Sep 17 00:00:00 2001
|
||||
From: John Crispin <john@phrozen.org>
|
||||
Date: Sat, 4 Sep 2021 05:47:27 +0200
|
||||
Subject: [PATCH 01/53] mac80211: update to latest HEAD
|
||||
Subject: [PATCH 01/72] mac80211: update to latest HEAD
|
||||
|
||||
Signed-off-by: John Crispin <john@phrozen.org>
|
||||
---
|
||||
@@ -9,7 +9,7 @@ Signed-off-by: John Crispin <john@phrozen.org>
|
||||
package/kernel/mac80211/ath.mk | 5 +-
|
||||
package/kernel/mac80211/broadcom.mk | 4 +-
|
||||
.../mac80211/files/lib/netifd/mac80211.sh | 36 -
|
||||
.../files/lib/netifd/wireless/mac80211.sh | 184 ++-
|
||||
.../files/lib/netifd/wireless/mac80211.sh | 214 ++-
|
||||
.../mac80211/files/lib/wifi/mac80211.sh | 110 +-
|
||||
.../patches/ath/120-owl-loader-compat.patch | 53 -
|
||||
.../patches/ath/402-ath_regd_optional.patch | 2 +-
|
||||
@@ -75,7 +75,7 @@ Signed-off-by: John Crispin <john@phrozen.org>
|
||||
...eck-per-vif-offload_flags-in-Tx-path.patch | 26 +
|
||||
.../500-mac80211_configure_antenna_gain.patch | 16 +-
|
||||
...the-dst-buffer-to-of_get_mac_address.patch | 237 +++
|
||||
70 files changed, 2751 insertions(+), 1159 deletions(-)
|
||||
70 files changed, 2777 insertions(+), 1163 deletions(-)
|
||||
delete mode 100644 package/kernel/mac80211/files/lib/netifd/mac80211.sh
|
||||
delete mode 100644 package/kernel/mac80211/patches/ath/120-owl-loader-compat.patch
|
||||
rename package/kernel/mac80211/patches/{ath => ath10k}/080-ath10k_thermal_config.patch (97%)
|
||||
@@ -286,7 +286,7 @@ index 92e5c0e395..0000000000
|
||||
- done
|
||||
-}
|
||||
diff --git a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
|
||||
index 9a9c35fb5f..a58af1fef0 100644
|
||||
index 9a9c35fb5f..97c567031e 100644
|
||||
--- a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
|
||||
+++ b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
|
||||
@@ -1,7 +1,6 @@
|
||||
@@ -310,7 +310,7 @@ index 9a9c35fb5f..a58af1fef0 100644
|
||||
config_add_boolean noscan ht_coex acs_exclude_dfs
|
||||
config_add_array ht_capab
|
||||
config_add_array channels
|
||||
@@ -44,11 +43,24 @@ drv_mac80211_init_device_config() {
|
||||
@@ -44,11 +43,26 @@ drv_mac80211_init_device_config() {
|
||||
su_beamformee \
|
||||
mu_beamformer \
|
||||
mu_beamformee \
|
||||
@@ -326,6 +326,8 @@ index 9a9c35fb5f..a58af1fef0 100644
|
||||
+ he_spr_sr_control \
|
||||
+ he_twt_required
|
||||
+ config_add_int \
|
||||
+ beamformer_antennas \
|
||||
+ beamformee_antennas \
|
||||
+ vht_max_a_mpdu_len_exp \
|
||||
+ vht_max_mpdu \
|
||||
+ vht_link_adapt \
|
||||
@@ -337,7 +339,7 @@ index 9a9c35fb5f..a58af1fef0 100644
|
||||
config_add_boolean \
|
||||
ldpc \
|
||||
greenfield \
|
||||
@@ -96,6 +108,23 @@ mac80211_add_capabilities() {
|
||||
@@ -96,6 +110,23 @@ mac80211_add_capabilities() {
|
||||
export -n -- "$__var=$__out"
|
||||
}
|
||||
|
||||
@@ -361,7 +363,7 @@ index 9a9c35fb5f..a58af1fef0 100644
|
||||
mac80211_hostapd_setup_base() {
|
||||
local phy="$1"
|
||||
|
||||
@@ -119,6 +148,9 @@ mac80211_hostapd_setup_base() {
|
||||
@@ -119,6 +150,9 @@ mac80211_hostapd_setup_base() {
|
||||
[ "$noscan" -gt 0 ] && hostapd_noscan=1
|
||||
[ "$tx_burst" = 0 ] && tx_burst=
|
||||
|
||||
@@ -371,7 +373,7 @@ index 9a9c35fb5f..a58af1fef0 100644
|
||||
ieee80211n=1
|
||||
ht_capab=
|
||||
case "$htmode" in
|
||||
@@ -126,7 +158,7 @@ mac80211_hostapd_setup_base() {
|
||||
@@ -126,7 +160,7 @@ mac80211_hostapd_setup_base() {
|
||||
HT40*|VHT40|VHT80|VHT160|HE40|HE80|HE160)
|
||||
case "$hwmode" in
|
||||
a)
|
||||
@@ -380,7 +382,7 @@ index 9a9c35fb5f..a58af1fef0 100644
|
||||
1) ht_capab="[HT40+]";;
|
||||
0) ht_capab="[HT40-]";;
|
||||
esac
|
||||
@@ -200,7 +232,7 @@ mac80211_hostapd_setup_base() {
|
||||
@@ -200,7 +234,7 @@ mac80211_hostapd_setup_base() {
|
||||
case "$htmode" in
|
||||
VHT20|HE20) enable_ac=1;;
|
||||
VHT40|HE40)
|
||||
@@ -389,7 +391,7 @@ index 9a9c35fb5f..a58af1fef0 100644
|
||||
1) idx=$(($channel + 2));;
|
||||
0) idx=$(($channel - 2));;
|
||||
esac
|
||||
@@ -208,7 +240,7 @@ mac80211_hostapd_setup_base() {
|
||||
@@ -208,7 +242,7 @@ mac80211_hostapd_setup_base() {
|
||||
vht_center_seg0=$idx
|
||||
;;
|
||||
VHT80|HE80)
|
||||
@@ -398,7 +400,7 @@ index 9a9c35fb5f..a58af1fef0 100644
|
||||
1) idx=$(($channel + 6));;
|
||||
2) idx=$(($channel + 2));;
|
||||
3) idx=$(($channel - 2));;
|
||||
@@ -219,15 +251,35 @@ mac80211_hostapd_setup_base() {
|
||||
@@ -219,15 +253,35 @@ mac80211_hostapd_setup_base() {
|
||||
vht_center_seg0=$idx
|
||||
;;
|
||||
VHT160|HE160)
|
||||
@@ -438,7 +440,35 @@ index 9a9c35fb5f..a58af1fef0 100644
|
||||
[ "$hwmode" = "a" ] || enable_ac=0
|
||||
|
||||
if [ "$enable_ac" != "0" ]; then
|
||||
@@ -337,16 +389,62 @@ mac80211_hostapd_setup_base() {
|
||||
@@ -242,6 +296,8 @@ mac80211_hostapd_setup_base() {
|
||||
mu_beamformee:1 \
|
||||
vht_txop_ps:1 \
|
||||
htc_vht:1 \
|
||||
+ beamformee_antennas:4 \
|
||||
+ beamformer_antennas:4 \
|
||||
rx_antenna_pattern:1 \
|
||||
tx_antenna_pattern:1 \
|
||||
vht_max_a_mpdu_len_exp:7 \
|
||||
@@ -282,6 +338,18 @@ mac80211_hostapd_setup_base() {
|
||||
RX-STBC-123:0x700:0x300:1 \
|
||||
RX-STBC-1234:0x700:0x400:1 \
|
||||
|
||||
+ [ "$(($vht_cap & 0x800))" -gt 0 -a "$su_beamformer" -gt 0 ] && {
|
||||
+ cap_ant="$(( ( ($vht_cap >> 16) & 3 ) + 1 ))"
|
||||
+ [ "$cap_ant" -gt "$beamformer_antennas" ] && cap_ant="$beamformer_antennas"
|
||||
+ [ "$cap_ant" -gt 1 ] && vht_capab="$vht_capab[SOUNDING-DIMENSION-$cap_ant]"
|
||||
+ }
|
||||
+
|
||||
+ [ "$(($vht_cap & 0x1000))" -gt 0 -a "$su_beamformee" -gt 0 ] && {
|
||||
+ cap_ant="$(( ( ($vht_cap >> 13) & 3 ) + 1 ))"
|
||||
+ [ "$cap_ant" -gt "$beamformee_antennas" ] && cap_ant="$beamformee_antennas"
|
||||
+ [ "$cap_ant" -gt 1 ] && vht_capab="$vht_capab[BF-ANTENNA-$cap_ant]"
|
||||
+ }
|
||||
+
|
||||
# supported Channel widths
|
||||
vht160_hw=0
|
||||
[ "$(($vht_cap & 12))" -eq 4 -a 1 -le "$vht160" ] && \
|
||||
@@ -337,16 +405,62 @@ mac80211_hostapd_setup_base() {
|
||||
esac
|
||||
|
||||
if [ "$enable_ax" != "0" ]; then
|
||||
@@ -504,9 +534,23 @@ index 9a9c35fb5f..a58af1fef0 100644
|
||||
fi
|
||||
|
||||
hostapd_prepare_device_config "$hostapd_conf_file" nl80211
|
||||
@@ -426,7 +524,11 @@ mac80211_generate_mac() {
|
||||
local oIFS="$IFS"; IFS=":"; set -- $ref; IFS="$oIFS"
|
||||
@@ -401,6 +515,7 @@ mac80211_get_addr() {
|
||||
|
||||
mac80211_generate_mac() {
|
||||
local phy="$1"
|
||||
+ local multiple_bssid="$2"
|
||||
local id="${macidx:-0}"
|
||||
|
||||
local ref="$(cat /sys/class/ieee80211/${phy}/macaddress)"
|
||||
@@ -424,9 +539,16 @@ mac80211_generate_mac() {
|
||||
local mask6=$6
|
||||
|
||||
local oIFS="$IFS"; IFS=":"; set -- $ref; IFS="$oIFS"
|
||||
-
|
||||
+ [ "$multiple_bssid" -eq 1 ] && {
|
||||
+ printf "02:%s:%s:%s:%s:%02x" $b1 $2 $3 $4 $5 $macidx
|
||||
+ return
|
||||
+ }
|
||||
macidx=$(($id + 1))
|
||||
- [ "$((0x$mask1))" -gt 0 ] && {
|
||||
+
|
||||
@@ -517,7 +561,7 @@ index 9a9c35fb5f..a58af1fef0 100644
|
||||
b1="0x$1"
|
||||
[ "$id" -gt 0 ] && \
|
||||
b1=$(($b1 ^ ((($id - !($b1 & 2)) << 2)) | 0x2))
|
||||
@@ -434,7 +536,7 @@ mac80211_generate_mac() {
|
||||
@@ -434,7 +556,7 @@ mac80211_generate_mac() {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -526,7 +570,7 @@ index 9a9c35fb5f..a58af1fef0 100644
|
||||
printf "%s:%s:%s:%s:%s:%02x" $1 $2 $3 $4 $5 $(( 0x$6 ^ $id ))
|
||||
return
|
||||
}
|
||||
@@ -449,7 +551,7 @@ mac80211_generate_mac() {
|
||||
@@ -449,7 +571,7 @@ mac80211_generate_mac() {
|
||||
find_phy() {
|
||||
[ -n "$phy" -a -d /sys/class/ieee80211/$phy ] && return 0
|
||||
[ -n "$path" ] && {
|
||||
@@ -535,7 +579,30 @@ index 9a9c35fb5f..a58af1fef0 100644
|
||||
[ -n "$phy" ] && return 0
|
||||
}
|
||||
[ -n "$macaddr" ] && {
|
||||
@@ -689,14 +791,8 @@ mac80211_prepare_iw_htmode() {
|
||||
@@ -528,11 +650,12 @@ mac80211_iw_interface_add() {
|
||||
rc="$?"
|
||||
}
|
||||
|
||||
- [ "$rc" != 0 ] && wireless_setup_failed INTERFACE_CREATION_FAILED
|
||||
+ [ "$rc" != 0 ] && echo "Failed to create interface $ifname"
|
||||
return $rc
|
||||
}
|
||||
|
||||
mac80211_prepare_vif() {
|
||||
+ local multiple_bssid=$1
|
||||
json_select config
|
||||
|
||||
json_get_vars ifname mode ssid wds powersave macaddr enable wpa_psk_file vlan_file
|
||||
@@ -546,7 +669,7 @@ mac80211_prepare_vif() {
|
||||
json_select ..
|
||||
|
||||
[ -n "$macaddr" ] || {
|
||||
- macaddr="$(mac80211_generate_mac $phy)"
|
||||
+ macaddr="$(mac80211_generate_mac $phy $multiple_bssid)"
|
||||
macidx="$(($macidx + 1))"
|
||||
}
|
||||
|
||||
@@ -689,14 +812,8 @@ mac80211_prepare_iw_htmode() {
|
||||
case "$htmode" in
|
||||
VHT20|HT20) iw_htmode=HT20;;
|
||||
HT40*|VHT40|VHT160)
|
||||
@@ -552,7 +619,7 @@ index 9a9c35fb5f..a58af1fef0 100644
|
||||
case "$htmode" in
|
||||
HT40+) iw_htmode="HT40+";;
|
||||
HT40-) iw_htmode="HT40-";;
|
||||
@@ -709,6 +805,12 @@ mac80211_prepare_iw_htmode() {
|
||||
@@ -709,6 +826,12 @@ mac80211_prepare_iw_htmode() {
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
@@ -565,7 +632,7 @@ index 9a9c35fb5f..a58af1fef0 100644
|
||||
esac
|
||||
[ "$auto_channel" -gt 0 ] && iw_htmode="HT40+"
|
||||
;;
|
||||
@@ -818,7 +920,6 @@ mac80211_setup_vif() {
|
||||
@@ -818,7 +941,6 @@ mac80211_setup_vif() {
|
||||
mesh)
|
||||
wireless_vif_parse_encryption
|
||||
[ -z "$htmode" ] && htmode="NOHT";
|
||||
@@ -573,7 +640,7 @@ index 9a9c35fb5f..a58af1fef0 100644
|
||||
if [ "$wpa" -gt 0 -o "$auto_channel" -gt 0 ] || chan_is_dfs "$phy" "$channel"; then
|
||||
mac80211_setup_supplicant $vif_enable || failed=1
|
||||
else
|
||||
@@ -832,7 +933,6 @@ mac80211_setup_vif() {
|
||||
@@ -832,7 +954,6 @@ mac80211_setup_vif() {
|
||||
adhoc)
|
||||
wireless_vif_parse_encryption
|
||||
if [ "$wpa" -gt 0 -o "$auto_channel" -gt 0 ]; then
|
||||
@@ -581,7 +648,7 @@ index 9a9c35fb5f..a58af1fef0 100644
|
||||
mac80211_setup_supplicant_noctl $vif_enable || failed=1
|
||||
else
|
||||
mac80211_setup_adhoc $vif_enable
|
||||
@@ -849,10 +949,30 @@ mac80211_setup_vif() {
|
||||
@@ -849,10 +970,30 @@ mac80211_setup_vif() {
|
||||
|
||||
get_freq() {
|
||||
local phy="$1"
|
||||
@@ -614,17 +681,18 @@ index 9a9c35fb5f..a58af1fef0 100644
|
||||
chan_is_dfs() {
|
||||
local phy="$1"
|
||||
local chan="$2"
|
||||
@@ -896,7 +1016,8 @@ drv_mac80211_setup() {
|
||||
@@ -896,7 +1037,9 @@ drv_mac80211_setup() {
|
||||
country chanbw distance \
|
||||
txpower antenna_gain \
|
||||
rxantenna txantenna \
|
||||
- frag rts beacon_int:100 htmode
|
||||
+ frag rts beacon_int:100 htmode \
|
||||
+ multiple_bssid:0 \
|
||||
+ num_global_macaddr
|
||||
json_get_values basic_rate_list basic_rate
|
||||
json_get_values scan_list scan_list
|
||||
json_select ..
|
||||
@@ -933,7 +1054,7 @@ drv_mac80211_setup() {
|
||||
@@ -933,7 +1076,7 @@ drv_mac80211_setup() {
|
||||
done
|
||||
|
||||
# convert channel to frequency
|
||||
@@ -633,7 +701,7 @@ index 9a9c35fb5f..a58af1fef0 100644
|
||||
|
||||
[ -n "$country" ] && {
|
||||
iw reg get | grep -q "^country $country:" || {
|
||||
@@ -958,6 +1079,7 @@ drv_mac80211_setup() {
|
||||
@@ -958,6 +1101,7 @@ drv_mac80211_setup() {
|
||||
set_default txantenna 0xffffffff
|
||||
set_default distance 0
|
||||
set_default antenna_gain 0
|
||||
@@ -641,6 +709,15 @@ index 9a9c35fb5f..a58af1fef0 100644
|
||||
|
||||
[ "$txantenna" = "all" ] && txantenna=0xffffffff
|
||||
[ "$rxantenna" = "all" ] && rxantenna=0xffffffff
|
||||
@@ -989,7 +1133,7 @@ drv_mac80211_setup() {
|
||||
mac80211_prepare_iw_htmode
|
||||
for_each_interface "sta adhoc mesh monitor" mac80211_prepare_vif
|
||||
NEWAPLIST=
|
||||
- for_each_interface "ap" mac80211_prepare_vif
|
||||
+ for_each_interface "ap" mac80211_prepare_vif ${multiple_bssid}
|
||||
NEW_MD5=$(test -e "${hostapd_conf_file}" && md5sum ${hostapd_conf_file})
|
||||
OLD_MD5=$(uci -q -P /var/state get wireless._${phy}.md5)
|
||||
if [ "${NEWAPLIST}" != "${OLDAPLIST}" ]; then
|
||||
diff --git a/package/kernel/mac80211/files/lib/wifi/mac80211.sh b/package/kernel/mac80211/files/lib/wifi/mac80211.sh
|
||||
index 3e99f06693..6aa46b0c74 100644
|
||||
--- a/package/kernel/mac80211/files/lib/wifi/mac80211.sh
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
35
backports/0031-ubus-update-to-the-latest-version.patch
Normal file
35
backports/0031-ubus-update-to-the-latest-version.patch
Normal 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
|
||||
|
||||
34
backports/0032-rpcd-bump-to-git-HEAD.patch
Normal file
34
backports/0032-rpcd-bump-to-git-HEAD.patch
Normal 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
|
||||
|
||||
@@ -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
|
||||
|
||||
29
backports/0051-bpf-headers-unset-PKG_CONFIG_PATH.patch
Normal file
29
backports/0051-bpf-headers-unset-PKG_CONFIG_PATH.patch
Normal 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
26
backports/0055-include-bpf.mk-fix-typo.patch
Normal file
26
backports/0055-include-bpf.mk-fix-typo.patch
Normal 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
|
||||
|
||||
@@ -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
|
||||
|
||||
34
backports/0057-include-bpf.mk-add-LD_LIBRARY_PATH.patch
Normal file
34
backports/0057-include-bpf.mk-add-LD_LIBRARY_PATH.patch
Normal 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
|
||||
|
||||
1088
backports/0058-kernel-backport-napi-threading-patches.patch
Normal file
1088
backports/0058-kernel-backport-napi-threading-patches.patch
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -36,7 +36,7 @@ URL="https://api.fbwifi.com/v2.0/tokens"
|
||||
BODY=string.format(
|
||||
"tokens=%s&traffic_type=%s&config_version=%s",
|
||||
json.encode(request.tokens),
|
||||
"'total'",
|
||||
"total",
|
||||
state:get("fbwifi", "main", "config_version")
|
||||
)
|
||||
|
||||
@@ -2,35 +2,43 @@ Index: qca-ssdk/include/hsl/phy/hsl_phy.h
|
||||
===================================================================
|
||||
--- qca-ssdk.orig/include/hsl/phy/hsl_phy.h
|
||||
+++ qca-ssdk/include/hsl/phy/hsl_phy.h
|
||||
@@ -541,6 +541,7 @@ typedef struct {
|
||||
@@ -562,6 +562,7 @@ typedef struct {
|
||||
#define QCA8033_PHY 0x004DD074
|
||||
#define QCA8035_PHY 0x004DD072
|
||||
/*qca808x_start*/
|
||||
+#define QCA8081_PHY 0x004DD100
|
||||
#define QCA8081_PHY_V1_1 0x004DD101
|
||||
#define INVALID_PHY_ID 0
|
||||
#define INVALID_PHY_ID 0xFFFFFFFF
|
||||
|
||||
@@ -559,6 +560,7 @@ typedef struct {
|
||||
@@ -576,11 +577,14 @@ typedef struct {
|
||||
#define AQUANTIA_PHY_109 0x03a1b502
|
||||
#define AQUANTIA_PHY_111 0x03a1b610
|
||||
#define AQUANTIA_PHY_111B0 0x03a1b612
|
||||
+#define AQUANTIA_PHY_111C 0x03a1b7e2
|
||||
#define AQUANTIA_PHY_112 0x03a1b660
|
||||
#define AQUANTIA_PHY_113C_A0 0x31c31C10
|
||||
#define AQUANTIA_PHY_113C_A1 0x31c31C11
|
||||
#define AQUANTIA_PHY_112C 0x03a1b792
|
||||
+#define AQUANTIA_PHY_114C 0x31c31C22
|
||||
|
||||
+#define AQUANTIA_PHY_114C 0x31c31C22
|
||||
+
|
||||
#define PHY_805XV2 0x004DD082
|
||||
#define PHY_805XV1 0x004DD081
|
||||
/*qca808x_start*/
|
||||
Index: qca-ssdk/src/hsl/phy/hsl_phy.c
|
||||
===================================================================
|
||||
--- qca-ssdk.orig/src/hsl/phy/hsl_phy.c
|
||||
+++ qca-ssdk/src/hsl/phy/hsl_phy.c
|
||||
@@ -231,6 +231,7 @@ phy_type_t hsl_phytype_get_by_phyid(a_ui
|
||||
@@ -231,6 +231,8 @@ phy_type_t hsl_phytype_get_by_phyid(a_ui
|
||||
case AQUANTIA_PHY_108:
|
||||
case AQUANTIA_PHY_109:
|
||||
case AQUANTIA_PHY_111:
|
||||
+ case AQUANTIA_PHY_111C:
|
||||
+ case AQUANTIA_PHY_114C:
|
||||
case AQUANTIA_PHY_111B0:
|
||||
case AQUANTIA_PHY_112:
|
||||
case AQUANTIA_PHY_113C_A0:
|
||||
@@ -250,6 +251,7 @@ phy_type_t hsl_phytype_get_by_phyid(a_ui
|
||||
@@ -250,6 +252,7 @@ phy_type_t hsl_phytype_get_by_phyid(a_ui
|
||||
phytype = MPGE_PHY_CHIP;
|
||||
break;
|
||||
/*qca808x_start*/
|
||||
|
||||
14
feeds/ipq807x/qca-ssdk/patches/200-eap101.patch
Normal file
14
feeds/ipq807x/qca-ssdk/patches/200-eap101.patch
Normal file
@@ -0,0 +1,14 @@
|
||||
diff --git a/src/hsl/phy/hsl_phy.c b/src/hsl/phy/hsl_phy.c
|
||||
index 5866a522..41227581 100755
|
||||
--- a/src/hsl/phy/hsl_phy.c
|
||||
+++ b/src/hsl/phy/hsl_phy.c
|
||||
@@ -608,6 +608,9 @@ hsl_port_phyid_get(a_uint32_t dev_id, fal_port_t port_id)
|
||||
return INVALID_PHY_ID;
|
||||
}
|
||||
|
||||
+ if (phy_id == MALIBU5PORT_PHY && of_machine_is_compatible("edgecore,eap101"))
|
||||
+ phy_id = MALIBU2PORT_PHY;
|
||||
+
|
||||
return phy_id;
|
||||
}
|
||||
|
||||
@@ -230,6 +230,8 @@ IN_SFP_PHY=TRUE
|
||||
IN_MALIBU_PHY=TRUE
|
||||
else ifeq (CPPE, $(CHIP_TYPE))
|
||||
IN_QCA808X_PHY=TRUE
|
||||
IN_QCA803X_PHY=TRUE
|
||||
IN_SFP_PHY=TRUE
|
||||
IN_PHY_I2C_MODE=TRUE
|
||||
IN_MALIBU_PHY=TRUE
|
||||
else ifeq (DESS, $(CHIP_TYPE))
|
||||
|
||||
@@ -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*
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -21,3 +21,4 @@ config chilli
|
||||
option kname 'chilli'
|
||||
option debug 0
|
||||
EOF
|
||||
/etc/init.d/chilli disable
|
||||
|
||||
@@ -22,6 +22,7 @@ let keys = {
|
||||
nasmac: false,
|
||||
macauth: false,
|
||||
macpassword: false,
|
||||
uamsecret: false,
|
||||
};
|
||||
|
||||
function get_value(key, value) {
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
|
||||
[ "$ACTION" == "ifup" ] || exit 0
|
||||
|
||||
[ "$INTERFACE" = "wan" ] && {
|
||||
[ "$INTERFACE" = "wan" -a "$(uci get chilli.@chilli[-1].disabled)" -neq 0 ] && {
|
||||
/etc/init.d/chilli restart
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
17
feeds/tip/luci/luci-mod-ucentral/Makefile
Normal file
17
feeds/tip/luci/luci-mod-ucentral/Makefile
Normal 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
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
@@ -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
|
||||
});
|
||||
@@ -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
|
||||
});
|
||||
@@ -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
|
||||
});
|
||||
@@ -0,0 +1,138 @@
|
||||
'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.value('wds', _('WiFi WDS uplink'));
|
||||
|
||||
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")';
|
||||
|
||||
o = s.option(form.Value, 'ssid', _('SSID'));
|
||||
o.depends('protocol', 'wds');
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.option(form.Value, 'passphrase', _('Passphrase'));
|
||||
o.depends('protocol', 'wds');
|
||||
o.password = true;
|
||||
o.rmempty = false;
|
||||
o.datatype = "rangelength(8, 31)";
|
||||
|
||||
o = s.option(form.ListValue, 'encryption', _('Encryption'));
|
||||
o.depends('protocol', 'wds');
|
||||
o.value('psk', 'PSK');
|
||||
o.value('psk-mixed', 'PSK-Mixed');
|
||||
o.value('psk2', 'PSK2');
|
||||
o.value('sae', 'SAE');
|
||||
o.value('sae-mixed', 'SAE-Mixed');
|
||||
o.password = true;
|
||||
|
||||
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
|
||||
});
|
||||
426
feeds/tip/luci/luci-mod-ucentral/po/de/ucentral.po
Normal file
426
feeds/tip/luci/luci-mod-ucentral/po/de/ucentral.po
Normal 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"
|
||||
385
feeds/tip/luci/luci-mod-ucentral/po/templates/ucentral.pot
Normal file
385
feeds/tip/luci/luci-mod-ucentral/po/templates/ucentral.pot
Normal 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 ""
|
||||
33
feeds/tip/luci/luci-mod-ucentral/root/sbin/certupdate
Executable file
33
feeds/tip/luci/luci-mod-ucentral/root/sbin/certupdate
Executable 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
|
||||
15
feeds/tip/luci/luci-mod-ucentral/root/sbin/profileupdate
Executable file
15
feeds/tip/luci/luci-mod-ucentral/root/sbin/profileupdate
Executable 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
|
||||
@@ -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" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
14
feeds/tip/luci/luci-theme-ucentral/Makefile
Normal file
14
feeds/tip/luci/luci-theme-ucentral/Makefile
Normal 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
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
});
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -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 |
@@ -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 |
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
294
feeds/tip/luci/luci.mk
Normal 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))))
|
||||
@@ -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
|
||||
|
||||
36
feeds/ucentral/atfpolicy/Makefile
Normal file
36
feeds/ucentral/atfpolicy/Makefile
Normal 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))
|
||||
8
feeds/ucentral/atfpolicy/files/atfpolicy.conf
Normal file
8
feeds/ucentral/atfpolicy/files/atfpolicy.conf
Normal 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
|
||||
57
feeds/ucentral/atfpolicy/files/atfpolicy.init
Normal file
57
feeds/ucentral/atfpolicy/files/atfpolicy.init
Normal 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
|
||||
}
|
||||
15
feeds/ucentral/atfpolicy/src/CMakeLists.txt
Normal file
15
feeds/ucentral/atfpolicy/src/CMakeLists.txt
Normal 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}
|
||||
)
|
||||
90
feeds/ucentral/atfpolicy/src/atf.h
Normal file
90
feeds/ucentral/atfpolicy/src/atf.h
Normal 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
|
||||
108
feeds/ucentral/atfpolicy/src/interface.c
Normal file
108
feeds/ucentral/atfpolicy/src/interface.c
Normal 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);
|
||||
}
|
||||
62
feeds/ucentral/atfpolicy/src/main.c
Normal file
62
feeds/ucentral/atfpolicy/src/main.c
Normal 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;
|
||||
}
|
||||
174
feeds/ucentral/atfpolicy/src/nl80211.c
Normal file
174
feeds/ucentral/atfpolicy/src/nl80211.c
Normal 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");
|
||||
}
|
||||
164
feeds/ucentral/atfpolicy/src/ubus.c
Normal file
164
feeds/ucentral/atfpolicy/src/ubus.c
Normal 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);
|
||||
}
|
||||
52
feeds/ucentral/qosify/Makefile
Normal file
52
feeds/ucentral/qosify/Makefile
Normal 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))
|
||||
BIN
feeds/ucentral/qosify/files/qosify-bpf.o
Normal file
BIN
feeds/ucentral/qosify/files/qosify-bpf.o
Normal file
Binary file not shown.
17
feeds/ucentral/qosify/files/qosify-defaults.conf
Normal file
17
feeds/ucentral/qosify/files/qosify-defaults.conf
Normal 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
|
||||
30
feeds/ucentral/qosify/files/qosify.conf
Normal file
30
feeds/ucentral/qosify/files/qosify.conf
Normal 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
|
||||
|
||||
2
feeds/ucentral/qosify/files/qosify.hotplug
Normal file
2
feeds/ucentral/qosify/files/qosify.hotplug
Normal file
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
ubus call qosify check_devices
|
||||
105
feeds/ucentral/qosify/files/qosify.init
Normal file
105
feeds/ucentral/qosify/files/qosify.init
Normal 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
|
||||
}
|
||||
15
feeds/ucentral/qosify/src/CMakeLists.txt
Normal file
15
feeds/ucentral/qosify/src/CMakeLists.txt
Normal 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}
|
||||
)
|
||||
112
feeds/ucentral/qosify/src/README
Normal file
112
feeds/ucentral/qosify/src/README
Normal 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
|
||||
563
feeds/ucentral/qosify/src/interface.c
Normal file
563
feeds/ucentral/qosify/src/interface.c
Normal 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);
|
||||
}
|
||||
|
||||
121
feeds/ucentral/qosify/src/loader.c
Normal file
121
feeds/ucentral/qosify/src/loader.c
Normal 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;
|
||||
}
|
||||
72
feeds/ucentral/qosify/src/main.c
Normal file
72
feeds/ucentral/qosify/src/main.c
Normal 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;
|
||||
}
|
||||
735
feeds/ucentral/qosify/src/map.c
Normal file
735
feeds/ucentral/qosify/src/map.c
Normal 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);
|
||||
}
|
||||
464
feeds/ucentral/qosify/src/qosify-bpf.c
Normal file
464
feeds/ucentral/qosify/src/qosify-bpf.c
Normal 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";
|
||||
39
feeds/ucentral/qosify/src/qosify-bpf.h
Normal file
39
feeds/ucentral/qosify/src/qosify-bpf.h
Normal 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
|
||||
95
feeds/ucentral/qosify/src/qosify.h
Normal file
95
feeds/ucentral/qosify/src/qosify.h
Normal 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
|
||||
416
feeds/ucentral/qosify/src/ubus.c
Normal file
416
feeds/ucentral/qosify/src/ubus.c
Normal 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;
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -146,7 +151,7 @@ addiface() {
|
||||
waitiface() {
|
||||
local iface=$1
|
||||
|
||||
ubus -t 75 wait_for hostapd.$1
|
||||
ubus -t 120 wait_for hostapd.$1
|
||||
|
||||
[ $? -eq 0 ] || exit 0
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
14
feeds/ucentral/ucentral-client/files/etc/init.d/ucentral-wdt
Executable file
14
feeds/ucentral/ucentral-client/files/etc/init.d/ucentral-wdt
Executable 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
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user