mirror of
https://dev.iopsys.eu/feed/iopsys.git
synced 2025-12-10 07:44:50 +01:00
Compare commits
17 commits
0f69b8d28f
...
7161c0afeb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7161c0afeb | ||
|
|
5c514051a2 | ||
|
|
9101095a0a | ||
|
|
2bd4c0c236 | ||
|
|
61bda623ca | ||
|
|
e2eaf6221a | ||
|
|
82183e9e3b | ||
|
|
edfbcb1074 | ||
|
|
5af1df3493 | ||
|
|
3ec6c21456 | ||
|
|
9d251b5d9d | ||
|
|
a3e4a0f6e9 | ||
|
|
d5044df134 | ||
|
|
cef4d4efea | ||
|
|
1f093159d8 | ||
|
|
22e6d80384 | ||
|
|
fe1bf101c3 |
40 changed files with 2138 additions and 132 deletions
|
|
@ -5,13 +5,13 @@
|
|||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=bbfdm
|
||||
PKG_VERSION:=1.18.15
|
||||
PKG_VERSION:=1.18.16
|
||||
|
||||
USE_LOCAL:=0
|
||||
ifneq ($(USE_LOCAL),1)
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://dev.iopsys.eu/bbf/bbfdm.git
|
||||
PKG_SOURCE_VERSION:=8f72146f0f42b76b43ef545136548dd2ca1b0388
|
||||
PKG_SOURCE_VERSION:=34378ab7c9e844e6638fdb2ea557d2fd21114bb0
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
PKG_MIRROR_HASH:=skip
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ STOP=05
|
|||
|
||||
USE_PROCD=1
|
||||
PROG=/usr/sbin/dm-service
|
||||
DM_AGENT_PROG=/usr/sbin/dm-agent
|
||||
|
||||
BBFDM_MICROSERVICE_DIR="/etc/bbfdm/services"
|
||||
|
||||
|
|
@ -24,7 +25,8 @@ validate_bbfdm_micro_service_section()
|
|||
_add_microservice()
|
||||
{
|
||||
local name path loglevel
|
||||
local enable enable_core unified_daemon
|
||||
local enable enable_core unified_daemon dm_framework
|
||||
local daemon_prog
|
||||
|
||||
# Check enable from micro-service
|
||||
path="${1}"
|
||||
|
|
@ -47,14 +49,25 @@ _add_microservice()
|
|||
return 0
|
||||
fi
|
||||
|
||||
json_get_var dm_framework dm-framework 0
|
||||
if [ "${dm_framework}" -eq "1" ] || [ "${dm_framework}" = "true" ]; then
|
||||
daemon_prog="${DM_AGENT_PROG}"
|
||||
else
|
||||
daemon_prog="${PROG}"
|
||||
fi
|
||||
|
||||
json_select config
|
||||
json_get_var loglevel loglevel 4
|
||||
|
||||
procd_open_instance "${name}"
|
||||
|
||||
procd_set_param command ${PROG}
|
||||
procd_set_param command ${daemon_prog}
|
||||
|
||||
# Only add parameters for dm-service, not for dm-agent
|
||||
if [ "${daemon_prog}" = "${PROG}" ]; then
|
||||
procd_append_param command -m "${name}"
|
||||
procd_append_param command -l "${loglevel}"
|
||||
fi
|
||||
|
||||
if [ "${enable_core}" -eq "1" ]; then
|
||||
procd_set_param limits core="unlimited"
|
||||
|
|
|
|||
|
|
@ -20,4 +20,9 @@ config BRIDGEMNGR_BRIDGE_VENDOR_EXT
|
|||
config BRIDGEMNGR_BRIDGE_VENDOR_PREFIX
|
||||
string "Package specific datamodel Vendor Prefix for TR181 extensions"
|
||||
default ""
|
||||
|
||||
config BRIDGEMNGR_USE_DM_FRAMEWORK
|
||||
bool "Use new DM framework support"
|
||||
default n
|
||||
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -20,13 +20,23 @@ PKG_LICENSE:=GPL-2.0-only
|
|||
PKG_LICENSE_FILES:=LICENSE
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
ifneq ($(CONFIG_BRIDGEMNGR_USE_DM_FRAMEWORK),y)
|
||||
include ../bbfdm/bbfdm.mk
|
||||
else
|
||||
include ../dm-framework/dm-framework.mk
|
||||
endif
|
||||
|
||||
define Package/bridgemngr
|
||||
CATEGORY:=Utilities
|
||||
TITLE:=Bridge Manager
|
||||
DEPENDS:=+libuci +libubox +libubus +libblobmsg-json
|
||||
DEPENDS+=+libbbfdm-api +libbbfdm-ubus +dm-service
|
||||
ifeq ($(CONFIG_BRIDGEMNGR_USE_DM_FRAMEWORK),y)
|
||||
DEPENDS+= +dm-framework
|
||||
PKG_BUILD_DEPENDS:=dm-framework
|
||||
else
|
||||
DEPENDS+= +libbbfdm-api +libbbfdm-ubus +dm-service
|
||||
endif
|
||||
endef
|
||||
|
||||
define Package/bridgemngr/description
|
||||
|
|
@ -37,10 +47,12 @@ define Package/$(PKG_NAME)/config
|
|||
source "$(SOURCE)/Config.in"
|
||||
endef
|
||||
|
||||
ifneq ($(CONFIG_BRIDGEMNGR_USE_DM_FRAMEWORK),y)
|
||||
MAKE_PATH:=src
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BRIDGEMNGR_BRIDGE_VENDOR_PREFIX),"")
|
||||
VENDOR_PREFIX = $(CONFIG_BBF_VENDOR_PREFIX)
|
||||
VENDOR_PREFIX = $(if $(CONFIG_BBF_VENDOR_PREFIX),$(CONFIG_BBF_VENDOR_PREFIX),$(CONFIG_DM_FRAMEWORK_VENDOR_PREFIX))
|
||||
else
|
||||
VENDOR_PREFIX = $(CONFIG_BRIDGEMNGR_BRIDGE_VENDOR_PREFIX)
|
||||
endif
|
||||
|
|
@ -48,22 +60,32 @@ endif
|
|||
TARGET_CFLAGS += -DBBF_VENDOR_PREFIX=\\\"$(VENDOR_PREFIX)\\\"
|
||||
|
||||
ifeq ($(CONFIG_BRIDGEMNGR_BRIDGE_VLAN),y)
|
||||
TARGET_CFLAGS += -DBRIDGE_VLAN_BACKEND
|
||||
TARGET_CFLAGS += -DBRIDGE_VLAN_BACKEND
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BRIDGEMNGR_COPY_PBITS),y)
|
||||
TARGET_CFLAGS+=-DBRIDGEMNGR_COPY_PBITS
|
||||
TARGET_CFLAGS += -DBRIDGEMNGR_COPY_PBITS
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BRIDGEMNGR_USE_DM_FRAMEWORK),y)
|
||||
define Build/Compile
|
||||
$(call Build/Compile/DM,./dm,$(PKG_BUILD_DIR)/dm_build,$(VENDOR_PREFIX))
|
||||
endef
|
||||
endif
|
||||
|
||||
define Package/bridgemngr/install
|
||||
$(INSTALL_DIR) $(1)/etc/init.d
|
||||
$(INSTALL_DIR) $(1)/etc/config
|
||||
|
||||
ifeq ($(CONFIG_BRIDGEMNGR_USE_DM_FRAMEWORK),y)
|
||||
$(call Build/Install/DM,./dm,$(PKG_BUILD_DIR)/dm_build,$(1),bridgemngr)
|
||||
else
|
||||
$(BBFDM_REGISTER_SERVICES) ./bbfdm_service.json $(1) $(PKG_NAME)
|
||||
$(BBFDM_INSTALL_MS_DM) $(PKG_BUILD_DIR)/src/libbridgemngr.so $(1) $(PKG_NAME)
|
||||
ifeq ($(CONFIG_BRIDGEMNGR_BRIDGE_VENDOR_EXT), y)
|
||||
$(BBFDM_INSTALL_MS_PLUGIN) $(PKG_BUILD_DIR)/src/libbridgeext.so $(1) $(PKG_NAME) 10
|
||||
$(BBFDM_INSTALL_MS_PLUGIN) -v ${VENDOR_PREFIX} ./files/VLAN_Filtering_Extension.json $(1) $(PKG_NAME) 11
|
||||
endif
|
||||
endif
|
||||
|
||||
$(INSTALL_BIN) ./files/etc/init.d/bridging $(1)/etc/init.d/
|
||||
|
|
|
|||
449
bridgemngr/dm/VLANBridge.json
Normal file
449
bridgemngr/dm/VLANBridge.json
Normal file
|
|
@ -0,0 +1,449 @@
|
|||
[
|
||||
{
|
||||
"object": "Device.Bridging.",
|
||||
"access": "readOnly",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "MaxBridgeEntries",
|
||||
"access": "readOnly",
|
||||
"dataType": "unsignedInt",
|
||||
"const" : "4094"
|
||||
},
|
||||
{
|
||||
"name": "MaxDBridgeEntries",
|
||||
"access": "readOnly",
|
||||
"dataType": "unsignedInt",
|
||||
"const" : "4094"
|
||||
},
|
||||
{
|
||||
"name": "MaxQBridgeEntries",
|
||||
"access": "readOnly",
|
||||
"dataType": "unsignedInt",
|
||||
"const" : "4094"
|
||||
},
|
||||
{
|
||||
"name": "MaxVLANEntries",
|
||||
"access": "readOnly",
|
||||
"dataType": "unsignedInt",
|
||||
"const" : "4094"
|
||||
},
|
||||
{
|
||||
"name": "BridgeNumberOfEntries",
|
||||
"access": "readOnly",
|
||||
"dataType": "unsignedInt"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"object": "Device.Bridging.Bridge.{i}.",
|
||||
"uniqueKeys": "Name,Alias",
|
||||
"access": "readWrite",
|
||||
"uci": "network.device",
|
||||
"flags": [
|
||||
"dmmap"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Enable",
|
||||
"access": "readWrite",
|
||||
"dataType": "boolean",
|
||||
"uci": "enabled",
|
||||
"uci-default": "true"
|
||||
},
|
||||
{
|
||||
"name": "Name",
|
||||
"access": "readOnly",
|
||||
"dataType": "string(:64)",
|
||||
"set_on_create": "bridge_",
|
||||
"db": true
|
||||
},
|
||||
{
|
||||
"name": "Alias",
|
||||
"access": "readWrite",
|
||||
"dataType": "string(:64)"
|
||||
},
|
||||
{
|
||||
"name": "Status",
|
||||
"access": "readOnly",
|
||||
"dataType": "enum",
|
||||
"enum": [
|
||||
"Disabled",
|
||||
"Enabled",
|
||||
"Error"
|
||||
],
|
||||
"default": "Disabled"
|
||||
},
|
||||
{
|
||||
"name": "Standard",
|
||||
"access": "readWrite",
|
||||
"dataType": "enum",
|
||||
"enum": [
|
||||
"802.1D-2004",
|
||||
"802.1Q-2005",
|
||||
"802.1Q-2011"
|
||||
],
|
||||
"default": "802.1Q-2011"
|
||||
},
|
||||
{
|
||||
"name": "PortNumberOfEntries",
|
||||
"access": "readOnly",
|
||||
"dataType": "unsignedInt"
|
||||
},
|
||||
{
|
||||
"name": "VLANNumberOfEntries",
|
||||
"access": "readOnly",
|
||||
"dataType": "unsignedInt"
|
||||
},
|
||||
{
|
||||
"name": "VLANPortNumberOfEntries",
|
||||
"access": "readOnly",
|
||||
"dataType": "unsignedInt"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"object": "Device.Bridging.Bridge.{i}.STP.",
|
||||
"access": "readOnly",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Enable",
|
||||
"access": "readWrite",
|
||||
"dataType": "boolean",
|
||||
"uci": "stp"
|
||||
},
|
||||
{
|
||||
"name": "Status",
|
||||
"access": "readOnly",
|
||||
"dataType": "enum",
|
||||
"enum": [
|
||||
"Disabled",
|
||||
"Enabled",
|
||||
"Error_Misconfigured",
|
||||
"Error"
|
||||
],
|
||||
"default": "Disabled"
|
||||
},
|
||||
{
|
||||
"name": "Protocol",
|
||||
"access": "readWrite",
|
||||
"dataType": "enum",
|
||||
"enum": [
|
||||
"STP",
|
||||
"RSTP"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BridgePriority",
|
||||
"access": "readWrite",
|
||||
"dataType": "unsignedInt(0:61440)",
|
||||
"default": "32768"
|
||||
},
|
||||
{
|
||||
"name": "HelloTime",
|
||||
"access": "readWrite",
|
||||
"dataType": "unsignedInt(100:1000)",
|
||||
"default": "200"
|
||||
},
|
||||
{
|
||||
"name": "MaxAge",
|
||||
"access": "readWrite",
|
||||
"dataType": "unsignedInt(600:4000)",
|
||||
"default": "2000"
|
||||
},
|
||||
{
|
||||
"name": "ForwardingDelay",
|
||||
"access": "readWrite",
|
||||
"dataType": "unsignedInt(4:30)",
|
||||
"default": "15"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"object": "Device.Bridging.Bridge.{i}.Port.{i}.",
|
||||
"uniqueKeys": "Alias,Name",
|
||||
"access": "readWrite",
|
||||
"flags": [
|
||||
"dmmap"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Enable",
|
||||
"access": "readWrite",
|
||||
"dataType": "boolean"
|
||||
},
|
||||
{
|
||||
"name": "Status",
|
||||
"access": "readOnly",
|
||||
"dataType": "enum",
|
||||
"enum": [
|
||||
"Up",
|
||||
"Down",
|
||||
"Unknown",
|
||||
"Dormant",
|
||||
"NotPresent",
|
||||
"LowerLayerDown",
|
||||
"Error"
|
||||
],
|
||||
"default": "Down"
|
||||
},
|
||||
{
|
||||
"name": "Alias",
|
||||
"access": "readWrite",
|
||||
"dataType": "string(:64)"
|
||||
},
|
||||
{
|
||||
"name": "Name",
|
||||
"access": "readOnly",
|
||||
"dataType": "string(:64)",
|
||||
"set_on_create": "port_",
|
||||
"db": "true",
|
||||
"flags": [
|
||||
"linker"
|
||||
],
|
||||
"js-value": "ifname"
|
||||
},
|
||||
{
|
||||
"name": "LastChange",
|
||||
"access": "readOnly",
|
||||
"dataType": "unsignedInt",
|
||||
"const": "0"
|
||||
},
|
||||
{
|
||||
"name": "LowerLayers",
|
||||
"access": "readWrite",
|
||||
"dataType": "pathRef[]",
|
||||
"pathRef": [
|
||||
"Device.Bridging.Bridge.{i}.Port."
|
||||
],
|
||||
"js-value": "ssidPath"
|
||||
},
|
||||
{
|
||||
"name": "ManagementPort",
|
||||
"access": "readWrite",
|
||||
"dataType": "boolean"
|
||||
},
|
||||
{
|
||||
"name": "PriorityRegeneration",
|
||||
"access": "readWrite",
|
||||
"dataType": "unsignedInt(0:7)[]",
|
||||
"default": "0,1,2,3,4,5,6,7"
|
||||
},
|
||||
{
|
||||
"name": "{BBF_VENDOR_PREFIX}EgressPriorityRegeneration",
|
||||
"access": "readWrite",
|
||||
"dataType": "unsignedInt(0:7)[]"
|
||||
},
|
||||
{
|
||||
"name": "Type",
|
||||
"access": "readWrite",
|
||||
"dataType": "enum",
|
||||
"enum": [
|
||||
"ProviderNetworkPort",
|
||||
"CustomerNetworkPort",
|
||||
"CustomerEdgePort",
|
||||
"CustomerVLANPort",
|
||||
"VLANUnawarePort"
|
||||
],
|
||||
"default": "CustomerVLANPort"
|
||||
},
|
||||
{
|
||||
"name": "PVID",
|
||||
"access": "readWrite",
|
||||
"dataType": "int(1:4094)",
|
||||
"default": "1"
|
||||
},
|
||||
{
|
||||
"name": "TPID",
|
||||
"access": "readWrite",
|
||||
"dataType": "unsignedInt",
|
||||
"default": "33024"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"object": "Device.Bridging.Bridge.{i}.Port.{i}.Stats.",
|
||||
"access": "readOnly",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "BytesSent",
|
||||
"dataType": "unsignedLong"
|
||||
},
|
||||
{
|
||||
"name": "BytesReceived",
|
||||
"dataType": "unsignedLong"
|
||||
},
|
||||
{
|
||||
"name": "PacketsSent",
|
||||
"dataType": "unsignedLong"
|
||||
},
|
||||
{
|
||||
"name": "PacketsReceived",
|
||||
"dataType": "unsignedLong"
|
||||
},
|
||||
{
|
||||
"name": "ErrorsSent",
|
||||
"dataType": "StatsCounter32"
|
||||
},
|
||||
{
|
||||
"name": "ErrorsReceived",
|
||||
"dataType": "StatsCounter32"
|
||||
},
|
||||
{
|
||||
"name": "UnicastPacketsSent",
|
||||
"dataType": "unsignedLong"
|
||||
},
|
||||
{
|
||||
"name": "DiscardPacketsSent",
|
||||
"dataType": "StatsCounter32"
|
||||
},
|
||||
{
|
||||
"name": "DiscardPacketsReceived",
|
||||
"dataType": "StatsCounter32"
|
||||
},
|
||||
{
|
||||
"name": "MulticastPacketsSent",
|
||||
"dataType": "unsignedLong"
|
||||
},
|
||||
{
|
||||
"name": "UnicastPacketsReceived",
|
||||
"dataType": "unsignedLong"
|
||||
},
|
||||
{
|
||||
"name": "MulticastPacketsReceived",
|
||||
"dataType": "unsignedLong"
|
||||
},
|
||||
{
|
||||
"name": "BroadcastPacketsSent",
|
||||
"dataType": "unsignedLong"
|
||||
},
|
||||
{
|
||||
"name": "BroadcastPacketsReceived",
|
||||
"dataType": "unsignedLong"
|
||||
},
|
||||
{
|
||||
"name": "UnknownProtoPacketsReceived",
|
||||
"dataType": "StatsCounter32"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"object": "Device.Bridging.Bridge.{i}.VLAN.{i}.",
|
||||
"uniqueKeys": "Alias,VLANID",
|
||||
"access": "readWrite",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Enable",
|
||||
"access": "readWrite",
|
||||
"dataType": "boolean"
|
||||
},
|
||||
{
|
||||
"name": "Name",
|
||||
"access": "readWrite",
|
||||
"dataType": "string(:64)",
|
||||
"set_on_create": "vlan_"
|
||||
},
|
||||
{
|
||||
"name": "Alias",
|
||||
"access": "readWrite",
|
||||
"dataType": "string(:64)"
|
||||
},
|
||||
{
|
||||
"name": "VLANID",
|
||||
"access": "readWrite",
|
||||
"dataType": "int(0:4094)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"object": "Device.Bridging.Bridge.{i}.VLANPort.{i}.",
|
||||
"uniqueKeys": "Alias,VLAN",
|
||||
"access": "readWrite",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Enable",
|
||||
"access": "readWrite",
|
||||
"dataType": "boolean"
|
||||
},
|
||||
{
|
||||
"name": "Alias",
|
||||
"access": "readWrite",
|
||||
"dataType": "string(:64)"
|
||||
},
|
||||
{
|
||||
"name": "VLAN",
|
||||
"access": "readWrite",
|
||||
"dataType": "pathRef",
|
||||
"pathRef": [
|
||||
"Device.Bridging.Bridge.{i}.VLAN."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Port",
|
||||
"access": "readWrite",
|
||||
"dataType": "pathRef",
|
||||
"pathRef": [
|
||||
"Device.Bridging.Bridge.{i}.Port."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Untagged",
|
||||
"access": "readWrite",
|
||||
"dataType": "boolean"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"object": "Device.Bridging.ProviderBridge.{i}.",
|
||||
"uniqueKeys": "Alias",
|
||||
"access": "readWrite",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Enable",
|
||||
"access": "readWrite",
|
||||
"dataType": "boolean"
|
||||
},
|
||||
{
|
||||
"name": "Status",
|
||||
"access": "readOnly",
|
||||
"dataType": "enum",
|
||||
"enum": [
|
||||
"Disabled",
|
||||
"Enabled",
|
||||
"Error_Misconfigured",
|
||||
"Error"
|
||||
],
|
||||
"default": "Disabled"
|
||||
},
|
||||
{
|
||||
"name": "Alias",
|
||||
"access": "readWrite",
|
||||
"dataType": "string(:64)"
|
||||
},
|
||||
{
|
||||
"name": "Type",
|
||||
"access": "readWrite",
|
||||
"dataType": "enum",
|
||||
"enum": [
|
||||
"S-VLAN",
|
||||
"PE"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "SVLANcomponent",
|
||||
"access": "readWrite",
|
||||
"dataType": "pathRef",
|
||||
"pathRef": [
|
||||
"Device.Bridging.Bridge."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "CVLANcomponents",
|
||||
"access": "readWrite",
|
||||
"dataType": "pathRef[]",
|
||||
"pathRef": [
|
||||
"Device.Bridging.Bridge."
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
343
bridgemngr/dm/bridge-apply.js
Normal file
343
bridgemngr/dm/bridge-apply.js
Normal file
|
|
@ -0,0 +1,343 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Genexis B.V. All rights reserved.
|
||||
*
|
||||
* This Software and its content are protected by the Dutch Copyright Act
|
||||
* ('Auteurswet'). All and any copying and distribution of the software
|
||||
* and its content without authorization by Genexis B.V. is
|
||||
* prohibited. The prohibition includes every form of reproduction and
|
||||
* distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
import {
|
||||
getUciOption, getUciByType, setUci, addUci, delUci
|
||||
} from '../uci.js';
|
||||
import { getParamValue, replaceArrayElement, isTrue } from '../utils.js';
|
||||
import * as dm from './dm_consts.js';
|
||||
import { getBridgeDeviceType, getTPIDFromDeviceType } from './common.js';
|
||||
|
||||
function findVLANPort(vlanPort, VLANs, Ports) {
|
||||
const [, vlanIndices] = _dm_node(vlanPort.VLAN);
|
||||
const vlanIdx = vlanIndices[vlanIndices.length - 1];
|
||||
const vlan = VLANs?.find(x => x['.index'] === vlanIdx);
|
||||
if (!vlan) {
|
||||
_log_error(`vlan not found for vlanPort: ${vlanPort.VLAN}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const [, portIndices] = _dm_node(vlanPort.Port);
|
||||
const portIdx = portIndices[portIndices.length - 1];
|
||||
const port = Ports?.find(x => x['.index'] === portIdx);
|
||||
if (!port) {
|
||||
_log_error(`port not found for vlanPort: ${vlanPort.Port}`);
|
||||
return;
|
||||
}
|
||||
|
||||
return [vlan, port];
|
||||
}
|
||||
|
||||
function createVLANDevice(devName, ifname, VLAN, Port) {
|
||||
const ingress_qos_mapping = Port.PriorityRegeneration !== '0,1,2,3,4,5,6,7'
|
||||
? Port.PriorityRegeneration.split(',').map((p, i) => `${i}:${p}`)
|
||||
: '';
|
||||
|
||||
const egress_qos_mapping = Port.X_IOPSYS_EU_EgressPriorityRegeneration !== ''
|
||||
? Port.X_IOPSYS_EU_EgressPriorityRegeneration.split(',').map((p, i) => `${i}:${p}`)
|
||||
: '';
|
||||
|
||||
const uciConfigs = {
|
||||
ifname: ifname,
|
||||
vid: VLAN.VLANID,
|
||||
name: ifname + '.' + VLAN.VLANID,
|
||||
type: getBridgeDeviceType(Port.Type),
|
||||
tpid: getTPIDFromDeviceType(Port.Type, Port.TPID),
|
||||
ingress_qos_mapping,
|
||||
egress_qos_mapping,
|
||||
};
|
||||
addUci('network', 'device', devName, uciConfigs);
|
||||
}
|
||||
|
||||
function applyBridge(bri, Ports, VLANs, VLANPorts) {
|
||||
deinitDeviceBridgingBridge(bri._key, false);
|
||||
|
||||
const ports = [];
|
||||
|
||||
for (const vlan of VLANs || []) {
|
||||
vlan.ports = [];
|
||||
vlan.hasUntagged = false;
|
||||
}
|
||||
|
||||
for (const vlanPort of VLANPorts || []) {
|
||||
if (!vlanPort.Enable || !vlanPort.Port || !vlanPort.VLAN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const [vlan, port] = findVLANPort(vlanPort, VLANs, Ports);
|
||||
if (!vlan || !port || port.LowerLayers === '' || !port.Enable || !vlan.Enable || vlan.VLANID <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
port.used = true;
|
||||
|
||||
if (port.Type === 'ProviderNetworkPort') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const devName = `br_${bri['.index']}_dev_${vlanPort['.index']}`;
|
||||
if (!port.LowerLayers.startsWith('Device.Ethernet.Interface')) {
|
||||
_log_error(`applyBridge, LowerLayers not found for port: ${port.LowerLayers}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const ifname = _dm_linker_value(port.LowerLayers);
|
||||
if (!ifname) {
|
||||
_log_error(`applyBridge, ifname not found for port: ${port.LowerLayers}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vlanPort.Untagged) {
|
||||
ports.push(ifname);
|
||||
vlan.hasUntagged = true;
|
||||
vlan.ports.push(ifname + ':u' + (vlanPort.PVID === vlan.VLANID ? '*' : ''));
|
||||
// vlan.ports.push(ifname + ':u*');
|
||||
} else {
|
||||
createVLANDevice(devName, ifname, vlan, port);
|
||||
const vlanDevName = ifname + '.' + vlan.VLANID;
|
||||
ports.push(vlanDevName);
|
||||
vlan.ports.push(vlanDevName + ':u*');
|
||||
}
|
||||
}
|
||||
|
||||
for (const port of Ports || []) {
|
||||
if (port.used || isTrue(port.ManagementPort)) {
|
||||
continue;
|
||||
}
|
||||
if (port.LowerLayers.startsWith('Device.Ethernet.Interface')) {
|
||||
const ifname = _dm_linker_value(port.LowerLayers);
|
||||
if (!ifname) {
|
||||
_log_error(`applyBridge, ifname not found for port: ${port.LowerLayers}`);
|
||||
continue;
|
||||
}
|
||||
ports.push(ifname);
|
||||
}
|
||||
}
|
||||
|
||||
if (ports.length > 0) {
|
||||
setUci('network', bri._key, { ports: ports });
|
||||
}
|
||||
|
||||
// create the bridge-vlan for the untagged port
|
||||
for (const vlan of VLANs || []) {
|
||||
if (vlan.hasUntagged) {
|
||||
addUci('network', 'bridge-vlan', `br_${bri['.index']}_bv_${vlan['.index']}`, {
|
||||
device: bri.Name,
|
||||
vlan: vlan.VLANID,
|
||||
ports: vlan.ports,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
applyProviderBridges();
|
||||
}
|
||||
|
||||
function applyPEBridges(ifname, vlanID, portLowerLayers, cvlanBridgePath) {const vlanPorts = _dm_get(cvlanBridgePath + '.VLANPort.');
|
||||
for (const vlanPort of vlanPorts || []) {
|
||||
if (!vlanPort.Enable || !vlanPort.Port || !vlanPort.VLAN) {
|
||||
continue;
|
||||
}
|
||||
const portVals = _dm_get(vlanPort.Port);
|
||||
if (portVals?.LowerLayers !== portLowerLayers || portVals?.Type !== 'CustomerEdgePort') {
|
||||
_log_error(`applyPEBridges, portVals not found for vlanPort: ${vlanPort.Port}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const vlan = _dm_get(vlanPort.VLAN);
|
||||
if (!vlan || vlan.VLANID <= 0 || !vlan.Enable) {
|
||||
_log_error(`applyPEBridges, vlan not found for vlanPort: ${vlanPort.VLAN}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const devName = ifname + '.' + vlan.VLANID;
|
||||
|
||||
const briName = getParamValue(cvlanBridgePath, '_key');
|
||||
if (!briName) {
|
||||
_log_error(`applyPEBridges, briName not found for cvlanBridgePath: ${cvlanBridgePath}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const ports = getUciOption('network', briName, 'ports') || [];
|
||||
const devs = getUciByType('network', 'device', { match: { name: devName } });
|
||||
if (devs.length === 0) {
|
||||
_log_error(`applyPEBridges, device not found for devName: ${devName}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const newName = `${ifname}.${vlanID}.${vlan.VLANID}`;
|
||||
setUci('network', devs[0]['.name'], {ifname: `${ifname}.${vlanID}`, name: newName});
|
||||
replaceArrayElement(ports, devName, newName);
|
||||
setUci('network', briName, { ports: ports });
|
||||
}
|
||||
}
|
||||
|
||||
function applyProviderBridge(pbridgeIndex, type, svlanBridgePath, cvlanBridgePaths) {
|
||||
const vlanPorts = _dm_get(svlanBridgePath + '.VLANPort.');
|
||||
const briName = getParamValue(svlanBridgePath, '_key');
|
||||
if (briName) {
|
||||
delUci('network', briName);
|
||||
}
|
||||
for (const vlanPort of vlanPorts || []) {
|
||||
if (!vlanPort.Enable || !vlanPort.Port || !vlanPort.VLAN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const portVals = _dm_get(vlanPort.Port);
|
||||
if (!portVals) {
|
||||
_log_error(`applyProviderBridge, portVals not found for vlanPort: ${vlanPort.Port}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (portVals.Type !== 'ProviderNetworkPort') {
|
||||
_log_error(`applyProviderBridge, portVals.Type is not ProviderNetworkPort for vlanPort: ${vlanPort.Port}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const ifname = _dm_linker_value(portVals.LowerLayers);
|
||||
if (!ifname) {
|
||||
_log_error(`applyProviderBridge, ifname not found for port: ${portVals.LowerLayers}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const vlan = _dm_get(vlanPort.VLAN);
|
||||
if (!vlan || !vlan.Enable || vlan.VLANID <= 0) {
|
||||
_log_error(`applyProviderBridge, vlan invalid for vlanPort: ${vlanPort.VLAN}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const devName = `pb_${pbridgeIndex}_dev_${vlanPort['.index']}`;
|
||||
createVLANDevice(devName, ifname, vlan, portVals);
|
||||
|
||||
cvlanBridgePaths.split(',').forEach(cvlanBridgePath => {
|
||||
if (type === 'S-VLAN') {
|
||||
const briName = getParamValue(cvlanBridgePath, '_key');
|
||||
if (briName) {
|
||||
let ports = getUciOption('network', briName, 'ports') || [];
|
||||
ports = ports.filter(x => !x.startsWith(ifname));
|
||||
ports.push(ifname + '.' + vlan.VLANID);
|
||||
setUci('network', briName, { ports: ports });
|
||||
} else {
|
||||
_log_error(`applyProviderBridge, briName not found for cvlanBridgePath: ${cvlanBridgePath}`);
|
||||
}
|
||||
} else {
|
||||
applyPEBridges(ifname, vlan.VLANID, portVals.LowerLayers, cvlanBridgePath);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function applyProviderBridges() {
|
||||
const pbridges = _dm_get(dm.DM_DEVICE_BRIDGING_PROVIDERBRIDGE);
|
||||
for (const pbridge of pbridges || []) {
|
||||
if (!pbridge.Enable || !pbridge.SVLANcomponent || !pbridge.CVLANcomponents || !pbridge.Type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
applyProviderBridge(pbridge['.index'], pbridge.Type, pbridge.SVLANcomponent, pbridge.CVLANcomponents);
|
||||
}
|
||||
}
|
||||
|
||||
function applyAllBridges() {
|
||||
const bridges = _dm_get(dm.DM_DEVICE_BRIDGING_BRIDGE);
|
||||
for (const bri of bridges || []) {
|
||||
applyBridge(bri, bri.Port, bri.VLAN, bri.VLANPort);
|
||||
}
|
||||
}
|
||||
|
||||
export function applyDeviceBridgingProviderBridge() {
|
||||
applyAllBridges();
|
||||
}
|
||||
|
||||
function isProviderBridge(ports) {
|
||||
return ports.some(port => port.Type === 'ProviderNetworkPort' || port.Type === 'CustomerEdgePort');
|
||||
}
|
||||
|
||||
export function applyDeviceBridgingBridgePort(ports, bri) {
|
||||
const vlans = _dm_get(dm.DM_DEVICE_BRIDGING_BRIDGE_VLAN, bri['.index']);
|
||||
const vlanPorts = _dm_get(dm.DM_DEVICE_BRIDGING_BRIDGE_VLANPORT, bri['.index']);
|
||||
if (isProviderBridge(ports)) {
|
||||
applyAllBridges();
|
||||
return;
|
||||
}
|
||||
applyBridge(bri, ports, vlans, vlanPorts);
|
||||
}
|
||||
|
||||
export function applyDeviceBridgingBridgeVLAN(vlans, bri) {
|
||||
const ports = _dm_get(dm.DM_DEVICE_BRIDGING_BRIDGE_PORT, bri['.index']);
|
||||
if (isProviderBridge(ports)) {
|
||||
applyAllBridges();
|
||||
return;
|
||||
}
|
||||
const vlanPorts = _dm_get(dm.DM_DEVICE_BRIDGING_BRIDGE_VLANPORT, bri['.index']);
|
||||
applyBridge(bri, ports, vlans, vlanPorts);
|
||||
}
|
||||
|
||||
export function applyDeviceBridgingBridgeVLANPort(vlanPorts, bri) {
|
||||
const ports = _dm_get(dm.DM_DEVICE_BRIDGING_BRIDGE_PORT, bri['.index']);
|
||||
if (isProviderBridge(ports)) {
|
||||
applyAllBridges();
|
||||
return;
|
||||
}
|
||||
const vlans = _dm_get(dm.DM_DEVICE_BRIDGING_BRIDGE_VLAN, bri['.index']);
|
||||
applyBridge(bri, ports, vlans, vlanPorts);
|
||||
}
|
||||
|
||||
export function initDeviceBridgingBridge(bri) {
|
||||
setUci('network', bri._key, {
|
||||
type: 'bridge',
|
||||
name: bri.Name,
|
||||
enabled: '0',
|
||||
});
|
||||
// create empty interface for the bridge
|
||||
addUci('network', 'interface', `itf_${bri._key}`, {
|
||||
device: bri.Name,
|
||||
bridge_empty: '1',
|
||||
});
|
||||
}
|
||||
|
||||
export const filterDeviceBridgingBridge = uci => uci.type === 'bridge';
|
||||
|
||||
function delVLANDevice(devName, devices, ethPorts) {
|
||||
if (ethPorts.find(x => x.name === devName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dev = devices.find(x => x.name === devName);
|
||||
if (!dev) {
|
||||
return;
|
||||
}
|
||||
|
||||
// delete possible vlan stack device
|
||||
delVLANDevice(dev.ifname, devices, ethPorts);
|
||||
delUci('network', dev['.name']);
|
||||
}
|
||||
|
||||
export function deinitDeviceBridgingBridge(uci, removeInterface = true) {
|
||||
const ports = getUciOption('network', uci, 'ports');
|
||||
const devices = getUciByType('network', 'device');
|
||||
|
||||
const ethPorts = devices.filter(x => x.type === undefined && x.eee !== undefined);
|
||||
ports?.forEach(port => {
|
||||
delVLANDevice(port, devices, ethPorts);
|
||||
});
|
||||
|
||||
const name = getUciOption('network', uci, 'name');
|
||||
// delete related bridge-vlan devices (query first to avoid noisy "section missing" logs)
|
||||
const bridgeVlans = getUciByType('network', 'bridge-vlan', { match: { device: name } }) || [];
|
||||
bridgeVlans.forEach(vlan => delUci('network', vlan['.name']));
|
||||
|
||||
if (removeInterface) {
|
||||
// delete the empty interface created for this bridge (query first)
|
||||
const interfaces = getUciByType('network', 'interface', { match: { device: name, bridge_empty: '1' } }) || [];
|
||||
interfaces.forEach(intf => delUci('network', intf['.name']));
|
||||
}
|
||||
}
|
||||
268
bridgemngr/dm/bridge-import.js
Normal file
268
bridgemngr/dm/bridge-import.js
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Genexis B.V. All rights reserved.
|
||||
*
|
||||
* This Software and its content are protected by the Dutch Copyright Act
|
||||
* ('Auteurswet'). All and any copying and distribution of the software
|
||||
* and its content without authorization by Genexis B.V. is
|
||||
* prohibited. The prohibition includes every form of reproduction and
|
||||
* distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
import { getUciByType } from '../uci.js';
|
||||
import { getBridgePortType, getTPIDFromDeviceType } from './common.js';
|
||||
|
||||
// find the port from bridge-vlan; returns [vlanId, isTagged, isPvid] or null
|
||||
function findPortFromBridgeVlan(bridgeVlans, portName) {
|
||||
if (!bridgeVlans) return null;
|
||||
|
||||
for (const bridgeVlan of bridgeVlans) {
|
||||
const port = bridgeVlan.ports?.find(x => x.split(':')[0] === portName);
|
||||
if (port) {
|
||||
const flags = port.includes(':') ? port.split(':')[1] : '';
|
||||
return [bridgeVlan.vlan, flags.includes('t'), flags.includes('*')];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function isVLANSubInterface(portName, ethPorts) {
|
||||
const names = portName.split('.');
|
||||
if (names.length > 1) {
|
||||
const baseIfname = names.slice(0, -1).join('.');
|
||||
if (ethPorts.find(x => x.ifname === baseIfname)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function createProviderBridge(dev, type, ethIndex, bridges, providerBridges, cVLANBridgeIndex) {
|
||||
const briIndex = bridges.length + 1;
|
||||
|
||||
let sVLANBridgeIndex = bridges.findIndex((x) => x['VLAN.']?.[0]?.VLANID === dev.vid && x['Port.']?.[0]?.LowerLayers === `Device.Ethernet.Interface.${ethIndex}`);
|
||||
if (sVLANBridgeIndex < 0) {
|
||||
// no management port needed for provider bridge
|
||||
bridges.push({
|
||||
Name: dev.name,
|
||||
Alias: `cpe-${dev.name}`,
|
||||
Standard: '802.1Q-2011',
|
||||
Enable: 1,
|
||||
'Port.': [{
|
||||
Enable: 1,
|
||||
Name: dev.name,
|
||||
Alias: `cpe-${dev.name}`,
|
||||
TPID: 34984,
|
||||
PVID: 1,
|
||||
Type: 'ProviderNetworkPort',
|
||||
LowerLayers: `Device.Ethernet.Interface.${ethIndex}`,
|
||||
}],
|
||||
'VLAN.': [{
|
||||
Enable: 1,
|
||||
VLANID: dev.vid,
|
||||
}],
|
||||
'VLANPort.': [{
|
||||
Enable: 1,
|
||||
VLAN: `Device.Bridging.Bridge.${briIndex}.VLAN.1`,
|
||||
Port: `Device.Bridging.Bridge.${briIndex}.Port.1`,
|
||||
Untagged: 1,
|
||||
}],
|
||||
_key: dev['.name'],
|
||||
});
|
||||
sVLANBridgeIndex = bridges.length;
|
||||
} else {
|
||||
sVLANBridgeIndex = sVLANBridgeIndex + 1;
|
||||
const pvBridge = providerBridges.find(x => x.SVLANcomponent === `Device.Bridging.Bridge.${sVLANBridgeIndex}`);
|
||||
if (pvBridge) {
|
||||
pvBridge.CVLANcomponents = pvBridge.CVLANcomponents + `,Device.Bridging.Bridge.${cVLANBridgeIndex}`;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
providerBridges.push({
|
||||
Alias: `cpe-${dev.name}`,
|
||||
Enable: 1,
|
||||
Type: type,
|
||||
SVLANcomponent: `Device.Bridging.Bridge.${sVLANBridgeIndex}`,
|
||||
CVLANcomponents: `Device.Bridging.Bridge.${cVLANBridgeIndex}`,
|
||||
_key: dev['.name'],
|
||||
});
|
||||
}
|
||||
|
||||
function addRegularEthernetPort(ethDevice, portIndex, briPorts) {
|
||||
const tpid = getTPIDFromDeviceType(ethDevice.type, ethDevice.tpid);
|
||||
|
||||
briPorts.push({
|
||||
Enable: 1,
|
||||
Name: ethDevice['ifname'],
|
||||
Alias: `cpe-${ethDevice['.name']}`,
|
||||
TPID: tpid,
|
||||
PVID: 1,
|
||||
Type: 'VLANUnawarePort',
|
||||
LowerLayers: `Device.Ethernet.Interface.${portIndex + 1}`,
|
||||
_key: ethDevice['.name'],
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function handleVlanDevice(bridgeIndex, device, ethPorts, devices, bridges, briPorts, briVLAN, briVLANPort, providerBridges) {
|
||||
let qinqDev;
|
||||
let ethIndex = ethPorts.findIndex(x => device.ifname === x.ifname);
|
||||
|
||||
if (device.type === '8021ad') {
|
||||
if (ethIndex < 0) {
|
||||
_log_error('base ethernet device not found', device.ifname);
|
||||
return;
|
||||
}
|
||||
createProviderBridge(device, 'S-VLAN', ethIndex + 1, bridges, providerBridges, bridgeIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ethIndex < 0) {
|
||||
qinqDev = devices.find(x => x.name === device.ifname);
|
||||
if (!qinqDev || !qinqDev.ifname) {
|
||||
_log_error('device ifname not found', device.ifname);
|
||||
return;
|
||||
}
|
||||
if (qinqDev.type !== '8021ad' || device.type !== '8021q') {
|
||||
_log_error('invalid qinq device type', qinqDev['.name'], device['.name']);
|
||||
return;
|
||||
}
|
||||
device.ifname = qinqDev.ifname;
|
||||
ethIndex = ethPorts.findIndex(x => device.ifname === x.ifname);
|
||||
if (ethIndex < 0) {
|
||||
_log_error('base ethernet device not found', device.ifname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (device.type !== '8021q') {
|
||||
_log_error('unsupported device type', device['.name'], device.type);
|
||||
return;
|
||||
}
|
||||
|
||||
let vlanIndex = briVLAN.findIndex(x => Number(x.VLANID) === Number(device.vid));
|
||||
if (vlanIndex < 0) {
|
||||
briVLAN.push({ Enable: 1, VLANID: Number(device.vid) });
|
||||
vlanIndex = briVLAN.length;
|
||||
} else {
|
||||
vlanIndex += 1;
|
||||
}
|
||||
|
||||
const portType = qinqDev ? 'CustomerEdgePort' : getBridgePortType(device.type);
|
||||
const tpid = getTPIDFromDeviceType(device.type, device.tpid);
|
||||
|
||||
briPorts.push({
|
||||
Enable: 1,
|
||||
Name: device['ifname'],
|
||||
Alias: `cpe-${device['.name']}`,
|
||||
TPID: tpid,
|
||||
PVID: device.pvid ? Number(device.vid): 1,
|
||||
Type: portType,
|
||||
LowerLayers: `Device.Ethernet.Interface.${ethIndex + 1}`,
|
||||
_key: device['.name'],
|
||||
});
|
||||
|
||||
briVLANPort.push({
|
||||
Enable: 1,
|
||||
VLAN: `Device.Bridging.Bridge.${bridgeIndex}.VLAN.${vlanIndex}`,
|
||||
Port: `Device.Bridging.Bridge.${bridgeIndex}.Port.${briPorts.length}`,
|
||||
Untagged: device.untagged ? 1 : 0,
|
||||
_key: device['.name'],
|
||||
});
|
||||
|
||||
if (qinqDev && qinqDev.vid) {
|
||||
createProviderBridge(qinqDev, 'PE', ethIndex + 1, bridges, providerBridges, bridgeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
function importBridge(dev, devices, bridges, bridgeVlans, providerBridges) {
|
||||
const briPorts = [];
|
||||
const briVLAN = [];
|
||||
const briVLANPort = [];
|
||||
|
||||
// create the management port first
|
||||
briPorts.push({
|
||||
Alias: `cpe-${dev.name}`,
|
||||
Enable: 1,
|
||||
Name: dev.name,
|
||||
ManagementPort: 1,
|
||||
PVID: 1,
|
||||
TPID: 37120,
|
||||
Type: 'CustomerVLANPort',
|
||||
});
|
||||
|
||||
bridges.push({
|
||||
Name: dev.name,
|
||||
Alias: `cpe-${dev.name}`,
|
||||
Enable: 1,
|
||||
'Port.': briPorts,
|
||||
'VLAN.': briVLAN,
|
||||
'VLANPort.': briVLANPort,
|
||||
_key: dev['.name'],
|
||||
});
|
||||
|
||||
const ethPorts = devices.filter(x => x.type === undefined && x.eee !== undefined);
|
||||
|
||||
for (const portName of (dev.ports || [])) {
|
||||
let device;
|
||||
const portIndex = ethPorts.findIndex(x => x.ifname === portName);
|
||||
const briVLANInfo = findPortFromBridgeVlan(bridgeVlans, portName);
|
||||
if (portIndex >= 0 && !briVLANInfo) {
|
||||
// Regular ethernet port
|
||||
const ethDevice = ethPorts[portIndex];
|
||||
addRegularEthernetPort(ethDevice, portIndex, briPorts);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (briVLANInfo && portIndex >= 0) {
|
||||
// bridge-vlan device
|
||||
device = {['.name']: portName, ifname: portName, type: '8021q', name: portName, vid: Number(briVLANInfo[0]), untagged: !briVLANInfo[1], pvid: briVLANInfo[2]};
|
||||
} else {
|
||||
// vlan device
|
||||
device = devices.find(x => x.name === portName);
|
||||
if (!device) {
|
||||
// check if it is a valid sub-interface
|
||||
if (isVLANSubInterface(portName, ethPorts)) {
|
||||
const ifname = portName.split('.').slice(0, -1).join('.');
|
||||
const vid = portName.split('.').pop();
|
||||
device = {['.name']: portName, ifname: ifname, type: '8021q', name: portName, vid: Number(vid)};
|
||||
} else {
|
||||
_log_error('device not found', portName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!device.ifname || !device.vid) {
|
||||
_log_error('ifname or vid not found', device['.name']);
|
||||
return;
|
||||
}
|
||||
|
||||
handleVlanDevice(bridges.length, device, ethPorts, devices, bridges, briPorts, briVLAN, briVLANPort, providerBridges);
|
||||
}
|
||||
|
||||
if (briPorts.length > 1) {
|
||||
const indexes = Array.from({ length: briPorts.length - 1 }, (v, i) => i + 2);
|
||||
briPorts[0].LowerLayers = indexes.map(i => `Device.Bridging.Bridge.${bridges.length}.Port.${i}`).join(',');
|
||||
}
|
||||
}
|
||||
|
||||
export function importDeviceBridgingBridge() {
|
||||
const bridges = [];
|
||||
const providerBridges = [];
|
||||
const devices = getUciByType('network', 'device');
|
||||
const bridgeVlans = getUciByType('network', 'bridge-vlan');
|
||||
devices?.forEach(dev => {
|
||||
if (dev.type === 'bridge') {
|
||||
const bridgeVlan = bridgeVlans?.filter(x => x.device === dev.name);
|
||||
importBridge(dev, devices, bridges, bridgeVlan, providerBridges);
|
||||
}
|
||||
});
|
||||
|
||||
if (providerBridges.length > 0) {
|
||||
_dm_update('Device.Bridging.ProviderBridge.', providerBridges);
|
||||
}
|
||||
|
||||
return bridges;
|
||||
}
|
||||
133
bridgemngr/dm/bridge.js
Normal file
133
bridgemngr/dm/bridge.js
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Genexis B.V. All rights reserved.
|
||||
*
|
||||
* This Software and its content are protected by the Dutch Copyright Act
|
||||
* ('Auteurswet'). All and any copying and distribution of the software
|
||||
* and its content without authorization by Genexis B.V. is
|
||||
* prohibited. The prohibition includes every form of reproduction and
|
||||
* distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
import * as std from 'std';
|
||||
import { isTrue } from '../utils.js';
|
||||
import { getUciByType } from '../uci.js';
|
||||
|
||||
function setMgmtPortLowerLayers(bri) {
|
||||
if (!bri) return 0;
|
||||
|
||||
const portPath = `Device.Bridging.Bridge.${bri['.index']}.Port.`;
|
||||
const mgmtPort = _dm_instances(portPath, '(ManagementPort="true" OR ManagementPort=1)');
|
||||
if (mgmtPort.length !== 1) return 0;
|
||||
|
||||
const nonMgmtPort = _dm_instances(portPath, '(ManagementPort="false" OR ManagementPort=0)');
|
||||
_dm_update(`${mgmtPort[0]}.LowerLayers`, nonMgmtPort.join(','));
|
||||
return 0;
|
||||
}
|
||||
|
||||
export function changedDeviceBridgingBridgePort(bri) {
|
||||
return setMgmtPortLowerLayers(bri);
|
||||
}
|
||||
|
||||
export function changedDeviceBridgingBridgePortManagementPort(bri) {
|
||||
return setMgmtPortLowerLayers(bri);
|
||||
}
|
||||
|
||||
export function getDeviceBridgingBridgeStatus(bri) {
|
||||
const enable = _dm_get(`Device.Bridging.Bridge.${bri['.index']}.Enable`);
|
||||
return enable ? 'Enabled' : 'Disabled';
|
||||
}
|
||||
|
||||
export function getDeviceBridgingBridgeSTPStatus(bri) {
|
||||
const stpState = std.loadFile(`/sys/class/net/${bri.Name}/bridge/stp_state`)?.trim();
|
||||
return stpState === '1' ? 'Enabled' : 'Disabled';
|
||||
}
|
||||
|
||||
export function getDeviceBridgingBridgePortStatus(bri, port) {
|
||||
if (!port['.db']) return 'Up';
|
||||
|
||||
const enable = _dm_get(`Device.Bridging.Bridge.${bri['.index']}.Port.${port['.index']}.Enable`);
|
||||
return enable ? 'Up' : 'Down';
|
||||
}
|
||||
|
||||
export function infoDeviceBridgingBridgePort(path, port) {
|
||||
const mgmtPort = _dm_get(`${path}.ManagementPort`);
|
||||
if (typeof mgmtPort === 'undefined' || mgmtPort) return;
|
||||
|
||||
const lower = _dm_get(`${path}.LowerLayers`);
|
||||
if (lower) {
|
||||
port.ifname = _dm_linker_value(lower);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to read network statistics
|
||||
function getNetworkStat(port, statName) {
|
||||
return std.loadFile(`/sys/class/net/${port.ifname}/statistics/${statName}`)?.trim();
|
||||
}
|
||||
|
||||
export const getDeviceBridgingBridgePortStatsBytesSent = (bri, port) =>
|
||||
getNetworkStat(port, 'tx_bytes');
|
||||
|
||||
export const getDeviceBridgingBridgePortStatsBytesReceived = (bri, port) =>
|
||||
getNetworkStat(port, 'rx_bytes');
|
||||
|
||||
export const getDeviceBridgingBridgePortStatsPacketsSent = (bri, port) =>
|
||||
getNetworkStat(port, 'tx_packets');
|
||||
|
||||
export const getDeviceBridgingBridgePortStatsPacketsReceived = (bri, port) =>
|
||||
getNetworkStat(port, 'rx_packets');
|
||||
|
||||
export const getDeviceBridgingBridgePortStatsErrorsSent = (bri, port) =>
|
||||
getNetworkStat(port, 'tx_errors');
|
||||
|
||||
export const getDeviceBridgingBridgePortStatsErrorsReceived = (bri, port) =>
|
||||
getNetworkStat(port, 'rx_errors');
|
||||
|
||||
export const getDeviceBridgingBridgePortStatsDiscardPacketsSent = (bri, port) =>
|
||||
getNetworkStat(port, 'tx_dropped');
|
||||
|
||||
export const getDeviceBridgingBridgePortStatsDiscardPacketsReceived = (bri, port) =>
|
||||
getNetworkStat(port, 'rx_dropped');
|
||||
|
||||
export const getDeviceBridgingBridgePortStatsMulticastPacketsReceived = (bri, port) =>
|
||||
getNetworkStat(port, 'multicast');
|
||||
|
||||
export const getDeviceBridgingBridgePortStatsUnicastPacketsSent = (bri, port) =>
|
||||
getNetworkStat(port, 'tx_unicast_packets');
|
||||
|
||||
export const getDeviceBridgingBridgePortStatsUnicastPacketsReceived = (bri, port) =>
|
||||
getNetworkStat(port, 'rx_unicast_packets');
|
||||
|
||||
export const getDeviceBridgingBridgePortStatsMulticastPacketsSent = (bri, port) =>
|
||||
getNetworkStat(port, 'tx_multicast_packets');
|
||||
|
||||
export const getDeviceBridgingBridgePortStatsBroadcastPacketsSent = (bri, port) =>
|
||||
getNetworkStat(port, 'tx_broadcast_packets');
|
||||
|
||||
export const getDeviceBridgingBridgePortStatsBroadcastPacketsReceived = (bri, port) =>
|
||||
getNetworkStat(port, 'rx_broadcast_packets');
|
||||
|
||||
export const getDeviceBridgingBridgePortStatsUnknownProtoPacketsReceived = (bri, port) =>
|
||||
getNetworkStat(port, 'rx_unknown_packets');
|
||||
|
||||
export function getDeviceBridgingBridgePort(bri) {
|
||||
const networkName = bri.Name.startsWith('br-') ? bri.Name.slice(3) : bri.Name;
|
||||
|
||||
const wifiIfaces = getUciByType('wireless', 'wifi-iface', { match: { multi_ap: '2', network: networkName } });
|
||||
wifiIfaces?.forEach(x => {
|
||||
const ssid = getUciByType('WiFi', 'SSID',
|
||||
{ match: { device: x.device, ssid: x.ssid}, confdir: '/etc/bbfdm/dmmap'});
|
||||
if (Array.isArray(ssid) && ssid[0].__instance__) {
|
||||
x.ssidPath = `Device.WiFi.SSID.${ssid[0].__instance__}`;
|
||||
}
|
||||
});
|
||||
|
||||
return wifiIfaces;
|
||||
}
|
||||
|
||||
export function setDeviceBridgingBridgePortManagementPort(val, bri, port) {
|
||||
if (isTrue(val)) {
|
||||
_db_set(`Device.Bridging.Bridge.${bri['.index']}.Port.${port['.index']}.Name`, bri.Name);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
56
bridgemngr/dm/common.js
Executable file
56
bridgemngr/dm/common.js
Executable file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Genexis B.V. All rights reserved.
|
||||
*
|
||||
* This Software and its content are protected by the Dutch Copyright Act
|
||||
* ('Auteurswet'). All and any copying and distribution of the software
|
||||
* and its content without authorization by Genexis B.V. is
|
||||
* prohibited. The prohibition includes every form of reproduction and
|
||||
* distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
export const bridgePortTypeMap = [
|
||||
{ portType: 'ProviderNetworkPort', devType: '8021ad' },
|
||||
{ portType: 'CustomerVLANPort', devType: '8021q' },
|
||||
{ portType: 'CustomerEdgePort', devType: '8021q' },
|
||||
{ portType: 'CustomerNetworkPort', devType: '8021q' },
|
||||
{ portType: 'VLANUnawarePort', devType: '' }
|
||||
];
|
||||
|
||||
export function getBridgePortType(devType) {
|
||||
const mapping = bridgePortTypeMap.find(map => map.devType === devType);
|
||||
return mapping ? mapping.portType : null;
|
||||
}
|
||||
|
||||
export function getBridgeDeviceType(portType) {
|
||||
const mapping = bridgePortTypeMap.find(map => map.portType === portType);
|
||||
return mapping ? mapping.devType : '';
|
||||
}
|
||||
|
||||
export function getDefaultTPID(deviceType) {
|
||||
switch (deviceType) {
|
||||
case '8021q':
|
||||
return '33024';
|
||||
case '8021ad':
|
||||
return '34984';
|
||||
default:
|
||||
return '37120';
|
||||
}
|
||||
}
|
||||
|
||||
export function getTPIDFromDeviceType(deviceType, explicitTPID) {
|
||||
// If explicit TPID is set, use it
|
||||
if (explicitTPID && explicitTPID !== '') {
|
||||
return parseInt(explicitTPID, 10);
|
||||
}
|
||||
|
||||
// Default TPID based on device type
|
||||
switch (deviceType) {
|
||||
case '8021q':
|
||||
return 33024;
|
||||
case '8021ad':
|
||||
return 34984;
|
||||
default:
|
||||
return 37120;
|
||||
}
|
||||
}
|
||||
170
dm-framework/Makefile
Executable file
170
dm-framework/Makefile
Executable file
|
|
@ -0,0 +1,170 @@
|
|||
#
|
||||
# Copyright (c) 2023 Genexis B.V. All rights reserved.
|
||||
# This Software and its content are protected by the Dutch Copyright Act
|
||||
# ('Auteurswet'). All and any copying and distribution of the software
|
||||
# and its content without authorization by Genexis B.V. is
|
||||
# prohibited. The prohibition includes every form of reproduction and
|
||||
# distribution.
|
||||
#
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=dm-framework
|
||||
PKG_VERSION:=1.0.0
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://dev.iopsys.eu/lcm/dm-framework.git
|
||||
PKG_SOURCE_VERSION:=ba2ec403f08cc0d5401a1610517f17490c94a978
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
PKG_MIRROR_HASH:=skip
|
||||
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
|
||||
# Build directories for each component
|
||||
DMAPI_BUILD_DIR:=$(PKG_BUILD_DIR)/dm-api-build
|
||||
DMAGENT_BUILD_DIR:=$(PKG_BUILD_DIR)/dm-agent-build
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
include ../bbfdm/bbfdm.mk
|
||||
|
||||
#
|
||||
# DM-API Package Definition
|
||||
#
|
||||
define Package/dm-api
|
||||
CATEGORY:=Genexis
|
||||
TITLE:=dm-api
|
||||
DEPENDS:=+libsqlite3 \
|
||||
+libjson-c +libstdcpp +quickjs \
|
||||
+libubus +libubox +libuci
|
||||
URL:=http://www.genexis.eu
|
||||
PKG_LICENSE:=GENEXIS
|
||||
PKG_LICENSE_URL:=
|
||||
endef
|
||||
|
||||
define Package/dm-api/description
|
||||
This package contains api for the dm-framework
|
||||
endef
|
||||
|
||||
#
|
||||
# DM-Agent Package Definition
|
||||
#
|
||||
define Package/dm-agent
|
||||
DEPENDS:=+dm-api +libubox +libubus +ubus
|
||||
CATEGORY:=Genexis
|
||||
TITLE:=dm-framework agent
|
||||
URL:=http://www.genexis.eu
|
||||
PKG_LICENSE:=GENEXIS
|
||||
PKG_LICENSE_URL:=
|
||||
endef
|
||||
|
||||
define Package/dm-agent/description
|
||||
This package contains dm-framework agent.
|
||||
endef
|
||||
|
||||
#
|
||||
# Build Preparation
|
||||
#
|
||||
define Build/Prepare
|
||||
$(call Build/Prepare/Default)
|
||||
|
||||
# Prepare dm-api
|
||||
mkdir -p $(DMAPI_BUILD_DIR)
|
||||
$(CP) -rf $(PKG_BUILD_DIR)/dm-api/* $(DMAPI_BUILD_DIR)/
|
||||
|
||||
# Prepare dm-agent
|
||||
mkdir -p $(DMAGENT_BUILD_DIR)
|
||||
$(CP) -rf $(PKG_BUILD_DIR)/dm-agent/* $(DMAGENT_BUILD_DIR)/
|
||||
endef
|
||||
|
||||
TARGET_CFLAGS += $(FPIC)
|
||||
|
||||
#
|
||||
# Build Compilation
|
||||
#
|
||||
define Build/Compile
|
||||
# Build dm-api
|
||||
$(MAKE) -C $(DMAPI_BUILD_DIR)\
|
||||
PROJECT_ROOT="$(DMAPI_BUILD_DIR)" \
|
||||
CROSS_COMPILE="$(TARGET_CROSS)" \
|
||||
ARCH="$(LINUX_KARCH)" \
|
||||
EXTRA_CFLAGS="$(TARGET_CFLAGS) -I$(DMAPI_BUILD_DIR)" \
|
||||
all
|
||||
|
||||
# Build dm-agent (depends on dm-api)
|
||||
$(MAKE) -C $(DMAGENT_BUILD_DIR)\
|
||||
PROJECT_ROOT="$(DMAGENT_BUILD_DIR)" \
|
||||
CROSS_COMPILE="$(TARGET_CROSS)" \
|
||||
ARCH="$(LINUX_KARCH)" \
|
||||
EXTRA_CFLAGS="$(TARGET_CFLAGS) -I$(DMAGENT_BUILD_DIR)" \
|
||||
all
|
||||
endef
|
||||
|
||||
#
|
||||
# Development Installation (headers and libraries)
|
||||
#
|
||||
define Build/InstallDev
|
||||
$(INSTALL_DIR) $(1)/usr/include
|
||||
$(INSTALL_DIR) $(1)/usr/lib
|
||||
|
||||
# DM-API development files - headers are now in dm-api/include/
|
||||
$(CP) $(DMAPI_BUILD_DIR)/include/dm_types.h $(1)/usr/include/
|
||||
$(CP) $(DMAPI_BUILD_DIR)/include/dm_node.h $(1)/usr/include/
|
||||
$(CP) $(DMAPI_BUILD_DIR)/core/dm_api.h $(1)/usr/include/
|
||||
$(CP) $(DMAPI_BUILD_DIR)/core/dm_linker.h $(1)/usr/include/
|
||||
$(CP) $(DMAPI_BUILD_DIR)/core/dbmgr.h $(1)/usr/include/
|
||||
$(CP) $(DMAPI_BUILD_DIR)/include/dm_log.h $(1)/usr/include/
|
||||
$(CP) $(DMAPI_BUILD_DIR)/utils/dm_list.h $(1)/usr/include/
|
||||
$(CP) $(DMAPI_BUILD_DIR)/libdmapi.so $(1)/usr/lib/
|
||||
|
||||
# Install json2code.js script and package.json to staging for other packages to use
|
||||
$(INSTALL_DIR) $(1)/usr/lib/dm-framework/scripts
|
||||
$(CP) $(PKG_BUILD_DIR)/scripts/json2code.js $(1)/usr/lib/dm-framework/scripts/
|
||||
$(CP) $(PKG_BUILD_DIR)/scripts/package.json $(1)/usr/lib/dm-framework/scripts/
|
||||
endef
|
||||
|
||||
#
|
||||
# Package Installation - DM-API
|
||||
#
|
||||
define Package/dm-api/install
|
||||
$(INSTALL_DIR) $(1)/usr/lib
|
||||
$(INSTALL_DIR) $(1)/sbin/
|
||||
$(INSTALL_DIR) $(1)/etc/bbfdm/dmf
|
||||
|
||||
$(INSTALL_BIN) $(DMAPI_BUILD_DIR)/libdmapi.so $(1)/usr/lib/
|
||||
$(CP) $(DMAPI_BUILD_DIR)/quickjs/uci.js $(1)/etc/bbfdm/dmf/
|
||||
$(CP) $(DMAPI_BUILD_DIR)/quickjs/utils.js $(1)/etc/bbfdm/dmf/
|
||||
endef
|
||||
|
||||
#
|
||||
# Package Installation - DM-Agent
|
||||
#
|
||||
define Package/dm-agent/install
|
||||
$(INSTALL_DIR) $(1)/usr/sbin
|
||||
$(INSTALL_DIR) $(1)/etc/init.d
|
||||
$(INSTALL_DIR) $(1)/etc/config
|
||||
$(BBFDM_REGISTER_SERVICES) ./dmf_service.json $(1) $(PKG_NAME)
|
||||
$(INSTALL_BIN) $(DMAGENT_BUILD_DIR)/dm-agent $(1)/usr/sbin
|
||||
endef
|
||||
|
||||
define Package/dm-framework
|
||||
CATEGORY:=Genexis
|
||||
TITLE:=DM Framework Meta Package
|
||||
DEPENDS:=+dm-api +dm-agent
|
||||
URL:=http://www.genexis.eu
|
||||
PKG_LICENSE:=GENEXIS
|
||||
endef
|
||||
|
||||
define Package/dm-framework/description
|
||||
This is a meta package that pulls in dm-api and dm-agent.
|
||||
endef
|
||||
|
||||
define Package/dm-framework/install
|
||||
true
|
||||
endef
|
||||
|
||||
# Register all three packages
|
||||
$(eval $(call BuildPackage,dm-api))
|
||||
$(eval $(call BuildPackage,dm-agent))
|
||||
$(eval $(call BuildPackage,dm-framework))
|
||||
33
dm-framework/dm-framework.mk
Normal file
33
dm-framework/dm-framework.mk
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# dm-framework.mk - Common rules for DM Framework
|
||||
|
||||
DM_SCRIPT_DIR ?= $(STAGING_DIR)/usr/lib/dm-framework/scripts
|
||||
JSON2CODE = $(DM_SCRIPT_DIR)/json2code.js
|
||||
|
||||
# Macro to generate code
|
||||
# $(1): Input directory (datamodels)
|
||||
# $(2): Output directory (where generated files go)
|
||||
# $(3): Vendor Prefix (optional)
|
||||
define Build/Compile/DM
|
||||
$(INSTALL_DIR) $(2)
|
||||
@# Install npm dependencies if not already installed
|
||||
@if [ ! -d "$(DM_SCRIPT_DIR)/node_modules" ]; then \
|
||||
cd $(DM_SCRIPT_DIR) && npm install --production; \
|
||||
fi
|
||||
node $(JSON2CODE) -i $(1) -o $(2) $(if $(3),--vendor-prefix $(3))
|
||||
$(TARGET_CC) $(TARGET_CFLAGS) -I$(2) -I$(STAGING_DIR)/usr/include/ -fPIC -c $(2)/dm.c -o $(2)/dm.o
|
||||
$(TARGET_CC) $(TARGET_LDFLAGS) -shared -o $(2)/lib$(PKG_NAME).so $(2)/dm.o
|
||||
endef
|
||||
|
||||
# Macro to install DM
|
||||
# $(1): Input directory (datamodels)
|
||||
# $(2): Output directory (build dir)
|
||||
# $(3): Destination directory (rootfs)
|
||||
# $(4): Package Name (subdir in /etc/bbfdm/dmf)
|
||||
define Build/Install/DM
|
||||
$(INSTALL_DIR) $(3)/etc/bbfdm/dmf/$(4)
|
||||
$(CP) $(2)/lib$(PKG_NAME).so $(3)/etc/bbfdm/dmf/$(4)/
|
||||
$(CP) $(1)/*.js $(3)/etc/bbfdm/dmf/$(4)/
|
||||
$(CP) $(2)/default.db $(3)/etc/bbfdm/dmf/default_dm.db
|
||||
$(CP) $(2)/exports.js $(3)/etc/bbfdm/dmf/$(4)/exports.js
|
||||
$(CP) $(2)/dm_consts.js $(3)/etc/bbfdm/dmf/$(4)/dm_consts.js
|
||||
endef
|
||||
17
dm-framework/dmf_service.json
Normal file
17
dm-framework/dmf_service.json
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"daemon": {
|
||||
"enable": "1",
|
||||
"service_name": "dmf",
|
||||
"dm-framework": true,
|
||||
"unified_daemon": false,
|
||||
"services": [
|
||||
{
|
||||
"parent_dm": "Device.",
|
||||
"object": "Bridging"
|
||||
}
|
||||
],
|
||||
"config": {
|
||||
"loglevel": "3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,12 +6,12 @@
|
|||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=ieee1905
|
||||
PKG_VERSION:=8.7.42
|
||||
PKG_VERSION:=8.7.43
|
||||
|
||||
LOCAL_DEV=0
|
||||
ifneq ($(LOCAL_DEV),1)
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_VERSION:=2e7d1377794b8d4f8aad252265110b09b129fdc8
|
||||
PKG_SOURCE_VERSION:=48f1eb0ffceea5b6cd98846d7f774387f1e57401
|
||||
PKG_SOURCE_URL:=https://dev.iopsys.eu/multi-ap/ieee1905.git
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)_$(PKG_SOURCE_VERSION).tar.xz
|
||||
PKG_MIRROR_HASH:=skip
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ PKG_NAME:=iopsys-analytics
|
|||
PKG_RELEASE:=$(COMMITCOUNT)
|
||||
PKG_LICENSE:=PROPRIETARY
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_VERSION:=25e32ac5a860aec6e53e3449565b71595073e014
|
||||
PKG_SOURCE_VERSION:=7c2780b4c24e5a1078c060bf9d3a03365f71f06a
|
||||
PKG_SOURCE_URL:=https://dev.iopsys.eu/iopsys/iopsys-analytics.git
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)_$(PKG_SOURCE_VERSION).tar.xz
|
||||
PKG_MIRROR_HASH:=skip
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@
|
|||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=map-agent
|
||||
PKG_VERSION:=6.5.0.7
|
||||
PKG_VERSION:=6.5.0.8
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_SOURCE_VERSION:=189c1d101ed4be399ebca6cad2c95808f6a7ffde
|
||||
PKG_SOURCE_VERSION:=725909127f3ba4be38ae6e8f13b70260062737a6
|
||||
PKG_MAINTAINER:=Jakob Olsson <jakob.olsson@iopsys.eu>
|
||||
|
||||
PKG_LICENSE:=BSD-3-Clause
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@
|
|||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=map-controller
|
||||
PKG_VERSION:=6.4.4.13
|
||||
PKG_VERSION:=6.4.4.14
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_SOURCE_VERSION:=bd0fb2b63830e19038d9495517c03fdc3900cdfa
|
||||
PKG_SOURCE_VERSION:=abd127215616717506fb03c94ca629f22768ff4f
|
||||
PKG_MAINTAINER:=Jakob Olsson <jakob.olsson@genexis.eu>
|
||||
|
||||
LOCAL_DEV=0
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
#!/bin/sh
|
||||
|
||||
. /lib/functions.sh
|
||||
|
||||
cfg="mapcontroller"
|
||||
config_load "$cfg"
|
||||
|
||||
used_ids=""
|
||||
|
||||
collect_used_ids() {
|
||||
local section="$1"
|
||||
local id
|
||||
|
||||
id=$(uci -q get ${cfg}.${section}.id)
|
||||
if [ -n "$id" ] && printf "%s" "$id" | grep -qE '^[0-9]+$'; then
|
||||
used_ids="$used_ids $id"
|
||||
fi
|
||||
}
|
||||
|
||||
# Find first available ID from 0 to INT32_MAX
|
||||
find_first_available_id() {
|
||||
local max_int=2147483647
|
||||
local expected=0
|
||||
local id
|
||||
|
||||
# Convert list to sorted unique list
|
||||
sorted_ids=$(printf "%s\n" $used_ids | sort -n | uniq)
|
||||
|
||||
for id in $sorted_ids; do
|
||||
if [ "$id" -eq "$expected" ]; then
|
||||
expected=$((expected + 1))
|
||||
elif [ "$id" -gt "$expected" ]; then
|
||||
# Found a gap -> return the gap
|
||||
echo "$expected"
|
||||
return
|
||||
fi
|
||||
done
|
||||
|
||||
# If no gaps, next available is `expected`
|
||||
if [ "$expected" -le "$max_int" ]; then
|
||||
echo "$expected"
|
||||
else
|
||||
echo -1
|
||||
fi
|
||||
}
|
||||
|
||||
# Assign ID if missing
|
||||
add_qos_rule_id() {
|
||||
local section="$1"
|
||||
local id
|
||||
|
||||
id=$(uci -q get ${cfg}.${section}.id)
|
||||
if [ -z "$id" ]; then
|
||||
new_id=$(find_first_available_id)
|
||||
[ "$new_id" -ge 0 ] || return # No available ID
|
||||
uci -q set ${cfg}.${section}.id="$new_id"
|
||||
|
||||
used_ids="$used_ids $new_id"
|
||||
fi
|
||||
}
|
||||
|
||||
# Step 1: Collect all existing IDs
|
||||
config_foreach collect_used_ids qos_rule
|
||||
|
||||
# Step 2: Assign IDs to rules missing them
|
||||
config_foreach add_qos_rule_id qos_rule
|
||||
|
|
@ -14,5 +14,3 @@ for sec in $sections; do
|
|||
|
||||
uci rename $cfg.$s=$sec
|
||||
done
|
||||
|
||||
uci commit $cfg
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@
|
|||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=parental-control
|
||||
PKG_VERSION:=1.4.4
|
||||
PKG_VERSION:=1.4.6
|
||||
|
||||
LOCAL_DEV:=0
|
||||
ifneq ($(LOCAL_DEV),1)
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://dev.iopsys.eu/network/parental-control.git
|
||||
PKG_SOURCE_VERSION:=d0eabdda9790d1df3cec30589c97214731108367
|
||||
PKG_SOURCE_VERSION:=11777ff069888fc543c2501110313b654bbbfbc9
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
PKG_MIRROR_HASH:=skip
|
||||
endif
|
||||
|
|
@ -27,7 +27,7 @@ define Package/parental-control
|
|||
CATEGORY:=Utilities
|
||||
TITLE:=URL filter
|
||||
DEPENDS:=+libuci +libnetfilter-queue +libnfnetlink +iptables-mod-nfqueue +libpthread
|
||||
DEPENDS+=+libubox +ubus +conntrack +libcurl +cmph
|
||||
DEPENDS+=+libubox +ubus +conntrack +libcurl +cmph +libjson-c
|
||||
DEPENDS+=+libbbfdm-api +libbbfdm-ubus +dm-service
|
||||
endef
|
||||
|
||||
|
|
@ -87,11 +87,10 @@ define Package/parental-control/install
|
|||
|
||||
$(INSTALL_DATA) ./files/etc/uci-defaults/40-parental_control_update_bundle_path $(1)/etc/uci-defaults/
|
||||
ifeq ($(CONFIG_PARENTAL_CONTROL_URLFILTERING),y)
|
||||
$(INSTALL_DATA) ./files/etc/uci-defaults/50-parental_control_add_bundles $(1)/etc/uci-defaults/
|
||||
$(CP) ./files/urlbundle_override.json $(1)/etc/parentalcontrol/
|
||||
$(INSTALL_DATA) ./files/etc/parentalcontrol/url_bundles.json $(1)/etc/parentalcontrol/
|
||||
$(INSTALL_DATA) ./files/etc/parentalcontrol/urlbundle_override.json $(1)/etc/parentalcontrol/
|
||||
else
|
||||
$(BBFDM_INSTALL_MS_PLUGIN) -v ${VENDOR_PREFIX} ./files/urlbundle_override.json $(1) parentalcontrol
|
||||
$(INSTALL_DATA) ./files/etc/uci-defaults/50-parental_control_disable_urlfilter $(1)/etc/uci-defaults/
|
||||
endif
|
||||
endef
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
config globals 'globals'
|
||||
option enable '1'
|
||||
option loglevel '3'
|
||||
option urlfilter '0'
|
||||
|
|
|
|||
76
parental-control/files/etc/parentalcontrol/url_bundles.json
Normal file
76
parental-control/files/etc/parentalcontrol/url_bundles.json
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
{
|
||||
"urlBundles": [
|
||||
{
|
||||
"url": "https://blocklistproject.github.io/Lists/alt-version/abuse-nl.txt",
|
||||
"name": "Abuse"
|
||||
},
|
||||
{
|
||||
"url": "https://blocklistproject.github.io/Lists/alt-version/ads-nl.txt",
|
||||
"name": "Ads"
|
||||
},
|
||||
{
|
||||
"url": "https://blocklistproject.github.io/Lists/alt-version/crypto-nl.txt",
|
||||
"name": "Crypto"
|
||||
},
|
||||
{
|
||||
"url": "https://blocklistproject.github.io/Lists/alt-version/drugs-nl.txt",
|
||||
"name": "Drugs"
|
||||
},
|
||||
{
|
||||
"url": "https://blocklistproject.github.io/Lists/alt-version/everything-nl.txt",
|
||||
"name": "Everything else"
|
||||
},
|
||||
{
|
||||
"url": "https://blocklistproject.github.io/Lists/alt-version/facebook-nl.txt",
|
||||
"name": "Facebook/Instagram"
|
||||
},
|
||||
{
|
||||
"url": "https://blocklistproject.github.io/Lists/alt-version/fraud-nl.txt",
|
||||
"name": "Fraud"
|
||||
},
|
||||
{
|
||||
"url": "https://blocklistproject.github.io/Lists/alt-version/gambling-nl.txt",
|
||||
"name": "Gambling"
|
||||
},
|
||||
{
|
||||
"url": "https://blocklistproject.github.io/Lists/alt-version/malware-nl.txt",
|
||||
"name": "Malware"
|
||||
},
|
||||
{
|
||||
"url": "https://blocklistproject.github.io/Lists/alt-version/phishing-nl.txt",
|
||||
"name": "Phishing"
|
||||
},
|
||||
{
|
||||
"url": "https://blocklistproject.github.io/Lists/alt-version/piracy-nl.txt",
|
||||
"name": "Piracy"
|
||||
},
|
||||
{
|
||||
"url": "https://blocklistproject.github.io/Lists/alt-version/porn-nl.txt",
|
||||
"name": "Porn"
|
||||
},
|
||||
{
|
||||
"url": "https://blocklistproject.github.io/Lists/alt-version/ransomware-nl.txt",
|
||||
"name": "Ransomware"
|
||||
},
|
||||
{
|
||||
"url": "https://blocklistproject.github.io/Lists/alt-version/redirect-nl.txt",
|
||||
"name": "Redirect"
|
||||
},
|
||||
{
|
||||
"url": "https://blocklistproject.github.io/Lists/alt-version/scam-nl.txt",
|
||||
"name": "Scam"
|
||||
},
|
||||
{
|
||||
"url": "https://blocklistproject.github.io/Lists/alt-version/tiktok-nl.txt",
|
||||
"name": "TikTok"
|
||||
},
|
||||
{
|
||||
"url": "https://blocklistproject.github.io/Lists/alt-version/torrent-nl.txt",
|
||||
"name": "Torrent"
|
||||
},
|
||||
{
|
||||
"url": "https://blocklistproject.github.io/Lists/alt-version/tracking-nl.txt",
|
||||
"name": "Tracking"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -25,14 +25,6 @@ check_mounted_app_partition() {
|
|||
|
||||
if check_mounted_app_partition; then
|
||||
uci -q set parentalcontrol.globals.bundle_path="${APPS_DIR}/parentalcontrol"
|
||||
|
||||
# configure the urlfilter if not configured
|
||||
urlfilter="$(uci -q get parentalcontrol.globals.urlfilter)"
|
||||
if [ -z "${urlfilter}" ]; then
|
||||
uci -q set parentalcontrol.globals.urlfilter='1'
|
||||
fi
|
||||
else
|
||||
uci -q set parentalcontrol.globals.urlfilter='0'
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
[ ! -f "/etc/config/parentalcontrol" ] && exit 0
|
||||
|
||||
COUNT=1
|
||||
|
||||
add_urlbundle()
|
||||
{
|
||||
local name url
|
||||
|
||||
url="${1}"; shift
|
||||
name="$*"
|
||||
|
||||
uci -q set parentalcontrol.urlbundle_${COUNT}=urlbundle
|
||||
uci -q set parentalcontrol.urlbundle_${COUNT}.name="${name}"
|
||||
uci -q set parentalcontrol.urlbundle_${COUNT}.download_url="${url}"
|
||||
|
||||
COUNT="$((COUNT+1))"
|
||||
}
|
||||
|
||||
urlfilter="$(uci -q get parentalcontrol.globals.urlfilter)"
|
||||
if [ "${urlfilter}" -eq "1" ]; then
|
||||
add_urlbundle "https://blocklistproject.github.io/Lists/alt-version/abuse-nl.txt" "Abuse"
|
||||
add_urlbundle "https://blocklistproject.github.io/Lists/alt-version/ads-nl.txt" "Ads"
|
||||
add_urlbundle "https://blocklistproject.github.io/Lists/alt-version/crypto-nl.txt" "Crypto"
|
||||
add_urlbundle "https://blocklistproject.github.io/Lists/alt-version/drugs-nl.txt" "Drugs"
|
||||
add_urlbundle 'https://blocklistproject.github.io/Lists/alt-version/everything-nl.txt' "Everything else"
|
||||
add_urlbundle 'https://blocklistproject.github.io/Lists/alt-version/facebook-nl.txt' 'Facebook/Instagram'
|
||||
add_urlbundle 'https://blocklistproject.github.io/Lists/alt-version/fraud-nl.txt' 'Fraud'
|
||||
add_urlbundle 'https://blocklistproject.github.io/Lists/alt-version/gambling-nl.txt' 'Gambling'
|
||||
add_urlbundle 'https://blocklistproject.github.io/Lists/alt-version/malware-nl.txt' 'Malware'
|
||||
add_urlbundle 'https://blocklistproject.github.io/Lists/alt-version/phishing-nl.txt' 'Phishing'
|
||||
add_urlbundle 'https://blocklistproject.github.io/Lists/alt-version/piracy-nl.txt' 'Piracy'
|
||||
add_urlbundle 'https://blocklistproject.github.io/Lists/alt-version/porn-nl.txt' 'Porn'
|
||||
add_urlbundle 'https://blocklistproject.github.io/Lists/alt-version/ransomware-nl.txt' 'Ransomware'
|
||||
add_urlbundle 'https://blocklistproject.github.io/Lists/alt-version/redirect-nl.txt' 'Redirect'
|
||||
add_urlbundle 'https://blocklistproject.github.io/Lists/alt-version/scam-nl.txt' 'Scam'
|
||||
add_urlbundle 'https://blocklistproject.github.io/Lists/alt-version/tiktok-nl.txt' 'TikTok'
|
||||
add_urlbundle 'https://blocklistproject.github.io/Lists/alt-version/torrent-nl.txt' 'Torrent'
|
||||
add_urlbundle 'https://blocklistproject.github.io/Lists/alt-version/tracking-nl.txt' 'Tracking'
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
. /lib/functions.sh
|
||||
|
||||
[ ! -f "/etc/config/parentalcontrol" ] && exit 0
|
||||
|
||||
uci -q set parentalcontrol.globals.urlfilter='0'
|
||||
|
||||
_delete_urlbundle() {
|
||||
uci_remove parentalcontrol "${1}"
|
||||
}
|
||||
|
||||
config_load "parentalcontrol"
|
||||
config_foreach _delete_urlbundle urlbundle
|
||||
|
|
@ -1,10 +1,12 @@
|
|||
#!/bin/sh
|
||||
|
||||
. /lib/functions.sh
|
||||
. /usr/share/libubox/jshn.sh
|
||||
|
||||
LOCKFILE="/tmp/sync_bundles.lock"
|
||||
log_level="$(uci -q get parentalcontrol.globals.loglevel)"
|
||||
log_level="${log_level:-1}"
|
||||
URLBUNDLE_JSON="/etc/parentalcontrol/url_bundles.json"
|
||||
DEBUG=0
|
||||
|
||||
log_err() {
|
||||
|
|
@ -85,6 +87,7 @@ update_bundle_file_from_url() {
|
|||
local success=0
|
||||
while [ $attempt -le 3 ]; do
|
||||
if curl -s -o "$temp_file" "$download_url"; then
|
||||
log_info "Download successful for $download_url"
|
||||
success=1
|
||||
break
|
||||
else
|
||||
|
|
@ -218,24 +221,33 @@ cleanup_bundle_files() {
|
|||
# Collect all download_url entries using config_foreach
|
||||
local urls=""
|
||||
get_download_url() {
|
||||
local section="$1"
|
||||
config_get url "$section" download_url
|
||||
config_get_bool enable "$1" enable 1
|
||||
local enable url
|
||||
|
||||
json_select "${2}"
|
||||
|
||||
json_get_var url url
|
||||
json_get_var enable enable
|
||||
enable="${enable:-1}"
|
||||
|
||||
if [ "${enable}" -eq 0 ]; then
|
||||
# bundle is disabled
|
||||
log_info "get_download_url: Skipping bundle ${name} not enabled"
|
||||
json_select ..
|
||||
return 0
|
||||
fi
|
||||
|
||||
url="${url#file://}"
|
||||
url="${url#https://}"
|
||||
url="${url#http://}"
|
||||
|
||||
url="${url##*/}" # Get everything after the last '/'
|
||||
urls="$urls $url"
|
||||
json_select ..
|
||||
}
|
||||
|
||||
config_load parentalcontrol
|
||||
config_foreach get_download_url urlbundle
|
||||
json_init
|
||||
json_load_file "${URLBUNDLE_JSON}"
|
||||
|
||||
json_for_each_item get_download_url "urlBundles"
|
||||
|
||||
# Loop through all files in the directory
|
||||
for file in "$dir"/*; do
|
||||
|
|
@ -294,30 +306,29 @@ handle_filter_for_bundles() {
|
|||
fi
|
||||
|
||||
check_bundle_exists() {
|
||||
local enable download_url name cfg
|
||||
local enable url name
|
||||
|
||||
cfg="$1"
|
||||
config_get name "$cfg" name
|
||||
config_get_bool enable "$cfg" enable 1
|
||||
config_get download_url "$cfg" download_url
|
||||
json_select "${2}"
|
||||
|
||||
json_get_var name name
|
||||
json_get_var url url
|
||||
json_get_var enable enable
|
||||
enable="${enable:-1}"
|
||||
|
||||
if [ "${enable}" -eq 0 ]; then
|
||||
log_info "Skipping bundle ${name} not enabled"
|
||||
log_info "check_bundle_exists: Skipping bundle ${name} not enabled"
|
||||
json_select ..
|
||||
return 0
|
||||
fi
|
||||
|
||||
handle_download_url "$download_url" "$name"
|
||||
local exit_status=$?
|
||||
if [ "$exit_status" -eq 1 ]; then
|
||||
uci -q set "parentalcontrol.${cfg}.status"="Error"
|
||||
else
|
||||
uci -q set "parentalcontrol.${cfg}.status"=""
|
||||
fi
|
||||
|
||||
uci commit parentalcontrol
|
||||
handle_download_url "${url}" "${name}"
|
||||
json_select ..
|
||||
}
|
||||
|
||||
config_foreach check_bundle_exists urlbundle
|
||||
json_init
|
||||
json_load_file "${URLBUNDLE_JSON}"
|
||||
|
||||
json_for_each_item check_bundle_exists "urlBundles"
|
||||
}
|
||||
|
||||
# Open file descriptor 200 for locking
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ MAKE_FLAGS = \
|
|||
EXTRA_LIBS="-latomic" \
|
||||
CROSS_PREFIX="$(TARGET_CROSS)"
|
||||
|
||||
# Ensure the static library is built with position independent code so it can
|
||||
# be linked into shared objects.
|
||||
TARGET_CFLAGS += -fPIC
|
||||
|
||||
define Build/Compile
|
||||
# The upstream Makefile uses the same CFLAGS for host and target builds,
|
||||
# which breaks cross-compilation. We work around this by first building
|
||||
|
|
|
|||
|
|
@ -28,4 +28,15 @@ config SSHMNGR_SFTP
|
|||
default y
|
||||
help
|
||||
Enable this option to support the SFTP protocol.
|
||||
|
||||
config SSHMNGR_SECURITY_MFA
|
||||
bool "MFA using PAM and Google authenticator"
|
||||
depends on SSHMNGR_BACKEND_OPENSSH_PAM
|
||||
default n
|
||||
help
|
||||
Enable this option to use MFA with PAM based Google authenticator.
|
||||
|
||||
config SSHMNGR_VENDOR_PREFIX
|
||||
string "Package specific datamodel Vendor Prefix for TR181 extensions"
|
||||
default ""
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ define Package/sshmngr
|
|||
DEPENDS+=+SSHMNGR_BACKEND_OPENSSH_PAM:openssh-server-pam +SSHMNGR_BACKEND_OPENSSH_PAM:openssh-client-utils
|
||||
DEPENDS+=+SSHMNGR_BACKEND_DROPBEAR:dropbear
|
||||
DEPENDS+=+SSHMNGR_SFTP:openssh-sftp-server
|
||||
DEPENDS+=+SSHMNGR_SECURITY_MFA:google-authenticator-libpam
|
||||
endef
|
||||
|
||||
define Package/sshmngr/description
|
||||
|
|
@ -44,6 +45,13 @@ define Package/$(PKG_NAME)/config
|
|||
source "$(SOURCE)/Config.in"
|
||||
endef
|
||||
|
||||
ifeq ($(CONFIG_SSHMNGR_VENDOR_PREFIX),"")
|
||||
VENDOR_PREFIX = $(CONFIG_BBF_VENDOR_PREFIX)
|
||||
else
|
||||
VENDOR_PREFIX = $(CONFIG_SSHMNGR_VENDOR_PREFIX)
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($(LOCAL_DEV),1)
|
||||
define Build/Prepare
|
||||
$(CP) -rf ./sshmngr/* $(PKG_BUILD_DIR)/
|
||||
|
|
@ -67,6 +75,16 @@ endif
|
|||
$(BBFDM_REGISTER_SERVICES) ./bbfdm_service.json $(1) $(PKG_NAME)
|
||||
$(BBFDM_INSTALL_MS_DM) $(PKG_BUILD_DIR)/src/libsshmngr.so $(1) $(PKG_NAME)
|
||||
|
||||
ifeq ($(CONFIG_SSHMNGR_BACKEND_OPENSSH_PAM),y)
|
||||
$(INSTALL_DIR) $(1)/etc/uci-defaults
|
||||
$(INSTALL_DATA) ./files/openssh_backend/lib/sshmngr/pam_config.sh $(1)/lib/sshmngr/
|
||||
$(INSTALL_BIN) ./files/openssh_backend/etc/uci-defaults/91-set-sshd-pam $(1)/etc/uci-defaults/
|
||||
ifeq ($(CONFIG_SSHMNGR_SECURITY_MFA),y)
|
||||
$(INSTALL_BIN) ./files/openssh_backend/etc/uci-defaults/92-set-ssh-mfa $(1)/etc/uci-defaults/
|
||||
$(BBFDM_INSTALL_MS_PLUGIN) -v ${VENDOR_PREFIX} ./files/openssh_backend/ssh_mfa_override.json $(1) $(PKG_NAME)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_PACKAGE_fail2ban),y)
|
||||
$(INSTALL_DIR) $(1)/etc/fail2ban/jail.d
|
||||
$(INSTALL_DIR) $(1)/etc/fail2ban/filter.d/
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
. /usr/share/libubox/jshn.sh
|
||||
. /lib/sshmngr/backend.sh
|
||||
|
||||
MFA_SECRET_FILE="/etc/security/mfa_secret"
|
||||
|
||||
add_server_name()
|
||||
{
|
||||
local server_sec="${1}"
|
||||
|
|
@ -44,7 +46,7 @@ get_pid()
|
|||
|
||||
case "$1" in
|
||||
list)
|
||||
echo '{ "dump" : {"server_name":"string"}, "kill_session" : {"session_pid":"string","server_name":"string"}, "list_keys" : {}, "add_pubkey" : {"current_key":"string","new_key":"string"}, "remove_pubkey" : {"key":"string"} }'
|
||||
echo '{ "dump" : {"server_name":"string"}, "kill_session" : {"session_pid":"string","server_name":"string"}, "list_keys" : {}, "add_pubkey" : {"current_key":"string","new_key":"string"}, "remove_pubkey" : {"key":"string"}, "get_mfa_key" : {}, "get_mfa_recovery" : {} }'
|
||||
;;
|
||||
call)
|
||||
case "$2" in
|
||||
|
|
@ -221,6 +223,31 @@ case "$1" in
|
|||
fi
|
||||
echo '{}'
|
||||
;;
|
||||
|
||||
get_mfa_key)
|
||||
mfa_key=""
|
||||
if [ -f "${MFA_SECRET_FILE}" ]; then
|
||||
mfa_key="$(head -n 1 "$MFA_SECRET_FILE" 2>/dev/null)"
|
||||
fi
|
||||
|
||||
json_init
|
||||
json_add_string "mfa_key" "${mfa_key}"
|
||||
json_dump
|
||||
;;
|
||||
|
||||
get_mfa_recovery)
|
||||
mfa_recovery_codes=""
|
||||
|
||||
if [ -f "${MFA_SECRET_FILE}" ]; then
|
||||
mfa_recovery_codes="$(tail -n 3 "$MFA_SECRET_FILE" 2>/dev/null | tr '\n' ',')"
|
||||
# remove trailing comma
|
||||
mfa_recovery_codes="${mfa_recovery_codes%,}"
|
||||
fi
|
||||
|
||||
json_init
|
||||
json_add_string "recovery_codes" "${mfa_recovery_codes}"
|
||||
json_dump
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
#!/bin/sh
|
||||
|
||||
# create or over-write our desired file
|
||||
# /etc/pam.d/sshd
|
||||
cat << 'EOF' > /etc/pam.d/sshd
|
||||
auth required pam_env.so
|
||||
auth include sshd-auth
|
||||
account required pam_nologin.so
|
||||
account include sshd-account
|
||||
session include common-session
|
||||
session required pam_limits.so
|
||||
password include sshd-password
|
||||
EOF
|
||||
|
||||
# /etc/pam.d/sshd-auth
|
||||
cat << 'EOF' > /etc/pam.d/sshd-auth
|
||||
auth [success=1 default=ignore] pam_unix.so nullok_secure
|
||||
auth requisite pam_deny.so
|
||||
auth required pam_permit.so
|
||||
EOF
|
||||
|
||||
# /etc/pam.d/sshd-password
|
||||
cat << 'EOF' > /etc/pam.d/sshd-password
|
||||
password [success=1 default=ignore] pam_unix.so sha512
|
||||
password requisite pam_deny.so
|
||||
password required pam_permit.so
|
||||
EOF
|
||||
|
||||
# /etc/pam.d/sshd-account
|
||||
cat << 'EOF' > /etc/pam.d/sshd-account
|
||||
account [success=1 new_authtok_reqd=done default=ignore] pam_unix.so
|
||||
account requisite pam_deny.so
|
||||
account required pam_permit.so
|
||||
EOF
|
||||
|
||||
exit 0
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#!/bin/sh
|
||||
|
||||
if [ -f /etc/config/sshd ]; then
|
||||
# make sure not to change already existing setting
|
||||
if ! uci -q get sshd.@sshd[0].UseMFA 2>&1 > /dev/null; then
|
||||
uci -q set sshd.@sshd[0].UseMFA=1
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
||||
228
sshmngr/files/openssh_backend/lib/sshmngr/pam_config.sh
Executable file
228
sshmngr/files/openssh_backend/lib/sshmngr/pam_config.sh
Executable file
|
|
@ -0,0 +1,228 @@
|
|||
#!/bin/sh
|
||||
|
||||
# List of required .so files
|
||||
REQUIRED_MODULES="
|
||||
/usr/lib/security/pam_faildelay.so
|
||||
/usr/lib/security/pam_faillock.so
|
||||
/usr/lib/security/pam_unix.so
|
||||
/usr/lib/security/pam_deny.so
|
||||
/usr/lib/security/pam_permit.so
|
||||
/usr/lib/security/pam_passwdqc.so
|
||||
"
|
||||
|
||||
MFA_APP="google-authenticator"
|
||||
MFA_LIB="/usr/lib/security/pam_google_authenticator.so"
|
||||
MFA_DIR="/etc/security"
|
||||
MFA_SECRET_FILE="${MFA_DIR}/mfa_secret"
|
||||
MFA_QR_FILE="${MFA_DIR}/mfa_qr"
|
||||
|
||||
log() {
|
||||
echo "$*" | logger -t sshd.init -p info
|
||||
}
|
||||
|
||||
log_err() {
|
||||
echo "$*" | logger -t sshd.init -p err
|
||||
}
|
||||
|
||||
check_required_modules() {
|
||||
for mod in $REQUIRED_MODULES; do
|
||||
if [ ! -f "$mod" ]; then
|
||||
log_err "ERROR: Cannot setup security policy, missing PAM module: $mod"
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
write_line() {
|
||||
local filepath="$1"
|
||||
local line="$2"
|
||||
|
||||
echo "$line" >> "$filepath"
|
||||
}
|
||||
|
||||
compare_and_replace() {
|
||||
local src dst
|
||||
src="$1"
|
||||
dst="$2"
|
||||
|
||||
if [ ! -f "$dst" ] || ! cmp -s "$src" "$dst"; then
|
||||
cp "$src" "$dst"
|
||||
log "Updated $dst"
|
||||
fi
|
||||
}
|
||||
|
||||
setup_mfa() {
|
||||
mkdir -p "$MFA_DIR"
|
||||
|
||||
if [ -f "${MFA_SECRET_FILE}" ] && [ -f "${MFA_QR_FILE}" ]; then
|
||||
log "Not updating MFA files, they already exist"
|
||||
return
|
||||
fi
|
||||
|
||||
touch "$MFA_SECRET_FILE"
|
||||
touch "$MFA_QR_FILE"
|
||||
chmod 600 "$MFA_SECRET_FILE"
|
||||
chmod 600 "$MFA_QR_FILE"
|
||||
|
||||
local cmd="$MFA_APP -f -s $MFA_SECRET_FILE -C -t -d -r 3 -R 30 -w 3 -Q UTF8 -e 3"
|
||||
|
||||
log "Running MFA app: $cmd"
|
||||
# if the google-authenticator senses that the output is not going to a terminal
|
||||
# then it does not print out the QR, so simple redirection does not work
|
||||
# we have to run the command inside a pseudo-terminal using script command
|
||||
# and then redirect that output to a file
|
||||
cmd="script -q -c \"$cmd\" $MFA_QR_FILE > /dev/null"
|
||||
eval "$cmd"
|
||||
}
|
||||
|
||||
update_auth() {
|
||||
# Write /etc/pam.d/sshd-auth
|
||||
local tmp_file pam_file
|
||||
tmp_file="/tmp/sshd-auth"
|
||||
pam_file="/etc/pam.d/sshd-auth"
|
||||
|
||||
local auth_enabled="${1}"
|
||||
local enabled="${2}"
|
||||
local mfa_enabled="${3}"
|
||||
|
||||
local faildelay="$(uci -q get users.authentication_policy.fail_delay || echo 3)"
|
||||
local faillock_lockout_time="$(uci -q get users.authentication_policy.faillock_lockout_time || echo 300)"
|
||||
local faillock_attempts="$(uci -q get users.authentication_policy.faillock_attempts || echo 6)"
|
||||
|
||||
# Convert seconds to microseconds for pam_faildelay
|
||||
local faildelay_usec=$((faildelay * 1000000))
|
||||
|
||||
rm -f "$tmp_file"
|
||||
touch "$tmp_file"
|
||||
|
||||
if [ "${auth_enabled}" -eq 1 ] && [ "${enabled}" -eq 1 ]; then
|
||||
write_line "$tmp_file" "auth optional pam_faildelay.so delay=$faildelay_usec"
|
||||
write_line "$tmp_file" "auth required pam_faillock.so preauth deny=$faillock_attempts even_deny_root unlock_time=$faillock_lockout_time"
|
||||
fi
|
||||
|
||||
write_line "$tmp_file" "auth [success=1 default=bad] pam_unix.so nullok_secure"
|
||||
write_line "$tmp_file" "auth [default=die] pam_faillock.so authfail audit deny=$faillock_attempts even_deny_root unlock_time=$faillock_lockout_time"
|
||||
|
||||
if [ "$mfa_enabled" -eq 1 ]; then
|
||||
write_line "$tmp_file" "auth [success=1 default=bad] pam_google_authenticator.so secret=$MFA_SECRET_FILE"
|
||||
write_line "$tmp_file" "auth [default=die] pam_faillock.so authfail audit deny=$faillock_attempts even_deny_root unlock_time=$faillock_lockout_time"
|
||||
fi
|
||||
|
||||
write_line "$tmp_file" "auth sufficient pam_faillock.so authsucc audit deny=$faillock_attempts even_deny_root unlock_time=$faillock_lockout_time"
|
||||
|
||||
write_line "$tmp_file" "auth requisite pam_deny.so"
|
||||
|
||||
compare_and_replace "$tmp_file" "$pam_file"
|
||||
}
|
||||
|
||||
build_pam_passwdqc_line() {
|
||||
local base="password requisite pam_passwdqc.so"
|
||||
local k v line
|
||||
|
||||
for line in $(uci show users.passwdqc 2>/dev/null); do
|
||||
case "$line" in
|
||||
users.passwdqc=*) continue ;;
|
||||
users.passwdqc.enabled=*) continue ;;
|
||||
esac
|
||||
|
||||
k="${line%%=*}"
|
||||
k="${k#users.passwdqc.}"
|
||||
v="${line#*=}"
|
||||
v="${v%\'}"
|
||||
v="${v#\'}"
|
||||
base="$base $k=$v"
|
||||
done
|
||||
|
||||
base="$base match=0"
|
||||
|
||||
echo "$base"
|
||||
}
|
||||
|
||||
# NOTE:
|
||||
# for some reason setting min 8 makes passwdqc accept minimum 12 letter password with this configuration
|
||||
# if we set it to 12 then we need atleast 16 characters and so on
|
||||
# passphrase = 0 means no space separated words
|
||||
# passphrase = N means the number of words required for a passphrase or 0 to disable the support for user-chosen passphrases.
|
||||
# rest can be figured out from passwdqc man page
|
||||
update_password() {
|
||||
local tmp_file pam_file enabled line
|
||||
tmp_file="/tmp/sshd-password"
|
||||
pam_file="/etc/pam.d/sshd-password"
|
||||
|
||||
local auth_enabled="${1}"
|
||||
|
||||
rm -f "$tmp_file"
|
||||
touch "$tmp_file"
|
||||
|
||||
# Check if section exists
|
||||
if uci -q get users.passwdqc >/dev/null 2>&1; then
|
||||
# if enabled is not present it is assumed to be 0
|
||||
enabled=$(uci -q get users.passwdqc.enabled || echo "0")
|
||||
if [ "${auth_enabled}" -eq 1 ] && [ "${enabled}" -eq 1 ]; then
|
||||
line="$(build_pam_passwdqc_line)"
|
||||
write_line "$tmp_file" "$line"
|
||||
fi
|
||||
fi
|
||||
|
||||
write_line "$tmp_file" "password [success=1 default=ignore] pam_unix.so sha512"
|
||||
write_line "$tmp_file" ""
|
||||
write_line "$tmp_file" "password requisite pam_deny.so"
|
||||
write_line "$tmp_file" "password required pam_permit.so"
|
||||
|
||||
compare_and_replace "$tmp_file" "$pam_file"
|
||||
}
|
||||
|
||||
update_account() {
|
||||
# Write /etc/pam.d/sshd-account
|
||||
local tmp_file pam_file
|
||||
tmp_file="/tmp/sshd-account"
|
||||
pam_file="/etc/pam.d/sshd-account"
|
||||
|
||||
local auth_enabled="${1}"
|
||||
local enabled="${2}"
|
||||
|
||||
rm -f "$tmp_file"
|
||||
touch "$tmp_file"
|
||||
|
||||
if [ "${auth_enabled}" -eq 1 ] && [ "${enabled}" -eq 1 ]; then
|
||||
write_line "$tmp_file" "account required pam_faillock.so"
|
||||
fi
|
||||
|
||||
write_line "$tmp_file" "account [success=1 new_authtok_reqd=done default=ignore] pam_unix.so"
|
||||
write_line "$tmp_file" ""
|
||||
write_line "$tmp_file" "account requisite pam_deny.so"
|
||||
write_line "$tmp_file" "account required pam_permit.so"
|
||||
|
||||
compare_and_replace "$tmp_file" "$pam_file"
|
||||
}
|
||||
|
||||
handle_security_policy() {
|
||||
local auth_enabled enabled
|
||||
local use_mfa mfa_enabled
|
||||
|
||||
# Read UCI values
|
||||
auth_enabled="$(uci -q get users.users.auth_policy_enable || echo 0)"
|
||||
enabled="$(uci -q get users.authentication_policy.enabled || echo 0)"
|
||||
use_mfa="$(uci -q get sshd.@sshd[0].UseMFA || echo 0)"
|
||||
|
||||
# if any .so files are missing, then we cannot setup security
|
||||
if ! check_required_modules; then
|
||||
return
|
||||
fi
|
||||
|
||||
# Detect and enable MFA only if requested and module exists
|
||||
if which "$MFA_APP" > /dev/null 2>&1 && [ "$use_mfa" = "1" ] && [ -f "$MFA_LIB" ]; then
|
||||
mfa_enabled=1
|
||||
setup_mfa
|
||||
else
|
||||
rm -rf "${MFA_QR_FILE}"
|
||||
rm -rf "${MFA_SECRET_FILE}"
|
||||
mfa_enabled=0
|
||||
fi
|
||||
|
||||
update_auth "${auth_enabled}" "${enabled}" "${mfa_enabled}"
|
||||
update_account "${auth_enabled}" "${enabled}"
|
||||
update_password "${auth_enabled}"
|
||||
}
|
||||
68
sshmngr/files/openssh_backend/ssh_mfa_override.json
Normal file
68
sshmngr/files/openssh_backend/ssh_mfa_override.json
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
{
|
||||
"json_plugin_version": 2,
|
||||
"Device.SSH.Server.{i}.": {
|
||||
"type": "object",
|
||||
"protocols": [
|
||||
"cwmp",
|
||||
"usp"
|
||||
],
|
||||
"access": false,
|
||||
"array": false,
|
||||
"{BBF_VENDOR_PREFIX}UseMFA": {
|
||||
"type": "boolean",
|
||||
"read": true,
|
||||
"write": true,
|
||||
"protocols": [
|
||||
"cwmp",
|
||||
"usp"
|
||||
],
|
||||
"mapping": [
|
||||
{
|
||||
"data": "@Parent",
|
||||
"type": "uci_sec",
|
||||
"key": "UseMFA"
|
||||
}
|
||||
]
|
||||
},
|
||||
"{BBF_VENDOR_PREFIX}MFA_Key": {
|
||||
"type": "string",
|
||||
"read": true,
|
||||
"write": false,
|
||||
"protocols": [
|
||||
"cwmp",
|
||||
"usp"
|
||||
],
|
||||
"mapping": [
|
||||
{
|
||||
"type": "ubus",
|
||||
"ubus": {
|
||||
"object": "sshmngr",
|
||||
"method": "get_mfa_key",
|
||||
"args": {},
|
||||
"key": "mfa_key"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"{BBF_VENDOR_PREFIX}MFA_Recovery_Codes": {
|
||||
"type": "string",
|
||||
"read": true,
|
||||
"write": false,
|
||||
"protocols": [
|
||||
"cwmp",
|
||||
"usp"
|
||||
],
|
||||
"mapping": [
|
||||
{
|
||||
"type": "ubus",
|
||||
"ubus": {
|
||||
"object": "sshmngr",
|
||||
"method": "get_mfa_recovery",
|
||||
"args": {},
|
||||
"key": "recovery_codes"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,11 +5,11 @@
|
|||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=sulu-base
|
||||
PKG_VERSION:=5.3.6
|
||||
PKG_VERSION:=5.3.8
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://dev.iopsys.eu/websdk/sulu.git
|
||||
PKG_SOURCE_VERSION:=ecb476afded4022ed1b23891329965aa4197fade
|
||||
PKG_SOURCE_VERSION:=d539ffdea1640b7cdeb55765c5737d8d7b6ab630
|
||||
PKG_MIRROR_HASH:=skip
|
||||
|
||||
SULU_MOD:=core
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@
|
|||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=sulu-builder
|
||||
PKG_VERSION:=5.3.6
|
||||
PKG_VERSION:=5.3.8
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://dev.iopsys.eu/websdk/sulu-builder.git
|
||||
PKG_SOURCE_VERSION:=15e0ff565a9d1c3b15739e8ebfa58267c97a3eb1
|
||||
PKG_SOURCE_VERSION:=fae099019a4dc74e529a909c110966c1cf10b4c7
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_SOURCE_VERSION)
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/sulu-$(PKG_VERSION)/sulu-builder-$(PKG_SOURCE_VERSION)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=sulu-theme-genexis
|
||||
PKG_VERSION:=5.3.6
|
||||
PKG_VERSION:=5.3.8
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://dev.iopsys.eu/gnx/sulu-theme-genexis
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@
|
|||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=tr143
|
||||
PKG_VERSION:=1.1.12
|
||||
PKG_VERSION:=1.1.13
|
||||
|
||||
LOCAL_DEV:=0
|
||||
ifneq ($(LOCAL_DEV),1)
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://dev.iopsys.eu/bbf/tr143d.git
|
||||
PKG_SOURCE_VERSION:=c0149efd8e5cd5d908988148281b6caabeac615e
|
||||
PKG_SOURCE_VERSION:=be8ee7b6c52817914f66875d36061f2f62b80af8
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
PKG_MIRROR_HASH:=skip
|
||||
endif
|
||||
|
|
@ -41,14 +41,15 @@ define Package/tr143/install
|
|||
|
||||
ifeq ($(CONFIG_TARGET_SUBTARGET),"an7581")
|
||||
$(BBFDM_INSTALL_SCRIPT) $(PKG_BUILD_DIR)/airoha/scripts/download $(1)
|
||||
$(BBFDM_INSTALL_SCRIPT) $(PKG_BUILD_DIR)/airoha/scripts/upload $(1)
|
||||
$(INSTALL_DATA) ./files/an7581/etc/uci-defaults/* $(1)/etc/uci-defaults/
|
||||
else
|
||||
$(BBFDM_INSTALL_SCRIPT) $(PKG_BUILD_DIR)/scripts/download $(1)
|
||||
$(BBFDM_INSTALL_SCRIPT) $(PKG_BUILD_DIR)/scripts/upload $(1)
|
||||
$(INSTALL_DATA) ./files/other/etc/uci-defaults/* $(1)/etc/uci-defaults/
|
||||
endif
|
||||
|
||||
$(BBFDM_INSTALL_SCRIPT) $(PKG_BUILD_DIR)/scripts/traceroute $(1)
|
||||
$(BBFDM_INSTALL_SCRIPT) $(PKG_BUILD_DIR)/scripts/upload $(1)
|
||||
$(BBFDM_INSTALL_SCRIPT) -d $(PKG_BUILD_DIR)/scripts/bbf_diag/ipping $(1)
|
||||
$(BBFDM_INSTALL_SCRIPT) -d $(PKG_BUILD_DIR)/scripts/bbf_diag/serverselection $(1)
|
||||
$(BBFDM_INSTALL_SCRIPT) -d $(PKG_BUILD_DIR)/scripts/bbf_diag/udpecho $(1)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
set_tr143_download_defaults() {
|
||||
set_tr143_diagnostic_defaults() {
|
||||
if [ ! -f /etc/bbfdm/dmmap/dmmap_diagnostics ]; then
|
||||
touch /etc/bbfdm/dmmap/dmmap_diagnostics
|
||||
fi
|
||||
|
|
@ -9,7 +9,11 @@ set_tr143_download_defaults() {
|
|||
uci -q -c /etc/bbfdm/dmmap set dmmap_diagnostics.download.DefaultNumberOfConnections='4'
|
||||
uci -q -c /etc/bbfdm/dmmap set dmmap_diagnostics.download.DownloadDiagnosticMaxConnections='8'
|
||||
|
||||
uci -q -c /etc/bbfdm/dmmap set dmmap_diagnostics.upload='upload'
|
||||
uci -q -c /etc/bbfdm/dmmap set dmmap_diagnostics.upload.DefaultNumberOfConnections='1'
|
||||
uci -q -c /etc/bbfdm/dmmap set dmmap_diagnostics.upload.UploadDiagnosticMaxConnections='8'
|
||||
|
||||
uci -q -c /etc/bbfdm/dmmap commit dmmap_diagnostics
|
||||
}
|
||||
|
||||
set_tr143_download_defaults
|
||||
set_tr143_diagnostic_defaults
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
set_tr143_download_defaults() {
|
||||
set_tr143_diagnostic_defaults() {
|
||||
if [ ! -f /etc/bbfdm/dmmap/dmmap_diagnostics ]; then
|
||||
touch /etc/bbfdm/dmmap/dmmap_diagnostics
|
||||
fi
|
||||
|
|
@ -9,7 +9,11 @@ set_tr143_download_defaults() {
|
|||
uci -q -c /etc/bbfdm/dmmap set dmmap_diagnostics.download.DefaultNumberOfConnections='1'
|
||||
uci -q -c /etc/bbfdm/dmmap set dmmap_diagnostics.download.DownloadDiagnosticMaxConnections='1'
|
||||
|
||||
uci -q -c /etc/bbfdm/dmmap set dmmap_diagnostics.upload='upload'
|
||||
uci -q -c /etc/bbfdm/dmmap set dmmap_diagnostics.upload.DefaultNumberOfConnections='1'
|
||||
uci -q -c /etc/bbfdm/dmmap set dmmap_diagnostics.upload.UploadDiagnosticMaxConnections='1'
|
||||
|
||||
uci -q -c /etc/bbfdm/dmmap commit dmmap_diagnostics
|
||||
}
|
||||
|
||||
set_tr143_download_defaults
|
||||
set_tr143_diagnostic_defaults
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue