Compare commits

..

375 Commits

Author SHA1 Message Date
Meng
662db5cfa8 Update makefiles commits 2025-11-03 03:51:45 +01:00
Xiaofeng Meng
903d5febbd bridgemngr with dm-framework 2025-11-03 03:50:28 +01:00
Amin Ben Romdhane
7df4486a43 decollector: 6.2.2.7 2025-10-31 10:28:18 +01:00
Amin Ben Romdhane
6818818127 decollector: 6.2.2.6 2025-10-30 16:39:00 +01:00
Amin Ben Romdhane
63c0fb7d3b ieee1905: 8.7.39 2025-10-30 16:37:41 +01:00
Jakob Olsson
2a38e7cd23 map-plugins: 1.2.5 2025-10-30 15:38:42 +01:00
Marina Maslova
8f6ae03e7e wifimngr: 20.1.8 2025-10-30 14:51:40 +04:00
Marina Maslova
fecbbe90af libwifi: 7.22.6 2025-10-30 14:51:15 +04:00
Roman Azarenko
fe1cdbd9bc iopsys-analytics: move iperf3 from default build to analytics
We're using `iperf3` for development and testing, so there is no need
to include it in the default firmware builds.
2025-10-30 09:43:51 +01:00
Vivek Kumar Dutta
67bf2c0227 bbfdm: 1.18.12 2025-10-30 11:06:53 +05:30
Jakob Olsson
307059d44b map-plugin: 1.2.4 2025-10-29 17:22:21 +01:00
Jakob Olsson
a8aa693e18 map-controller: 6.4.4.8 2025-10-29 17:12:27 +01:00
Reidar Cederqvist
53fc48997a Sulu: upgrade to version 5.2.2 2025-10-29 16:54:41 +01:00
Jakob Olsson
9e180eb2bf map-controller: set enable_bsta_steer to '1' by default 2025-10-29 16:40:30 +01:00
Jakob Olsson
b98ccac057 map-controler: 6.4.4.6 2025-10-29 13:47:51 +01:00
Jouni Ikonen
fb236949fc usermngr: json schema to validate the role acl 2025-10-29 15:53:04 +05:30
Erik Karlsson
5631c28df4 sulu: disregard client-provided X-Forwarded-For
This prevents clients from lying about their identity to the MQTT
broker by supplying their own X-Forwarded-For in the request.
2025-10-29 10:39:53 +01:00
Sukru Senli
8170684100 sulu: adapt to mosquitto-auth-shadow->mosquitto-auth-plugin change 2025-10-29 09:36:15 +00:00
Sukru Senli
332a35102d mosquitto-auth-plugin: add per-user subnet-based access control with IPv4/IPv6 support
- Implement whitelist/blacklist subnet filtering for MQTT users
- Add full IPv4 and IPv6 CIDR subnet matching support
- Check subnet restrictions during authentication (MOSQ_EVT_BASIC_AUTH)
- Reject login immediately if subnet check fails (return MOSQ_ERR_AUTH)
- Parse subnet ACL files via auth_opt_subnet_acl_file option
- Support multiple subnets per user (up to 32 allow + 32 deny rules)
- Support both IPv4 (e.g., 192.168.1.0/24) and IPv6 (e.g., 2001:db8::/32) CIDR notation
- Deny rules take precedence over allow rules for both IP versions
- Localhost (127.0.0.1 and ::1) always allowed
- Backward compatible: users without subnet rules are not affected
- Configuration format: 'subnet allow|deny <username> <cidr>'
- Integrates with existing shadow/PAM authentication and topic ACLs
2025-10-29 09:33:49 +00:00
Sukru Senli
ba5e332b0d rename mosquitto-auth-shadow to mosquitto-auth-plugin 2025-10-29 09:33:49 +00:00
Jakob Olsson
09560fb532 map-agent: 6.4.3.6 2025-10-28 16:37:17 +01:00
Janusz Dziedzic
c4cf8cb24b libwifi: 7.22.5 2025-10-28 15:14:29 +00:00
Amin Ben Romdhane
56c94f1ec6 decollector: 6.2.2.5 2025-10-28 14:30:03 +01:00
Amin Ben Romdhane
279fe9d291 bbfdm: 1.18.11 2025-10-28 14:26:50 +01:00
Vivek Kumar Dutta
924675d271 netmode: 1.1.8 2025-10-28 15:29:17 +05:30
Jakob Olsson
64cf5c7c9f map-controller: 6.4.4.5 2025-10-28 10:15:03 +01:00
Vivek Kumar Dutta
9fa9b1adbf sysmngr: Fix set_bootbank status 2025-10-28 13:51:43 +05:30
Jakob Olsson
9944917399 libwifi: 7.22.4 2025-10-27 17:30:35 +01:00
Amin Ben Romdhane
2a25fc0ec7 ieeee1905: 8.7.38 2025-10-27 17:12:52 +01:00
Jakob Olsson
ebd7e68714 map-controller: 6.4.4.4 2025-10-27 16:37:17 +01:00
Jakob Olsson
000762c0cb map-plugins: 1.2.2 2025-10-27 14:21:17 +01:00
Amin Ben Romdhane
c4328f411f decollector: 6.2.2.4 2025-10-24 14:32:49 +02:00
Vivek Kumar Dutta
0428934a69 bbfdm: 1.18.10 2025-10-24 16:30:02 +05:30
Erik Karlsson
580d24e04a logmngr: simplify default PID to 0 logic
Note that the "add" directive only adds if nothing is already present.
2025-10-24 10:28:37 +02:00
Mohd Husaam Mehdi
95778a4262 usermngr: added password expiry extension 2025-10-24 11:37:26 +05:30
Vivek Kumar Dutta
02ee448479 bbfdm: 1.18.9 2025-10-24 09:45:13 +05:30
Jakob Olsson
0dcc9743a2 map-agent: 6.4.3.5 2025-10-23 16:18:58 +02:00
Amin Ben Romdhane
1a1a1e1255 decollector: 6.2.2.3 2025-10-23 13:18:36 +02:00
Vivek Kumar Dutta
9710e46c51 obuspa: Fix group set method 2025-10-23 15:59:17 +05:30
Amin Ben Romdhane
19e69f7b61 decollector: 6.2.2.2 2025-10-23 11:18:47 +02:00
Mohd Husaam Mehdi
e319c85064 logmngr: set pid to 0 when it does not exist 2025-10-23 14:23:11 +05:30
Jakob Olsson
29638a28f7 map-agent: 6.4.3.4 2025-10-23 10:29:20 +02:00
Jakob Olsson
ccb337ecbd map-controller: 6.4.4.3 2025-10-23 10:27:39 +02:00
Amin Ben Romdhane
5474b1c6d0 wifidmd: 1.4.1: Move WiFi.DataElements Object to decollector 2025-10-22 12:40:46 +02:00
Amin Ben Romdhane
8df0ad8e46 decollector: 6.2.2.1: introduce WiFi.DataElements. tree 2025-10-22 12:40:34 +02:00
Jakob Olsson
6e358a6bd1 Revert "decollector: introduce data model"
This reverts commit 20a28db536.
2025-10-22 12:34:01 +02:00
Amin Ben Romdhane
20a28db536 decollector: introduce data model 2025-10-22 10:30:06 +00:00
Sukru Senli
c6ee9114bc netmode: skip obuspa restart 2025-10-22 08:58:33 +02:00
Sukru Senli
89fb4a0857 netmode: enable by default and auto-detect mode 2025-10-22 08:43:15 +02:00
Markus Gothe
8d86188ff1 obuspa: Fix spelling of log messages.
Abbrevations like UCI must be in capital letters.
Add correct punctation.
2025-10-21 16:27:34 +02:00
Jakob Olsson
18d6afea15 map-agent: 6.4.3.3 2025-10-21 10:41:58 +02:00
Vivek Kumar Dutta
0cb9aac1f1 userinterface: vendor extension for FirstLogin 2025-10-21 12:14:16 +05:30
Sukru Senli
dfe2af4643 netmode: fix static mode
and improve other modes
2025-10-20 16:45:09 +02:00
Amin Ben Romdhane
2fe133227d bbfdm: 1.18.8 2025-10-20 13:37:31 +02:00
Sukru Senli
15f17da6e5 netmode: add static mode and vlanid and dns servers as arguments to all modes 2025-10-20 12:52:39 +02:00
Vivek Kumar Dutta
2e56ef292c bbfdm:micro-services: Fix probable segfault during startup 2025-10-17 22:50:51 +05:30
Marina Maslova
65e4bebc0f libwifi: 7.22.3 2025-10-17 15:04:02 +04:00
Jakob Olsson
ceb577a6ab map-controller: config: add zerotouch, rate, bsteer plugins to default 2025-10-17 10:19:46 +02:00
Jakob Olsson
2d45a45126 map-agent: map_genconfig: add dpp_chirp section for 2.4GHz 2025-10-17 10:19:46 +02:00
Vivek Dutta
45294a9f0c usermngr: Only select shadow pam utils with security hardening
(cherry picked from commit 4e33db2700)

Co-authored-by: Vivek Kumar Dutta <vivek.dutta@iopsys.eu>
2025-10-17 11:19:59 +05:30
Jakob Olsson
eb5c837353 map-controller: 6.4.4.1 2025-10-16 16:37:54 +02:00
Vivek Kumar Dutta
495d95dcc8 icwmp: 9.10.5 2025-10-16 18:01:44 +05:30
Suvendhu Hansa
32e5dc46b3 usermngr: Vendor extension for Security Hardening parameters 2025-10-16 15:23:34 +05:30
Erik Karlsson
6980c1e2e5 ponmngr: use iopsys-environment for reading production data
U-Boot environment is kept as a fallback for legacy reasons.
2025-10-16 08:55:36 +00:00
Erik Karlsson
da727b4dc1 ponmngr: use get_mac_label to read MAC address 2025-10-16 08:55:36 +00:00
Vivek Kumar Dutta
d8aaacc4c9 obuspa: Optimize startup to avoid db corruption
- Force update values from uci on firmware update
- In case of reload(uci update), old sql db gets deleted and created from uci
- Use In memory sql journal mode
2025-10-16 12:30:35 +05:30
Vivek Kumar Dutta
e036702c16 wifidmd: align with bbfdm 2025-10-15 17:15:32 +05:30
Vivek Kumar Dutta
604a105bc9 usermngr: align with bbfdm 2025-10-15 17:15:32 +05:30
Vivek Kumar Dutta
04bdaa950f timemngr: align with bbfdm 2025-10-15 17:15:32 +05:30
Vivek Kumar Dutta
54fdaf2b43 sysmngr: align with bbfdm 2025-10-15 17:15:32 +05:30
Vivek Kumar Dutta
644e98e595 qosmngr: align with bbfdm 2025-10-15 17:15:31 +05:30
Vivek Kumar Dutta
9fc594d74f periodicstats: align with bbfdm 2025-10-15 17:15:31 +05:30
Vivek Kumar Dutta
ac7cfb581e parental-control: align with bbfdm 2025-10-15 17:15:31 +05:30
Vivek Kumar Dutta
ba75b33fc5 ethmngr: align with bbfdm 2025-10-15 17:15:31 +05:30
Vivek Kumar Dutta
912978164b bulkdata: align with bbfdm 2025-10-15 17:15:30 +05:30
Vivek Kumar Dutta
7a50c328e1 bbfdm: Fix typo in ubus APIs 2025-10-15 17:15:30 +05:30
Vivek Kumar Dutta
f8c9088db7 tr143: 1.1.8 2025-10-15 17:14:35 +05:30
Vivek Kumar Dutta
fd34c3e9f3 ethmngr: 3.1.1 2025-10-15 14:36:01 +05:30
Suvendhu Hansa
70d7d7a64d usermngr: Added password strength validation 2025-10-15 13:48:40 +05:30
Janusz Dziedzic
112f4cb99d wifimngr: 20.1.7 2025-10-15 05:48:52 +00:00
Jakob Olsson
2380a6de86 map-agent: 6.4.3.2 2025-10-14 17:22:30 +02:00
Filip Matusiak
b0c168322e self-diagnostics: get map-agent backhaul status 2025-10-14 16:12:41 +02:00
Filip Matusiak
22d8a0992c map-agent: 6.4.3.1 2025-10-14 16:12:33 +02:00
Janusz Dziedzic
3c075c293c wifimngr: 20.1.6 2025-10-13 16:25:56 +00:00
Suvendhu Hansa
17ae16e5d2 passwdqc: Install pwqcheck tool 2025-10-13 17:56:57 +05:30
Erik Karlsson
46dc9e86d8 logmngr: include pid when migrating also 2025-10-13 10:50:55 +02:00
Mohd Husaam Mehdi
0b3420240d logmngr: include pid in log output by fluent-bit 2025-10-10 19:33:27 +05:30
Jakob Olsson
83ca06b626 map-controller: 6.4.4.0: add ZEROTOUCH_DPP 2025-10-10 13:54:52 +02:00
Jakob Olsson
2dafb9ec2c map-plugin: 1.2.1 2025-10-10 13:53:33 +02:00
Jakob Olsson
c2c54e5ca0 map-agent: 6.4.3.0 2025-10-10 13:51:53 +02:00
Janusz Dziedzic
9314e4bbf3 wifimngr: 20.1.5 2025-10-10 08:42:29 +00:00
Janusz Dziedzic
5840332288 libwifi: 7.22.2 2025-10-10 08:42:29 +00:00
Anjan Chanda
bb4fffb680 map-plugins: 1.2.0 2025-10-10 09:06:56 +02:00
Marina Maslova
4b2b09080d map-agent: 6.4.2.4 2025-10-09 18:38:45 +04:00
Elena Vengerova
ba651b5457 libwifi: 7.22.1 2025-10-09 18:04:27 +04:00
Janusz Dziedzic
1509db0630 wifimngr: 20.1.4 2025-10-09 12:56:14 +00:00
Mohd Husaam Mehdi
85e97ca660 parental-control: improve bundle sync logic
* handle the case when interface comes up after parental-control
* handle the case when bundle size can't be fetched for some reason
2025-10-09 14:32:52 +05:30
Vivek Kumar Dutta
f9640bc237 tr143: workaround for download byte mismatch 2025-10-09 14:32:02 +05:30
Amin Ben Romdhane
72b16e33ab decollector: 6.2.1.13 2025-10-08 16:41:27 +02:00
Amin Ben Romdhane
4e81706967 wifidmd: 1.3.12 2025-10-08 16:10:09 +02:00
Anjan Chanda
483fc2e6cb wifimngr: 20.1.3 2025-10-08 12:14:47 +02:00
Mohd Husaam Mehdi
c2594f2d37 parental-control: fix handling of tcp and ipv6 based dns responses 2025-10-06 21:18:32 +05:30
Jakob Olsson
fb2eac485b map-agent: 6.4.2.3 2025-10-06 17:09:55 +02:00
Elena Vengerova
c867ab610e libwifi: 7.22.0 2025-10-06 15:14:13 +04:00
Janusz Dziedzic
ef8d667b83 wifimngr: 20.1.2 2025-10-06 08:42:34 +00:00
Mohd Husaam Mehdi
3934674c81 parental-control: config option for nfqueue number 2025-10-06 11:25:36 +05:30
Amin Ben Romdhane
4f53f35dc1 bbfdm: 1.18.5 2025-10-04 19:44:55 +02:00
Erik Karlsson
4fe815299a sulu: fix faulty ACL generation logic
Also remove leftovers from QR code generation and pointless uci_load

(cherry picked from commit 91dced7427)
2025-10-03 11:40:49 +02:00
Vivek Kumar Dutta
9394517727 sulu: Fix migration scripts
(cherry picked from commit 9a36c0310f)
2025-10-03 11:40:17 +02:00
Vivek Kumar Dutta
742b357026 obuspa: Skip overriding of uci in case of firstboot
(cherry picked from commit f317c67aed)
2025-10-03 11:37:42 +02:00
Jakob Olsson
d383896918 map-controller: 6.4.3.5 2025-10-03 09:55:47 +02:00
Jakob Olsson
646f5d6e1c map-plugins: 1.1.1 2025-10-03 09:55:46 +02:00
Jakob Olsson
d897632279 map-controller: 6.4.3.4 2025-10-02 16:51:01 +02:00
Janusz Dziedzic
47e93f13c1 wifimngr: 20.1.1 2025-10-02 13:13:15 +00:00
Janusz Dziedzic
70bb662514 libwifi: 7.21.0 2025-10-02 13:12:29 +00:00
Jakob Olsson
6f9ec4bf7d map-controller: 6.4.3.3 2025-10-02 13:20:33 +02:00
Janusz Dziedzic
fc88c554c1 libwifi: 7.20.9 2025-10-02 09:04:58 +00:00
Jakob Olsson
5ba6ade386 map-controller: 6.4.3.2 2025-10-02 09:38:23 +02:00
Jakob Olsson
0d1b585c5d map-controller: 6.4.3.1 2025-10-01 17:15:58 +02:00
Jakob Olsson
bf43efa993 map-agent: 6.4.2.2 2025-10-01 13:24:18 +02:00
Erik Karlsson
0e3545cacb timemngr: do not fail uci-defaults on keep-settings upgrade
(cherry picked from commit 22bded8f33)
2025-10-01 09:49:42 +02:00
Jakob Olsson
fefe14d540 map-agent: 6.4.2.1 2025-09-29 10:50:04 +02:00
Anjan Chanda
b6df14f78e map-agent: 6.4.2.0 2025-09-26 12:06:44 +02:00
Anjan Chanda
24cfbe2e48 map-plugins: 1.1.0 2025-09-26 12:06:44 +02:00
Jakob Olsson
eee28bb66c map-controller: 6.4.3.0 2025-09-26 09:46:59 +02:00
Mohd Husaam Mehdi
5fcee38906 ssdpd: add UPnPIGD param support in UPnP datamodel 2025-09-26 10:18:07 +05:30
Filip Matusiak
72a9da5bd3 map-controller: 6.4.2.10 2025-09-25 14:37:20 +02:00
Marina Maslova
2cf19c9469 libwifi: set mtk driver flags for mt7987a refboard 2025-09-23 14:28:47 +00:00
Janusz Dziedzic
bd0fed8409 libwifi: 7.20.8 2025-09-23 14:15:42 +00:00
Jakob Olsson
b23e510dd3 map-controller: config: add name to unique sections
channel_plan and sta_steering are unique sections, and should be named. Additionally added uci-default script to name the sections if missing
2025-09-23 11:49:12 +02:00
Suvendhu Hansa
bf06544066 wifidmd: use bbfdm external handler for sync after reloads 2025-09-23 14:01:17 +05:30
Vivek Kumar Dutta
85762b4641 bbfdm: execute sync handler if defined 2025-09-23 14:01:17 +05:30
Husaam Mehdi
60dafc2028 logmngr: Fix /dev/log permission to allow all processes to write 2025-09-22 18:57:28 +05:30
Suvendhu Hansa
e6054d9f8f icwmp: update dhcp on-boading
- disable dhcp_discovery once on-boarded
- Only allow `https` url through dhcp option 43
2025-09-22 12:56:25 +05:30
Anjan Chanda
8b106e6b58 wifimngr: 20.1.0 2025-09-22 09:08:44 +02:00
Vivek Kumar Dutta
41edb9f1a5 tr143: 1.1.6 2025-09-22 11:00:16 +05:30
Vivek Kumar Dutta
f6026298e8 bridgemngr: 1.1.4 2025-09-19 15:22:46 +05:30
Jakob Olsson
c3ab091cdc hostmngr: 1.4.0: bump version 2025-09-18 17:25:41 +02:00
Jakob Olsson
dcfca56db8 hostmngr: 1.3.2 2025-09-18 17:07:20 +02:00
Markus Gothe
991657fc99 dslmngr: airoha: Fix QoS uplink bandwidth monitor. 2025-09-17 19:41:36 +02:00
Markus Gothe
90f13664e9 qosmng: airoha: Don't flush HW NAT unless necessary. 2025-09-17 18:03:31 +02:00
Vivek Kumar Dutta
e843c83d0c tr104: Vendor extension for SIP bind Interface 2025-09-17 18:45:06 +05:30
Jakob Olsson
7d5c13a9f5 map-controller: 6.4.2.8: obsolete config option initial_channel_scan 2025-09-17 15:13:51 +02:00
Markus Gothe
417a5c5428 qosmngr: airoha: Fix uplink bandwidth calculation.
For lower speeds we need to adjust the bandwidth
calculation for QoS to work on AN7581 (but not on EN7523).

Also make sure we clear old HW NAT entries if the uplink
bandwidth changes for QoS to take effect immediaty.
2025-09-17 14:51:18 +02:00
Vivek Kumar Dutta
0074af0d3c bridgemngr: Fix deletion of ProviderBridge 2025-09-17 16:17:52 +05:30
Jakob Olsson
fae1f7d816 map-controller: 6.4.2.8 2025-09-17 12:21:04 +02:00
Janusz Dziedzic
f500a8c749 libwifi: 7.20.7 2025-09-17 06:20:24 +00:00
Janusz Dziedzic
af9e4f99c6 libwifi: 7.20.6 2025-09-17 06:19:08 +00:00
Vivek Kumar Dutta
e451e32f77 bridgemngr: 1.1.2 2025-09-16 16:53:42 +05:30
Vivek Kumar Dutta
26cbba9724 icwmp: 9.10.3 2025-09-16 16:12:07 +05:30
arbala
5be4e38c68 map-plugins: 1.0.32 2025-09-16 11:59:18 +02:00
arbala
549534f8aa map-controller: 6.4.2.7 2025-09-16 11:16:35 +02:00
arbala
f4a623e637 wifidmd: 1.3.10 2025-09-16 11:14:33 +02:00
Anjan Chanda
833a9a002a libwifi: 7.20.5 2025-09-16 10:38:59 +02:00
Erik Karlsson
ff4e68f70a fdtextract: fix CI pipeline
Argument parsing is also made more strict so that -z/--size cannot be
used together with other options.
2025-09-16 08:30:44 +00:00
Markus Gothe
b471113bfa qosmngr: airoha: Fix TCP ACK prioritization. 2025-09-15 15:57:06 +02:00
Markus Gothe
2b997a4386 qosmngr: airoha: flush HW NAT to directly apply changes. 2025-09-15 15:54:32 +02:00
Markus Gothe
06a280707a Revert "qosmngr: airoha: flush HW NAT to directly apply changes."
This reverts commit c54fd95889.
2025-09-15 15:51:50 +02:00
Markus Gothe
c54fd95889 qosmngr: airoha: flush HW NAT to directly apply changes. 2025-09-15 11:13:08 +02:00
Vivek Kumar Dutta
86fb3db75b bulkdata: 2.1.21 2025-09-15 12:38:19 +05:30
Vivek Kumar Dutta
70cda05eda usermngr: 1.4.1 2025-09-15 12:37:18 +05:30
Vivek Kumar Dutta
502aab4f3c periodicstats: 1.6.1 2025-09-15 12:35:04 +05:30
Vivek Kumar Dutta
34b63e84aa icwmp: 9.10.2 2025-09-15 12:32:18 +05:30
Vivek Kumar Dutta
5f2aa06285 bbfdm: Fix setting debug log_level 2025-09-15 12:29:59 +05:30
Suvendhu Hansa
5232cc61ac bbfdm: handle externally changed uci 2025-09-14 12:47:21 +05:30
Anjan Chanda
98d8e9866c map-plugins: 1.0.31 2025-09-12 17:02:49 +02:00
Vivek Kumar Dutta
0e59fd0d47 parental-control: 1.3.2 2025-09-11 15:03:46 +05:30
Anjan Chanda
a7e8e65d88 map-controller: 6.4.2.6 2025-09-11 10:45:06 +02:00
Suvendhu Hansa
1fd74364fa wifidmd: add external apply handler 2025-09-11 14:10:32 +05:30
Suvendhu Hansa
20c49302c1 bbfdm: add default apply handler 2025-09-11 13:59:47 +05:30
Anjan Chanda
c2e5ade3bb ieee1905: 8.7.37 2025-09-10 17:08:14 +02:00
Anjan Chanda
b933622547 map-plugins: 1.0.24 2025-09-10 17:06:16 +02:00
Reidar Cederqvist
7b12c29425 sulu: update to version 5.1.1 for IOWRT-7.6.0ALPHA2 2025-09-10 16:01:27 +02:00
Vivek Kumar Dutta
082452bfb5 mosquitto-auth-shadow: support libpam based authentication 2025-09-10 15:32:24 +05:30
Mohd Husaam Mehdi
a6b8987dac parental-control: only flush relevant connections using conntrack 2025-09-10 12:14:27 +05:30
Vivek Kumar Dutta
d1307bfd76 obuspa: Fix setting multiple params 2025-09-09 18:34:08 +05:30
Andreas Gnau
edd78f675e peripheral_manager: Remove
Remove peripheral_manager, it is no longer used or maintainted.

Signed-off-by: Andreas Gnau <andreas.gnau@iopsys.eu>
2025-09-09 13:23:06 +02:00
Janusz Dziedzic
3a1772e1b8 ieee1905: 8.7.36 2025-09-09 09:36:29 +00:00
Jakob Olsson
b2dd40cae3 map-controller: 6.4.2.2 2025-09-08 16:27:29 +02:00
Jakob Olsson
24f22d0ecc map-agent: 6.4.1.11 2025-09-08 13:59:36 +02:00
Jakob Olsson
a86f478014 map-controller: 6.4.2.1 2025-09-08 11:18:12 +02:00
Vivek Kumar Dutta
9a59ccc498 swmodd: Replace jq with jsonfilter 2025-09-06 15:14:24 +05:30
Vivek Kumar Dutta
15e4dd732a obuspa: 10.0.7.3 2025-09-06 09:57:18 +05:30
Husaam Mehdi
784a281fa6 logmngr: 1.1.4 2025-09-05 19:24:00 +05:30
Vivek Kumar Dutta
8f82b31658 obuspa: align with bbfdm 2025-09-05 19:10:41 +05:30
Vivek Kumar Dutta
3745b4e913 icwmp: align with bbfdm 2025-09-05 19:10:41 +05:30
Suvendhu Hansa
90d646319b bbfdm: update critical service config & dmmap path 2025-09-05 19:10:41 +05:30
Vivek Kumar Dutta
13064e27b3 bbfdm: Only commit changes done by datamodel 2025-09-05 19:10:41 +05:30
Vivek Kumar Dutta
539bf50985 ieee1905: 8.7.35 2025-09-05 18:42:16 +05:30
Anjan Chanda
1b7b377bd1 map-plugins: 1.0.18 - fix build when multiple plugins selected 2025-09-05 11:41:40 +02:00
Anjan Chanda
1c9ba1c83c map-plugins: 1.0.18 (bsteer) 2025-09-05 10:07:00 +02:00
Anjan Chanda
e307ee7aa8 map-controller: 6.4.2.0 2025-09-05 08:58:23 +02:00
Jakob Olsson
6bcf7987d7 map-agent: 6.4.1.10 2025-09-04 16:08:10 +02:00
Vivek Kumar Dutta
ff146bf093 tr104: 1.0.39 2025-09-04 18:32:44 +05:30
Vivek Kumar Dutta
0f23bee1da userinterface: Support for ISP info parameters 2025-09-04 18:06:03 +05:30
Amin Ben Romdhane
2070630b07 wifidmd: 1.3.9 2025-09-04 12:51:48 +02:00
Amin Ben Romdhane
f1702b3e70 map-controller: 6.4.1.3 2025-09-04 12:50:47 +02:00
Amin Ben Romdhane
9634b0678b wifidmd: 1.3.8 2025-09-03 17:21:18 +02:00
Amin Ben Romdhane
d395030be7 decollector: 6.2.1.12 2025-09-03 17:20:15 +02:00
Amin Ben Romdhane
4cb0504eb3 map-agent: 6.4.1.9 2025-09-03 17:19:11 +02:00
Mohd Husaam Mehdi
6df57301f9 logmngr: fix severity and facility configuration issues 2025-09-03 18:44:21 +05:30
Vivek Kumar Dutta
f527b8a25a obuspa: fallback to get connection params from db 2025-09-03 18:08:52 +05:30
Jakob Olsson
fbba67542e map-agent: 6.4.1.8 2025-09-02 17:27:43 +02:00
Amin Ben Romdhane
824d6d3abe decollector: 6.2.1.11 2025-09-02 16:30:45 +02:00
Jakob Olsson
1a9a339cc6 map-controller: 6.4.1.2 2025-09-02 13:04:54 +02:00
Vivek Kumar Dutta
0533f114d1 bbfdm: 1.17.7 2025-09-02 14:15:18 +05:30
Andreas Gnau
dc579e3c60 xmppc: Remove the dependency on jq
jq is used inside xmppc init script but it is not declared as a
dependency. Remove this usage of jq.

jq is a complex piece of software that requires security maintenance and
adds bloat to the image. Using existing tools like jshn and jsonfilter
is preferred where the additional functionality provided by jq is not
required.

Signed-off-by: Andreas Gnau <andreas.gnau@iopsys.eu>
2025-09-02 10:07:45 +02:00
Andreas Gnau
d232e76905 packet-capture-diagnostics: Don't use jq
jq is used inside packetcapture but it is not declared as a dependency.
Remove this usage of jq.

jq is a complex piece of software that requires security maintenance and
adds bloat to the image. Using existing tools like jshn and jsonfilter
is preferred where the additional functionality provided by jq is not
required.

Signed-off-by: Andreas Gnau <andreas.gnau@iopsys.eu>
2025-09-02 10:06:16 +02:00
Filip Matusiak
2fffb45748 map-controller: 6.4.1.1 2025-09-02 10:00:24 +02:00
Filip Matusiak
b15f1b5026 map-agent: 6.4.1.7 2025-09-02 09:59:48 +02:00
Amin Ben Romdhane
43a0dfc863 wifidmd: 1.3.7 2025-08-29 10:11:28 +02:00
Jakob Olsson
307381c9af decollector: 6.2.1.10 2025-08-28 18:10:13 +02:00
Vivek Kumar Dutta
1a80f2df47 parental-control: improve dns packet inspection 2025-08-28 12:05:15 +05:30
Mohd Husaam Mehdi
9b79eb42db parental-control: improve packet capture rules for DNS 2025-08-28 11:53:12 +05:30
Mohd Husaam Mehdi
602926b076 parental-control: flush hw_nat along with conntrack 2025-08-28 11:22:11 +05:30
Vivek Kumar Dutta
74cfe57095 sulu: remove jq dependency 2025-08-28 10:56:55 +05:30
Jakob Olsson
01845eded6 map-controller: 6.4.1.0 2025-08-27 16:39:08 +02:00
arbala
11dce5812c map-agent: 6.4.1.6 2025-08-27 15:17:58 +02:00
Vivek Kumar Dutta
7af15ec9a9 sshmngr: 1.1.1 2025-08-27 16:24:12 +05:30
Vivek Kumar Dutta
8359755dc8 bbfdm: 1.17.6 2025-08-27 16:05:18 +05:30
Amin Ben Romdhane
1a735b7730 wifidmd: 1.3.6 2025-08-26 16:26:29 +02:00
Vivek Kumar Dutta
6a008d3419 bbfdm: 1.17.5 2025-08-26 18:52:24 +05:30
Vivek Kumar Dutta
6142da5d43 sshmngr: align with bbfdm dmmap schema 2025-08-26 11:56:31 +05:30
Mohd Husaam Mehdi
f5715d478a fluent-bit: fix kmsg plugin issues
* improved type conversion
* improved error checking while string parsing
* misc improvements
2025-08-26 11:30:20 +05:30
Amin Ben Romdhane
bce9364d14 wifidmd: 1.3.5 2025-08-25 17:38:14 +02:00
Amin Ben Romdhane
425949900b decollector: 6.2.1.9 2025-08-25 17:37:22 +02:00
Amin Ben Romdhane
938681c270 map-controller: 6.4.0.18 2025-08-25 17:36:05 +02:00
Jakob Olsson
30f7a15450 map-agent: 6.4.1.5 2025-08-25 16:08:24 +02:00
Jakob Olsson
4d4006309b map-agent: 6.4.1.4 2025-08-25 15:43:18 +02:00
Vivek Kumar Dutta
41f1e0d52a bbfdm: 1.17.4 2025-08-23 17:41:26 +05:30
Vivek Kumar Dutta
db207a87fc obuspa: Integrate v10.0.7 2025-08-23 10:08:37 +05:30
Jakob Olsson
89ab349565 map-agent: 6.4.1.3 2025-08-22 16:30:08 +02:00
Filip Matusiak
8ffe108f95 map-controller: 6.4.0.17
Set debug level to 2 (INFO) by default.
2025-08-22 16:20:24 +02:00
Erik Karlsson
074d9268b0 sulu: depend on local MQTT listener regardlessly of variant 2025-08-22 16:09:49 +05:30
Vivek Kumar Dutta
fc7b21aa73 bbfdm: Fix fault message for 9007 2025-08-22 15:15:37 +05:30
Husaam Mehdi
6f83732b0e logmngr: use multiple workers for logging 2025-08-22 12:08:27 +05:30
Erik Karlsson
97141307ed sulu: remove faulty mosquitto option
The actual spelling of this option is require_certificate and it is
anyway not relevant here since it is not a TLS listener.
2025-08-21 15:19:46 +02:00
Vivek Dutta
ddec5540bc sulu: Fix restarting of mqtt broker 2025-08-21 18:39:36 +05:30
Filip Matusiak
09b97ae69d self-diagnostics: get status of MLD stations 2025-08-21 11:18:18 +00:00
Jakob Olsson
977c1b5767 map-agent: 6.4.1.2 2025-08-21 12:31:22 +02:00
Anjan Chanda
467b3897fb Revert "libwifi: 7.13.0"
This reverts commit 9917da1ca3.
2025-08-21 09:50:01 +02:00
Filip Matusiak
a688381a3c self-diagnostics: update wifi data collection 2025-08-20 15:12:51 +00:00
Vivek Kumar Dutta
9bad79439b usermngr: 1.4.0 2025-08-20 20:29:50 +05:30
Vivek Dutta
608b9637b0 parental-control: fix cleanup when bundle is default enabled
(cherry picked from commit 8bdc47344a)

Co-authored-by: Mohd Husaam Mehdi <husaam.mehdi@iopsys.eu>
2025-08-20 20:28:06 +05:30
Vivek Dutta
fcd59e95f0 parental-control: auto enable urlbundle based on /apps 2025-08-20 20:27:48 +05:30
Vivek Kumar Dutta
5820d98e2c iopsys-analytics: enable dmcli remote connection 2025-08-20 20:09:17 +05:30
Erik Karlsson
9c6b9d6260 logmngr: use fluent-bit filters to adapt kmsg fields and add hostname 2025-08-20 13:25:27 +00:00
Erik Karlsson
9fad74246e fluent-bit: human readable time in file output 2025-08-20 13:25:27 +00:00
Erik Karlsson
aab3f74290 fluent-bit: remove patches for hostname and kmsg field adaptation
Filters will be used instead.
2025-08-20 13:25:27 +00:00
Jakob Olsson
0eb2ce3728 map-agent: 6.4.1.1 2025-08-20 15:19:51 +02:00
Anjan Chanda
f9aabb68d5 wifimngr: 20.0.0 2025-08-20 10:56:02 +02:00
Anjan Chanda
9917da1ca3 libwifi: 7.13.0 2025-08-20 10:38:39 +02:00
Anjan Chanda
acf7344c13 libeasy: 7.5.0 2025-08-20 10:10:16 +02:00
Filip Matusiak
693ff8bd19 map-controller: 6.4.0.16
Reduce stale sta timeout to 20 days, to avoid exceeding
max value of parameter to uloop_timeout_set.
2025-08-20 07:25:12 +00:00
Jakob Olsson
c1286064bb map-agent: 6.4.1.0 2025-08-19 15:17:14 +02:00
Erik Karlsson
2503b1fc72 logmngr: miscellaneous fixes
Always migrate configuration. Do not set executable bit on config
files and uci-defaults scripts. Remove unused /lib/functions.sh
include. Remove redundant "default y" on choice.
2025-08-19 11:07:11 +00:00
Vivek Kumar Dutta
d468c13b3f usp-js: 1.2.9 2025-08-19 13:42:18 +05:30
Vivek Kumar Dutta
064611a15d obuspa: removed test controller definition 2025-08-19 13:42:18 +05:30
Filip Matusiak
5c427dd08a map-controller: config: change default sta timeout to 20d 2025-08-18 15:14:07 +00:00
Amin Ben Romdhane
1703e6d328 wifidmd: 1.3.4 2025-08-18 17:10:59 +02:00
Amin Ben Romdhane
35c27393ce map-controller: 6.4.0.15 2025-08-18 17:09:31 +02:00
Amin Ben Romdhane
fca93627ba bbfdm: 1.17.2 2025-08-18 10:36:21 +02:00
Erik Karlsson
417a127dd9 quickjs: clean up integration
Pass CFLAGS and LDFLAGS the correct way via environment variables and
not as arguments so the upstream Makefile CFLAGS/LDFLAGS do not get
overwritten and no ugly workaround is needed. Set PREFIX correctly and
do not set CONFIG_SMALL which was implemented in a patch that was
dropped. Remove commented out code (libquickjs.lto.a is no longer
built by default). Set PKG_SOURCE_DATE correctly as the date of the
upstream git repo and not the date of the OpenWrt package. Fix
whitespace issues in patch. Do not create empty /usr/lib/quickjs
2025-08-17 13:28:55 +05:30
arbala
afde0b98ad map-agent: 6.4.0.3 2025-08-15 16:45:12 +02:00
Markus Gothe
a0069cc9be qos: airoha: Fix mapping of accounter. 2025-08-14 21:20:07 +02:00
Markus Gothe
368255f50b qos: airoha: Use Meter 0 for IF-based QoS. 2025-08-14 18:34:40 +02:00
Janusz Dziedzic
ad1233ff32 wifimngr: 17.7.8 2025-08-14 14:47:23 +00:00
Janusz Dziedzic
697ddc356e libwifi: 7.14.0 2025-08-14 14:25:45 +00:00
Janusz Dziedzic
b82eb8325e libwifi: 7.13.9 2025-08-14 11:56:01 +00:00
Suvendhu Hansa
c150053a83 usermngr: modify password policy 2025-08-14 16:40:17 +05:30
Vivek Kumar Dutta
7ee83ff47f usp-js: 1.2.8 2025-08-14 16:27:42 +05:30
Vivek Kumar Dutta
98905256f8 periodicstats: Align with new dmmap 2025-08-14 12:42:51 +05:30
Amin Ben Romdhane
a8a511c4ff wifidmd: 1.3.3 2025-08-12 13:35:04 +02:00
Amin Ben Romdhane
d0d90946b3 map-agent: 6.4.0.2 2025-08-12 13:34:04 +02:00
Vivek Dutta
c2ad0fa44d swmodd: disable lxc support in defaults 2025-08-12 15:20:10 +05:30
Vivek Kumar Dutta
be7fa433c5 obuspa: Fix fault msg in failed set cmd 2025-08-12 15:07:35 +05:30
Mohd Husaam Mehdi
01e9d7c0bc usermngr: add UCI support for passwdqc parameters 2025-08-12 12:17:21 +05:30
Suvendhu Hansa
2f398a2671 icwmp: generate a random cpe port if not defined 2025-08-12 10:11:52 +05:30
Markus Gothe
8254547866 udhcpc_obuspa_opt125.user: Fix typo 2025-08-11 23:25:08 +02:00
Janusz Dziedzic
e8ceb167b5 ieee1905: 8.7.34 2025-08-11 11:38:51 +00:00
Amin Ben Romdhane
434c794671 decollector: 6.2.1.8 2025-08-11 12:19:37 +02:00
George Yang
9628be4812 dectmngr-3.7.11 2025-08-08 17:09:57 +02:00
Markus Gothe
bd90dc7ec2 libdsl: 7.3.2 2025-08-11 09:05:22 +02:00
Janusz Dziedzic
e0736df927 wifimngr: 17.7.7 2025-08-11 05:24:03 +00:00
Amin Ben Romdhane
afa58be1f8 wifidmd: 1.3.2 2025-08-09 22:03:24 +02:00
Vivek Kumar Dutta
3cbcac96ba netmode: Fix dm-service depedency 2025-08-08 16:55:35 +05:30
Suvendhu Hansa
a92f32eba4 icwmp: Fix overriding of port definition 2025-08-08 12:52:57 +05:30
Amin Ben Romdhane
842968da4f wifidmd: 1.3.1 2025-08-07 15:21:16 +02:00
Jakob Olsson
60ef90c1b6 map-agent: 6.4.0.1 2025-08-07 15:17:22 +02:00
Suvendhu Hansa
56cec9cb7f icwmpd: retry on bind failure 2025-08-07 18:06:53 +05:30
Vivek Kumar Dutta
4042d46009 tr104: Fix CallControlGroup Extension references 2025-08-07 17:48:46 +05:30
Markus Gothe
d6dfc5bd08 libdsl: Fix issue with G.vectoring. 2025-08-07 14:15:25 +02:00
Vivek Kumar Dutta
451036aebc obuspa: Integrated v10.0.6 2025-08-07 17:33:16 +05:30
Amin Ben Romdhane
8d01ace7a6 wifidmd: 1.3.0 2025-08-07 12:37:44 +02:00
Jakob Olsson
d7e22b922b map-agent: map-dynamic-backhaul: pass macaddr when setting uplink 2025-08-07 10:40:26 +02:00
Elena Vengerova
a1d535058d libwifi: 7.13.8 2025-08-06 22:37:57 +04:00
Markus Gothe
1bb307ef4f xdsl_wan: ros -> roc. 2025-08-06 19:50:31 +02:00
Markus Gothe
404a642e41 xdsl_wan: Enable vectoring and G.iNP by default. 2025-08-06 19:33:52 +02:00
Elena Vengerova
ae3f1819e6 libwifi: invent target for Mediatek, change path for vendor header search
Mediatek passes rather -I$(LINUX_DIR)/include/uapi/linux/mtk_nl80211_inc
than installs header with vendor attributes into the toolchain.
2025-08-06 21:00:38 +04:00
Elena Vengerova
fbd8f64c40 mapagent: invent branch for logan driver handling
Logan driver assumes that ra/rai interface names are used.
It's the same for all platforms.
2025-08-06 16:32:33 +00:00
Jakob Olsson
369fc0d4bb map-agent: 6.4.0.0: dynbh rework 2025-08-06 16:29:57 +00:00
Jakob Olsson
b44afe067f map-agent: remove dynbhd 2025-08-06 16:29:57 +00:00
Suvendhu Hansa
d69245f570 map-agent: map_genconfig: use ubus uci to commit mapcontroller changes 2025-08-06 14:53:54 +00:00
Suvendhu Hansa
c3564ff528 wifidmd: Reload wifidmd by signal 2025-08-06 20:19:54 +05:30
Vivek Kumar Dutta
fafe1d9447 icwmp: 9.9.10 2025-08-06 18:41:01 +05:30
Husaam Mehdi
e35bf1d509 logmngr: add support for Syslog Source and Template 2025-08-05 17:06:51 +05:30
Amin Ben Romdhane
8e11e5dbc8 twamp: 1.5.0 2025-08-04 17:09:23 +02:00
Amin Ben Romdhane
2698ee9358 netmngr: 1.2.0 2025-08-04 16:50:16 +02:00
Amin Ben Romdhane
92be6f1129 ethmngr: 3.1.0 2025-08-04 16:49:03 +02:00
Amin Ben Romdhane
4dfc196968 bbfdm: 1.17.1 2025-08-04 16:47:16 +02:00
Mohd Husaam Mehdi
1c17fed77d fluent-bit: align kmsg output fields with syslog fields
- this allows for a better mapping to the data model
- this reduces load on fluent-bit because now one OUTPUT section
  is sufficient (earlier we needed two output sections because of
  two different templates)
2025-08-04 14:33:28 +05:30
Markus Gothe
27b9fb9350 logmngr: Make sure we never fail to setup /var/log/messages.
If it fails during MP the verfication of buttons will not work
as expected. The problem is that the file is created before
data is commited and when power is cut prematurely it won't
re-create the file, maybe because the uci-default script has
been removed already as well.
2025-07-30 21:49:58 +02:00
arbala
b917a2177e map-agent: 6.3.7.3 2025-07-30 16:08:02 +02:00
Vivek Kumar Dutta
2372de4864 logmngr: fix /dev/log creation 2025-07-30 17:31:26 +05:30
Vivek Kumar Dutta
c5d7ddd851 logmngr: generate kmsg,log config if dev exists 2025-07-29 13:33:50 +00:00
arbala
a688b2091c map-agent: 6.3.7.2 2025-07-29 15:27:25 +02:00
Vivek Kumar Dutta
bfc7e6a78a tr143: 1.1.5 2025-07-29 18:16:33 +05:30
Suvendhu Hansa
41495cf6e5 icwmp,obuspa,gateway-info: Fix ShellCheck issues 2025-07-29 18:11:53 +05:30
Vivek Kumar Dutta
d3d1b444de obuspa: Integrate v10.0.5 2025-07-25 09:09:29 +05:30
Janusz Dziedzic
9681b6222c map-controller: 6.4.0.14 2025-07-24 10:55:16 +00:00
Meng
d20fb01a1b Upgrade quickjs to latest stable
Reworked the 002-fix_std_loadFile.patch
Removed the patches:
- 000-build-options.patch: the build options are now done in the
  Makefile
- 001-no-fenv-dtoa-libbf.patch: this patch is not needed anymore
  in the latest version: quickJS now uses a custom, high-precision
  floating-point conversion library that doesn't rely on the system's
  printf/snprintf for floating-point formatting.
2025-07-24 07:06:09 +00:00
Mohd Husaam Mehdi
85e49b3df6 usermngr: 1.3.11 2025-07-24 09:13:45 +05:30
Mohd Husaam Mehdi
511e0af668 passwdqc: align with usermngr (move PAM setup to usermngr) 2025-07-23 13:12:31 +05:30
Mohd Husaam Mehdi
1151478d13 linux-pam: align with usermngr (move PAM setup to usermngr) 2025-07-23 13:12:31 +05:30
Mohd Husaam Mehdi
7e87028731 usermngr: add support for USERMNGR_SECURITY_HARDENING
* this compile time flag will set up faildelay, lock out upon
  6 failed attempts during login via shell or console and enable
  password strength checks when changing password
* this will set openssh usePam option
* openssh and shadow-utils with PAM backend need to be selected for
  this compile time flag to work
2025-07-23 13:12:31 +05:30
arbala
cb18ecc420 map-controller: 6.4.0.13 2025-07-23 09:38:11 +02:00
Jakob Olsson
e581c05d27 map-agent: 6.3.7.1 2025-07-22 16:11:01 +02:00
Jakob Olsson
3ae6c52e7d map-agent: 6.3.7.0 2025-07-22 14:56:12 +02:00
Amin Ben Romdhane
498a06916b netmode: Align with reference updates 2025-07-21 17:46:16 +05:30
Suvendhu Hansa
332057fdd4 wifidmd,map-agent: Fix WiFi lagecy nodes for extenders 2025-07-21 17:44:04 +05:30
Vivek Kumar Dutta
58aff3cb45 obuspa: Improve file handling 2025-07-21 17:40:53 +05:30
Vivek Kumar Dutta
5678b6dcaa bbfdm: Optimize datamodel references 2025-07-21 17:08:38 +05:30
Vivek Kumar Dutta
a597c514f7 bbfdm: 1.16.8 2025-07-18 17:10:20 +05:30
Mohd Husaam Mehdi
3c1dcf90eb usermngr: set compile time flag to use pam with shadow-utils 2025-07-18 16:27:42 +05:30
Mohd Husaam Mehdi
62dc6c28a3 firewallmngr: 1.0.10 2025-07-17 19:45:09 +05:30
Amin Ben Romdhane
2703ea0421 timemngr: 1.1.11 2025-07-17 15:35:25 +02:00
Amin Ben Romdhane
b4a0572b7c bridgemngr: 1.1.1 2025-07-17 15:34:09 +02:00
Husaam Mehdi
428055c911 sshmngr: use openssh-with-pam as the default backend 2025-07-17 16:16:18 +05:30
Mohd Husaam Mehdi
97723f9e7a usermngr: include passwdqc and linux-pam
* passwdqc helps us enforce strong passwords policy
* linux-pam helps in managing failed login attempts
2025-07-17 14:48:32 +05:30
Vivek Kumar Dutta
2dceb5b44b wifidmd: 1.1.38 2025-07-16 16:51:49 +05:30
Vivek Kumar Dutta
8c9689caf7 fluent-bit: build using git proto 2025-07-16 11:56:36 +05:30
Janusz Dziedzic
af5bb94c8c fluent-bit: fix package hash 2025-07-15 14:45:26 +02:00
Janusz Dziedzic
9db65fcfba libwifi: 7.13.7 2025-07-15 10:24:24 +00:00
Vivek Kumar Dutta
2b43c27e53 xmppc: Fix ConnReqXMPPConnection reference 2025-07-15 10:07:05 +05:30
Vivek Kumar Dutta
c16f4d3f82 wifidmd: 1.1.37 2025-07-14 19:09:46 +05:30
Janusz Dziedzic
99a4f3c036 map-controller: 6.4.0.12 2025-07-14 12:37:53 +02:00
Erik Karlsson
71217d4f68 ieee1905: avoid installing datamodel_description.json into root 2025-07-14 08:50:46 +02:00
Vivek Kumar Dutta
ad012d7549 wifidmd: fix log spamming when radio disabled 2025-07-14 10:01:09 +05:30
Vivek Kumar Dutta
6cca837500 sulu: support dynamic QR 2025-07-14 09:49:23 +05:30
Amin Ben Romdhane
6bec3c159c bbfdm: Ensure UCI savedir paths are created before initialization from C code 2025-07-14 00:37:43 +02:00
Mohd Husaam Mehdi
fd921bb196 fluent-bit: bump version and adjust patch accordingly 2025-07-10 14:53:55 +05:30
Janusz Dziedzic
60d2f92da3 wifimngr: 17.7.6 2025-07-10 08:51:47 +00:00
Janusz Dziedzic
8f83250890 libwifi: 7.13.6 2025-07-10 08:50:48 +00:00
Vivek Kumar Dutta
652ec8a4af wifidmd: Updated default log level 2025-07-09 16:58:15 +05:30
Vivek Kumar Dutta
937b824055 tr143: 1.1.4 2025-07-09 16:56:02 +05:30
Vivek Kumar Dutta
889723079b bridgemngr: Add support for Bridge Type 2025-07-09 16:52:06 +05:30
Janusz Dziedzic
7a457ae32a libwifi: 7.13.5 2025-07-09 12:39:38 +02:00
Vivek Kumar Dutta
7e5e38e657 wifidmd: Support for AgentOnboard event 2025-07-09 15:44:40 +05:30
Vivek Kumar Dutta
44edac6572 icwmp: return 9003 for duplicate param in spv 2025-07-09 15:42:10 +05:30
Amin Ben Romdhane
fea3e1e4ef timemngr: Added support for SupportedZones object 2025-07-09 14:54:54 +05:30
Vivek Kumar Dutta
eae31a6dd4 obuspa: Integrated v10.0.4 2025-07-09 14:29:55 +05:30
Husaam Mehdi
3a1a65d5df logmngr: Use kmsg module instead of klogd 2025-07-09 12:45:43 +05:30
Husaam Mehdi
70a22d0299 logmngr: Include kernel logs 2025-07-09 12:43:46 +05:30
Amin Ben Romdhane
2a19a1a92a ieeee1905: Add data model description 2025-07-09 11:28:59 +05:30
Mohd Husaam Mehdi
5b865c9dbc fluent-bit: fix kmsg plugin and add syslog timestamp to kmsg logs 2025-07-09 11:20:51 +05:30
Mohd Husaam Mehdi
bc041faf04 fluent-bit: enable kmsg plugin 2025-07-09 11:20:51 +05:30
Janusz Dziedzic
de08bc79a1 ieee1905: 8.7.33 2025-07-08 08:16:56 +00:00
Vivek Kumar Dutta
9ab8dbdb3b dslmngr: 1.2.10 2025-07-04 15:15:57 +05:30
Vivek Kumar Dutta
f3cb8ad566 sulu: 5.0.4 2025-07-04 14:43:12 +05:30
Vivek Kumar Dutta
95e9630c4b libdsl: 7.3.0 2025-07-04 12:20:08 +05:30
Vivek Kumar Dutta
2c6a9e76c8 wifidmd: 1.1.33 2025-07-04 12:09:39 +05:30
Suvendhu Hansa
653b74aacf icwmp: avoid unexpected DHCP release at runtime 2025-07-03 11:25:50 +05:30
Reidar Cederqvist
c6437fbf53 Update Sulu to version 5.0.3 2025-07-02 18:02:48 +00:00
Markus Gothe
3a4ad69af9 libdsl: initial Airoha integration. 2025-07-02 16:02:27 +02:00
Suvendhu Hansa
0379e816c5 tr143: init/clean modules from DownloadDiagnostics test 2025-07-02 14:43:40 +05:30
260 changed files with 4505 additions and 347252 deletions

View File

@@ -5,13 +5,13 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=bbfdm
PKG_VERSION:=1.16.6
PKG_VERSION:=1.18.12
USE_LOCAL:=0
ifneq ($(USE_LOCAL),1)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://dev.iopsys.eu/bbf/bbfdm.git
PKG_SOURCE_VERSION:=1615b42e405faceceac825f9c0387a58b90785ae
PKG_SOURCE_VERSION:=adfdb54d625b952c533670f093dae008782ff56a
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
PKG_MIRROR_HASH:=skip
endif
@@ -55,7 +55,7 @@ define Package/dm-service
CATEGORY:=Utilities
SUBMENU:=TRx69
TITLE:=Datamodel ubus backend to expose micro-service tree
DEPENDS:=+libuci +libubox +libubus +libblobmsg-json +libjson-c +libbbfdm-api +libbbfdm-ubus +bbf_configmngr
DEPENDS:=+libuci +libubox +libubus +libblobmsg-json +libjson-c +libbbfdm-api +libbbfdm-ubus +bbf_configmngr +libeasy
endef
define Package/bbf_configmngr
@@ -149,10 +149,10 @@ define Package/bbfdmd/install
$(INSTALL_DIR) $(1)/etc/hotplug.d/iface
$(INSTALL_BIN) ./files/etc/hotplug.d/iface/85-bbfdm-sysctl $(1)/etc/hotplug.d/iface/85-bbfdm-sysctl
$(INSTALL_DIR) $(1)/lib/upgrade/keep.d
$(INSTALL_DATA) ./files/lib/upgrade/keep.d/bbf $(1)/lib/upgrade/keep.d/bbf
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) ./files/etc/uci-defaults/91-fix-bbfdmd-enabled-option $(1)/etc/uci-defaults/
$(INSTALL_BIN) ./files/etc/uci-defaults/ruleng.bbfdm $(1)/etc/uci-defaults
@@ -183,6 +183,7 @@ define Package/bbf_configmngr/install
$(INSTALL_BIN) ./files/etc/init.d/bbf_configd $(1)/etc/init.d/bbf_configd
$(INSTALL_BIN) $(PKG_BUILD_DIR)/utilities/files/usr/share/bbfdm/scripts/bbf_config_notify.sh $(1)/usr/share/bbfdm/scripts/
$(INSTALL_BIN) $(PKG_BUILD_DIR)/utilities/files/usr/share/bbfdm/scripts/bbf_default_reload.sh $(1)/etc/bbfdm/
$(INSTALL_DATA) ./files/etc/bbfdm/critical_services.json $(1)/etc/bbfdm/
endef

View File

@@ -1,23 +1,51 @@
{
"usp": [
"firewall",
"network",
"dhcp",
"time",
"wireless",
"ieee1905",
"mapcontroller",
"mosquitto",
"nginx",
"netmode"
"/etc/config/firewall",
"/etc/bbfdm/dmmap/dmmap_firewall",
"/etc/config/network",
"/etc/bbfdm/dmmap/IP",
"/etc/bbfdm/dmmap/Ethernet",
"/etc/bbfdm/dmmap/GRE",
"/etc/bbfdm/dmmap/IPv6rd",
"/etc/bbfdm/dmmap/PPP",
"/etc/bbfdm/dmmap/Routing",
"/etc/config/dhcp",
"/etc/bbfdm/dmmap/dmmap_dhcp",
"/etc/bbfdm/dmmap/dmmap_dhcp_client",
"/etc/bbfdm/dmmap/dmmap_dhcp_relay",
"/etc/bbfdm/dmmap/dmmap_dhcpv6",
"/etc/config/time",
"/etc/bbfdm/dmmap/dmmap_time",
"/etc/config/mapcontroller",
"/etc/config/wireless",
"/etc/bbfdm/dmmap/WiFi",
"/etc/config/ieee1905",
"/etc/config/mosquitto",
"/etc/config/nginx",
"/etc/config/netmode",
"/etc/bbfdm/dmmap/dmmap_netmode"
],
"cwmp": [
"firewall",
"network",
"dhcp",
"mapcontroller",
"wireless",
"time",
"netmode"
"/etc/config/firewall",
"/etc/bbfdm/dmmap/dmmap_firewall",
"/etc/config/network",
"/etc/bbfdm/dmmap/IP",
"/etc/bbfdm/dmmap/Ethernet",
"/etc/bbfdm/dmmap/GRE",
"/etc/bbfdm/dmmap/IPv6rd",
"/etc/bbfdm/dmmap/PPP",
"/etc/bbfdm/dmmap/Routing",
"/etc/config/dhcp",
"/etc/bbfdm/dmmap/dmmap_dhcp",
"/etc/bbfdm/dmmap/dmmap_dhcp_client",
"/etc/bbfdm/dmmap/dmmap_dhcp_relay",
"/etc/bbfdm/dmmap/dmmap_dhcpv6",
"/etc/config/mapcontroller",
"/etc/config/wireless",
"/etc/bbfdm/dmmap/WiFi",
"/etc/config/time",
"/etc/bbfdm/dmmap/dmmap_time",
"/etc/config/netmode",
"/etc/bbfdm/dmmap/dmmap_netmode"
]
}

View File

@@ -10,19 +10,10 @@ log() {
echo "${@}"|logger -t bbf.config -p info
}
create_needed_directories()
{
mkdir -p /tmp/bbfdm/.cwmp
mkdir -p /tmp/bbfdm/.usp
mkdir -p /tmp/bbfdm/.bbfdm
}
start_service()
{
local log_level
create_needed_directories
config_load bbfdm
config_get log_level "reload_handler" log_level 2
@@ -36,6 +27,6 @@ start_service()
service_triggers() {
for config_file in /etc/config/*; do
config_name=$(basename "$config_file")
procd_add_config_trigger "config.change" "$config_name" /usr/share/bbfdm/scripts/bbf_config_notify.sh
procd_add_config_trigger "config.change" "$config_name" /usr/share/bbfdm/scripts/bbf_config_notify.sh "$config_name"
done
}

View File

@@ -1,6 +1,6 @@
#!/bin/sh /etc/rc.common
START=97
START=60
STOP=05
USE_PROCD=1
@@ -62,7 +62,7 @@ _add_microservice()
procd_open_instance "${name}"
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}"

View File

@@ -7,13 +7,13 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=bulkdata
PKG_VERSION:=2.1.20
PKG_VERSION:=2.1.23
LOCAL_DEV:=0
ifneq ($(LOCAL_DEV),1)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://dev.iopsys.eu/bbf/bulkdata.git
PKG_SOURCE_VERSION:=a5e57962938ca143ede65d92be90b6e9fce66e15
PKG_SOURCE_VERSION:=f54550f2d587a701c0a8d5cac4a0910a99ce92cf
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
PKG_MIRROR_HASH:=skip
endif

View File

@@ -4,4 +4,16 @@ config DECOLLECTOR_EASYMESH_VERSION
int "Support Easymesh version"
default 6
config DECOLLECTOR_BUILD_TR181_PLUGIN
bool "Build TR-181 mapping module (responsible for Device.WiFi.DataElements.)"
default y
config DECOLLECTOR_VENDOR_EXTENSIONS
bool "Iopsys vendor extensions for Device.WiFi.DataElements."
default y
config DECOLLECTOR_VENDOR_PREFIX
string "Package specific datamodel Vendor Prefix for TR181 extensions"
default ""
endmenu

View File

@@ -6,12 +6,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=decollector
PKG_VERSION:=6.2.1.7
PKG_VERSION:=6.2.2.7
LOCAL_DEV=0
ifneq ($(LOCAL_DEV),1)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=ca92325ece080389ffb405c95048b64071eda653
PKG_SOURCE_VERSION:=9d1399c09f55da14a8de55828ba57c0e296ce62f
PKG_SOURCE_URL:=https://dev.iopsys.eu/multi-ap/decollector.git
PKG_SOURCE:=$(PKG_NAME)-$(PKG_SOURCE_VERSION).tar.gz
PKG_MIRROR_HASH:=skip
@@ -24,6 +24,7 @@ PKG_LICENSE:=BSD-3-Clause
PKG_LICENSE_FILES:=LICENSE
include $(INCLUDE_DIR)/package.mk
include $(TOPDIR)/feeds/iopsys/bbfdm/bbfdm.mk
define Package/decollector
SECTION:=utils
@@ -66,6 +67,18 @@ MAKE_PATH:=src
TARGET_CFLAGS += -DEASYMESH_VERSION=$(CONFIG_DECOLLECTOR_EASYMESH_VERSION)
ifeq ($(CONFIG_DECOLLECTOR_BUILD_TR181_PLUGIN),y)
MAKE_FLAGS += DECOLLECTOR_BUILD_TR181_PLUGIN=y
ifeq ($(CONFIG_DECOLLECTOR_VENDOR_EXTENSIONS),y)
TARGET_CFLAGS += -DDECOLLECTOR_VENDOR_EXTENSIONS
ifeq ($(CONFIG_DECOLLECTOR_VENDOR_PREFIX),"")
TARGET_CFLAGS += -DCUSTOM_PREFIX=\\\"$(CONFIG_BBF_VENDOR_PREFIX)\\\"
else
TARGET_CFLAGS += -DCUSTOM_PREFIX=\\\"$(CONFIG_DECOLLECTOR_VENDOR_PREFIX)\\\"
endif
endif
endif
EXECS := \
$(if $(CONFIG_PACKAGE_decollector),decollector)
@@ -76,6 +89,7 @@ define Package/decollector/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) ./files/decollector.init $(1)/etc/init.d/decollector
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/decollector $(1)/usr/sbin/
$(BBFDM_REGISTER_SERVICES) ./bbfdm_service.json $(1) $(PKG_NAME)
endef
$(eval $(call BuildPackage,decollector))

View File

@@ -0,0 +1,26 @@
{
"daemon": {
"enable": "1",
"service_name": "decollector",
"unified_daemon": true,
"services": [
{
"parent_dm": "Device.WiFi.",
"object": "DataElements"
}
],
"config": {
"loglevel": "3"
},
"apply_handler": {
"uci": [
{
"file": [
"mapcontroller"
],
"external_handler": "/etc/wifidmd/bbf_config_reload.sh"
}
]
}
}
}

View File

@@ -2,13 +2,13 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=dectmngr
PKG_RELEASE:=3
PKG_VERSION:=3.7.10
PKG_VERSION:=3.7.11
LOCAL_DEV=0
ifneq ($(LOCAL_DEV),1)
PKG_SOURCE_URL:=https://dev.iopsys.eu/iopsys/dectmngr.git
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=1f851980a6ba616df54f79930225f8bcd563b711
PKG_SOURCE_VERSION:=815ee44808169b8e1efa2cac44bd7d238ad33cdc
PKG_MIRROR_HASH:=skip
endif

207
dm-framework/Makefile Executable file
View File

@@ -0,0 +1,207 @@
#
# 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:=37dade4a2df6eaf6a4291a06ac776641ed81a79e
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
DATAMODELS_BUILD_DIR:=$(PKG_BUILD_DIR)/datamodels-build
DMAPI_BUILD_DIR:=$(PKG_BUILD_DIR)/dm-api-build
DMAGENT_BUILD_DIR:=$(PKG_BUILD_DIR)/dm-agent-build
include $(INCLUDE_DIR)/package.mk
-include $(TOPDIR)/feeds/iopsys/bbfdm/bbfdm.mk
#
# Datamodels Package Definition
#
define Package/datamodels
SECTION:=utils
CATEGORY:=Genexis
TITLE:=dm-framework Datamodel
URL:=http://www.genexis.eu
PKG_LICENSE:=GENEXIS
PKG_LICENSE_URL:=
endef
define Package/datamodels/description
This package contains dm-framework datamodel.
endef
#
# DM-API Package Definition
#
define Package/dm-api
CATEGORY:=Genexis
TITLE:=dm-api
PKG_BUILD_DEPENDS:=datamodels
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 +datamodels +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 datamodels
mkdir -p $(DATAMODELS_BUILD_DIR)
$(CP) -rf $(PKG_BUILD_DIR)/datamodels/* $(DATAMODELS_BUILD_DIR)/
# Copy scripts from top-level scripts directory
mkdir -p $(DATAMODELS_BUILD_DIR)/scripts
$(CP) -rf $(PKG_BUILD_DIR)/scripts/* $(DATAMODELS_BUILD_DIR)/scripts/
cd $(DATAMODELS_BUILD_DIR); \
npm install better-sqlite3 quickjs && \
node ./scripts/json2code.js && \
node ./scripts/qjs-handlers-validate.js
# 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 datamodels first (dependency for others)
$(MAKE) -C $(DATAMODELS_BUILD_DIR)\
PROJECT_ROOT="$(DATAMODELS_BUILD_DIR)" \
CROSS_COMPILE="$(TARGET_CROSS)" \
ARCH="$(LINUX_KARCH)" \
EXTRA_CFLAGS="$(TARGET_CFLAGS) -I$(DATAMODELS_BUILD_DIR)" \
all
# Build dm-api (depends on datamodels)
$(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 both)
$(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
# Datamodels development files
$(INSTALL_DIR) $(1)/usr/include
$(INSTALL_DIR) $(1)/usr/lib
$(CP) $(DATAMODELS_BUILD_DIR)/dm.h $(1)/usr/include/
$(CP) $(DATAMODELS_BUILD_DIR)/libdm.so $(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/
endef
#
# Package Installation - Datamodels
#
define Package/datamodels/install
$(INSTALL_DIR) $(1)/usr/lib
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_DIR) $(1)/etc/bbfdm
$(INSTALL_DIR) $(1)/usr/lib/dmf_handlers
$(INSTALL_BIN) $(DATAMODELS_BUILD_DIR)/default.db $(1)/etc/bbfdm/default_dm.db
$(INSTALL_BIN) $(DATAMODELS_BUILD_DIR)/libdm.so $(1)/usr/lib/
# Copy handler files from datamodels directory (new structure)
# Copy .js files from root datamodels directory
( cd $(DATAMODELS_BUILD_DIR); \
find . -maxdepth 1 -type f -name '*.js' -not -path './.*' -exec $(INSTALL_BIN) {} $(1)/usr/lib/dmf_handlers/{} \; )
# Copy .js files from subdirectories, preserving folder structure (skip hidden files/folders)
( cd $(DATAMODELS_BUILD_DIR); \
find . -type d -mindepth 1 -not -path './.*' -not -path './scripts*' -exec $(INSTALL_DIR) $(1)/usr/lib/dmf_handlers/{} \; ; \
find . -type f -name '*.js' -mindepth 2 -not -path './.*' -not -path './scripts*' -exec $(INSTALL_BIN) {} $(1)/usr/lib/dmf_handlers/{} \; )
endef
#
# Package Installation - DM-API
#
define Package/dm-api/install
$(INSTALL_DIR) $(1)/usr/lib
$(INSTALL_DIR) $(1)/sbin/
$(INSTALL_BIN) $(DMAPI_BUILD_DIR)/libdmapi.so $(1)/usr/lib/
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
$(INSTALL_BIN) ./files/etc/init.d/bridging $(1)/etc/init.d/
$(INSTALL_DATA) ./files/etc/config/bridging $(1)/etc/config/
$(BBFDM_REGISTER_SERVICES) ./bbfdm_service.json $(1) dm-agent
$(INSTALL_BIN) $(DMAGENT_BUILD_DIR)/dm-agent $(1)/usr/sbin
endef
# Register all three packages
$(eval $(call BuildPackage,datamodels))
$(eval $(call BuildPackage,dm-api))
$(eval $(call BuildPackage,dm-agent))

Binary file not shown.

View File

@@ -1,76 +0,0 @@
#
# 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:=datamodels
PKG_VERSION:=1.0.0
PKG_RELEASE:=1
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)/package.mk
define Package/$(PKG_NAME)
SECTION:=utils
CATEGORY:=Genexis
TITLE:=GeneOS Datamodel
URL:=http://www.genexis.eu
PKG_LICENSE:=GENEXIS
PKG_LICENSE_URL:=
endef
define Package/$(PKG_NAME)/description
This package contains GeneOS datamodel.
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) -rf ./src/* $(PKG_BUILD_DIR)/
cd $(PKG_BUILD_DIR); \
npm install better-sqlite3 quickjs && \
node ./scripts/json2code.js && \
node ./scripts/qjs-handlers-validate.js
endef
TARGET_CFLAGS += $(FPIC) -I$(PKG_BUILD_DIR)
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR)\
PROJECT_ROOT="$(PKG_BUILD_DIR)" \
CROSS_COMPILE="$(TARGET_CROSS)" \
ARCH="$(LINUX_KARCH)" \
EXTRA_CFLAGS="$(TARGET_CFLAGS)" \
all
endef
define Build/InstallDev
$(INSTALL_DIR) $(1)/usr/include
$(INSTALL_DIR) $(1)/usr/lib
$(CP) $(PKG_BUILD_DIR)/dm_types.h $(1)/usr/include/
$(CP) $(PKG_BUILD_DIR)/dm_node.h $(1)/usr/include/
$(CP) $(PKG_BUILD_DIR)/dm.h $(1)/usr/include/
$(CP) $(PKG_BUILD_DIR)/libdm.so $(1)/usr/lib/
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/lib
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_DIR) $(1)/etc/bbfdm
$(INSTALL_DIR) $(1)/usr/lib/dmf_handlers
$(INSTALL_BIN) $(PKG_BUILD_DIR)/default.db $(1)/etc/bbfdm/default_dm.db
$(INSTALL_BIN) $(PKG_BUILD_DIR)/libdm.so $(1)/usr/lib/
# Copy only .js handler files recursively, preserving folder structure (skip hidden files/folders)
( cd $(PKG_BUILD_DIR)/dm-files; \
find . -type d -not -path './.*' -exec $(INSTALL_DIR) $(1)/usr/lib/dmf_handlers/{} \; ; \
find . -type f -name '*.js' -not -path './.*' -exec $(INSTALL_BIN) {} $(1)/usr/lib/dmf_handlers/{} \; )
endef
$(eval $(call BuildPackage,$(PKG_NAME)))

View File

@@ -1,41 +0,0 @@
#
# 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.
#
#
PROG = libdm.so
SRCS = dm_node.c
# the next files are generated
SRCS += dm.c
OBJS = $(SRCS:.c=.o)
DEPS = $(SRCS:.c=.d)
CC = $(CROSS_COMPILE)gcc
STRIP = $(CROSS_COMPILE)strip
CFLAGS = -I$(STAGING_DIR)/usr/include $(EXTRA_CFLAGS)
CFLAGS += -MMD -MP
LDFLAGS = -shared
CFLAGS += -Wall -Werror -fpic
all: $(PROG)
$(PROG): $(OBJS)
$(CC) $^ $(LDFLAGS) -o $@
%.o: %.c
$(CC) $(CFLAGS) -c $^ -o $@
clean:
rm -f $(PROG) *.o core $(DEPS) dm.c dm.h
-include $(DEPS)

View File

@@ -1,443 +0,0 @@
[
{
"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",
"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",
"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."
]
}
]
}
]

View File

@@ -1,166 +0,0 @@
/*
* 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 * as dm from '../dm_consts.js';
import { getBridgeDeviceType } from './common.js';
function clearUnusedDevice(oldPorts, newPorts, devices) {
oldPorts?.forEach(port => {
if (port.includes('.') && !newPorts?.includes(port)) {
const dev = devices?.find(x => x.name === port);
if (dev?.['.name']) delUci('network', dev['.name']);
}
});
}
function applyBridge(bri, ports, VLANs, VLANPorts) {
const ifnames = [];
const devices = getUciByType('network', 'device')?.filter(x => x.type !== undefined);
const portsVal = getUciOption('network', bri._key, 'ports');
if (portsVal) delUci('network', bri._key, null, 'ports');
// get ports ethernet ifnames
for (const port of ports || []) {
if (port.ManagementPort || !port.LowerLayers.includes('Ethernet.Interface') || !port.Enable) {
continue;
}
let ifname = _dm_linker_value(port.LowerLayers);
if (!ifname) {
_log_error(`ifname not found for port: ${port.LowerLayers}`);
continue;
}
// check vlan
const portPath = `Device.Bridging.Bridge.${bri['.index']}.Port.${port['.index']}`;
const vp = VLANPorts?.find(x => x.Port === portPath);
if (!vp?.VLAN) {
ifnames.push(ifname);
continue;
}
// get index of the vlan
const [, indices] = _dm_node(vp.VLAN);
const vlanIdx = indices[indices.length - 1];
const vlan = VLANs?.find(x => x['.index'] === vlanIdx);
if (!vlan || vlan.VLANID <= 0) {
ifnames.push(ifname);
continue;
}
const eth = ifname;
ifname = `${ifname}.${vlan.VLANID}`;
const dev = devices?.find(x => x.name === ifname);
let devName;
if (dev) {
devName = dev['.name'];
} else {
devName = `br_${bri['.index']}_port_${vp['.index']}`;
addUci('network', 'device', devName, {
ifname: eth,
name: ifname,
vid: vlan.VLANID,
});
}
const uciConfigs = {};
// Handle Type parameter - determine device type based on port Type or default behavior
let deviceType = '';
if (port.Type) {
deviceType = getBridgeDeviceType(port.Type);
if (deviceType) uciConfigs.type = deviceType;
} else if (!vp.Untagged) {
uciConfigs.type = '8021q';
deviceType = '8021q';
}
// Handle TPID parameter
if (port.TPID) {
// If TPID is explicitly set, use it and derive device type if needed
uciConfigs.tpid = port.TPID;
// Set device type based on TPID if not already set
if (!deviceType) {
if (port.TPID === '33024') {
uciConfigs.type = '8021q';
} else if (port.TPID === '34984') {
uciConfigs.type = '8021ad';
}
}
}
uciConfigs.disabled = vlan.Enable && vp.Enable ? '0' : '1';
uciConfigs.ingress_qos_mapping = port.PriorityRegeneration !== '0,1,2,3,4,5,6,7'
? port.PriorityRegeneration.split(',').map((p, i) => `${i}:${p}`)
: '';
uciConfigs.egress_qos_mapping = port.X_IOPSYS_EU_EgressPriorityRegeneration !== ''
? port.X_IOPSYS_EU_EgressPriorityRegeneration.split(',').map((p, i) => `${i}:${p}`)
: '';
setUci('network', devName, uciConfigs);
ifnames.push(ifname);
}
clearUnusedDevice(portsVal, ifnames, devices);
if (ifnames.length > 0) {
setUci('network', bri._key, { ports: ifnames });
}
}
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']);
applyBridge(bri, ports, vlans, vlanPorts);
}
export function applyDeviceBridgingBridgeVLAN(vlans, bri) {
const ports = _dm_get(dm.DM_DEVICE_BRIDGING_BRIDGE_PORT, bri['.index']);
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']);
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';
export function deinitDeviceBridgingBridge(uci) {
const ports = getUciOption('network', uci, 'ports');
ports?.forEach(port => {
if (port.includes('.')) {
const dev = getUciByType('network', 'device', { match: { name: port } });
if (dev) delUci('network', dev[0]['.name']);
}
});
}

View File

@@ -1,125 +0,0 @@
/*
* 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';
function importBridge(dev, devices, bridges) {
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.ifname?.startsWith('eth'));
for (const portName of (dev.ports || [])) {
let portIndex = ethPorts.findIndex(x => x.ifname === portName);
if (portIndex >= 0) {
// Regular ethernet port
const ethDevice = ethPorts[portIndex];
const portType = getBridgePortType(ethDevice.type) || 'CustomerVLANPort';
const tpid = getTPIDFromDeviceType(ethDevice.type, ethDevice.tpid);
briPorts.push({
Enable: 1,
Name: ethDevice['.name'],
Alias: `cpe-${ethDevice['.name']}`,
TPID: tpid,
PVID: 1,
Type: portType,
LowerLayers: `Device.Ethernet.Interface.${portIndex + 1}`,
_key: ethDevice['.name'],
});
} else {
// vlan device
const device = devices.find(x => x.name === portName);
if (!device) {
_log_error('device not found', portName);
continue;
}
if (device.type === '8021q' || device.type === 'untagged' || device.type === '8021ad' || device.type === 'transparent') {
let vlanIndex = briVLAN.findIndex(x => x.VLANID === device.vid);
if (vlanIndex < 0) {
briVLAN.push({ Enable: 1, VLANID: device.vid });
vlanIndex = briVLAN.length;
} else {
vlanIndex += 1;
}
// Get the base ethernet device to determine the correct port index
const baseEthDevice = ethPorts.find(x => device.ifname === x.ifname);
const basePortIndex = baseEthDevice ? ethPorts.indexOf(baseEthDevice) : 0;
const portType = getBridgePortType(device.type) || 'CustomerVLANPort';
const tpid = getTPIDFromDeviceType(device.type, device.tpid);
briPorts.push({
Enable: 1,
Name: device['.name'],
Alias: `cpe-${device['.name']}`,
TPID: tpid,
PVID: device.vid,
Type: portType,
LowerLayers: `Device.Ethernet.Interface.${basePortIndex + 1}`,
_key: device['.name'],
});
briVLANPort.push({
Enable: 1,
VLAN: `Device.Bridging.Bridge.${bridges.length}.VLAN.${vlanIndex}`,
Port: `Device.Bridging.Bridge.${bridges.length}.Port.${briPorts.length}`,
Untagged: device.type === 'untagged' ? 1 : 0,
_key: device['.name'],
});
} else {
_log_error('unknown device type:', device.type);
}
}
}
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 devices = getUciByType('network', 'device');
devices?.forEach(dev => {
if (dev.type === 'bridge') {
importBridge(dev, devices, bridges);
}
});
return bridges;
}

View File

@@ -1,133 +0,0 @@
/*
* 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' } });
wifiIfaces?.forEach(x => {
const ssid = getUciByType('dmmap_wireless', 'ssid',
{ match: { device: x.device, ssid: x.ssid}, confdir: '/etc/bbfdm/dmmap'});
if (Array.isArray(ssid) && ssid.length > 0) {
x.ssidPath = _dm_linker_path("Device.WiFi.SSID.", "Name", ssid[0].name) ?? '';
}
});
return wifiIfaces?.filter(x => x.network === networkName);
}
export function setDeviceBridgingBridgePortManagementPort(val, bri, port) {
if (isTrue(val)) {
_db_set(`Device.Bridging.Bridge.${bri['.index']}.Port.${port['.index']}.Name`, bri.Name);
}
return 1;
}

View File

@@ -1,61 +0,0 @@
/*
* 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: 'CustomerNetworkPort', devType: '8021ad' },
{ portType: 'CustomerVLANPort', devType: '8021q' },
{ portType: 'CustomerVLANPort', devType: 'untagged' },
{ portType: 'CustomerVLANPort', devType: '' },
{ portType: 'CustomerVLANPort', devType: undefined },
{ portType: 'VLANUnawarePort', devType: 'transparent' }
];
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 : null;
}
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;
case 'untagged':
case 'transparent':
case '':
case undefined:
default:
return 37120;
}
}

View File

@@ -1,126 +0,0 @@
/* eslint-disable no-undef */
/*
* Wrapper around the native QuickJS C binding `_uci_call` which speaks to
* libuci directly (see qjs_uci_api.c). The exported helpers mimic the public
* API of the original uci.js module so that existing call-sites can switch to
* this implementation by simply importing uci2.js.
*/
export function uciBool(val) {
// by default enable is true if it is not defined
return (val === undefined || val === '1' || val === 'true' || val === 'enable' || val === 'yes');
}
function callUci(method, args) {
const [ret, res] = _uci_call(method, args);
if (ret !== 0) {
// Returning undefined on error keeps behaviour consistent with the
// original helpers which silently return undefined.
return [ret, undefined];
}
return [ret, res];
}
export function getUci(args) {
const [, res] = callUci('get', args);
if (res) {
if (res.values) {
if (!args.section) {
return Object.values(res.values);
}
return res.values;
}
if (res.value !== undefined) {
return res.value;
}
}
return undefined;
}
export function getUciOption(config, section, option, extraArgs) {
let args = { config, section, option };
if (extraArgs) {
args = { ...args, ...extraArgs };
}
return getUci(args);
}
export function getUciByType(config, type, extraArgs) {
let args = { config, type };
if (extraArgs) {
args = { ...args, ...extraArgs };
}
return getUci(args);
}
export function getUciSection(config, section, extraArgs) {
let args = { config, section };
if (extraArgs) {
args = { ...args, ...extraArgs };
}
return getUci(args);
}
export function setUci(cfg, section, values, type, match, extraArgs) {
let args = { config: cfg, section };
if (type) args.type = type;
if (values) args.values = values;
if (match) args.match = match;
if (extraArgs) args = { ...args, ...extraArgs };
const [ret] = callUci('set', args);
return ret;
}
export function addUci(cfg, type, name, values, extraArgs) {
let args = { config: cfg, type };
if (name) args.name = name;
if (values) args.values = values;
if (extraArgs) args = { ...args, ...extraArgs };
const [, res] = callUci('add', args);
return res || undefined;
}
export function delUci(cfg, section, type, option, options, match, extraArgs) {
let args = { config: cfg };
if (section) args.section = section;
if (type) args.type = type;
if (option) args.option = option;
if (options) args.options = options;
if (match) args.match = match;
if (extraArgs) args = { ...args, ...extraArgs };
const [, res] = callUci('delete', args);
return res || undefined;
}
export function delUciOption(config, section, option, match, extraArgs) {
let args = { config, section, option };
if (match) args.match = match;
if (extraArgs) args = { ...args, ...extraArgs };
const [, res] = callUci('delete', args);
return res || undefined;
}
export function uciChanges(cfg, extraArgs) {
let args = { config: cfg };
if (extraArgs) args = { ...args, ...extraArgs };
const [, res] = callUci('changes', args);
return res && res.changes ? res.changes : undefined;
}
export function commitUci(cfg, extraArgs) {
let args = { config: cfg };
if (extraArgs) args = { ...args, ...extraArgs };
const [ret] = callUci('commit', args);
return ret;
}
export function revertUci(cfg, extraArgs) {
let args = { config: cfg };
if (extraArgs) args = { ...args, ...extraArgs };
const [ret] = callUci('revert', args);
return ret;
}

View File

@@ -1,268 +0,0 @@
/*
* 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.
*
*/
/* eslint-disable no-undef */
/* eslint-disable no-bitwise */
import * as os from 'os';
import * as std from 'std';
export function macAddressToBase64(macAddress) {
// Split the MAC address into an array of bytes using the colon separator
const bytes = macAddress.split(':');
// Convert the bytes from hexadecimal to decimal
const decimalBytes = bytes.map((byte) => parseInt(byte, 16));
// Convert the decimal bytes into an array of 8-bit binary strings
const binaryBytes = decimalBytes.map((byte) => byte.toString(2).padStart(8, '0'));
// Concatenate the binary strings into a single string
const binaryString = binaryBytes.join('');
// Split the binary string into groups of 6 bits
const base64Chars = [];
for (let i = 0; i < binaryString.length; i += 6) {
base64Chars.push(binaryString.slice(i, i + 6));
}
// Convert each group of 6 bits to a decimal number
const decimalBase64 = base64Chars.map((char) => parseInt(char, 2));
// Create the base64 character set
const base64CharacterSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
// Map the decimal numbers to their corresponding base64 characters
const base64String = decimalBase64.map((num) => base64CharacterSet.charAt(num)).join('');
return base64String;
}
export function tr181Path(path, uciPath, keyName, keyVal) {
if (!keyVal) {
return '';
}
const [uciConfig, uciType] = uciPath.split('.');
const args = { config: uciConfig, type: uciType };
const [, res] = _ubus_call('uci', 'get', args);
if (!res || !res.values) {
_log_error('tr181Path: invalid result');
return '';
}
let insts = Object.values(res.values);
if (uciConfig === 'network' && uciType === 'interface') {
insts = insts.filter((x) => x.device !== 'lo' && !x.device?.startsWith('@') && x.proto !== 'dhcpv6');
}
const index = insts.findIndex((x) => x[keyName] === keyVal);
if (index < 0) {
return '';
}
if (path.startsWith('Device.')) {
return `${path}${index + 1}`;
}
return `Device.${path}${index + 1}`;
}
export function tr181IPInterface(uci) {
return tr181Path('IP.Interface.', 'network.interface', '.name', uci);
}
export function prefixLengthToSubnetMask(prefixLength) {
if (!prefixLength) {
return '';
}
const mask = 0xFFFFFFFF << (32 - prefixLength);
const subnetMask = [
(mask >>> 24) & 0xFF,
(mask >>> 16) & 0xFF,
(mask >>> 8) & 0xFF,
mask & 0xFF,
].join('.');
return subnetMask;
}
export function fileExists(path) {
let exists = false;
if (path !== '') {
// eslint-disable-next-line no-unused-vars
const [obj, err] = os.stat(path);
exists = (err === 0);
}
return exists;
}
export function waitUntilFileExists(path, timeoutMs = 10000) {
const startTime = Date.now();
while (!fileExists(path) && (Date.now() - startTime < timeoutMs)) {
os.sleep(100);
}
return fileExists(path);
}
export function runCommand(command) {
const fp = std.popen(command, 'r');
if (fp) {
const result = fp.readAsString();
if (fp.close() === 0)
return result;
else
return undefined;
}
return undefined;
}
export function fileExistsWithRegex(directory, regex) {
const [files, err] = os.readdir(directory);
if (err) {
_log_warn(`fileExistsWithRegex(): Could not read directory: ${directory}`);
}
for (let i = 0; i < files.length; i += 1) {
if (regex.test(files[i])) {
return true;
}
}
return false;
}
export function isIPv4Address(addr) {
return addr?.includes('.');
}
export function isIPv6Address(addr) {
return addr?.includes(':');
}
// find the pathname in LowerLayers
export function findPathInLowerlayer(path, inst, instKey) {
const lowerlayer = _dm_get(`${path}.LowerLayers`);
if (lowerlayer === '') {
return false;
}
if (lowerlayer.includes(instKey)) {
if (lowerlayer.includes(inst)) {
return true;
}
} else {
const layers = lowerlayer.split(',');
if (layers.find((x) => findPathInLowerlayer(x, inst, instKey))) {
return true;
}
}
return false;
}
export function hex2a(hex) {
let i = 0;
let str = '';
for (i = 0; i < hex.length; i += 2) {
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
}
return str;
}
export function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
export function lowercaseFirstLetter(string) {
return string.charAt(0).toLowerCase() + string.slice(1);
}
export function getIfnameOperState(ifname) {
if (!ifname) {
return 'Down';
}
const res = std.loadFile(`/sys/class/net/${ifname}/operstate`);
if (res) {
return capitalizeFirstLetter(res.trim());
}
return 'Down';
}
export function getIfnameState(ifname, name) {
if (!ifname) {
return '';
}
const res = std.loadFile(`/sys/class/net/${ifname}/${name}`);
return res?.trim();
}
export function strToHex(str) {
if (!str) {
return '';
}
let hex = '';
for (let i = 0; i < str.length; i += 1) {
hex += str.charCodeAt(i).toString(16);
}
return hex;
}
// transform the object of following object:
// {
// 'SSIDtoVIDMapping.1.SSID': 'abc',
// 'SSIDtoVIDMapping.1.VID': 100,
// 'SSIDtoVIDMapping.2.SSID': 'xyz',
// 'SSIDtoVIDMapping.2.VID': 200,
// Enable: 'true'
// }
// into:
// {
// SSIDtoVIDMapping: [ { SSID: 'abc', VID: 100 }, { SSID: 'xyz', VID: 200 } ],
// Enable: 'true'
// }
export function transformInputObject(obj) {
const result = {};
Object.entries(obj).forEach(([key, value]) => {
const splitKey = key.split('.');
if (splitKey.length < 3) {
result[key] = value; // add invalid keys directly to the result
return;
}
const mainKey = splitKey[0];
const index = parseInt(splitKey[1], 10) - 1;
const prop = splitKey[2];
if (!result[mainKey]) {
result[mainKey] = [];
}
if (!result[mainKey][index]) {
result[mainKey][index] = {};
}
result[mainKey][index][prop] = value;
});
return result;
}
export function isTrue(val) {
return val === 'true' || val === '1' || val === true;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,290 +0,0 @@
/*
* 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.
*
*/
#ifndef DM_NODE_H
#define DM_NODE_H
#include "dm_types.h"
enum NODE_FLAG {
FLAG_NONE = 0x0,
FLAG_COUNTER = 0x40,
FLAG_HAS_MIN = 0x80,
FLAG_HAS_MAX = 0x100,
FLAG_HAS_ORDER = 0x400,
FLAG_WRITABLE = 0x800,
FLAG_CONFIDENTIAL = 0x1000,
FLAG_CWMP_ONLY = 0x4000,
FLAG_USP_ONLY = 0x8000,
FLAG_INTERNAL= 0x10000,
};
enum DM_UCI_MAP_TYPE {
DM_UCI_MAP_TYPE_NONE = 0,
DM_UCI_MAP_TYPE_SIMPLE = 0x01, // simple value 2 value
DM_UCI_MAP_TYPE_DISABLE = 0x02, // uci disable bool type
DM_UCI_MAP_TYPE_TABLE = 0x04, // a JSON object is used for mapping, {uci: dm}
DM_UCI_MAP_TYPE_INTERFACE = 0x08, // ip interface
DM_UCI_MAP_TYPE_JS = 0x10, // js code
};
struct dm_uci_map {
unsigned int type;
const char *map;
const char *key;
};
struct dm_node_info {
enum DM_NODE_TYPE type;
dm_node_id_t node_id;
const char *const name;
const struct dm_node_info *const parent;
const char *const table_name; // if NULL the value is not stored in the database
const char *pathname;
enum NODE_FLAG flag;
dm_node_id_t depends_node_id;
};
struct dm_parameter {
struct dm_node_info node;
enum DM_DATA_TYPE data_type;
long min;
long max;
int list;
union {
// for enum data type
const char **enum_strings;
// for counter data type
dm_node_id_t counter_object;
// for path data type
const dm_node_id_t *paths;
} data;
const char *set_on_create;
const char *js_val;
const char *const_val;
const char *default_val;
const char *default_uci_val;
struct dm_uci_map map;
};
struct command_arg {
const char *name;
enum DM_DATA_TYPE type;
int min;
int max;
int list;
const char **enum_values;
int mandatory;
};
struct dm_command {
struct dm_node_info node;
int async;
const struct command_arg *inputs;
int inputs_cnt;
const struct command_arg *outputs;
int outputs_cnt;
};
struct event_arg {
const char *name;
enum DM_DATA_TYPE type;
};
struct dm_event {
struct dm_node_info node;
const struct event_arg *args;
int args_cnt;
const char *ubus_event;
};
struct dm_object {
struct dm_node_info node;
int param_num;
const struct dm_node_info *const *const param_list;
int command_num;
const struct dm_node_info *const *const command_list;
int object_num;
const struct dm_node_info *const *const event_list;
int event_num;
const struct dm_node_info *const *const object_list;
int paths_refs_num;
const struct dm_node_info *const *const paths_refs_list;
const char *key_param_names;
struct dm_uci_map map;
const char *js_val;
int fixed_objects;
};
const struct dm_node_info *dm_node_get_root(void);
const struct dm_node_info *dm_node_get_info(dm_node_id_t id);
/**
* This function will look up a parameter by ID
* @pre None
* @post valid dm_parameter pointer returned or NULL if error
* @param id The actual id for which we want to retrieve a
* pointer to the dm_parameter struct
* @return NULL in case id is out of range or if id does not point
* to a parameter node, a pointer to the dm_parameter struct otherwise
*/
const struct dm_parameter *dm_node_get_parameter(dm_node_id_t id);
const struct dm_command *dm_node_get_command(dm_node_id_t id);
const struct dm_event *dm_node_get_event(dm_node_id_t id);
/**
* This function will look up a command by ID
* @pre None
* @post valid dm_command pointer returned or NULL if error
* @param id The actual id for which we want to retrieve a
* pointer to the dm_parameter struct
* @return NULL in case id is out of range or if id does not point
* to a command node, a pointer to the dm_command struct otherwise
*/
const struct dm_command *dm_node_get_command(dm_node_id_t id);
/**
* This function will look up an object by ID
* @pre None
* @post valid dm_object pointer returned or NULL if error
* @param id The actual id for which we want to retrieve a
* pointer to the dm_object struct
* @return NULL in case id is out of range or if id does not point
* to an object node, a pointer to the dm_object struct otherwise
* Note that if the id points to an object list a pointer to the
* first object is returned
*/
const struct dm_object *dm_node_get_object(dm_node_id_t id);
int dm_node_is_valid(dm_node_id_t id);
int dm_node_is_parameter(dm_node_id_t id);
int dm_node_is_command(dm_node_id_t id);
int dm_node_is_event(dm_node_id_t id);
int dm_node_is_writable(dm_node_id_t id);
int dm_node_is_object(dm_node_id_t id);
int dm_node_is_objectlist(dm_node_id_t id);
int dm_node_is_counter(dm_node_id_t id);
int dm_node_is_text_type(dm_node_id_t id);
int dm_node_is_bool_type(dm_node_id_t id);
int dm_node_is_ul_type(dm_node_id_t id);
int dm_node_is_unsigned_type(dm_node_id_t id);
int dm_node_is_confidential(dm_node_id_t id);
int dm_node_is_cwmp_only(dm_node_id_t id);
int dm_node_is_usp_only(dm_node_id_t id);
int dm_node_is_internal(dm_node_id_t id);
dm_node_id_t dm_node_counter_id(dm_node_id_t id);
int dm_node_has_db(dm_node_id_t id);
const char *dm_node_object_keys(dm_node_id_t id);
int dm_node_is_fixed_objects(dm_node_id_t id);
int dm_node_max_data_size(dm_node_id_t id);
int dm_node_param_mem_size(dm_node_id_t node_id);
const char *get_param_xsd_type(enum DM_DATA_TYPE type);
const char *dm_node_name(dm_node_id_t id);
dm_node_id_t dm_node_id_parent(dm_node_id_t id);
int dm_node_parent(const dm_node_t *node, dm_node_t *parent);
// get first multi-instance parent
int dm_node_i_parent(const dm_node_t *node, dm_node_t *parent);
dm_node_id_t dm_node_i_parent_id(const dm_node_id_t id);
int dm_node_index_cnt(dm_node_id_t id);
enum DM_DATA_TYPE dm_node_data_type(dm_node_id_t id);
dm_node_id_t dm_node_get_apply_depends(dm_node_id_t id);
dm_node_id_t dm_node_get_extends(dm_node_id_t id);
/*
Get the full name of a node.
@param node[in] Node ID whose name we want to retrieve
@param name[out] Location where the node name is written
@param name_len[in] Amount of space available in name
@return 0 in case of success, -1 in case of failure
*/
int dm_node2name(const dm_node_t *node, char *name, int name_len);
int dm_node2name_with_index(const dm_node_t *node, char *name, int name_len, const char *index_replacement);
int dm_name2node(const struct dm_node_info *parent, const char *name, dm_node_t *node);
int dm_path2node(const char *path, dm_node_t *node);
int dm_node_verify_param_data(dm_node_id_t id, const char *data);
// is parameter ancestor is the ancestor or parent of parameter id
int dm_node_is_ancestor(dm_node_id_t id, dm_node_id_t ancestor);
// is parameter data type a list (comman separated)
int dm_node_is_param_list(dm_node_id_t id);
dm_index_t dm_node_last_index(const dm_node_t *node);
int dm_node_is_index_complete(const dm_node_t *node);
/** Compare if two nodes are identical.
Two nodes are considered identical if their id, their index arrays and the cnt is the same
@param node1[in] first node for the comparison
@param node2[in] second node for the comparison
@return 1 if identical, 0 if not identical
*/
int dm_node_equal(const dm_node_t *node1, const dm_node_t *node2);
int dm_node_has_path(dm_node_id_t node_id, dm_node_id_t path);
// return 0-(max-1) for valid string, -1 for unknown enum string
int dm_node_get_enum_index(dm_node_id_t id, const char *enum_str);
// return the enum string for valid index: 0-(max-1), otherwise return NULL
const char *dm_node_get_enum_str(dm_node_id_t id, int index);
/** Remove path name from the path names separated with comma
@param paths path names separated with with comma
@param node node of path name that is to be removed
@return 0 if successful, -1 for failure
*/
int tr181_paths_remove(dm_path_t paths, const dm_node_t *node);
/** Append one path name to the path names separated with comma
@param paths path names separated with with comma
@param node node of path name that is to be appended
@return 0 if successful, -1 for failure
*/
int tr181_paths_add(dm_path_t paths, const dm_node_t *node);
// Find the "Order" parameter node from all its child nodes
int dm_node_find_order_param(const dm_node_t *obj_node, dm_node_t *order_node);
/** Return the database table for a node
@param node The node for which the database table is returned
@return pointer to the name of the database table (NULL if the node is not in the database
*/
const char *dm_node_get_table_name(const struct dm_node_info *node);
// Get child node id by its name
dm_node_id_t dm_node_get_child_id(dm_node_id_t id, const char *name);
// get child node by name
int dm_node_get_child(const dm_node_t *node, const char *name, dm_node_t *child);
const char *dm_node_str(const dm_node_t *node);
const char *dm_node_id_str(const dm_node_id_t id);
// compare if the nodes are compatible, this is if node1 and node2 have the same id and
// all indexes of node1 are a subset of node2 or vice versa
int dm_node_compatible(const dm_node_t *node1, const dm_node_t *node2);
// get the string xsd type of the data type
const char *dm_node_get_param_xsd_type(dm_node_id_t id);
/** Get the output argument type of the command node
@param [in] id node id
@param [in] arg_name argument name of the command
@return pointer of const string if successful, NULL for failure
*/
const struct command_arg *dm_node_get_command_output_arg(dm_node_id_t id, const char *arg_name);
// return 1 if verified, otherwise 0.
int dm_node_verify_command_input(dm_node_id_t id, const char *input_name, const char *input_value);
// Compare the command argument pathname with index (index part will be skipped for comparision)
// ex, "result.{i}.abc" == "result.100.abc"
// return 0 if equal, otherwise 1
int dm_node_compare_command_arg_name(const char* str1, const char* str2);
#endif

View File

@@ -1,97 +0,0 @@
/*
* 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.
*
*/
#ifndef DM_TYPES_H
#define DM_TYPES_H
#define MAX_DM_NODE_DEPTH 8
#define INVALID_DM_INDEX ((dm_index_t)0)
#define INVALID_DM_NODE_ID ((dm_node_id_t)-1)
typedef unsigned int dm_node_id_t;
typedef unsigned int dm_index_t;
typedef dm_index_t dm_index_path_t[MAX_DM_NODE_DEPTH];
typedef struct
{
dm_index_path_t index;
} node_index_path_t;
typedef struct
{
dm_node_id_t id;
dm_index_path_t index;
int cnt;
} dm_node_t;
#define dm_init_node(id) \
{ \
id, {0}, 0 \
}
typedef unsigned int dm_uint_t;
typedef int dm_int_t;
typedef int dm_bool_t;
typedef char dm_enum_t[128];
typedef char dm_ip_t[64];
// IPv4 or IPv6 routing prefix in Classless Inter-Domain Routing (CIDR) notation [RFC4632].
// This is specified as an IP address followed by an appended "/n" suffix,
// where n (the prefix size) is an integer in the range 0-32 (for IPv4) or 0-128 (for IPv6)
// that indicates the number of (leftmost) '1' bits of the routing prefix.
// If the IP address part is unspecified or inapplicable, it MUST be an empty string unless
// otherwise specified by the parameter definition. In this case the IP prefix will be of the form "/n".
// IPv4 example: 192.168.1.0/24
// IPv6 example: 2001:edff:fe6a:f76::/64
typedef char dm_ip_prefix_t[64];
typedef char dm_mac_t[20]; // 18 would suffice but there can be word access when getting a value; hence rounded up to 20 */
typedef char dm_date_time_t[64];
typedef char dm_url_t[260];
typedef unsigned long dm_ulong_t;
typedef unsigned long long dm_ulonglong_t;
typedef char dm_path_t[1024];
typedef char dm_domain_t[256];
#define dm_true 1
#define dm_false 0
enum DM_DATA_TYPE {
DM_DATA_INT = 0,
DM_DATA_LONG,
DM_DATA_UINT,
DM_DATA_ULONG,
DM_DATA_BOOLEAN,
DM_DATA_STRING,
DM_DATA_HEXBINARY,
DM_DATA_BASE64,
DM_DATA_IP,
DM_DATA_IPV4,
DM_DATA_IPV6,
DM_DATA_IP_PREFIX,
DM_DATA_IPV6_PREFIX,
DM_DATA_MAC,
DM_DATA_DATETIME,
DM_DATA_ENUM,
DM_DATA_URL,
DM_PATH_NAME,
DM_DATA_UNKNOWN
};
enum DM_NODE_TYPE {
DM_NODE_PARAMETER = 0,
DM_NODE_OBJECT,
DM_NODE_OBJECT_LIST,
DM_NODE_COMMAND,
DM_NODE_EVENT
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,508 +0,0 @@
/* eslint-disable no-await-in-loop */
/*
* 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.
*
*/
const assert = require('assert');
const fs = require('fs');
const xml2js = require('xml2js');
const util = require('util');
const readFile = util.promisify(fs.readFile);
const writeFile = util.promisify(fs.writeFile);
const parser = new xml2js.Parser();
const parseXML = util.promisify(parser.parseString);
const cwmpTr181XmlFile = 'tr-181-2-19-1-cwmp-full.xml';
const uspTr181XmlFile = 'tr-181-2-19-1-usp-full.xml';
const uspTr181VendorExtXmlFile = 'tr-181-vendor-extensions-usp.xml';
const Tr104USPXmlFile = 'tr-104-2-0-2-usp-full.xml';
const Tr104CWMPXmlFile = 'tr-104-2-0-2-cwmp-full.xml';
let cwmpModel;
let uspModel;
let uspVendorExtModel;
let tr181 = true;
async function saveFile(file, obj) {
await writeFile(file, JSON.stringify(obj, null, 4));
console.log('saved file:', file);
}
function getRange(attr) {
if (typeof attr[0] !== 'object') {
return '';
}
if (attr[0].range) {
const range = attr[0].range[0].$;
return `(${range.minInclusive ?? ''}:${range.maxInclusive ?? ''})`;
}
return '';
}
function objParent(obj) {
let parent;
if (obj.endsWith('}.')) {
parent = obj.slice(0, -5);
} else {
parent = obj.slice(0, -1);
}
return parent.substring(0, parent.lastIndexOf('.'));
}
function parsePathRef(obj, ref) {
let path = obj.$.name;
ref = ref.trim().replace(/\n$/, '');
if (ref.startsWith('.')) {
if (path.startsWith('Device.Services.VoiceService.') && !path.endsWith('()')) {
return `Device.Services.VoiceService.{i}${ref}`;
}
return `Device${ref}`;
}
if (ref.startsWith('#')) {
while (ref.startsWith('#')) {
path = objParent(path);
ref = ref.slice(1);
}
return path + ref;
}
if (ref.startsWith('Device.')) {
return ref;
}
return path + ref;
}
function getParamType(obj, res, syntaxType) {
const intTypes = [
'int',
'long',
'unsignedInt',
'unsignedLong',
];
const intType = intTypes.find((x) => Object.keys(syntaxType).includes(x));
if (intType) {
res.dataType = `${intType}${getRange(syntaxType[intType])}`;
} else if (syntaxType.boolean) {
res.dataType = 'boolean';
} else if (syntaxType.dateTime) {
res.dataType = 'dateTime';
} else if (syntaxType.string) {
const attr = syntaxType.string[0];
if (typeof attr === 'object') {
if (attr.enumeration) {
res.dataType = 'enum';
res.enum = attr.enumeration.map((x) => x.$.value);
} else if (attr.pathRef) {
res.dataType = 'pathRef';
if (attr.pathRef[0].$.targetParent) {
res.pathRef = attr.pathRef[0].$.targetParent.split(' ').filter((x) => x).map((x) => parsePathRef(obj, x));
}
} else if (attr.enumerationRef) {
res.dataType = 'enum';
res.enumerationRef = parsePathRef(obj, attr.enumerationRef[0].$.targetParam);
} else if (attr.size) {
res.dataType = `string(${attr.size[0].$?.minLength ?? ''}:${attr.size[0].$?.maxLength ?? ''})`;
} else if (attr.pattern) {
// handle it as enum
res.dataType = 'enum';
res.enum = attr.pattern.map((x) => x.$.value);
} else {
assert(false, `unknown string type: ${JSON.stringify(syntaxType, null, 2)}`);
}
} else {
res.dataType = 'string';
}
} else if (syntaxType.dataType) {
res.dataType = syntaxType.dataType[0].$.ref;
if (res.dataType === 'Alias') {
res.dataType = 'string(:64)';
} else if (res.dataType === 'DiagnosticsState') {
res.dataType = 'enum';
res.enum = ['None', 'Requested', 'Canceled', 'Complete', 'Error'];
} else if (res.dataType === 'StatsCounter64') {
res.dataType = 'unsignedLong';
}
} else if (syntaxType.hexBinary) {
res.dataType = 'hexBinary';
const { size } = syntaxType.hexBinary[0];
if (size) {
res.dataType += `(${size[0].$?.minLength ?? ''}:${size[0].$?.maxLength ?? ''})`;
}
} else if (syntaxType.base64) {
res.dataType = 'base64';
const { size } = syntaxType.base64[0];
if (size) {
res.dataType += `(${size[0].$?.minLength ?? ''}:${size[0].$?.maxLength ?? ''})`;
}
} else if (syntaxType.decimal) {
res.dataType = 'decimal';
const { size } = syntaxType.decimal[0];
if (size) {
res.dataType += `(${size[0].$?.minLength ?? ''}:${size[0].$?.maxLength ?? ''})`;
}
} else {
console.log(`unknown datatype:\n ${JSON.stringify(syntaxType, null, 4)}`);
res.dataType = 'unknown';
}
if (syntaxType.list) {
res.dataType += '[]';
}
}
function getParamObj(obj, param, proto) {
const res = {
name: param.$.name,
};
if (proto) {
res.proto = proto;
}
res.access = param.$.access;
const syntaxType = param.syntax[0];
getParamType(obj, res, syntaxType);
if (syntaxType.$?.hidden) {
res.hidden = true;
}
if (syntaxType.default && syntaxType.default[0].$?.value) {
const def = syntaxType.default[0].$?.value;
if (def !== 'false' && def !== '') {
res.default = syntaxType.default[0].$?.value;
}
}
return res;
}
let allObjects = [];
function generateCWMPObjects(objs) {
objs.forEach((obj) => {
const o = allObjects.find((x) => x.object === obj.$.name);
if (o) {
const params = obj.parameter.map((param) => getParamObj(obj, param, 'cwmp'));
o.parameters = o.parameters.concat(params);
} else {
allObjects.push({
object: obj.$.name,
proto: 'cwmp',
fixedObject: obj.$['dmr:fixedObject'],
uniqueKeys: obj.uniqueKey?.map((x) => x.parameter[0].$.ref).join(','),
// numEntriesParameter: obj.$.numEntriesParameter,
access: obj.$.access,
parameters: obj.parameter?.map((param) => (
getParamObj(obj, param, 'cwmp'))) ?? [],
});
}
});
}
function getCommandInput(cmdInfo) {
if (!cmdInfo.input) {
return [];
}
const objParams = [];
if (cmdInfo.input[0].object) {
cmdInfo.input[0].object.forEach((obj) => {
obj.parameter.forEach((p) => {
const inputParams = {
parameter: obj.$.name + p.$.name,
mandatory: p.$.mandatory === 'true',
};
getParamType(cmdInfo, inputParams, p.syntax[0]);
objParams.push(inputParams);
});
});
}
const params = cmdInfo.input[0].parameter?.map((p) => {
const inputParams = {
parameter: p.$.name,
mandatory: p.$.mandatory === 'true',
};
getParamType(cmdInfo, inputParams, p.syntax[0]);
return inputParams;
});
return objParams.concat(params ?? []);
}
function getCommandOutput(cmdInfo) {
if (!cmdInfo.output) {
return [];
}
const outParams = cmdInfo.output[0].parameter?.map((p) => {
const outputs = {
parameter: p.$.name,
};
getParamType(cmdInfo, outputs, p.syntax[0]);
return outputs;
}) ?? [];
const outObjs = cmdInfo.output[0].object?.map((obj) => {
const outputs = {
object: obj.$.name,
};
outputs.parameters = obj.parameter?.map((p) => {
const outs = {
parameter: p.$.name,
};
getParamType(cmdInfo, outs, p.syntax[0]);
return outs;
});
return outputs;
}) ?? [];
return outParams.concat(outObjs);
}
function generateUSPObjects(objs) {
objs.forEach((obj) => {
const o = allObjects.find((x) => x.object === obj.$.name);
if (o) {
delete o.proto;
obj.parameter?.forEach((p) => {
const param = o.parameters.find((x) => x.name === p.$.name);
if (param) {
delete param.proto;
} else {
o.parameters.push(getParamObj(obj, p, 'usp'));
}
});
if (obj.command) {
const cmds = obj.command.map((cmd) => ({
name: cmd.$.name,
async: !!cmd.$.async,
input: getCommandInput(cmd),
output: getCommandOutput(cmd),
}));
if (o.commands) {
o.commands = o.commands.concat(cmds);
} else {
o.commands = cmds;
}
}
if (obj.event) {
const events = obj.event.map((ev) => ({
name: ev.$.name,
parameter: ev.parameter?.map((p) => p.$.name),
}));
if (o.events) {
o.events = o.events.concat(events);
} else {
o.events = events;
}
}
} else {
const cwmpObj = cwmpModel.object.find((x) => x.$.name === obj.$.name);
const newObj = {
object: obj.$.name,
proto: cwmpObj ? undefined : 'usp',
uniqueKeys: obj.uniqueKey?.map((x) => x.parameter[0].$.ref).join(','),
// numEntriesParameter: obj.$.numEntriesParameter,
access: obj.$.access,
fixedObject: obj.$['dmr:fixedObject'],
parameters: obj.parameter?.map((param) => (
getParamObj(obj, param, (cwmpObj && cwmpObj.parameter?.find((x) => x.$.name === param.$.name)) ? undefined : 'usp'))) ?? [],
};
if (obj.command) {
newObj.commands = obj.command.map((cmd) => ({
name: cmd.$.name,
async: !!cmd.$.async,
input: getCommandInput(cmd),
output: getCommandOutput(cmd),
}));
}
if (obj.event) {
newObj.events = obj.event.map((ev) => ({
name: ev.$.name,
parameter: ev.parameter?.map((p) => p.$.name),
}));
}
allObjects.push(newObj);
}
});
}
function mergeProfileObjs(obj1, obj2) {
if (!obj1) {
return obj2;
}
if (!obj2) {
return obj1;
}
obj2.forEach((obj) => {
const o = obj1.find((x) => x.object === obj.object);
if (o) {
if (o.parameter) {
o.parameter = o.parameter.concat(obj.parameter ?? []);
} else {
o.parameter = obj.parameter;
}
if (o.command) {
o.command = o.command.concat(obj.command ?? []);
} else {
o.command = obj.command;
}
if (o.event) {
o.event = o.event.concat(obj.event ?? []);
} else {
o.event = obj.event;
}
} else {
obj1.push(obj);
}
});
return obj1;
}
function parseProfileObjects(model, profileName) {
const profile = model.profile.find((x) => x.$.name === profileName);
if (!profile) {
return [];
}
// assert(profile, `profile not found ${profileName}`);
const objs = profile.object?.map((o) => ({
object: o.$.ref,
parameter: o.parameter?.map((p) => p.$.ref),
command: o.command?.map((c) => c.$.ref),
event: o.event?.map((e) => e.$.ref),
}));
const exts = profile.$.extends ?? profile.$.base;
if (exts) {
let res = objs;
exts.split(' ').forEach((ext) => {
const extObjs = parseProfileObjects(model, ext);
res = mergeProfileObjs(res, extObjs);
});
return res;
}
return objs;
}
async function getProfileObjects(model, profileName) {
const profileObjs = parseProfileObjects(model, profileName);
const objs = [];
profileObjs.forEach((obj) => {
const targetObj = model.object.find((o) => o.$.name === obj.object);
assert(targetObj, `object not found ${obj.object}`);
const keys = targetObj.uniqueKey?.map((x) => x.parameter[0].$.ref);
targetObj.parameter = targetObj.parameter?.filter((x) => obj.parameter?.includes(x.$.name) || (keys?.includes(x.$.name)));
targetObj.command = targetObj.command?.filter((x) => obj.command?.includes(x.$.name));
objs.push(targetObj);
});
return objs;
}
async function loadXMLModel(file) {
const xmlData = await readFile(file, 'utf8');
const jsonData = await parseXML(xmlData);
const [model] = jsonData['dm:document'].model;
return model;
}
function printUsage() {
console.log('Usage:\nnode makeDM.js <tr181|tr104> [profile]');
}
(async () => {
try {
if (process.argv.length < 3 || (process.argv[2] !== 'tr181' && process.argv[2] !== 'tr104')) {
printUsage();
process.exit(-1);
}
if (process.argv[2] === 'tr104') {
tr181 = false;
}
if (tr181 && fs.existsSync(uspTr181VendorExtXmlFile)) {
uspVendorExtModel = await loadXMLModel(uspTr181VendorExtXmlFile);
} else if (tr181) {
console.warn(`Optional vendor extension file '${uspTr181VendorExtXmlFile}' not found, skipping.`);
}
if (tr181) {
cwmpModel = await loadXMLModel(cwmpTr181XmlFile);
uspModel = await loadXMLModel(uspTr181XmlFile);
} else {
cwmpModel = await loadXMLModel(Tr104CWMPXmlFile);
uspModel = await loadXMLModel(Tr104USPXmlFile);
cwmpModel.object.forEach((obj) => {
obj.$.name = `Device.Services.${obj.$.name}`;
});
cwmpModel.profile.forEach((prof) => {
prof.object?.forEach((obj) => {
obj.$.ref = `Device.Services.${obj.$.ref}`;
});
});
uspModel.object.forEach((obj) => {
obj.$.name = `Device.Services.${obj.$.name}`;
});
uspModel.profile.forEach((prof) => {
prof.object?.forEach((obj) => {
obj.$.ref = `Device.Services.${obj.$.ref}`;
});
});
}
if (process.argv.length === 3) {
generateCWMPObjects(cwmpModel.object);
generateUSPObjects(uspModel.object);
if (tr181 && uspVendorExtModel) {
generateUSPObjects(uspVendorExtModel.object);
}
const fileName = `${tr181 ? 'tr181' : 'tr104'}-full-objects.json`;
await saveFile(fileName, allObjects);
process.exit(0);
}
for (const arg of process.argv.slice(3)) {
// profile
const profile = arg;
const cwmpObjects = await getProfileObjects(cwmpModel, profile);
const uspObjects = await getProfileObjects(uspModel, profile);
generateCWMPObjects(cwmpObjects);
generateUSPObjects(uspObjects);
await saveFile(`${profile}.json`, allObjects);
allObjects = [];
}
} catch (error) {
console.error(`Error while reading file: ${error}`);
console.log(error.stack);
}
})();

View File

@@ -1,88 +0,0 @@
// This script is used to load and validate the js handlers code in dm-file.
(function () {
const fs = require('fs');
const path = require('path');
const { spawnSync } = require('child_process');
// Root directory (dm-files) relative to this script
const dmFilesRoot = path.resolve(__dirname, '../dm-files');
/**
* Recursively walk a directory and collect all *.js files that do not start with a dot.
* @param {string} dir - directory to walk
* @param {string[]} out - accumulator for file paths
*/
function collectJsFiles(dir, out) {
const entries = fs.readdirSync(dir, { withFileTypes: true });
for (const entry of entries) {
// Skip hidden files/directories (starting with ".")
if (entry.name.startsWith('.')) {
continue;
}
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
collectJsFiles(fullPath, out);
} else if (entry.isFile() && fullPath.endsWith('.js')) {
out.push(fullPath);
}
}
}
/**
* Validate a single JavaScript file with QuickJS (qjs).
* Exits the process with -1 on failure.
* @param {string} filePath - absolute path of the JS file
*/
function validateWithQjs(filePath) {
// Extract directory and filename for proper working directory
const fileDir = path.dirname(filePath);
const fileName = path.basename(filePath);
// Capture stdout/stderr so we can print them on failure
// Set the working directory to the file's directory
const result = spawnSync('qjs', [fileName], {
encoding: 'utf8',
cwd: fileDir
});
if (result.status === 0) {
return; // Validated successfully
}
// Show QuickJS output so user sees error details
console.error(`\n===== QuickJS validation failed: ${filePath} =====`);
if (result.stdout) {
console.error(result.stdout.trim());
}
if (result.stderr) {
console.error(result.stderr.trim());
}
console.error('===============================================');
process.exit(-1);
}
function main() {
if (!fs.existsSync(dmFilesRoot)) {
console.error(`dm-files directory not found at: ${dmFilesRoot}`);
process.exit(-1);
}
const jsFiles = [];
collectJsFiles(dmFilesRoot, jsFiles);
if (jsFiles.length === 0) {
console.log('No JavaScript files found to validate.');
return;
}
console.log(`Validating ${jsFiles.length} JavaScript file(s) with QuickJS...`);
jsFiles.forEach(validateWithQjs);
console.log('All files validated successfully.');
}
// Execute when run directly (not required when imported)
if (require.main === module) {
main();
}
})();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -1,64 +0,0 @@
#
# 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:=bridgemngr
PKG_VERSION:=1.0.0
PKG_RELEASE:=1
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
PLATFORM_CONFIG:=$(TOPDIR)/.config
include $(INCLUDE_DIR)/package.mk
include ../../bbfdm/bbfdm.mk
define Package/$(PKG_NAME)
DEPENDS:=+dm-api +datamodels +libubox +libubus +ubus
CATEGORY:=Genexis
TITLE:=GeneOS agent
URL:=http://www.genexis.eu
PKG_LICENSE:=GENEXIS
PKG_LICENSE_URL:=
endef
define Package/$(PKG_NAME)/description
This package contains GeneOS agent.
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) -rf ./src/* $(PKG_BUILD_DIR)/
endef
TARGET_CFLAGS += $(FPIC) -I$(PKG_BUILD_DIR)
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR)\
PROJECT_ROOT="$(PKG_BUILD_DIR)" \
CROSS_COMPILE="$(TARGET_CROSS)" \
ARCH="$(LINUX_KARCH)" \
EXTRA_CFLAGS="$(TARGET_CFLAGS)" \
all
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_BIN) ./files/etc/init.d/bridging $(1)/etc/init.d/
$(INSTALL_DATA) ./files/etc/config/bridging $(1)/etc/config/
$(BBFDM_REGISTER_SERVICES) ./bbfdm_service.json $(1) $(PKG_NAME)
$(INSTALL_DIR) $(1)/lib/upgrade/keep.d
# $(INSTALL_BIN) ./files/etc/init.d/dm-agent $(1)/etc/init.d/dm-agent
$(INSTALL_BIN) $(PKG_BUILD_DIR)/dm-agent $(1)/usr/sbin
endef
$(eval $(call BuildPackage,$(PKG_NAME)))

View File

@@ -1,37 +0,0 @@
#
# 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.
#
#
PROG = dm-agent
SRCS = dm_agent.c
OBJS = $(SRCS:.c=.o)
DEPS = $(SRCS:.c=.d)
CC = $(CROSS_COMPILE)gcc
STRIP = $(CROSS_COMPILE)strip
CFLAGS = -Wall -Werror $(EXTRA_CFLAGS)
CFLAGS += -MMD -MP -std=gnu99
LDFLAGS += -ldm -ldmapi -lubus -luci -lubox -ljson-c -lblobmsg_json
all: $(PROG)
$(PROG): $(OBJS)
$(CC) $^ $(LDFLAGS) -o $@
%.o: %.c
$(CC) -c $(CFLAGS) $^ -o $@
clean:
rm -f $(PROG) *.o core $(DEPS)
-include $(DEPS)

File diff suppressed because it is too large Load Diff

View File

@@ -1,75 +0,0 @@
#
# 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-api
PKG_VERSION:=1.0
PKG_RELEASE:=1
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
PLATFORM_CONFIG:=$(TOPDIR)/.config
AUTO_CONF_H:=$(PKG_BUILD_DIR)/autoconf.h
include $(INCLUDE_DIR)/package.mk
define Package/$(PKG_NAME)
CATEGORY:=Genexis
TITLE:=dm-api
PKG_BUILD_DEPENDS:=datamodels
DEPENDS:=+libsqlite3 \
+libjson-c +libstdcpp +quickjs \
+libubus +libubox +libuci
# Depedencies for RG products
URL:=http://www.genexis.eu
PKG_LICENSE:=GENEXIS
PKG_LICENSE_URL:=
endef
define Package/$(PKG_NAME)/description
This package contains api for the dm-framework
endef
define Build/Prepare
$(CP) -rf ./src/* $(PKG_BUILD_DIR)/
endef
TARGET_CFLAGS += $(FPIC) -I$(PKG_BUILD_DIR)
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR)\
PROJECT_ROOT="$(PKG_BUILD_DIR)" \
CROSS_COMPILE="$(TARGET_CROSS)" \
ARCH="$(LINUX_KARCH)" \
EXTRA_CFLAGS="$(TARGET_CFLAGS)" \
all
endef
define Build/InstallDev
$(INSTALL_DIR) $(1)/usr/include
$(INSTALL_DIR) $(1)/usr/lib
$(CP) $(PKG_BUILD_DIR)/core/dm_api.h $(1)/usr/include/
$(CP) $(PKG_BUILD_DIR)/core/dm_linker.h $(1)/usr/include/
$(CP) $(PKG_BUILD_DIR)/core/dbmgr.h $(1)/usr/include/
$(CP) $(PKG_BUILD_DIR)/include/dm_log.h $(1)/usr/include/
$(CP) $(PKG_BUILD_DIR)/utils/dm_list.h $(1)/usr/include/
$(CP) $(PKG_BUILD_DIR)/libdmapi.so $(1)/usr/lib/
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/lib
$(INSTALL_DIR) $(1)/sbin/
$(INSTALL_BIN) $(PKG_BUILD_DIR)/libdmapi.so $(1)/usr/lib/
endef
$(eval $(call BuildPackage,$(PKG_NAME)))

View File

@@ -1,64 +0,0 @@
#
# 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.
#
#
PROG = libdmapi.so
SRCS = \
core/dm_api.c \
core/dm_linker.c \
core/dbmgr.c \
core/inode_buf.c \
core/dm_apply.c \
core/dm_import.c \
core/db_upgrade.c \
utils/dm_list.c \
utils/dm_log.c \
utils/ubus_client.c \
utils/utils.c \
quickjs/qjs.c \
quickjs/qjs_log.c \
quickjs/qjs_dm_api.c \
quickjs/qjs_uci_api.c \
quickjs/qjs_ubus_api.c
OBJS = $(SRCS:.c=.o)
DEPS = $(SRCS:.c=.d)
CC = $(CROSS_COMPILE)gcc
STRIP = $(CROSS_COMPILE)strip
CFLAGS += \
-I core \
-I $(STAGING_DIR)/usr/include $(EXTRA_CFLAGS) \
-I handlers/common \
-I handlers/tr181 \
-I include \
-I utils \
-I quickjs
CFLAGS += -MMD -MP -std=gnu99
LDFLAGS = -shared
CFLAGS += -Wall -Werror -fpic
LDFLAGS += -lquickjs -lsqlite3 -latomic
# END for src from mgmt-agent
all: $(PROG)
$(PROG): $(OBJS)
$(CC) $^ $(LDFLAGS) -o $@
%.o: %.c
$(CC) -c $(CFLAGS) $^ -o $@
clean:
rm -f $(PROG) *.o core $(DEPS)
-include $(DEPS)

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +0,0 @@
/*
* 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.
*
*/
#ifndef DB_UPGRADE_H
#define DB_UPGRADE_H
int get_db_user_version(const char *db_path, int *user_version);
int upgrade_db(const char *curr_db, const char *new_db, int new_version);
#endif

View File

@@ -1,684 +0,0 @@
/*
* 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 "dbmgr.h"
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dm.h"
#include "dm_log.h"
#include "dm_node.h"
#include "sqlite3.h"
#define MAX_SQL_STATEMENT_LEN 4096
static sqlite3 *transaction_db = NULL;
static char sql_statement[MAX_SQL_STATEMENT_LEN];
// sqlite busy handler: the SQLITE_BUSY could happen when one process trys to access db
// (read out of session in our case) while another process is in the process of commiting
// a transaction. the busy time is normally short within 100 ms.
static int db_busy_handler(void *context, int count)
{
dmlog_debug("db_busy_handler %s, %d", sql_statement, count);
// non-zero means retry..
return 1;
}
static char *_get_node_rel_path_name(const struct dm_node_info *head,
const struct dm_node_info *node)
{
static char _path_name[512] = {'\0'};
if (node != NULL && node != head) {
_get_node_rel_path_name(head, node->parent);
}
if ((node == head) || (node == NULL)) /* end of recursion make sure pathname is the empty string */
{
memset(_path_name, 0, sizeof(_path_name));
} else {
strcat(_path_name, node->name);
strcat(_path_name, "_");
}
return _path_name;
}
static const char *get_node_rel_path_name(const struct dm_node_info *head,
const struct dm_node_info *node)
{
char *name = _get_node_rel_path_name(head, node);
int len = strlen(name);
// remove last '_'
if (len > 0) {
name[len - 1] = '\0';
}
return name;
}
static const char *get_table_field_name(const struct dm_node_info *node)
{
const struct dm_node_info *p = node;
while (p->parent != dm_node_get_root()) {
if (p->type == DM_NODE_OBJECT_LIST) {
break;
}
p = p->parent;
}
return get_node_rel_path_name(p, node);
}
static const char *get_int_str(int i)
{
static char digit[16];
sprintf(digit, "%d", i);
return digit;
}
static void get_db_index_condition(const struct dm_node_info *info, char *buf, const dm_index_t indexes[], int *cnt)
{
if (info == NULL) {
return;
}
if (info != dm_node_get_root()) {
get_db_index_condition(info->parent, buf, indexes, cnt);
}
if (info->type == DM_NODE_OBJECT_LIST && indexes[*cnt] > 0) {
if (*cnt > 0) {
strcat(buf, " AND ");
}
strcat(buf, "\"IndexOf");
strcat(buf, info->name);
strcat(buf, "\"");
strcat(buf, "=");
strcat(buf, get_int_str(indexes[*cnt]));
(*cnt)++;
}
}
static void get_db_index_field(const struct dm_node_info *info, char *buf, int *cnt)
{
if (info == NULL)
return;
if (info != dm_node_get_root())
get_db_index_field(info->parent, buf, cnt);
if (info->type == DM_NODE_OBJECT_LIST) {
if (*cnt > 0) {
strcat(buf, ",");
}
strcat(buf, "\"IndexOf");
strcat(buf, info->name);
strcat(buf, "\"");
(*cnt)++;
}
}
static const char *get_query_sql(const dm_node_t *node, int max_in_list)
{
const struct dm_node_info *info = dm_node_get_info(node->id);
if (info == NULL) {
dmlog_error("get_query_sql, node id not found");
return NULL;
}
strcpy(sql_statement, "select ");
if (dm_node_is_parameter(node->id)) {
if (max_in_list)
strcat(sql_statement, "MAX(");
strcat(sql_statement, "\"");
strcat(sql_statement, get_table_field_name(info));
strcat(sql_statement, "\"");
if (max_in_list)
strcat(sql_statement, ")");
} else if (dm_node_is_objectlist(node->id)) {
const char *node_name = dm_node_name(node->id);
if (node_name == NULL)
return NULL;
strcat(sql_statement, "\"IndexOf");
strcat(sql_statement, node_name);
strcat(sql_statement, "\"");
} else {
return NULL;
}
strcat(sql_statement, " FROM ");
strcat(sql_statement, dm_node_get_table_name(info));
if (node->cnt > 0) {
strcat(sql_statement, " WHERE ");
int cnt = 0;
if (max_in_list) {
// start from parant of the object.
info = dm_node_get_info(dm_node_id_parent(dm_node_id_parent(node->id)));
}
get_db_index_condition(info, sql_statement, node->index, &cnt);
}
strcat(sql_statement, ";");
return sql_statement;
}
static const char *get_query_all_indexes_sql(const dm_node_t *node, const char *keys, int sort)
{
const struct dm_node_info *info = dm_node_get_info(node->id);
if (info == NULL) {
dmlog_error("get_query_all_indexes_sql, node id not found");
return NULL;
}
if (dm_node_is_counter(node->id)) {
dm_node_id_t counter = dm_node_counter_id(node->id);
if (counter == INVALID_DM_NODE_ID) {
dmlog_error("invalid counter id %d", counter);
return NULL;
}
info = dm_node_get_info(counter);
if (info == NULL) {
dmlog_error("info is NULL");
return NULL;
}
strcpy(sql_statement, "select COUNT(\"IndexOf");
strcat(sql_statement, info->name);
strcat(sql_statement, "\")");
} else {
strcpy(sql_statement, "select");
strcat(sql_statement, " IndexOf");
strcat(sql_statement, info->name);
int index_cnt = dm_node_index_cnt(node->id);
if (index_cnt > 1 && node->cnt < index_cnt - 1) {
const struct dm_node_info *pinfo = dm_node_get_info(dm_node_i_parent_id(node->id));
if (pinfo) {
strcat(sql_statement, ",IndexOf");
strcat(sql_statement, pinfo->name);
} else {
dmlog_error("get_query_all_indexes_sql, invalid node: %s", dm_node_str(node));
}
}
struct dm_object *obj = (struct dm_object *)info;
if (obj->key_param_names != NULL) {
strcat(sql_statement, ",_key");
char *tmp = strdup(obj->key_param_names);
char *key = strtok(tmp, ",");
while (key != NULL) {
strcat(sql_statement, ",\"");
strcat(sql_statement, key);
strcat(sql_statement, "\"");
key = strtok(NULL, ",");
}
free(tmp);
}
}
strcat(sql_statement, " FROM ");
strcat(sql_statement, dm_node_get_table_name(info));
if (dm_node_index_cnt(info->parent->node_id) > 0 && node->cnt > 0) {
strcat(sql_statement, " WHERE ");
int cnt = 0;
get_db_index_condition(info->parent, sql_statement, node->index, &cnt);
if (keys != NULL && keys[0] != '\0') {
strcat(sql_statement, " AND ");
}
} else if (keys != NULL && keys[0] != '\0') {
strcat(sql_statement, " WHERE ");
}
if (keys != NULL && keys[0] != '\0') {
strcat(sql_statement, keys);
}
if (sort && info->flag & FLAG_HAS_ORDER)
strcat(sql_statement, " ORDER BY \"Order\"");
strcat(sql_statement, ";");
return sql_statement;
}
// The SQL standard specifies that single-quotes in strings are escaped
// by putting two single quotes in a row.
static void strcat_str_data(char *dest, const char *data)
{
int len = strlen(dest);
for (; *data != '\0'; data++, len++) {
if (*data == '\'') {
dest[len] = '\'';
len++;
dest[len] = '\'';
} else {
dest[len] = *data;
}
}
dest[len] = '\0';
}
static const char *get_update_sql(const dm_node_t *node, const char *data)
{
const struct dm_node_info *info = dm_node_get_info(node->id);
if (info == NULL) {
dmlog_error("get_update_sql, node id not found");
return NULL;
}
strcpy(sql_statement, "UPDATE ");
strcat(sql_statement, dm_node_get_table_name(info));
strcat(sql_statement, " SET \"");
strcat(sql_statement, get_table_field_name(info));
strcat(sql_statement, "\" = ");
strcat(sql_statement, "\'");
if (strchr(data, '\'') != NULL)
// containing single quotes, needs special handling.
strcat_str_data(sql_statement, (const char *)data);
else
strcat(sql_statement, (const char *)data);
strcat(sql_statement, "\'");
if (node->cnt > 0) {
strcat(sql_statement, " WHERE ");
int cnt = 0;
get_db_index_condition(info, sql_statement, node->index, &cnt);
}
strcat(sql_statement, ";");
return sql_statement;
}
static int db_next_index_callback(void *context, int argc, char *argv[], char *cols[])
{
(void)argc;
(void)cols;
int *next_index = (int *)context;
if (argv[0]) {
*next_index = atoi(argv[0]);
}
return 0;
}
static int exec_sql(const char *sql, sqlite_callback callback, void *context)
{
if (transaction_db == NULL) {
dmlog_error("db is not opened");
return -1;
}
char *err_msg = NULL;
int ret = sqlite3_exec(transaction_db, sql, callback, context, &err_msg);
if (ret != SQLITE_OK) {
dmlog_error("SQL command(%s) error: %s", sql, err_msg);
sqlite3_free(err_msg);
return -1;
}
return 0;
}
// sql in transaction
static int exec_trans_sql(const char *sql, sqlite_callback callback, void *context)
{
return exec_sql(sql, callback, context);
}
static int get_object_next_index(const dm_node_t *node)
{
const struct dm_node_info *info = dm_node_get_info(node->id);
if (info == NULL)
return -1;
const struct dm_node_info *p = info->parent;
while (p != dm_node_get_root() && p->parent != dm_node_get_root()) {
if (p->type == DM_NODE_OBJECT_LIST) {
break;
}
p = p->parent;
}
strcpy(sql_statement, "select ");
strcat(sql_statement, "\"NextIndexOf");
strcat(sql_statement, get_node_rel_path_name(p, info));
strcat(sql_statement, "\" FROM ");
if (p->parent == dm_node_get_root()) {
strcat(sql_statement, dm_node_get_root()->name);
strcat(sql_statement, "_");
strcat(sql_statement, p->name);
} else {
const char *tb = dm_node_get_table_name(p);
if (tb == NULL) {
dmlog_error("no db table for node %s", dm_node_str(node));
return -1;
}
strcat(sql_statement, tb);
if (dm_node_index_cnt(node->id) > 1) {
strcat(sql_statement, " WHERE ");
int cnt = 0;
get_db_index_condition(info->parent, sql_statement, node->index, &cnt);
}
}
strcat(sql_statement, ";");
int next_index = -1;
exec_sql(sql_statement, db_next_index_callback, &next_index);
return next_index;
}
static int update_object_next_index(const dm_node_t *node, int next_index)
{
const struct dm_node_info *info = dm_node_get_info(node->id);
if (info == NULL)
return -1;
const struct dm_node_info *p = info->parent;
while (p != dm_node_get_root() && p->parent != dm_node_get_root()) {
if (p->type == DM_NODE_OBJECT_LIST) {
break;
}
p = p->parent;
}
strcpy(sql_statement, "UPDATE ");
if (p->parent == dm_node_get_root()) {
strcat(sql_statement, dm_node_get_root()->name);
strcat(sql_statement, "_");
strcat(sql_statement, p->name);
} else {
strcat(sql_statement, dm_node_get_table_name(p));
}
strcat(sql_statement, " SET \"NextIndexOf");
strcat(sql_statement, get_node_rel_path_name(p, info));
strcat(sql_statement, "\" = ");
strcat(sql_statement, get_int_str(next_index));
if (dm_node_index_cnt(node->id) > 1) {
strcat(sql_statement, " WHERE ");
int cnt = 0;
get_db_index_condition(info->parent, sql_statement, node->index, &cnt);
}
strcat(sql_statement, ";");
return exec_trans_sql(sql_statement, NULL, NULL);
}
static const char *get_insert_sql(const dm_node_t *node, int new_index)
{
int i;
int cnt = 0;
const struct dm_node_info *info = dm_node_get_info(node->id);
if (info == NULL) {
dmlog_error("get_insert_sql, node id not found");
return NULL;
}
strcpy(sql_statement, "insert INTO ");
strcat(sql_statement, dm_node_get_table_name(info));
strcat(sql_statement, " (");
get_db_index_field(info, sql_statement, &cnt);
strcat(sql_statement, ") VALUES(");
cnt = dm_node_index_cnt(node->id);
for (i = 0; i < cnt - 1; i++) {
strcat(sql_statement, get_int_str(node->index[i]));
strcat(sql_statement, ",");
}
strcat(sql_statement, get_int_str(new_index));
strcat(sql_statement, ");");
return sql_statement;
}
static const char *get_delete_sql_condition(const dm_node_t *node)
{
static char condition[256];
const struct dm_node_info *info = dm_node_get_info(node->id);
if (info == NULL) {
dmlog_error("get_delete_sql_condition, node id not found");
return NULL;
}
if (node->cnt > 0) {
strcpy(condition, " WHERE ");
int cnt = 0;
get_db_index_condition(info, condition, node->index, &cnt);
} else {
return NULL;
}
return condition;
}
int dbmgr_init(const char *db_file)
{
int ret = sqlite3_open_v2(db_file, &transaction_db, SQLITE_OPEN_READWRITE, NULL);
if (SQLITE_OK != ret || transaction_db == NULL) {
dmlog_error("sqlite3_open_v2 failed");
return -1;
}
sqlite3_busy_timeout(transaction_db, SQLITE_BUSY_TIMEOUT);
sqlite3_busy_handler(transaction_db, db_busy_handler, NULL);
dmlog_info("dbmgr_init OK");
return 0;
}
int dbmgr_finalize(void)
{
if (transaction_db) {
sqlite3_close(transaction_db);
transaction_db = NULL;
}
return 0;
}
int dbmgr_tranx_begin(void)
{
dmlog_debug("dbmgr_tranx_begin");
return exec_trans_sql("BEGIN;", NULL, NULL);
}
int dbmgr_tranx_revert(void)
{
dmlog_debug("dbmgr_tranx_revert");
return exec_trans_sql("ROLLBACK;", NULL, NULL);
}
int dbmgr_tranx_commit(void)
{
dmlog_debug("dbmgr_tranx_commit");
int ret = exec_trans_sql("COMMIT;", NULL, NULL);
if (ret != 0) {
dmlog_error("dbmgr_tranx_commit, sql COMMIT; failed");
return -1;
}
return 0;
}
static int db_get_data_callback(void *context, int cnt, char *data[], char *names[])
{
if (cnt <= 0 || data[0] == NULL) {
dmlog_debug("db_get_data_callback, no data");
return 0;
}
char **val = context;
*val = strdup(data[0]);
return 0;
}
static int _dbmgr_get(const dm_node_t *node, char **value, int get_max_in_list)
{
const char *sql = get_query_sql(node, get_max_in_list);
if (sql == NULL) {
return -1;
}
return exec_sql(sql, db_get_data_callback, value);
}
int dbmgr_get(const dm_node_t *node, char **value)
{
int retval = _dbmgr_get(node, value, 0);
return retval;
}
int dbmgr_get_child(const dm_node_t *node, const char *child_name, char **value)
{
dm_node_t child_node = *node;
child_node.id = dm_node_get_child_id(node->id, child_name);
return dbmgr_get(&child_node, value);
}
int dbmgr_get_max(const dm_node_t *node, unsigned int *max)
{
char *value = NULL;
if (_dbmgr_get(node, &value, 1) < 0 || value == NULL) {
return -1;
}
*max = atoi(value);
free(value);
return 0;
}
int dbmgr_set(const dm_node_t *node, const char *data)
{
const char *sql = get_update_sql(node, data);
int ret = exec_trans_sql(sql, NULL, NULL);
if (ret != 0)
return -1;
return 0;
}
int dbmgr_set_uint(const dm_node_t *node, unsigned int data)
{
char *str;
asprintf(&str, "%u", data);
int ret = dbmgr_set(node, str);
free(str);
return ret;
}
int dbmgr_get_next_free_index(const dm_node_t *node)
{
return get_object_next_index(node);
}
int dbmgr_add(const dm_node_t *node)
{
int next_index = get_object_next_index(node);
if (next_index <= 0) {
dmlog_error("dbmgr_add Error: next_index is %d", next_index);
return 0;
}
const char *sql = get_insert_sql(node, next_index);
int ret = exec_trans_sql(sql, NULL, NULL);
if (ret != 0)
return -1;
if (update_object_next_index(node, next_index + 1) != 0) {
return 0; // 0 means invalid index
}
return next_index;
}
static int delete_db_instances(const struct dm_node_info *info, const char *conditions)
{
if (info == NULL) {
dmlog_info("delete_db_instances node not found");
return -1;
}
const char *table_name = dm_node_get_table_name(info);
if (info->type == DM_NODE_OBJECT_LIST && table_name) {
strcpy(sql_statement, "DELETE FROM ");
strcat(sql_statement, table_name);
if (conditions != NULL && *conditions != '\0') {
strcat(sql_statement, conditions);
}
strcat(sql_statement, ";");
return exec_trans_sql(sql_statement, NULL, NULL);
}
return 0;
}
int dbmgr_del(const dm_node_t *node)
{
return delete_db_instances(dm_node_get_info(node->id), get_delete_sql_condition(node));
}
int dbmgr_query_indexes(const dm_node_t *node, const char *keys, sqlite_callback cb, void *context, int sort)
{
const char *sql = get_query_all_indexes_sql(node, keys, sort);
return exec_sql(sql, cb, context);
}

View File

@@ -1,39 +0,0 @@
/*
* 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.
*
*/
#ifndef DBMGR_H
#define DBMGR_H
#include "dm_types.h"
typedef int (*sqlite_callback)(void *, int, char *[], char *[]);
int dbmgr_init(const char *db_file);
int dbmgr_finalize(void);
int dbmgr_tranx_begin(void);
int dbmgr_tranx_revert(void);
int dbmgr_tranx_commit(void);
int dbmgr_get(const dm_node_t *node, char **value);
int dbmgr_get_child(const dm_node_t *node, const char *child_name, char **value);
int dbmgr_get_max(const dm_node_t *node, unsigned int *max);
int dbmgr_set(const dm_node_t *node, const char *data);
int dbmgr_set_uint(const dm_node_t *node, unsigned int data);
int dbmgr_add(const dm_node_t *node);
int dbmgr_del(const dm_node_t *node);
int dbmgr_query_indexes(const dm_node_t *node, const char *keys, sqlite_callback cb, void *context,
int sort);
int dbmgr_get_next_free_index(const dm_node_t *node);
#endif /* DBMGR_H */

File diff suppressed because it is too large Load Diff

View File

@@ -1,265 +0,0 @@
/*
* 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.
*
*/
#ifdef __cplusplus
extern "C" {
#endif
#ifndef DM_API_H
#define DM_API_H
#include <json-c/json.h>
#include "dm_types.h"
#include "dm_node.h"
struct dm_uci_context {
int id;
const char *savedir;
};
/** Initialize dmapi.
* @return 0 in case of success, or < 0 in case of error
*/
int dmapi_init(const char *service_name);
// Transaction action when session is end
enum TRANX_ACTION {
TRANX_NO_ACTION = 0,
TRANX_ROLLBACK,
TRANX_COMMIT,
TRANX_COMMIT_AND_APPLY
};
/** Start a session.
* Only one session can be started and active
* While starting the session the lock is taken to avoid race conditions
* @pre dmapi_init should be called successfully
* @return 0 in case of success, or a nonzero value in case of error
*/
int dmapi_session_start();
/** End a session.
* Only one session can be started and active
* @pre dmapi_session_start should be called successfully
* @param action[in] one of the actions defined in TRANX_ACTION
* @return 0 in case of success, or a nonzero value in case of error
*/
int dmapi_session_end(int action);
/** Apply changes in a session.
* @pre dmapi_session_start should be called successfully
* @return 0 in case of success, or a nonzero value in case of error
*/
int dmapi_session_apply(void);
/** Commits a transaction in a session.
* @pre dmapi_session_start should be called successfully
* and have modified parameters or objects by calling
* dmapi_xxx_set/add/del
* @return 0 in case of success, or a nonzero value in case of error
*/
int dmapi_session_commit(void);
/** Revert changes made in current session.
* @pre dmapi_session_start should be called successfully
* and have modified parameters or objects by calling
* dmapi_xxx_set/add/del
* @return 0 in case of success, or a nonzero value in case of error
*/
int dmapi_session_revert(void);
/** Check if session in the dmapi context is valid and active.
* @pre dmapi_init should be called successfully
* @return 1 if active, or 0 when invalid or not started
*/
int dmapi_in_session(void);
/** Delete a dmapi communication context.
* @pre dmapi_init should be called successfully
* @return none
*/
void dmapi_quit(void);
/** Enable or disable feature of "session on the fly"
* With this feature enabled, session will be started automatically when set/add/del APIs are called,
* so you don't have to call dmapi_session_start explicitly before modifying data models.
* but you still need to end the session explicitly by calling dmapi_session_end.
* @param enable: 0: disable, 1: enable
* @pre dmapi_init should be called successfully
* @return none
*/
void dmapi_set_session_on_fly(int enable);
/** Set UCI savedir
* @param savedir: UCI savedir
* @pre dmapi_init should be called successfully
* @return none
*/
void dmapi_set_uci_savedir(const char *savedir);
/** Enable or disable feature of "Auto reference deletion" when deleting objects
* this feature should be not enabled by cwmp client.
* @param enable: 0: disable, 1: enable
* @pre dmapi_init should be called successfully
* @return none
*/
void dmapi_set_dm_auto_del(int enable);
/** Get parameter value of specific parameter node.
*
* @pre dmapi_init should be called successfully
*
* @param[in] node - pointer to parameter node
* @param[out] value - pointer to pointer to save the result, the value must be freed after use.
*
* @return 0 in case of success, or a nonzero value in case of error
*/
int dmapi_param_get(const dm_node_t *node, char **value);
/** Set parameter value of specific parameter node.
*
* @pre dmapi_session_start should be called successfully
*
* @param[in] node - pointer to parameter node
* @param[in] param_data - pointer to string parameter value to set
*
* @return 0 in case of success, or a nonzero value in case of error
*/
int dmapi_param_set(const dm_node_t *node, const char *param_data);
/** Add specific object node.
*
* @pre dmapi_session_start should be called successfully
*
* @param[in] node - pointer to object node, the index of the node will be updated upon success
*
* @return 0 in case of success, or a nonzero value in case of error
*/
int dmapi_object_add(dm_node_t *node);
/** Delete specific object node.
*
* @pre dmapi_session_start should be called successfully
*
* @param[in] node - pointer to object node
*
* @return 0 in case of success, or a nonzero value in case of error
*/
int dmapi_object_del(const dm_node_t *node);
/** Operate on the command node.
*
* @param[in] node - pointer to multi-object node as input
* @param[in] args - arguments in json format.
* @param[out] json_input - input of the command as json string format.
* @param[out] output - output of the command as json_object.
*
* @return 0 in case of success, -1 in case of error
*/
int dmapi_operate(const dm_node_t *node, const char *json_input, struct json_object **json_output);
/** Check if an object instance exist
* @param[in] node - node as input
* @param[in] db_only - if the node should be in db or not
* @return 1 if exist, otherwise return 0
*/
int dmapi_node_exist(const dm_node_t *node, int db_only);
typedef void *dm_nodelist_h;
#define DM_INVALID_NODELIST ((dm_nodelist_h)NULL)
// macro to iterate the node list
#define nodelist_for_each_node(node, list) \
for ((node) = dm_nodelist_first((list)); (node) != NULL; (node) = dm_nodelist_next((list)))
/** Get all instances of a multi-object node, node must be a multi-object type.
* @param node[in] pointer to multi-object node as input
* @return handle of instances list in case of success, NULL value in case of error
*/
dm_nodelist_h dm_nodelist_get(const dm_node_t *node);
// for only db
dm_nodelist_h dm_nodelist_get_db(const dm_node_t *node);
/** Get all instances of a multi-object node, node must be a multi-object type.
* @param node[in] pointer to multi-object node as input
* @param keys[in] sql condition
* @param only_db[in] true if only get db instance.
* @return handle of instances list in case of success, NULL value in case of error
*/
dm_nodelist_h dm_nodelist_find(const dm_node_t *node,
const char *keys, int only_db);
/** Wrapper interface for dm_nodelist_find to find only one node as expected.
* If more than one are found, the first one will be the result
* @param node[in] pointer to multi-object node as input
* @param keys[in] sql condition
* @param only_db[in] true if only get db instance.
* @param result[out] as output
* @return 0 if not found, or a nonzero value when found
*/
int dm_nodelist_find_first(const dm_node_t *node,
const char *keys, dm_node_t *result, int only_db);
/** Free a node list.
* @pre dm_nodelist_get or dm_nodelist_find should be called successfully
* @param list[in] handler of node list as input
* @return none
*/
void dm_nodelist_free(dm_nodelist_h list);
/** Get first instance of node instance list.
* @pre dm_nodelist_get or dm_nodelist_find should be called successfully
* @param list[in] handler of node list as input
* @return node pointer on success, NULL when node does not exist
*/
const dm_node_t *dm_nodelist_first(dm_nodelist_h list);
/** Get next instance of node instance list.
* @pre dm_nodelist_get or dm_nodelist_find should be called successfully
* @param list[in] handler of node list as input
* @return node pointer on success, NULL when node does not exist
*/
const dm_node_t *dm_nodelist_next(dm_nodelist_h list);
/** Get count of instance in the list.
* @pre dm_nodelist_get or dm_nodelist_find should be called successfully
* @param[in] list handler of node list as input
* @return number of instances
*/
int dm_nodelist_cnt(dm_nodelist_h list);
/** Get each node by index, scope is from [0 - (max_cnt-1)].
* @pre dm_nodelist_get or dm_nodelist_find should be called successfully
* @param list_h[in] handler of node list as input
* @param i[in] index value as input
* @return node pointer
*/
const dm_node_t *dm_nodelist_node(dm_nodelist_h list_h, int i);
/** Get node index by sequence number, scope is from [0 - (max_cnt-1)].
* @pre dm_nodelist_get or dm_nodelist_find should be called successfully
* @param list_h[in] handler of node list as input
* @param i[in] index value as input
* @return index of node
*/
dm_index_t dm_nodelist_index(dm_nodelist_h list_h, int i);
const char *dm_nodelist_key(dm_nodelist_h list_h, int i, const char *key);
void dmapi_dump_node_buffer(const dm_node_t *node);
int dmapi_handle_ubus_event(dm_node_id_t id, const char *json_event_str, struct json_object **res);
#endif /* for dmapi_H */
#ifdef __cplusplus
}
#endif

View File

@@ -1,725 +0,0 @@
/*
* 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 "dm_apply.h"
#include <quickjs/quickjs-libc.h>
#include <stdlib.h>
#include <string.h>
#include "dbmgr.h"
#include "dm_api.h"
#include "dm_list.h"
#include "dm_log.h"
#include "dm_node.h"
#include "qjs_uci_api.h"
#include "qjs.h"
#include "ubus_client.h"
typedef struct {
const char* key;
int order;
} key_order_pair;
// datamodel change list during the session
static dm_list_h changed_node_list = NULL;
static dm_list_h apply_uci_list = NULL;
void add_apply_package(char *package)
{
if (!package) {
return;
}
if (apply_uci_list == NULL) {
apply_uci_list = dm_list_create(NULL);
}
// add the uci package name to the apply list
if (!dm_list_contains(apply_uci_list, (const void*)package)) {
dmlog_debug("add uci package to apply: %s", package);
dm_list_append(apply_uci_list, package);
} else {
free(package);
}
}
void del_apply_package(char *package)
{
if (!package || !apply_uci_list) {
return;
}
dmlog_debug("remove uci package to apply: %s", package);
dm_list_remove(apply_uci_list, package);
}
void dm_apply_reset_changes(void)
{
if (changed_node_list) {
dm_list_free(changed_node_list);
changed_node_list = NULL;
}
if (apply_uci_list) {
dm_list_free(apply_uci_list);
apply_uci_list = NULL;
}
}
static int node_change_cmp(const void *change1, const void *change2)
{
struct node_change *n1 = (struct node_change *)change1;
struct node_change *n2 = (struct node_change *)change2;
return !(dm_node_compatible(&n1->node, &n2->node) && (n1->redirected == n2->redirected));
}
static dm_node_id_t find_parent_with_apply_handler(const struct dm_node_info *node_info)
{
if (node_info == NULL) {
return INVALID_DM_NODE_ID;
}
if (qjs_has_apply_handler(node_info->node_id)) {
return node_info->node_id;
}
return find_parent_with_apply_handler(node_info->parent);
}
int dm_appy_add_change(enum DATAMODEL_ACTION action, const dm_node_t *node)
{
dmlog_debug("add change %s", dm_node_str(node));
if (changed_node_list == NULL) {
changed_node_list = dm_list_create(node_change_cmp);
}
struct node_change *pchange = calloc(1, sizeof(struct node_change));
pchange->action = action;
pchange->node = *node;
const struct dm_node_info * info = dm_node_get_info(node->id);
const char *uci_map;
const struct dm_parameter *param = NULL;
// special handling for "Order" parameter
if (info->type == DM_NODE_PARAMETER && info->flag & FLAG_HAS_ORDER) {
// Order parameter,
param = (const struct dm_parameter *)info;
const struct dm_object *pobj = dm_node_get_object(dm_node_i_parent_id(node->id));
if (param->map.map == NULL && pobj->map.map) {
pchange->node.cnt--;
goto end;
}
}
if (info->type == DM_NODE_PARAMETER) {
param = (const struct dm_parameter *)info;
uci_map = param->map.map;
} else {
const struct dm_object *obj = (const struct dm_object *)info;
uci_map = obj->map.map;
}
if (uci_map == NULL && !qjs_has_apply_handler(node->id)) {
// look for parent handler
const dm_node_id_t pid = dm_node_i_parent_id(node->id);
if (pid != INVALID_DM_NODE_ID) {
const struct dm_object *pobj = dm_node_get_object(pid);
if (pobj && pobj->map.map) {
if (param && param->data_type == DM_PATH_NAME && param->data.paths &&
dm_node_get_info(param->data.paths[0])->depends_node_id == pid) {
goto end;
}
dmlog_debug("skip apply for %s", dm_node_str(node));
free(pchange);
return 0;
}
}
dm_node_id_t id = find_parent_with_apply_handler(info->parent);
if (id == INVALID_DM_NODE_ID) {
dmlog_debug("ignored node change for apply %s", dm_node_str(node));
free(pchange);
return 0;
}
pchange->node.id = id;
pchange->node.cnt = dm_node_index_cnt(id);
}
dm_node_id_t depend = dm_node_get_apply_depends(pchange->node.id);
if (depend != INVALID_DM_NODE_ID) {
pchange->node.id = depend;
pchange->redirected = 1;
}
end:
if (dm_list_contains(changed_node_list, (const void*)pchange)) {
free(pchange);
return 0;
}
if (dm_node_is_objectlist(pchange->node.id)) {
pchange->node.cnt = dm_node_index_cnt(pchange->node.id) - 1;
}
dm_list_append(changed_node_list, pchange);
dmlog_debug("added node change %s", dm_node_str(&pchange->node));
return 0;
}
static char *get_package_name(const char *uci_path)
{
char *dot_position = strchr(uci_path, '.');
if (dot_position == NULL) {
dmlog_error("missing dot in the uci_path: %s", uci_path);
return NULL;
}
int length = dot_position - uci_path;
char *result = (char *)malloc(length + 1); // +1 for the null-terminator
strncpy(result, uci_path, length);
result[length] = '\0';
return result;
}
static char *get_package_type(const char *uci_path)
{
char *dot_position = strchr(uci_path, '.');
if (dot_position == NULL) {
dmlog_error("missing dot in the uci_path: %s", uci_path);
return NULL;
}
size_t length = strlen(dot_position + 1) + 1;
char *substring = malloc(length);
strncpy(substring, dot_position + 1, length);
substring[length - 1] = '\0';
return substring;
}
static dm_nodelist_h find_refer_instances(const dm_node_t *node, const dm_node_t *ref_node)
{
dm_path_t path;
dm_node2name(ref_node, path, sizeof(dm_path_t));
const struct dm_object *obj = dm_node_get_object(node->id);
// find the parameter that refers to the "ref_node"
for (int i = 0; i < obj->param_num; i++) {
const struct dm_parameter *param = (const struct dm_parameter*)obj->param_list[i];
if (param->data_type == DM_PATH_NAME && param->data.paths[0] == ref_node->id) {
const struct dm_node_info *param_info = dm_node_get_info(param->node.node_id);
char *search = NULL;
asprintf(&search, "%s='%s'", param_info->name, path);
dmlog_debug("search key: %s", search);
dm_nodelist_h res = dm_nodelist_find(node, search, 1);
free(search);
return res;
}
}
return DM_INVALID_NODELIST;
}
static void apply_param_uci_map(const dm_node_t *node, const dm_node_t *parent, const struct dm_uci_map *map)
{
dmlog_debug("apply_param_uci_map: %s", dm_node_str(node));
char *val = NULL;
if (dbmgr_get(node, &val) < 0 || val == NULL) {
return;
}
char *uci_path = NULL;
char *uci_pkg = NULL;
if (map->map) {
if (parent && strchr(map->map, '.') == NULL) {
char *uci_key = NULL;
dm_node_t key_node;
const struct dm_object *obj = dm_node_get_object(parent->id);
if (dm_node_get_child(parent, "_key", &key_node) < 0) {
dmlog_error("failed to get _key %s", dm_node_str(parent));
goto end;
}
if (dbmgr_get(&key_node, &uci_key) < 0 || uci_key == NULL) {
dmlog_error("failed to call dbmgr_get %s", dm_node_str(&key_node));
goto end;
}
if (obj->map.map == NULL) {
dmlog_error("missing uci map %s", dm_node_str(parent));
free(uci_key);
goto end;
}
uci_pkg = get_package_name(obj->map.map);
asprintf(&uci_path, "%s.%s.%s", uci_pkg, uci_key, map->map);
free(uci_key);
} else {
uci_path = strdup(map->map);
uci_pkg = get_package_name(map->map);
}
if (map->type == DM_UCI_MAP_TYPE_SIMPLE || map->type == DM_UCI_MAP_TYPE_INTERFACE) {
if (dm_node_data_type(node->id) == DM_PATH_NAME) {
// the the uci to the section name of the corresponding pathname
if (val[0] == '\0') {
dm_uci_set(uci_path, val);
} else {
char *key = NULL;
dm_node_t ref_node;
dm_path2node(val, &ref_node);
dbmgr_get_child(&ref_node, "_key", &key);
if (key != NULL) {
dm_uci_set(uci_path, key);
free(key);
} else {
dmlog_error("failed to get key of node %s", val);
}
}
} else {
if (dm_node_is_bool_type(node->id)) {
if (strcmp(val, "1") == 0 || strcmp(val, "true") == 0)
dm_uci_set(uci_path, "1");
else
dm_uci_set(uci_path, "0");
} else {
dm_uci_set(uci_path, val);
}
}
} else if (map->type == DM_UCI_MAP_TYPE_DISABLE) {
if (strcmp(val, "1") == 0 || strcmp(val, "true") == 0)
dm_uci_set(uci_path, "0");
else
dm_uci_set(uci_path, "1");
} else {
dmlog_debug("not support apply uci type: %s", dm_node_str(node));
}
free(uci_path);
}
qjs_call_apply_param_handler(node, val);
add_apply_package(uci_pkg);
end:
free(val);
return;
}
struct dm_inst_key {
const char *key;
dm_node_t node;
};
static int dm_inst_list_cmp(const void *item1, const void *item2)
{
struct dm_inst_key *inst1 = (struct dm_inst_key *)item1;
struct dm_inst_key *inst2 = (struct dm_inst_key *)item2;
if (strcmp((const char*)inst1->key, (const char*)inst2->key) == 0) {
return 0;
}
return 1;
}
static void free_dm_inst_list(dm_list_h list)
{
int cnt = dm_list_cnt(list);
for (int i = 0; i < cnt; i++) {
struct dm_inst_key *inst = dm_list_get(list, i);
free((char *)inst->key);
}
dm_list_free(list);
}
static dm_list_h get_obj_key_list(dm_nodelist_h list)
{
const dm_node_t *n = NULL;
dm_list_h key_list = dm_list_create(dm_inst_list_cmp);
nodelist_for_each_node(n, list)
{
char *key = NULL;
if (dbmgr_get_child(n, "_key", &key) == 0 && key != NULL) {
struct dm_inst_key *ins = malloc(sizeof(struct dm_inst_key));
ins->key = key;
ins->node = *n;
dm_list_append(key_list, ins);
} else {
dmlog_error("failed to get key for node: %s", dm_node_str(n));
}
}
return key_list;
}
static int apply_obj_uci_map(const dm_node_t *node, const struct dm_uci_map *map)
{
int ret = 0;
char *pkg_name = get_package_name(map->map);
char *type = get_package_type(map->map);
dm_nodelist_h list = dm_nodelist_get_db(node);
dm_list_h keys = get_obj_key_list(list);
dm_list_h sect_list = dm_list_create(NULL);
char *uci_key = NULL;
if (map->key != NULL && dm_node_index_cnt(node->id) > 1) {
dm_node_t parent;
dm_node_i_parent(node, &parent);
dbmgr_get_child(&parent, "_key", &uci_key);
}
json_object *json_list = NULL;
if (dm_uci_get_section_list(pkg_name, type, NULL, 0, &json_list) == 0 && json_list != NULL) {
json_object_object_foreach(json_list, key, val) {
if (!qjs_uci_filter(node, val)) {
continue;
}
const char *key_val = NULL;
if (map->key != NULL) {
json_object *val_obj;
if (json_object_object_get_ex(val, map->key, &val_obj)) {
key_val = json_object_get_string(val_obj);
}
}
if (uci_key && strcmp(uci_key, key_val) != 0) {
continue;
}
struct dm_inst_key inst;
inst.key = key;
if (!dm_list_contains(keys, &inst)) {
// special handling for user: set "deleted" instead of deleting
if (strcmp(pkg_name, "users") == 0 && strcmp(type, "user") == 0) {
char *tmp;
asprintf(&tmp, "%s.%s.deleted", pkg_name, key);
dm_uci_set(tmp, "1");
free(tmp);
} else {
dmlog_debug("uci-map: del uci: %s.%s", pkg_name, key);
if (qjs_call_uci_deinit_handler(node, key) == 0) {
dm_uci_del(pkg_name, key);
} else {
dmlog_debug("uci-map: skipped deleting %s", key);
}
}
} else {
dm_list_append(sect_list, strdup(key));
}
}
json_object_put(json_list);
}
int key_cnt = dm_list_cnt(keys);
for (int i = 0; i < key_cnt; i++) {
struct dm_inst_key *inst = dm_list_get(keys, i);
if (!dm_list_contains(sect_list, (const void*)inst->key)) {
// add section for the new instance
dmlog_debug("uci-map: add uci: %s.%s", pkg_name, type);
name_val_t opt_val;
int opt_cnt = 0;
if (uci_key != NULL && map->key) {
opt_val.name = map->key;
opt_val.value = uci_key;
opt_cnt = 1;
}
if (dm_uci_add(pkg_name, type, inst->key, &opt_val, opt_cnt) < 0) {
dmlog_error("failed to add new uci section");
ret = -1;
}
qjs_call_uci_init_handler(&inst->node);
}
}
if (pkg_name) {
add_apply_package(pkg_name);
pkg_name = NULL;
}
free(type);
if (pkg_name) {
free(pkg_name);
}
if (uci_key) {
free(uci_key);
}
dm_nodelist_free(list);
free_dm_inst_list(keys);
dm_list_free(sect_list);
return ret;
}
static int compare_order(const void* a, const void* b) {
key_order_pair* pair_a = (key_order_pair*)a;
key_order_pair* pair_b = (key_order_pair*)b;
return pair_a->order - pair_b->order;
}
static void reorder_uci_sections(const char *pkg, key_order_pair *pairs, int cnt)
{
qsort(pairs, cnt, sizeof(key_order_pair), compare_order);
struct blob_buf b;
memset(&b, 0, sizeof(b));
blob_buf_init(&b, 0);
blobmsg_add_string(&b, "config", pkg);
void *a = blobmsg_open_array(&b, "sections");
for (int i = 0; i < cnt; ++i) {
blobmsg_add_string(&b, NULL, pairs[i].key);
}
blobmsg_close_array(&b, a);
ubus_client_call("uci", "order", b.head, NULL, NULL);
blob_buf_free(&b);
add_apply_package((char*)pkg);
}
// reorder the uci sections according to the "Order" value
static void apply_order(const dm_node_t *node, const char *uci_map)
{
dmlog_info("apply_order, %s, %s", dm_node_str(node), uci_map);
dm_nodelist_h list = dm_nodelist_get_db(node);
int cnt = dm_nodelist_cnt(list);
if (cnt <= 1) {
dm_nodelist_free(list);
return;
}
key_order_pair* pairs = calloc(cnt, sizeof(key_order_pair));
for (int i = 0; i < cnt; i++) {
char* order_str = NULL;
dbmgr_get_child(dm_nodelist_node(list, i), "Order", &order_str);
if (order_str == NULL) {
dmlog_error("apply_order, failed to get Order");
goto exit;
}
pairs[i].order = atoi(order_str);
free(order_str);
pairs[i].key = dm_nodelist_key(list, i, "_key");
if (pairs[i].key == NULL) {
dmlog_error("apply_order, unexpected empty key value");
goto exit;
}
}
char *pkg = get_package_name(uci_map);
reorder_uci_sections(pkg, pairs, cnt);
exit:
for (int i = 0; i < cnt; i++) {
if (pairs[i].key) {
JS_FreeCString(qjs_ctx(), pairs[i].key);
}
}
free(pairs);
dm_nodelist_free(list);
}
static void apply_extended_obj(const dm_node_t *node, const char *path, dm_node_id_t id)
{
dmlog_debug("apply_extended_obj: %s, %s", dm_node_str(node), path);
dm_node_t ref_node;
if (path == NULL) {
return;
}
if (path[0] == '\0') {
// call the deinit handler for the extended object
dm_node_t n = {id};
char *uci_key = NULL;
dbmgr_get_child(node, "_key", &uci_key);
if (uci_key) {
qjs_call_uci_deinit_handler(&n, uci_key);
free(uci_key);
}
return;
}
if (dm_path2node(path, &ref_node) != 0) {
dmlog_error("apply_order, invalid path: %s", path);
return;
}
const struct dm_object *obj = dm_node_get_object(ref_node.id);
for (int i = 0; i < obj->param_num; i++) {
const struct dm_parameter *param = (const struct dm_parameter *)obj->param_list[i];
if (param->node.table_name == NULL) {
continue;
}
if (param->map.map == NULL && !qjs_has_apply_handler(node->id)) {
continue;
}
dm_node_t n = ref_node;
n.id = obj->param_list[i]->node_id;
apply_param_uci_map(&n, node, &param->map);
}
}
void dm_apply_node(struct node_change *change)
{
const dm_node_t *node = &change->node;
dm_node_t *pparent = NULL;
const struct dm_object *parent_obj = NULL;
dm_node_t parent_node;
if (dm_node_i_parent(node, &parent_node) == 0) {
pparent = &parent_node;
parent_obj = dm_node_get_object(parent_node.id);
}
if (parent_obj && parent_obj->map.map && parent_obj->node.depends_node_id != INVALID_DM_NODE_ID) {
// apply to the referenced object that it "extends"
dm_node_t refer_node = parent_node;
refer_node.id = parent_obj->node.depends_node_id;
refer_node.cnt--;
dm_nodelist_h res = find_refer_instances(&refer_node, &parent_node);
const dm_node_t *pnode = NULL;
nodelist_for_each_node(pnode, res) {
if (qjs_has_apply_handler(node->id)) {
qjs_call_apply_obj_handler(node, pnode);
}
else if (dm_node_is_parameter(node->id)) {
const struct dm_parameter *param = dm_node_get_parameter(node->id);
apply_param_uci_map(node, pnode, &param->map);
}
}
dm_nodelist_free(res);
return;
}
if (dm_node_is_parameter(node->id)) {
const struct dm_parameter *param = dm_node_get_parameter(node->id);
if (param->data_type == DM_PATH_NAME && param->data.paths) {
if (pparent && dm_node_get_info(param->data.paths[0])->depends_node_id == pparent->id) {
char *val = NULL;
dbmgr_get(node, &val);
apply_extended_obj(pparent, val, param->data.paths[0]);
return;
}
}
if (param->map.map != NULL || qjs_has_apply_handler(node->id)) {
apply_param_uci_map(node, pparent, &param->map);
if (param->node.flag & FLAG_HAS_ORDER) {
const struct dm_object *pobj = dm_node_get_object(dm_node_i_parent_id(node->id));
if (pobj && pobj->map.map) {
dm_node_t pnode;
dm_node_i_parent(node, &pnode);
apply_order(&pnode, pobj->map.map);
}
}
}
} else if (dm_node_is_objectlist(node->id)) {
const struct dm_object *obj = dm_node_get_object(node->id);
if (obj->map.map != NULL && obj->map.type == DM_UCI_MAP_TYPE_SIMPLE ) {
if (obj->node.depends_node_id == INVALID_DM_NODE_ID) {
apply_obj_uci_map(node, &obj->map);
}
} else if (qjs_has_apply_handler(node->id)) {
qjs_call_apply_obj_handler(node, node);
}
} else if (qjs_has_apply_handler(node->id)) {
qjs_call_apply_obj_handler(node, node);
} else {
dmlog_error("dm_apply_node, node is not handled: %s", dm_node_str(node));
}
}
static int commit_changes()
{
int ret = 0;
if (changed_node_list == NULL)
return 0;
int i;
int cnt = dm_list_cnt(changed_node_list);
for (i = 0; i < cnt; i++) {
struct node_change *change = (struct node_change *)dm_list_get(changed_node_list, i);
dmlog_debug("apply node: %s", dm_node_str(&change->node));
if (change->redirected) {
qjs_call_apply_obj_handler(&change->node, &change->node);
} else {
dm_apply_node(change);
}
dmlog_debug("end of apply node: %s", dm_node_str(&change->node));
}
return ret;
}
// reset parameters that are confidential in db.
static void reset_confidentials()
{
if (changed_node_list == NULL)
return;
int i;
// dbmgr_tranx_begin();
int cnt = dm_list_cnt(changed_node_list);
for (i = 0; i < cnt; i++) {
struct node_change *change = (struct node_change *)dm_list_get(changed_node_list, i);
if (dm_node_is_confidential(change->node.id)) {
if (dbmgr_set(&change->node, "") < 0) {
dmlog_error("failed to reset confidentail parameter: %s", dm_node_str(&change->node));
}
}
}
// dbmgr_tranx_commit();
}
int dm_apply_reset(void)
{
dm_apply_reset_changes();
return 0;
}
// static int reload_service(const char *svc)
// {
// struct blob_buf bb = {};
// if (svc == NULL) {
// return 0;
// }
// blob_buf_init(&bb, 0);
// blobmsg_add_string(&bb, "config", svc);
// int ret = ubus_client_call("uci", "commit", bb.head, NULL, NULL);
// if (ret != 0) {
// dmlog_error("failed to reload service %s", svc);
// } else {
// dmlog_info("reloaded service %s", svc);
// }
// blob_buf_free(&bb);
// return ret;
// }
int dm_apply_do_apply()
{
// int i;
commit_changes();
// the commit will be done in the bbf_config daemon
// int cnt = dm_list_cnt(apply_uci_list);
// for (i = 0; i < cnt; i++) {
// char *pkg_name = dm_list_get(apply_uci_list, i);
// dm_uci_commit(pkg_name);
// }
// cnt = dm_list_cnt(apply_uci_list);
// for (i = 0; i < cnt; i++) {
// char *pkg_name = dm_list_get(apply_uci_list, i);
// reload_service(pkg_name);
// }
reset_confidentials();
dm_apply_reset();
return 0;
}

View File

@@ -1,37 +0,0 @@
/*
* 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.
*
*/
#ifndef DM_APPLY_H
#define DM_APPLY_H
#include <quickjs/quickjs.h>
#include "dm_node.h"
enum DATAMODEL_ACTION {
DATA_MODEL_ADD,
DATA_MODEL_SET,
DATA_MODEL_DELETE
};
struct node_change {
dm_node_t node;
enum DATAMODEL_ACTION action;
int redirected;
};
int dm_appy_add_change(enum DATAMODEL_ACTION action, const dm_node_t *node);
void dm_apply_reset_changes(void);
int dm_apply_reset(void);
int dm_apply_do_apply();
void dm_apply_node(struct node_change *change);
void add_apply_package(char *package);
#endif /* DM_APPLY_H */

View File

@@ -1,373 +0,0 @@
/*
* 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 <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "qjs_uci_api.h"
#include "dbmgr.h"
#include "dm.h"
#include "dm_log.h"
#include "dm_node.h"
#include "ubus_client.h"
#include "dm_api.h"
#include "qjs.h"
#include "dm_list.h"
static char* get_tr181_pathname(const char *pn, const char *uci_path, const char *uci_val)
{
json_object *values;
if (uci_val == NULL || uci_val[0] == '\0') {
return NULL;
}
char *path = strdup(uci_path);
char *config = strtok(path, ".");
char *type = strtok(NULL, ".");
if (dm_uci_get_section_list(config, type, NULL, 0, &values) < 0 || values == NULL) {
dmlog_error("get_tr181_pathname, dm_uci_get_section_list failed");
free(path);
return NULL;
}
free(path);
int is_network_interface = 0;
dm_list_h itf_dev_list = NULL;
// special handling for network interface
if (strcmp(uci_path, "network.interface") == 0) {
is_network_interface = 1;
itf_dev_list = dm_list_create(NULL);
}
int index = 1;
// Iterate over all keys in the 'values' object
json_object_object_foreach(values, key, value) {
(void)key;
struct json_object *name_value = NULL;
struct json_object *anonymous = NULL;
if (json_object_object_get_ex(value, ".anonymous", &anonymous)
&& json_object_get_boolean(anonymous)) {
json_object_object_get_ex(value, "name", &name_value);
} else {
json_object_object_get_ex(value, ".name", &name_value);
}
if (is_network_interface) {
// special handling for network interface: skip the loopback and dhcpv6 interfaces.
struct json_object *dev_value;
if (json_object_object_get_ex(value, "device", &dev_value)) {
const char *dev_name = json_object_get_string(dev_value);
if (strcmp(dev_name, "lo") == 0) {
continue;
}
if (dm_list_contains(itf_dev_list, (const void*)dev_name)) {
continue;
}
dm_list_append(itf_dev_list, strdup(dev_name));
}
}
if (strcmp(json_object_get_string(name_value), uci_val) == 0) {
// Found the object with the given name, return its index
char *ret_val = NULL;
asprintf(&ret_val, "%s%d", pn, index);
json_object_put(values);
return ret_val;
} else {
index++;
}
}
if (is_network_interface) {
dm_list_free(itf_dev_list);
}
json_object_put(values);
return NULL;
}
static int import_pathname(const dm_node_t *node, char *uci_value)
{
const struct dm_parameter * param = dm_node_get_parameter(node->id);
if (param->data.paths) {
dm_node_t ref_node = *node;
ref_node.id = param->data.paths[0];
const struct dm_object *obj = dm_node_get_object(ref_node.id);
if (obj && obj->map.map) {
dm_path_t pathname;
ref_node.cnt = dm_node_index_cnt(ref_node.id) - 1;
if (dm_node2name(&ref_node, pathname, sizeof(pathname)) < 0) {
dmlog_error("import_pathname, invalid node");
return -1;
}
// trim the last {i}.
int len = strlen(pathname);
pathname[len - 4] = '\0';
char *pn = get_tr181_pathname(pathname, obj->map.map, uci_value);
if (pn) {
int ret = dmapi_param_set(node, pn);
free(pn);
return ret;
} else {
dmlog_error("import_pathname, get_tr181_pathname failed");
return -1;
}
}
}
return -1;
}
static int importParam(const dm_node_t *node, const struct dm_uci_map *map)
{
char * val = NULL;
if (map->type == DM_UCI_MAP_TYPE_JS) {
JSValue result = qjs_eval_buf(map->map, strlen(map->map), "eval-import-js", JS_EVAL_TYPE_GLOBAL);
if (!JS_IsUndefined(result) && !JS_IsException(result)) {
const char *result_cstr = JS_ToCString(qjs_ctx(), result);
dmapi_param_set(node, result_cstr);
JS_FreeCString(qjs_ctx(), result_cstr);
JS_FreeValue(qjs_ctx(), result);
} else {
dmlog_error("failed to import js: %s", map->map);
}
return 0;
} else {
if (node->cnt == 0 || strchr(map->map, '.') != NULL) {
// uci option with full path
dm_uci_get(map->map, &val);
} else {
// uci option from the js object.
char *buf;
asprintf(&buf, "_arg['%s']", map->map);
JSValue result = qjs_eval_buf(buf, strlen(buf), "eval-uci-js", JS_EVAL_TYPE_GLOBAL);
free(buf);
if (!JS_IsException(result) && !JS_IsUndefined(result)) {
const char *result_cstr = JS_ToCString(qjs_ctx(), result);
val = strdup(result_cstr);
JS_FreeCString(qjs_ctx(), result_cstr);
}
JS_FreeValue(qjs_ctx(), result);
}
}
const struct dm_parameter * param = dm_node_get_parameter(node->id);
if (val == NULL) {
// uci option not present, use the default value defined in JSON if exist.
if (param->default_uci_val) {
dmapi_param_set(node, param->default_uci_val);
}
return 0;
}
if (map->type == DM_UCI_MAP_TYPE_DISABLE) {
if (*val == '0') {
dmapi_param_set(node, "true");
} else {
dmapi_param_set(node, "false");
}
} else if (param->data_type == DM_DATA_BOOLEAN) {
if (*val == '1' || !strcmp(val, "true") || !strcmp(val, "yes")) {
dmapi_param_set(node, "true");
} else {
dmapi_param_set(node, "false");
}
} else if (map->type == DM_UCI_MAP_TYPE_INTERFACE) {
char *pn = get_tr181_pathname("Device.IP.Interface.", "network.interface", val);
if (pn) {
dmapi_param_set(node, pn);
free(pn);
} else {
dmlog_error("import_pathname for network interface failed %s, %s", val, dm_node_str(node));
}
} else {
if (dm_node_data_type(node->id) == DM_PATH_NAME) {
import_pathname(node, val);
} else {
if (param->data_type == DM_DATA_ENUM && param->data.enum_strings) {
// convert the uci case to the tr181 case, ex 'udp' => 'UDP', 'up' => 'Up'
int i = 0;
while (param->data.enum_strings[i]) {
if (strcasecmp(param->data.enum_strings[i], val) == 0) {
dmapi_param_set(node, param->data.enum_strings[i]);
break;
}
i++;
}
if (!param->data.enum_strings[i]) {
dmlog_error("uci value %s not found in the enum, %s", val, dm_node_str(node));
}
} else {
dmapi_param_set(node, val);
}
}
}
free(val);
return 0;
}
static int import_dm_obj(const dm_node_t *node, JSValue js_values);
static int handle_obj_uci_map(const dm_node_t *node, const struct dm_uci_map *map)
{
int ret;
char *path = strdup(map->map);
char *config = strtok(path, ".");
char *type = strtok(NULL, ".");
json_object *values_obj;
if (map->key != NULL && dm_node_index_cnt(node->id) > 1) {
dm_node_t parent;
dm_node_i_parent(node, &parent);
const struct dm_object *obj = dm_node_get_object(parent.id);
if (obj->map.map == NULL || obj->map.type != DM_UCI_MAP_TYPE_SIMPLE) {
dmlog_error("handle_obj_uci_map missing parent map uci: %s", dm_node_str(node));
return -1;
}
char *key_val = NULL;
if (dbmgr_get_child(&parent, "_key", &key_val) < 0 || key_val == NULL) {
dmlog_error("handle_obj_uci_map dbmgr_get_child failed: %s", dm_node_str(node));
return -1;
}
name_val_t match = {map->key, key_val};
ret = dm_uci_get_section_list(config, type, &match, 1, &values_obj);
free(key_val);
} else {
ret = dm_uci_get_section_list(config, type, NULL, 0, &values_obj);
}
free(path);
if (ret != 0 || values_obj == NULL) {
dmlog_warn("dm_uci_get_section_list failed, uci: %s", map->map);
// uci could be missing, skip the error
return 0;
}
int obj_index = 0;
json_object_object_foreach(values_obj, key, val) {
(void)key;
if (!qjs_uci_filter(node, val)) {
continue;
}
dm_node_t new_inst = *node;
if (dmapi_object_add(&new_inst) < 0) {
dmlog_error("failed to add new instance");
ret = -1;
break;
}
json_object *name_obj;
if (json_object_object_get_ex(val, ".name", &name_obj)) {
dm_node_t key_node = new_inst;
key_node.id = dm_node_get_child_id(new_inst.id, "_key");
if (dmapi_param_set(&key_node, json_object_get_string(name_obj)) < 0) {
dmlog_error("failed to set param value");
ret = -1;
}
} else {
dmlog_error("failed to get uci name");
ret = -1;
break;
}
JSValue js_val = json_object_to_jsvalue(val);
JS_SetPropertyStr(qjs_ctx(), qjs_global(), "_arg", js_val);
JS_SetPropertyStr(qjs_ctx(), js_val, ".index", JS_NewInt32(qjs_ctx(), obj_index));
obj_index++;
ret = import_dm_obj(&new_inst, js_val);
if (ret < 0) {
dmlog_error("failed to import node %s", dm_node_str(&new_inst));
// break;
}
}
json_object_put(values_obj);
return 0;
}
extern int update_dm_value(JSContext *ctx, const char *key, JSValue value);
static int import_dm_obj(const dm_node_t *node, JSValue js_values) {
if (qjs_has_import_handler(node->id)) {
int ret = 0;
dm_path_t node_path;
dm_node2name(node, node_path, sizeof(dm_path_t));
if (dm_node_is_object(node->id)) {
strcat(node_path, ".");
}
JSValue input_val = js_values;
JSValue js_val = qjs_call_import_handler(node, input_val);
if (!JS_IsException(js_val) && !JS_IsUndefined(js_val)) {
int len = strlen(node_path);
if (node_path[len-2] == '}') {
node_path[len-4] = '\0';
}
const char *imported_val = get_js_value_str(js_val);
free_js_cstr(imported_val);
ret = update_dm_value(qjs_ctx(), node_path, js_val);
if (ret < 0) {
dmlog_error("update_dm_value failed");
}
}
JS_FreeValue(qjs_ctx(), js_val);
return ret;
}
if (dm_node_is_parameter(node->id)) {
if (dm_node_is_confidential(node->id) || !dm_node_has_db(node->id)) {
return 0;
}
const struct dm_parameter * param = dm_node_get_parameter(node->id);
if (param->map.map == NULL) {
return 0;
}
return importParam(node, &param->map);
}
if (dm_node_is_objectlist(node->id) && !dm_node_is_index_complete(node)) {
const struct dm_object *obj = dm_node_get_object(node->id);
if (obj->map.map != NULL && obj->map.type == DM_UCI_MAP_TYPE_SIMPLE) {
return handle_obj_uci_map(node, &obj->map);
} else {
dmlog_debug("ignored import for object: %s", dm_node_str(node));
}
return 0;
}
if (dm_node_is_object(node->id) || dm_node_is_objectlist(node->id)) {
const struct dm_object * obj = dm_node_get_object(node->id);
for (int i = 0; i < obj->param_num; i++) {
dm_node_t param_node = *node;
param_node.id = obj->param_list[i]->node_id;
if (import_dm_obj(&param_node, js_values) < 0) {
dmlog_error("import param failed: %s", dm_node_str(&param_node));
}
}
for (int i = 0; i < obj->object_num; i++) {
dm_node_t node_obj = *node;
node_obj.id = obj->object_list[i]->node_id;
if (import_dm_obj(&node_obj, js_values) < 0) {
dmlog_debug("import object failed: %s", dm_node_str(&node_obj));
}
}
}
return 0;
}
int importDM()
{
dm_node_t root_node = dm_init_node(DM_DEVICE);
return import_dm_obj(&root_node, JS_UNDEFINED);
}

View File

@@ -1,624 +0,0 @@
/*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <uci.h>
#include <stdint.h>
#include "dm_api.h"
#include "dm_node.h"
#include "dm_log.h"
#include "dm.h"
#include "dbmgr.h"
#define LOCK_FILE "/var/lock/bbfdm_reference_db.lock"
#define UCI_PACKAGE "bbfdm_reference_db"
extern const dm_node_id_t dm_linker_nodes[];
// Forward declarations
static char *calculate_hash(const char *input);
static int process_linker_node(struct uci_context *ctx, struct uci_package *pkg,
const char *service_hash, const dm_node_t *node);
static int clear_service_entries(struct uci_context *ctx, struct uci_package *pkg,
const char *service_hash);
static int ensure_uci_sections(struct uci_context *ctx, struct uci_package *pkg);
// FNV-1 32-bit parameters
#define FNV_OFFSET_BASIS 0x811C9DC5U
#define FNV_PRIME 0x1000193U
/*
* Calculate 8-character uppercase hex hash using the FNV-1 algorithm.
* Returns malloc-ed string (must be freed by caller) or NULL on error.
*/
static char *calculate_hash(const char *input) {
if (!input) {
return NULL;
}
uint32_t hash = FNV_OFFSET_BASIS;
const unsigned char *ptr = (const unsigned char *)input;
while (*ptr) {
hash *= FNV_PRIME;
hash ^= (uint32_t)(*ptr);
ptr++;
}
char *result = malloc(9); // 8 chars + null terminator
if (!result) {
return NULL;
}
snprintf(result, 9, "%08X", hash);
return result;
}
/**
* Check if a node ID is in the linker nodes array
*/
int is_linker_node(dm_node_id_t node_id) {
for (int i = 0; dm_linker_nodes[i] != INVALID_DM_NODE_ID; i++) {
if (dm_linker_nodes[i] == node_id) {
return 1;
}
}
return 0;
}
int object_has_linker_param(dm_node_id_t object_id) {
const struct dm_object *obj = dm_node_get_object(object_id);
if (!obj) {
return 0;
}
for (int i = 0; i < obj->param_num; i++) {
const struct dm_node_info *info = obj->param_list[i];
if (is_linker_node(info->node_id)) {
return 1;
}
}
return 0;
}
/**
* Process a single linker parameter node
*/
static int process_linker_node(struct uci_context *ctx, struct uci_package *pkg,
const char *service_hash, const dm_node_t *node) {
const struct dm_parameter *param = dm_node_get_parameter(node->id);
if (!param) return -1;
// Check if this parameter is a linker node
if (!is_linker_node(node->id)) {
dmlog_error("Not a linker parameter %s", dm_node_str(node));
return 0; // Not a linker parameter
}
// Get the parent object path
dm_node_t parent_node;
if (dm_node_i_parent(node, &parent_node) != 0) {
dmlog_error("Failed to get parent node for %s", dm_node_str(node));
return -1;
}
// Get parent path
dm_path_t parent_path;
if (dm_node2name(&parent_node, parent_path, sizeof(parent_path)) != 0) {
dmlog_error("Failed to get parent path for %s", dm_node_str(&parent_node));
return -1;
}
// Get current path (same as parent for leaf parameters)
dm_path_t current_path;
if (dm_node2name(&parent_node, current_path, sizeof(current_path)) != 0) {
dmlog_error("Failed to get current path for %s", dm_node_str(&parent_node));
return -1;
}
// Get parameter value
char *key_value = NULL;
if (dbmgr_get(node, &key_value) != 0 || !key_value) {
dmlog_debug("No value found for linker parameter %s", dm_node_str(node));
return 0;
}
// Compose linker string directly from parent_path, keeping instance numbers intact
const char *key_name = param->node.name;
size_t len_linker = strlen(parent_path) + strlen(key_name) + strlen(key_value) + 6; // extra for [==].
char *linker_string = malloc(len_linker);
if (!linker_string) {
dmlog_error("Failed to allocate memory for linker string");
free(key_value);
return -1;
}
dm_node_t parent_node_with_index = parent_node;
parent_node_with_index.cnt = 0;
dm_path_t parent_path_with_index;
if (dm_node2name_with_index(&parent_node_with_index, parent_path_with_index, sizeof(parent_path_with_index), "*") != 0) {
dmlog_error("Failed to get parent path for %s", dm_node_str(&parent_node));
return -1;
}
parent_path_with_index[strlen(parent_path_with_index) - 2] = '\0';
snprintf(linker_string, len_linker, "%s[%s==%s].", parent_path_with_index, key_name, key_value);
// Calculate hashes
char *hash_path = calculate_hash(linker_string);
char *hash_value = calculate_hash(current_path);
if (!hash_path || !hash_value) {
dmlog_error("Failed to calculate hashes for %s", linker_string);
free(linker_string);
free(key_value);
free(hash_path);
free(hash_value);
return -1;
}
// Update UCI sections
struct uci_section *ref_path_section = uci_lookup_section(ctx, pkg, "reference_path");
struct uci_section *ref_value_section = uci_lookup_section(ctx, pkg, "reference_value");
struct uci_section *service_section = uci_lookup_section(ctx, pkg, service_hash);
if (!ref_path_section || !ref_value_section || !service_section) {
dmlog_error("Failed to find required UCI sections");
free(linker_string);
free(key_value);
free(hash_path);
free(hash_value);
return -1;
}
// Set reference_path option
struct uci_ptr ptr;
memset(&ptr, 0, sizeof(ptr));
ptr.package = pkg->e.name;
ptr.section = "reference_path";
ptr.option = hash_path;
ptr.value = current_path;
uci_set(ctx, &ptr);
// Set reference_value option
memset(&ptr, 0, sizeof(ptr));
ptr.package = pkg->e.name;
ptr.section = "reference_value";
ptr.option = hash_value;
ptr.value = (strlen(key_value) > 0) ? key_value : "#";
uci_set(ctx, &ptr);
// Add to service section lists
memset(&ptr, 0, sizeof(ptr));
ptr.package = pkg->e.name;
ptr.section = service_hash;
ptr.option = "reference_path";
ptr.value = hash_path;
uci_add_list(ctx, &ptr);
memset(&ptr, 0, sizeof(ptr));
ptr.package = pkg->e.name;
ptr.section = service_hash;
ptr.option = "reference_value";
ptr.value = hash_value;
uci_add_list(ctx, &ptr);
// dmlog_debug("Processed linker: %s -> %s (path_hash=%s, value_hash=%s)",
// linker_string, current_path, hash_path, hash_value);
// Cleanup
free(linker_string);
free(key_value);
free(hash_path);
free(hash_value);
return 0;
}
/**
* Process all linker nodes by iterating through the linker nodes array
*/
static int process_all_linker_nodes(struct uci_context *ctx, struct uci_package *pkg,
const char *service_hash) {
// Iterate through all linker nodes
for (int i = 0; dm_linker_nodes[i] != INVALID_DM_NODE_ID; i++) {
dm_node_id_t linker_id = dm_linker_nodes[i];
// Check if this is a parameter node
if (!dm_node_is_parameter(linker_id)) {
continue;
}
// Get all instances of multi-instance objects that contain this linker parameter
const struct dm_parameter *param = dm_node_get_parameter(linker_id);
if (!param || !param->node.parent) {
continue;
}
// Find the object that contains this parameter
dm_node_id_t parent_id = param->node.parent->node_id;
// Only handle multi-instance objects; skip single-instance objects
if (dm_node_is_objectlist(parent_id)) {
dm_node_t parent_node = {0};
parent_node.id = parent_id;
// For multi-index nodes, bypass inode buffer and go directly to DB
dm_nodelist_h list = dm_nodelist_find(&parent_node, NULL, 1);
if (list != DM_INVALID_NODELIST) {
const dm_node_t *instance_node;
nodelist_for_each_node(instance_node, list) {
// dmlog_debug("processing linker node %s", dm_node_str(instance_node));
// Create the parameter node for this instance
dm_node_t param_node = *instance_node;
param_node.id = linker_id;
// Process this linker parameter instance
process_linker_node(ctx, pkg, service_hash, &param_node);
}
dm_nodelist_free(list);
}
}
}
return 0;
}
/**
* Clear existing entries for this service
*/
static int clear_service_entries(struct uci_context *ctx, struct uci_package *pkg,
const char *service_hash) {
struct uci_section *service_section = uci_lookup_section(ctx, pkg, service_hash);
if (!service_section) {
return 0; // Section doesn't exist yet
}
// Clear the lists
struct uci_ptr ptr;
memset(&ptr, 0, sizeof(ptr));
ptr.package = pkg->e.name;
ptr.section = service_hash;
ptr.option = "reference_path";
uci_delete(ctx, &ptr);
memset(&ptr, 0, sizeof(ptr));
ptr.package = pkg->e.name;
ptr.section = service_hash;
ptr.option = "reference_value";
uci_delete(ctx, &ptr);
return 0;
}
/**
* Ensure required UCI sections exist
*/
static int ensure_uci_sections(struct uci_context *ctx, struct uci_package *pkg) {
struct uci_ptr ptr;
// Ensure reference_path section exists
memset(&ptr, 0, sizeof(ptr));
ptr.package = pkg->e.name;
ptr.section = "reference_path";
ptr.value = "reference_path";
if (uci_set(ctx, &ptr) != UCI_OK) {
return -1;
}
// Ensure reference_value section exists
memset(&ptr, 0, sizeof(ptr));
ptr.package = pkg->e.name;
ptr.section = "reference_value";
ptr.value = "reference_value";
if (uci_set(ctx, &ptr) != UCI_OK) {
return -1;
}
return 0;
}
/**
* Main API function to refresh linker nodes
*/
int dm_refresh_linker_nodes(const char *service_name) {
dmlog_debug("dm_refresh_linker_nodes start");
if (!service_name) {
dmlog_error("Service name is required");
return -1;
}
// Step 1: Open and lock the reference database
int lock_fd = open(LOCK_FILE, O_CREAT | O_RDWR, 0644);
if (lock_fd < 0) {
dmlog_error("Failed to open lock file: %s", LOCK_FILE);
return -1;
}
if (flock(lock_fd, LOCK_EX) != 0) {
dmlog_error("Failed to acquire exclusive lock");
close(lock_fd);
return -1;
}
// Step 2: Calculate service hash
char *service_hash = calculate_hash(service_name);
if (!service_hash) {
dmlog_error("Failed to calculate service hash");
close(lock_fd);
return -1;
}
dmlog_debug("service_hash: %s", service_hash);
// Step 3: Initialize UCI context and point to /var/state for runtime reference DB
struct uci_context *ctx = uci_alloc_context();
if (!ctx) {
dmlog_error("Failed to allocate UCI context");
free(service_hash);
close(lock_fd);
return -1;
}
// Use /var/state as configuration directory
uci_set_confdir(ctx, "/var/state");
// Load or create the UCI package
struct uci_package *pkg = NULL;
if (uci_load(ctx, UCI_PACKAGE, &pkg) != UCI_OK) {
// Package doesn't exist, create it
struct uci_ptr ptr;
memset(&ptr, 0, sizeof(ptr));
ptr.package = UCI_PACKAGE;
if (uci_set(ctx, &ptr) != UCI_OK) {
dmlog_error("Failed to create UCI package: %s", UCI_PACKAGE);
uci_free_context(ctx);
free(service_hash);
close(lock_fd);
return -1;
}
pkg = ptr.p;
}
// Step 4: Ensure required sections exist
if (ensure_uci_sections(ctx, pkg) != 0) {
dmlog_error("Failed to ensure UCI sections");
uci_free_context(ctx);
free(service_hash);
close(lock_fd);
return -1;
}
// Create service section
struct uci_ptr ptr;
memset(&ptr, 0, sizeof(ptr));
ptr.package = pkg->e.name;
ptr.section = service_hash;
ptr.value = "service";
uci_set(ctx, &ptr);
// Step 5: Clear existing entries for this service
clear_service_entries(ctx, pkg, service_hash);
// Step 6: Process all linker nodes
if (process_all_linker_nodes(ctx, pkg, service_hash) != 0) {
dmlog_error("Failed to process linker nodes");
uci_free_context(ctx);
free(service_hash);
close(lock_fd);
return -1;
}
// Step 7: Commit changes
if (uci_commit(ctx, &pkg, false) != UCI_OK) {
dmlog_error("Failed to commit UCI changes");
uci_free_context(ctx);
free(service_hash);
close(lock_fd);
return -1;
}
// Cleanup
uci_free_context(ctx);
free(service_hash);
// Step 8: Release lock
flock(lock_fd, LOCK_UN);
close(lock_fd);
dmlog_info("Successfully refreshed linker nodes for service: %s", service_name);
return 0;
}
/*
* Resolve the linker parameter value for a given object instance path.
* The object_path should include the instance number, for example
* "Device.IP.Interface.1"
* On success, *value will point to a malloc()'d string that must be freed
* by the caller. The function returns 0 on success or -1 on error.
*/
int dm_resolve_linker(const char *object_path, char **value) {
if (!object_path || !value) {
dmlog_error("Invalid arguments to dm_resolve_linker");
return -1;
}
*value = NULL;
/* Calculate the hash used as option name in the reference_value section */
char *hash_str = calculate_hash(object_path);
if (!hash_str) {
dmlog_error("Failed to calculate hash for %s", object_path);
return -1;
}
struct uci_context *ctx = uci_alloc_context();
if (!ctx) {
dmlog_error("Failed to allocate UCI context");
free(hash_str);
return -1;
}
/* reference DB lives in /var/state */
uci_set_confdir(ctx, "/var/state");
struct uci_package *pkg = NULL;
if (uci_load(ctx, UCI_PACKAGE, &pkg) != UCI_OK || !pkg) {
dmlog_error("Failed to load UCI package %s", UCI_PACKAGE);
uci_free_context(ctx);
free(hash_str);
return -1;
}
struct uci_section *ref_value_section = uci_lookup_section(ctx, pkg, "reference_value");
if (!ref_value_section) {
dmlog_error("reference_value section not found in %s", UCI_PACKAGE);
uci_free_context(ctx);
free(hash_str);
return -1;
}
const char *str_val = uci_lookup_option_string(ctx, ref_value_section, hash_str);
if (!str_val) {
dmlog_debug("No linker value found for %s (hash=%s)", object_path, hash_str);
uci_free_context(ctx);
free(hash_str);
return -1;
}
/* Allocate and copy result for caller */
if (strcmp(str_val, "#") == 0) {
/* '#' is used to represent an empty string */
*value = strdup("");
} else {
*value = strdup(str_val);
}
if (!*value) {
uci_free_context(ctx);
free(hash_str);
return -1;
}
uci_free_context(ctx);
free(hash_str);
return 0;
}
/**
* Resolve the object path for a given linker value.
*
* This helper reconstructs the deterministic linker string of the form
* "<base_path>[<key_name>==<key_value>]."
* that was generated by dm_refresh_linker_nodes() and uses its hash to
* look up the real object path from the reference database.
*
* If no matching entry exists in the database the function will fall
* back to returning the linker string itself, exactly mimicking the
* behaviour of legacy _bbfdm_get_references().
*
* The caller is responsible for freeing the returned string.
*
* @param base_path Base object path ending with a dot (e.g. "Device.WiFi.SSID.")
* @param key_name Parameter name that acts as linker key (e.g. "Name")
* @param key_value Desired value of the linker key
* @param object_path [out] malloc-allocated string holding either the
* resolved object path (e.g. "Device.WiFi.SSID.4")
* (NULL when no match is found)
* @return 0 when resolved, -1 if no match/error
*/
int dm_resolve_linker_path(const char *base_path,
const char *key_name,
const char *key_value,
char **object_path) {
if (!base_path || !key_name || !key_value || !object_path) {
dmlog_error("Invalid arguments to dm_resolve_linker_path");
return -1;
}
if (strlen(base_path) == 0 || strlen(key_name) == 0 || strlen(key_value) == 0) {
dmlog_error("base_path, key_name and key_value must not be empty");
return -1;
}
*object_path = NULL;
/* Compose the linker string that was used as basis for the reference hash */
size_t linker_len = strlen(base_path) + strlen(key_name) + strlen(key_value) + 6; /* "[==]." */
char *linker_string = malloc(linker_len);
if (!linker_string) {
return -1;
}
snprintf(linker_string, linker_len, "%s[%s==%s].", base_path, key_name, key_value);
/* Calculate hash for use as option name inside reference_path section */
char *hash_path = calculate_hash(linker_string);
if (!hash_path) {
free(linker_string);
return -1;
}
/* Open UCI context pointing to runtime reference DB (/var/state) */
struct uci_context *ctx = uci_alloc_context();
if (!ctx) {
dmlog_error("Failed to allocate UCI context");
free(linker_string);
free(hash_path);
return -1;
}
uci_set_confdir(ctx, "/var/state");
struct uci_package *pkg = NULL;
if (uci_load(ctx, UCI_PACKAGE, &pkg) != UCI_OK || !pkg) {
dmlog_error("Failed to load UCI package %s", UCI_PACKAGE);
uci_free_context(ctx);
free(linker_string);
free(hash_path);
return -1;
}
struct uci_section *ref_path_section = uci_lookup_section(ctx, pkg, "reference_path");
if (!ref_path_section) {
dmlog_error("reference_path section not found in %s", UCI_PACKAGE);
uci_free_context(ctx);
free(linker_string);
free(hash_path);
return -1;
}
const char *uci_path = uci_lookup_option_string(ctx, ref_path_section, hash_path);
int ret = -1; /* default: not resolved */
if (uci_path) {
/* Matching object path found */
*object_path = strdup(uci_path);
if (*object_path)
ret = 0;
} else {
/* No match. Leave *object_path NULL and return error */
ret = -1;
}
uci_free_context(ctx);
free(linker_string);
free(hash_path);
return ret;
}

View File

@@ -1,89 +0,0 @@
/*
* 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.
*
*/
#ifndef DM_LINKER_H
#define DM_LINKER_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* Refresh linker nodes for a given service
*
* This function walks through the entire data model tree and updates the
* UCI reference database with linker parameter information for the specified
* service. It creates a deterministic mapping between object paths and their
* linker parameter values.
*
* The function:
* 1. Takes an exclusive lock on the reference database
* 2. Calculates a service hash from the service name
* 3. Prepares the UCI package with required sections
* 4. Walks through all multi-instance objects looking for linker parameters
* 5. Builds linker strings and generates hashes
* 6. Updates the UCI reference database
* 7. Commits changes and releases the lock
*
* @param service_name The UBus object name of the service (e.g., "bbfdm.core")
* @return 0 on success, -1 on error
*/
int dm_refresh_linker_nodes(const char *service_name);
/**
* Check if a node ID is a linker node
*
* This function checks if the given node ID is in the linker nodes array.
*
* @param node_id The node ID to check
* @return 1 if the node is a linker node, 0 otherwise
*/
int is_linker_node(dm_node_id_t node_id);
/**
* Check if an object has a linker parameter
*
* This function checks if the given object has any parameters that are linker nodes.
*
* @param object_id The object ID to check
* @return 1 if the object has a linker parameter, 0 otherwise
*/
int object_has_linker_param(dm_node_id_t object_id);
/**
* Resolve the linker parameter value for a given object instance path
*
* This helper looks up the reference database that was populated by
* dm_refresh_linker_nodes() and returns the value of the linker
* parameter belonging to the supplied object path.
*
* The caller is responsible for freeing the returned string.
*
* @param object_path Full object path including instance number
* (e.g. "Device.IP.Interface.1")
* @param value[out] Pointer that will receive the malloc-allocated value
* @return 0 on success, -1 on failure
*/
int dm_resolve_linker(const char *object_path, char **value);
/*
* Resolve object path from a linker value.
* Returns 0 and sets *object_path on success.
* Returns -1 and leaves *object_path NULL if no matching object path exists
* or on error.
*/
int dm_resolve_linker_path(const char *base_path, const char *key_name, const char *key_value, char **object_path);
#ifdef __cplusplus
}
#endif
#endif /* DM_LINKER_H */

View File

@@ -1,478 +0,0 @@
/*
* 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 <stdio.h>
#include <stdlib.h>
#include "inode_buf.h"
#include "dm_log.h"
#include "qjs.h"
#include "utils.h"
#define GROWTH_FACTOR 2
#define DB_INFO_TIMEOUT 2000
extern void dmapi_refresh_instance_buf(const dm_node_t *node);
static struct inode_entry *inode_g = NULL;
dm_inst_array_t* dm_inst_array_create(size_t initial_capacity) {
dm_inst_array_t *array = calloc(1, sizeof(dm_inst_array_t));
if (initial_capacity <= 0) {
initial_capacity = 1;
}
array->data = calloc(initial_capacity, sizeof(inst_entry_t));
array->size = 0;
array->capacity = initial_capacity;
return array;
}
static void get_all_i_node(dm_node_id_t id, dm_node_id_t *nodes_id, int *cnt)
{
if (!dm_node_is_objectlist(id)) {
id = dm_node_i_parent_id(id);
if (id == INVALID_DM_NODE_ID) {
*cnt = 0;
return;
}
}
nodes_id[0] = id;
*cnt = 1;
dm_node_id_t p = dm_node_i_parent_id(id);
while (p != INVALID_DM_NODE_ID) {
nodes_id[*cnt] = p;
(*cnt)++;
if (*cnt >= MAX_DM_NODE_DEPTH) {
dmlog_info("too long inode");
// panic
break;
}
p = dm_node_i_parent_id(p);
}
}
static struct inode_entry *find_inode_entry(struct inode_entry *head, const dm_node_id_t key)
{
struct inode_entry *current = head;
while (current != NULL) {
if (current->key == key) {
return current;
}
current = current->next;
}
return NULL;
}
static inst_entry_t* dm_inst_array_find(dm_inst_array_t *array, unsigned int index) {
if (array == NULL) {
return NULL;
}
for (size_t i = 0; i < array->size; i++) {
if (array->data[i].index == index) {
return &array->data[i];
}
}
return NULL;
}
static inst_entry_t *find_inst(struct inode_entry *entry, unsigned int index, int *db)
{
inst_entry_t *inst = dm_inst_array_find(entry->insts, index);
if (inst == NULL) {
inst = dm_inst_array_find(entry->dyn_insts, index);
if (db && inst) {
*db = 0;
}
} else if (db) {
*db = 1;
}
return inst;
}
static void free_inode(struct inode_entry *inode);
void dm_inst_array_free(dm_inst_array_t *array) {
if (array == NULL) {
return;
}
for (size_t i = 0; i < array->size; i++) {
JS_FreeValue(qjs_ctx(), array->data[i].value);
free_inode(array->data[i].inode);
}
if (array->data){
free(array->data);
}
free(array);
}
static void free_insts(struct inode_entry *entry)
{
dm_inst_array_free(entry->insts);
dm_inst_array_free(entry->dyn_insts);
entry->insts = NULL;
entry->dyn_insts = NULL;
}
static void free_inode(struct inode_entry *inode)
{
if (inode == NULL) {
return;
}
struct inode_entry *current = inode;
struct inode_entry *next;
while (current != NULL) {
next = current->next;
free_insts(current);
free(current);
current = next;
}
}
int inode_buf_get_js_values(const dm_node_t *node, JSValue values[])
{
int cnt = 0;
dm_node_id_t nodes_id[MAX_DM_NODE_DEPTH];
get_all_i_node(node->id, nodes_id, &cnt);
struct inode_entry **inode = &inode_g;
dm_node_t curr_node;
curr_node.cnt = 0;
int index_i = 0;
for (int i = cnt - 1; i >= 0; i--) {
if (index_i >= node->cnt) {
// not complete index: A.1.B.1.C.{i}.
return index_i;
}
curr_node.id = nodes_id[i];
struct inode_entry *entry = find_inode_entry(*inode, nodes_id[i]);
if (entry == NULL) {
dmapi_refresh_instance_buf(&curr_node);
entry = find_inode_entry(*inode, nodes_id[i]);
}
if (entry == NULL) {
dmlog_error("inode_buf_get_js_values, inode_entry %s not found, %s", dm_node_str(&curr_node), dm_node_str(node));
return -1;
}
int db = 0;
inst_entry_t *inst = find_inst(entry, node->index[index_i], &db);
if (inst == NULL) {
dmlog_error("inode_buf_get_js_values, nst_entry not found %s, %d", dm_node_str(node), node->index[index_i]);
return -1;
}
values[index_i++] = inst->value;
inode = &inst->inode;
curr_node.index[curr_node.cnt] = inst->index;
curr_node.cnt++;
if (db && qjs_has_info_handler(curr_node.id)) {
if (inst->value_time == 0) {
qjs_call_info_handler(&curr_node, inst->value);
inst->value_time = get_uptime_msecs();
} else {
unsigned int now = get_uptime_msecs();
if ((now - inst->value_time) >= DB_INFO_TIMEOUT) {
qjs_call_info_handler(&curr_node, inst->value);
inst->value_time = now;
}
}
}
}
return cnt;
}
struct inode_entry *inode_buf_find(const dm_node_t *node, int *retry)
{
int cnt = 0;
dm_node_id_t nodes_id[MAX_DM_NODE_DEPTH];
get_all_i_node(node->id, nodes_id, &cnt);
struct inode_entry *inode = inode_g;
int index_i = 0;
for (int i = cnt - 1; i >= 0; i--) {
struct inode_entry *entry = find_inode_entry(inode, nodes_id[i]);
if (entry == NULL) {
if (retry) {
*retry = 1;
}
return NULL;
}
if (entry->key == node->id) {
return entry;
}
if (index_i >= node->cnt) {
if (retry) {
*retry = 0;
}
dmlog_error("inode_buf_find, invalid node(missing index) %s", dm_node_str(node));
return NULL;
}
inst_entry_t *inst = find_inst(entry, node->index[index_i], NULL);
if (inst == NULL) {
dmlog_error("inode_buf_find, instance not found %s", dm_node_str(node));
if (retry) {
*retry = 0;
}
return NULL;
}
inode = inst->inode;
index_i++;
}
return NULL;
}
static void create_inode_inst(struct inode_entry **inode, const dm_node_id_t key, dm_inst_array_t *insts, int dynamic)
{
struct inode_entry *entry = calloc(1, sizeof(struct inode_entry));
entry->key = key;
if (dynamic) {
entry->dyn_insts = insts;
entry->dyn_time = get_uptime_msecs();
} else {
entry->insts = insts;
}
entry->next = *inode;
*inode = entry;
}
static void resize_if_needed(dm_inst_array_t *array) {
if (array->size >= array->capacity) {
size_t new_cap = array->capacity * GROWTH_FACTOR;
inst_entry_t *new_data = realloc(array->data, new_cap * sizeof(inst_entry_t));
if (new_data == NULL) {
/* keep original buffer; log and return to avoid losing pointer */
dmlog_error("resize_if_needed: realloc failed (cap=%zu)", new_cap);
return;
}
array->data = new_data;
array->capacity = new_cap;
}
}
void dm_inst_array_append(dm_inst_array_t *array, inst_entry_t *value) {
resize_if_needed(array);
array->data[array->size++] = *value;
}
int dm_inst_array_remove(dm_inst_array_t *array, unsigned int index) {
if (!array) {
return 0;
}
for (size_t i = 0; i < array->size; i++) {
if (array->data[i].index == index) {
JS_FreeValue(qjs_ctx(), array->data[i].value);
free_inode(array->data[i].inode);
for (size_t j = i; j < array->size - 1; j++) {
array->data[j] = array->data[j + 1];
}
array->size--;
return 1;
}
}
return 0;
}
int inode_buf_append_db_inst(const dm_node_t *node, inst_entry_t *inst)
{
dm_inst_array_t * arr = dm_inst_array_create(1);
dm_inst_array_append(arr, inst);
return inode_buf_add_inst(node, arr, 0, 1);
}
int inode_buf_del_db_inst(const dm_node_t *node)
{
int retry;
struct inode_entry *entry = inode_buf_find(node, &retry);
if (!entry) {
if (retry == 0) {
return -1;
}
dm_node_t n = *node;
n.cnt = node->cnt - 1;
dmapi_refresh_instance_buf(&n);
entry = inode_buf_find(node, &retry);
}
if (!entry) {
dmlog_error("inode_buf_del_db_inst, node not found: %s", dm_node_str(node));
return -1;
}
if (dm_inst_array_remove(entry->insts, dm_node_last_index(node))) {
// dmlog_debug("removed instance from buffer: %s", dm_node_str(node));
return 0;
}
dmlog_error("inode_buf_del_db_inst, instance not found: %s", dm_node_str(node));
return -1;
}
static void update_instances(struct inode_entry *inode, dm_inst_array_t *insts, int dynamic)
{
if (dynamic) {
dm_inst_array_free(inode->dyn_insts);
inode->dyn_insts = insts;
inode->dyn_time = get_uptime_msecs();
} else {
dm_inst_array_free(inode->insts);
inode->insts = insts;
}
}
int inode_buf_add_inst(const dm_node_t *node, dm_inst_array_t *insts, int dynamic, int append)
{
dm_node_id_t nodes_id[MAX_DM_NODE_DEPTH];
int cnt;
get_all_i_node(node->id, nodes_id, &cnt);
struct inode_entry **inode = &inode_g;
int index_i = 0;
dm_node_t curr_node;
curr_node.cnt = 0;
// dmlog_debug("inode_buf_add_inst %s, inst_cnt: %d, dynamic: %d", dm_node_str(node), insts->size, dynamic);
for (int i = cnt - 1; i >= 0; i--) {
curr_node.id = nodes_id[i];
struct inode_entry *entry = find_inode_entry(*inode, nodes_id[i]);
if (entry == NULL && i != 0) {
dmapi_refresh_instance_buf(&curr_node);
entry = find_inode_entry(*inode, nodes_id[i]);
}
if (entry == NULL) {
if (i == 0) {
// create the instance
if (!append) {
create_inode_inst(inode, nodes_id[i], insts, dynamic);
} else {
// dmlog_debug("first time to add instance, refresh all");
dm_inst_array_free(insts);
dmapi_refresh_instance_buf(node);
}
return 0;
} else {
dmlog_error("inode buffer not found: %s", dm_node_str(&curr_node));
return -1;
}
} else {
if (i == 0) {
if (!append) {
update_instances(entry, insts, dynamic);
} else {
// currently only append one instance.
dm_inst_array_append(entry->insts, &insts->data[0]);
if (insts->data) {
free(insts->data);
}
free(insts);
}
return 0;
}
}
inst_entry_t *inst = find_inst(entry, node->index[index_i], NULL);
if (inst == NULL) {
dmlog_error("inode_buf_add_inst inst_entry not found");
return -1;
}
index_i++;
inode = &inst->inode;
curr_node.index[curr_node.cnt] = inst->index;
curr_node.cnt++;
}
dmlog_error("failed to add instance buffer for %s", dm_node_str(node));
return -1;
}
int inode_buf_update_param_value(const dm_node_t *node, const char *value)
{
JSValue args[MAX_DM_NODE_DEPTH];
int ret = inode_buf_get_js_values(node, args);
if (ret != node->cnt) {
dmlog_error("inode_buf_update_param_value failed, node:%s, ret: %d", dm_node_str(node), ret);
return -1;
}
const struct dm_node_info *info = dm_node_get_info(node->id);
JS_SetPropertyStr(qjs_ctx(), args[ret - 1], info->name, JS_NewString(qjs_ctx(), value));
return 0;
}
void inode_buf_free_all()
{
free_inode(inode_g);
inode_g = NULL;
}
static void print_inst_array(dm_inst_array_t *arr, int ident)
{
if (arr == NULL) {
dmlog_info("no instances");
return;
}
for (int i = 0; i < arr->size; i++) {
const char *str = get_js_value_str(arr->data[i].value);
dmlog_info("idx:%d", arr->data[i].index);
dmlog_info("val: \n%s", str);
free_js_cstr(str);
}
}
static void print_inode_insts(struct inode_entry *inode, int level)
{
dmlog_info("db instances:");
print_inst_array(inode->insts, level);
dmlog_info("dynamic instances (created time:%d)", inode->dyn_time);
print_inst_array(inode->dyn_insts, level);
}
void inode_buf_dump(const dm_node_t *node)
{
dmlog_info("node buffer: %s", dm_node_str(node));
struct inode_entry *entry = inode_buf_find(node, NULL);
if (!entry) {
dmlog_info("node buffer not found: %s", dm_node_str(node));
return;
}
if (dm_node_is_index_complete(node)) {
int db;
inst_entry_t *inst = find_inst(entry, node->index[node->cnt-1], &db);
if (!inst) {
dmlog_info("node buffer (inst) not found: %s", dm_node_str(node));
return;
} else {
dmlog_info("instance buffer (db:%d):", db);
dmlog_info("index: %d", inst->index);
const char *str = get_js_value_str(inst->value);
dmlog_info("value: %s", str);
free_js_cstr(str);
}
} else {
dmlog_info("inode buffer:");
print_inode_insts(entry, 0);
}
}

View File

@@ -1,99 +0,0 @@
/*
* 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.
*
*/
#ifndef I_NODE_BUF_H
#define I_NODE_BUF_H
#include <time.h>
#include <quickjs/quickjs.h>
#include "dm_node.h"
/*
Buffer for Multi-object instance.
An example of buffer is as following:
inode_entry * head -+
|
v
inode_entry [Device.IP.Interface.{i}.] -> [Device.Ethernet.Link.{i}.]
| |
v v
inst_entry [instance 1] -> [instance 2] ...
|
v
inode_entry [Device.IP.Interface.{i}.IPv4Address.{i}.] -> [Device.IP.Interface.{i}.IPv46ddress.{i}.]
|
v
inst_entry [instance 1] -> [instance 2]
*/
struct inode_entry;
typedef struct {
unsigned int index;
JSValue value; // key value for the instance
struct inode_entry *inode; // head of child inode buf (in recursive)
unsigned int value_time;
} inst_entry_t;
typedef struct {
inst_entry_t *data;
size_t size;
size_t capacity;
} dm_inst_array_t;
dm_inst_array_t* dm_inst_array_create(size_t initial_capacity);
void dm_inst_array_append(dm_inst_array_t *array, inst_entry_t *value);
struct inode_entry {
dm_node_id_t key;
dm_inst_array_t *insts;
dm_inst_array_t *dyn_insts;
struct inode_entry *next;
unsigned int dyn_time;
};
/** Buffer new db instances for the multi-instance object.
* @param[in] node node of instance
* @param[in] insts instance array
* @param[in] cnt length of instance array
* @param[in] dynamic if the instances are dynamic or in db
* @return 0 in case of success, or a nonzero value in case of error
*/
int inode_buf_add_inst(const dm_node_t *node, dm_inst_array_t *insts, int dynamic, int append);
/** Get instance values for the node
* @param[in] node node of instance
* @param[in] values values to store the result
* @return number of values found in case of success, or -1 in case of error
*/
int inode_buf_get_js_values(const dm_node_t *node, JSValue values[]);
/** find inode buffer according to node
* @param[in] node node of instance
* @param[in] retry can be retried or not
* @return pointer of inode_entry if found, otherwise NULL
*/
struct inode_entry *inode_buf_find(const dm_node_t *node, int *retry);
/** Free all the buffer
* @return none
*/
void inode_buf_free_all(void);
int inode_buf_append_db_inst(const dm_node_t *node, inst_entry_t *inst);
int inode_buf_del_db_inst(const dm_node_t *node);
int inode_buf_update_param_value(const dm_node_t *node, const char *value);
void inode_buf_dump(const dm_node_t *node);
#endif

View File

@@ -1,20 +0,0 @@
/*
* 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.
*
*/
#ifndef DMLOG_H
#define DMLOG_H
void dmlog_init(const char *name, int log_level);
void dmlog_info(const char *fmt, ...);
void dmlog_warn(const char *fmt, ...);
void dmlog_error(const char *fmt, ...);
void dmlog_debug(const char *fmt, ...);
void dmlog_close();
#endif /* DMLOG_H */

View File

@@ -1,50 +0,0 @@
/*
* QuickJS UCI helper public API
*
* Provides initialisation helpers for the shared libuci context used by
* qjs_uci_api.c as well as the QuickJS registration entry point.
*/
#ifndef QJS_UCI_API_H
#define QJS_UCI_API_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* Initialise the shared libuci context.
* Safe to call multiple times subsequent calls are no-ops.
* Returns 0 on success, -1 on failure.
*/
int qjs_uci_global_init(void);
/* Set the directory where libuci stores pending changes (may be NULL). */
void qjs_uci_global_set_savedir(const char *save_dir);
/* Free the shared libuci context at shutdown (optional). */
void qjs_uci_global_cleanup(void);
/* Register the _uci_call() C binding with QuickJS. */
int qjs_uci_api_init(void);
#include <json-c/json.h>
/* Simple name/value helper used by dm_uci_* helpers */
typedef struct {
const char *name;
const char *value;
} name_val_t;
int dm_uci_get(const char *uci_path, char **value);
int dm_uci_set(const char *uci_path, const char *value);
int dm_uci_add(const char *config, const char *type, const char *section_name, name_val_t *opt_values, int value_cnt);
int dm_uci_del(const char *config, const char *section);
int dm_uci_get_section_list(const char *config, const char *type, name_val_t *match, int match_cnt, struct json_object **res);
int dm_uci_commit(const char *config);
#ifdef __cplusplus
}
#endif
#endif /* QJS_UCI_API_H */

File diff suppressed because it is too large Load Diff

View File

@@ -1,55 +0,0 @@
/*
* 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.
*
*/
#ifndef QJS_H
#define QJS_H
#include <uci.h>
#include <json-c/json.h>
#include <quickjs/quickjs.h>
#include "dm_node.h"
int qjs_init(void);
void qjs_register_c_api(const char *name, JSCFunction func, int param_len);
int qjs_has_get_handler(dm_node_id_t id);
int qjs_has_set_handler(dm_node_id_t id);
int qjs_call_set_handler(const dm_node_t *node, const char *value);
int qjs_has_import_handler(dm_node_id_t id);
int qjs_has_apply_handler(dm_node_id_t id);
int qjs_has_changed_handler(dm_node_id_t id);
int qjs_has_info_handler(dm_node_id_t id);
int qjs_has_key_handler(dm_node_id_t id);
int qjs_call_get_handler(const dm_node_t *node, char **res);
int qjs_call_apply_param_handler(const dm_node_t *node, const char *value);
int qjs_call_apply_obj_handler(const dm_node_t *node, const dm_node_t *ext_node);
JSValue qjs_call_import_handler(const dm_node_t *node, JSValue values);
int qjs_call_operate_handler(const dm_node_t *node, const char *json_input, json_object **json_output);
JSValue qjs_call_get_instance_handler(const dm_node_t *node, int start_index);
int qjs_call_changed_handler(const dm_node_t *node);
int qjs_call_info_handler(const dm_node_t *node, JSValue obj);
int qjs_call_key_handler(const dm_node_t *node, char **res);
JSContext *qjs_ctx();
JSValue qjs_global();
int qjs_array_len(JSValue arr);
const char *get_js_value_str(JSValue value);
const char *qjs_get_property_str(JSValue obj, const char *prop_name);
void free_js_cstr(const char *str);
void qjs_log_exception();
JSValue qjs_eval_buf(const void *buf, int buf_len, const char *filename, int eval_flags);
JSValue json_object_to_jsvalue(json_object *json_obj);
int qjs_uci_filter(const dm_node_t *node, json_object *obj);
int qjs_call_event_handler(dm_node_id_t node_id, const char *ubus_json_msg, struct json_object **res);
int qjs_call_uci_init_handler(const dm_node_t *node);
int qjs_call_uci_deinit_handler(const dm_node_t *node, const char *uci_section);
#endif

View File

@@ -1,18 +0,0 @@
/*
* 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.
*
*/
#ifndef QJS_API_H
#define QJS_API_H
int qjs_dm_api_init(void);
int qjs_ubus_api_init(void);
int qjs_log_api_init(void);
#endif

View File

@@ -1,580 +0,0 @@
/*
* 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 <quickjs/quickjs-libc.h>
#include <quickjs/quickjs.h>
#include <string.h>
#include "dbmgr.h"
#include "dm_api.h"
#include "dm_apply.h"
#include "dm_log.h"
#include "dm_node.h"
#include "dm_types.h"
#include "qjs.h"
#include "qjs_api.h"
#include "inode_buf.h"
#include "dm_linker.h"
JSValue get_object(const dm_node_t *node, int only_db)
{
int i;
if (dm_node_is_parameter(node->id)) {
char *value = NULL;
if (only_db) {
if (dbmgr_get(node, &value) < 0 || value == NULL) {
dmlog_error("dbmgr_get failed to get param: %s", dm_node_str(node));
return JS_UNDEFINED;
}
} else {
if (dmapi_param_get(node, &value) < 0 || value == NULL) {
dmlog_error("dmapi_param_get failed to get param: %s", dm_node_str(node));
return JS_UNDEFINED;
}
}
JSValue param;
enum DM_DATA_TYPE type = dm_node_data_type(node->id);
if (dm_node_is_param_list(node->id)) {
param = JS_NewString(qjs_ctx(), value);
} else if (type == DM_DATA_BOOLEAN) {
if (strcmp(value, "1") == 0 || strcmp(value, "true") == 0) {
param = JS_NewBool(qjs_ctx(), 1);
} else {
param = JS_NewBool(qjs_ctx(), 0);
}
} else if (type == DM_DATA_INT) {
param = JS_NewInt32(qjs_ctx(), atoi(value));
} else if (type == DM_DATA_UINT || type == DM_DATA_ULONG) {
param = JS_NewUint32(qjs_ctx(), strtoul (value, NULL, 0));
} else {
param = JS_NewString(qjs_ctx(), value);
}
free(value);
return param;
} else if (dm_node_is_object(node->id) || (dm_node_is_objectlist(node->id) && dm_node_is_index_complete(node))) {
const struct dm_object *obj = dm_node_get_object(node->id);
JSValue obj_val = JS_NewObject(qjs_ctx());
for (i = 0; i < obj->param_num; i++) {
dm_node_t param_node = *node;
param_node.id = obj->param_list[i]->node_id;
if (only_db && !dm_node_has_db(param_node.id)) {
continue;
}
JSValue param_val = get_object(&param_node, only_db);
if (JS_IsException(param_val)) {
JS_FreeValue(qjs_ctx(), obj_val);
return JS_UNDEFINED;
} else {
JS_SetPropertyStr(qjs_ctx(), obj_val, obj->param_list[i]->name, param_val);
}
}
if (dm_node_is_objectlist(node->id)) {
JS_SetPropertyStr(qjs_ctx(), obj_val, ".index", JS_NewUint32(qjs_ctx(), node->index[node->cnt - 1]));
}
for (i = 0; i < obj->object_num; i++) {
dm_node_t obj_node = *node;
obj_node.id = obj->object_list[i]->node_id;
if (dm_node_is_objectlist(obj_node.id)
&& only_db && !dm_node_has_db(obj_node.id)) {
continue;
}
JSValue child_obj = get_object(&obj_node, only_db);
if (JS_IsUndefined(child_obj)) {
JS_FreeValue(qjs_ctx(), obj_val);
return JS_UNDEFINED;
} else {
JS_SetPropertyStr(qjs_ctx(), obj_val, obj->object_list[i]->name, child_obj);
}
}
return obj_val;
} else if (dm_node_is_objectlist(node->id)) {
dm_nodelist_h list = dm_nodelist_find(node, NULL, only_db);
JSValue arr = JS_NewArray(qjs_ctx());
// JS_SetPropertyStr(qjs_ctx(), res, node->name, arr);
for (i = 0; i < dm_nodelist_cnt(list); i++) {
const dm_node_t *n = dm_nodelist_node(list, i);
JSValue ins_val = get_object(n, only_db);
if (JS_IsUndefined(ins_val)) {
JS_FreeValue(qjs_ctx(), arr);
/* free node list before returning to avoid leak */
dm_nodelist_free(list);
return JS_UNDEFINED;
} else {
// add index into the objecct
// JS_SetPropertyStr(qjs_ctx(), ins_val, "index", JS_NewInt32(qjs_ctx(), n->index[n->cnt - 1]));
JS_DefinePropertyValueUint32(qjs_ctx(), arr, i, ins_val, JS_PROP_C_W_E);
}
}
dm_nodelist_free(list);
return arr;
} else {
dmlog_error("get_object, unknown node: %s", dm_node_str(node));
return JS_UNDEFINED;
}
}
static JSValue _dm_get(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
int only_db = 1;
dm_node_t node;
if (argc < 1) {
dmlog_info("_dm_get, missing argument");
return JS_UNDEFINED;
}
if (JS_IsString(argv[0])) {
const char *path = JS_ToCString(ctx, argv[0]);
if (dm_path2node(path, &node) < 0) {
dmlog_error("_dm_get, invalid pathname: %s", path);
JS_FreeCString(ctx, path);
return JS_UNDEFINED;
}
JS_FreeCString(ctx, path);
if (argc >= 2) {
only_db = JS_ToBool(ctx, argv[1]);
}
} else if (JS_IsNumber(argv[0])) {
JS_ToUint32(ctx, &node.id, argv[0]);
if (argc >= 2) {
if (JS_IsNumber(argv[1])) {
node.cnt = 1;
JS_ToUint32(ctx, &node.index[0], argv[1]);
} else if (JS_IsArray(ctx, argv[1])) {
JSValue length = JS_GetPropertyStr(ctx, argv[1], "length");
JS_ToInt32(ctx, &node.cnt , length);
JS_FreeValue(ctx, length);
for (unsigned int i = 0; i < node.cnt; i++) {
JSValue index_val = JS_GetPropertyUint32(ctx, argv[1], i);
JS_ToUint32(ctx, &node.index[i], index_val);
JS_FreeValue(ctx, index_val);
}
} else {
dmlog_error("_dm_get, invalid index");
return JS_UNDEFINED;
}
} else {
node.cnt = 0;
}
} else {
dmlog_error("_dm_get, invalid parameter");
return JS_UNDEFINED;
}
JSValue val = get_object(&node, only_db);
if (JS_IsException(val)) {
return JS_UNDEFINED;
}
return val;
}
static JSValue _set_param_value(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int only_db)
{
int ret = -1;
dm_node_t node;
if (argc < 2) {
dmlog_info("_dm_set, missing argument");
return JS_NewInt32(ctx, ret);
}
const char *value = NULL;
if (JS_IsString(argv[0])) {
const char *path = JS_ToCString(ctx, argv[0]);
if (dm_path2node(path, &node) < 0) {
dmlog_error("_dm_set, invalid pathname: %s", path);
JS_FreeCString(ctx, path);
return JS_NewInt32(ctx, ret);
}
JS_FreeCString(ctx, path);
value = JS_ToCString(ctx, argv[1]);
} else if (JS_IsNumber(argv[0])) {
JS_ToUint32(ctx, &node.id, argv[0]);
if (dm_node_index_cnt(node.id) > 0) {
if (JS_IsNumber(argv[1])) {
node.cnt = 1;
JS_ToUint32(ctx, &node.index[0], argv[1]);
} else if (JS_IsArray(ctx, argv[1])) {
JSValue length = JS_GetPropertyStr(ctx, argv[1], "length");
JS_ToInt32(ctx, &node.cnt , length);
JS_FreeValue(ctx, length);
for (unsigned int i = 0; i < node.cnt; i++) {
JSValue index_val = JS_GetPropertyUint32(ctx, argv[1], i);
JS_ToUint32(ctx, &node.index[i], index_val);
JS_FreeValue(ctx, index_val);
}
} else {
dmlog_error("_dm_get, invalid index");
return JS_NewInt32(ctx, ret);
}
value = JS_ToCString(ctx, argv[2]);
} else {
node.cnt = 0;
value = JS_ToCString(ctx, argv[1]);
}
} else {
dmlog_error("_dm_get, invalid parameter");
return JS_NewInt32(ctx, ret);
}
if (value != NULL) {
if (only_db) {
// dbmgr_tranx_begin();
ret = dbmgr_set(&node, value);
if (dm_node_index_cnt(node.id) > 0) {
ret |= inode_buf_update_param_value(&node, value);
}
// dbmgr_tranx_commit();
} else {
dmapi_param_set(&node, value);
}
JS_FreeCString(ctx, value);
} else {
dmlog_error("_dm_set, missing value");
return JS_NewInt32(ctx, -1);
}
return JS_NewInt32(ctx, ret);
}
static JSValue _db_set(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
return _set_param_value(ctx, this_val, argc, argv, 1);
}
static JSValue _dm_set(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
return _set_param_value(ctx, this_val, argc, argv, 0);
}
static JSValue _dm_node_id(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
dm_node_t node;
if (argc < 1 || !JS_IsString(argv[0])) {
dmlog_info("_dm_node_id, invalid argument");
return JS_UNDEFINED;
}
const char *path = JS_ToCString(ctx, argv[0]);
if (dm_path2node(path, &node) < 0) {
dmlog_info("_dm_node_id, invalid pathname: %s", path);
return JS_NewInt32(ctx, -1);
}
JS_FreeCString(ctx, path);
return JS_NewUint32(ctx, node.id);
}
static JSValue _dm_node(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
dm_node_t node;
if (argc < 1 || !JS_IsString(argv[0])) {
dmlog_info("_dm_node, invalid argument");
return JS_UNDEFINED;
}
JSValue arr = JS_NewArray(qjs_ctx());
const char *path = JS_ToCString(ctx, argv[0]);
if (dm_path2node(path, &node) < 0) {
dmlog_info("_dm_node, invalid pathname: %s", path);
JS_DefinePropertyValueUint32(qjs_ctx(), arr, 0, JS_NewInt32(ctx, -1), JS_PROP_C_W_E);
JS_DefinePropertyValueUint32(qjs_ctx(), arr, 1, JS_NewArray(qjs_ctx()), JS_PROP_C_W_E);
} else {
JS_DefinePropertyValueUint32(qjs_ctx(), arr, 0, JS_NewUint32(ctx, node.id), JS_PROP_C_W_E);
JSValue index_arr = JS_NewArray(qjs_ctx());
for (int i = 0; i < node.cnt; i++) {
JS_DefinePropertyValueUint32(qjs_ctx(), index_arr, i, JS_NewUint32(ctx, node.index[i]), JS_PROP_C_W_E);
}
JS_DefinePropertyValueUint32(qjs_ctx(), arr, 1, index_arr, JS_PROP_C_W_E);
}
JS_FreeCString(ctx, path);
return arr;
}
static JSValue _dm_instances(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
int only_db = 1;
dm_node_t node;
const char *keys = NULL;
if (argc < 1) {
dmlog_info("_dm_node, invalid argument");
return JS_UNDEFINED;
}
JSValue arr = JS_NewArray(qjs_ctx());
const char *path = JS_ToCString(ctx, argv[0]);
if (dm_path2node(path, &node) < 0) {
dmlog_info("_dm_node, invalid pathname: %s", path);
JS_FreeCString(ctx, path);
return arr;
}
JS_FreeCString(ctx, path);
if (argc >= 2 && JS_IsString(argv[1])) {
keys = JS_ToCString(ctx, argv[1]);
}
if (argc >= 3) {
only_db = JS_ToBool(ctx, argv[2]);
}
dm_nodelist_h list = dm_nodelist_find(&node, keys, only_db);
if (keys != NULL) {
JS_FreeCString(ctx, keys);
}
const dm_node_t *pnode = NULL;
int i = 0;
nodelist_for_each_node(pnode, list)
{
dm_path_t path;
dm_node2name(pnode, path, sizeof(path));
JS_DefinePropertyValueUint32(qjs_ctx(), arr, i++, JS_NewString(ctx, path), JS_PROP_C_W_E);
}
dm_nodelist_free(list);
return arr;
}
int update_dm_value(JSContext *ctx, const char *key, JSValue value)
{
if (JS_IsString(value) || JS_IsNumber(value) || JS_IsBool(value)) {
dm_node_t node;
if (dm_path2node(key, &node) < 0) {
dmlog_error("update_dm_value, invalid pathname: %s", key);
return -1;
}
if (!dm_node_is_parameter(node.id) || !dm_node_is_index_complete(&node)) {
dmlog_error("update_dm_value, unexpected parameter: %s", key);
return -1;
}
const char *value_str = JS_ToCString(ctx, value);
if (dm_node_is_bool_type(node.id)) {
if (*value_str == '1' || !strcmp(value_str, "true")) {
dmapi_param_set(&node, "true");
} else {
dmapi_param_set(&node, "false");
}
} else {
dmapi_param_set(&node, value_str);
}
JS_FreeCString(ctx, value_str);
} else if (JS_IsArray(ctx, value)) {
dm_node_t node;
if (dm_path2node(key, &node) < 0) {
dmlog_error("update_dm_value, invalid pathname: %s", key);
return -1;
}
// multi-instance node is expected.
if (!dm_node_is_objectlist(node.id)) {
dmlog_error("update_dm_value, unexpected multi-instance object: %s", key);
return -1;
}
uint32_t len;
JSValue length = JS_GetPropertyStr(ctx, value, "length");
JS_ToUint32(ctx, &len, length);
JS_FreeValue(ctx, length);
for (unsigned int i = 0; i < len; i++) {
if (dmapi_object_add(&node) < 0) {
dmlog_error("update_dm_value, failed to add instance %s", key);
return -1;
}
dm_path_t path;
dm_node2name(&node, path, sizeof(path));
strlcat(path, ".", sizeof(path));
// new path as the new key
JSValue inst_val = JS_GetPropertyUint32(ctx, value, i);
if (update_dm_value(ctx, path, inst_val) < 0) {
dmlog_error("update_dm_value, failed to update instance %s", path);
JS_FreeValue(ctx, inst_val);
return -1;
}
JS_FreeValue(ctx, inst_val);
}
} else if (JS_IsObject(value)) {
uint32_t len, i;
JSPropertyEnum *tab;
if (JS_GetOwnPropertyNames(ctx, &tab, &len, value,
JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0) {
dmlog_error("_dm_update, JS_GetOwnPropertyNames failed");
return -1;
}
for (i = 0; i < len; i++) {
JSValue child_val = JS_GetProperty(ctx, value, tab[i].atom);
const char *child_key = JS_AtomToCString(ctx, tab[i].atom);
char *new_key = NULL;
asprintf(&new_key, "%s%s", key, child_key);
update_dm_value(ctx, new_key, child_val);
free(new_key);
/* release converted atom string */
JS_FreeCString(ctx, child_key);
JS_FreeValue(ctx, child_val);
}
js_free(ctx, tab);
} else if (JS_IsUndefined(value)) {
dmlog_debug("update_dm_value, skip update value for %s", key);
}
return 0;
}
static JSValue _dm_update(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
if (argc < 2) {
dmlog_info("_dm_update, invalid argument");
return JS_UNDEFINED;
}
const char *path = JS_ToCString(ctx, argv[0]);
int ret = update_dm_value(ctx, path, argv[1]);
/* release path string allocated by QuickJS */
JS_FreeCString(ctx, path);
return JS_NewInt32(ctx, ret);
}
static JSValue _dm_apply(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
dm_node_t node;
if (argc < 1) {
dmlog_info("_dm_apply, missing argument");
return JS_UNDEFINED;
}
if (JS_IsString(argv[0])) {
const char *path = JS_ToCString(ctx, argv[0]);
if (dm_path2node(path, &node) < 0) {
dmlog_error("_dm_apply, invalid pathname: %s", path);
JS_FreeCString(ctx, path);
return JS_UNDEFINED;
}
JS_FreeCString(ctx, path);
} else if (JS_IsNumber(argv[0])) {
JS_ToUint32(ctx, &node.id, argv[0]);
if (argc >= 2) {
if (JS_IsNumber(argv[1])) {
node.cnt = 1;
JS_ToUint32(ctx, &node.index[0], argv[1]);
} else if (JS_IsArray(ctx, argv[1])) {
JSValue length = JS_GetPropertyStr(ctx, argv[1], "length");
JS_ToInt32(ctx, &node.cnt , length);
JS_FreeValue(ctx, length);
for (unsigned int i = 0; i < node.cnt; i++) {
JSValue index_val = JS_GetPropertyUint32(ctx, argv[1], i);
JS_ToUint32(ctx, &node.index[i], index_val);
JS_FreeValue(ctx, index_val);
}
} else {
dmlog_error("_dm_apply, invalid index");
return JS_UNDEFINED;
}
} else {
node.cnt = 0;
}
} else {
dmlog_error("_dm_apply, invalid parameter");
return JS_UNDEFINED;
}
struct node_change change;
change.node = node;
change.redirected = 0;
change.action = DATA_MODEL_SET;
dm_apply_node(&change);
return JS_NewInt32(ctx, 0);
}
static JSValue _dm_resolve(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
if (argc < 1 || !JS_IsString(argv[0])) {
dmlog_info("_dm_resolve, invalid argument");
return JS_UNDEFINED;
}
const char *path = JS_ToCString(ctx, argv[0]);
char *val = NULL;
if (dm_resolve_linker(path, &val) != 0 || val == NULL) {
JS_FreeCString(ctx, path);
return JS_UNDEFINED;
}
JSValue js_val = JS_NewString(ctx, val);
free(val);
JS_FreeCString(ctx, path);
return js_val;
}
static JSValue _dm_resolve_path(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
if (argc < 3 || !JS_IsString(argv[0]) || !JS_IsString(argv[1]) || !JS_IsString(argv[2])) {
dmlog_info("_dm_resolve_path, invalid argument");
return JS_UNDEFINED;
}
const char *base_path = JS_ToCString(ctx, argv[0]);
const char *key_name = JS_ToCString(ctx, argv[1]);
const char *key_value = JS_ToCString(ctx, argv[2]);
char *obj_path = NULL;
if (dm_resolve_linker_path(base_path, key_name, key_value, &obj_path) != 0 || obj_path == NULL) {
JS_FreeCString(ctx, base_path);
JS_FreeCString(ctx, key_name);
JS_FreeCString(ctx, key_value);
return JS_UNDEFINED;
}
JSValue js_val = JS_NewString(ctx, obj_path);
free(obj_path);
JS_FreeCString(ctx, base_path);
JS_FreeCString(ctx, key_name);
JS_FreeCString(ctx, key_value);
return js_val;
}
int qjs_dm_api_init()
{
qjs_register_c_api("_dm_get", _dm_get, 1);
qjs_register_c_api("_dm_set", _dm_set, 2);
qjs_register_c_api("_db_set", _db_set, 2);
qjs_register_c_api("_dm_node_id", _dm_node_id, 1);
qjs_register_c_api("_dm_node", _dm_node, 1);
qjs_register_c_api("_dm_instances", _dm_instances, 1);
qjs_register_c_api("_dm_update", _dm_update, 1);
qjs_register_c_api("_dm_apply", _dm_apply, 1);
qjs_register_c_api("_dm_linker_value", _dm_resolve, 1);
qjs_register_c_api("_dm_linker_path", _dm_resolve_path, 3);
return 0;
}

View File

@@ -1,70 +0,0 @@
/*
* 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 <quickjs/quickjs.h>
#include "dm_log.h"
#include "qjs.h"
#include "qjs_api.h"
enum LOG_TYPE {
QJS_LOG_INFO,
QJS_LOG_ERROR,
QJS_LOG_DEBUG
};
static JSValue _log(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, enum LOG_TYPE type)
{
// keep it simple at the moment: syslog for each parameter independently.
for (int i = 0; i < argc; i++) {
JSValue json = JS_JSONStringify(ctx, argv[i], JS_UNDEFINED, JS_UNDEFINED);
const char *msg = JS_ToCString(ctx, json);
if (type == QJS_LOG_INFO) {
dmlog_info(msg);
} else if (type == QJS_LOG_ERROR) {
dmlog_error(msg);
} else {
dmlog_debug(msg);
}
JS_FreeCString(ctx, msg);
JS_FreeValue(ctx, json);
}
return JS_UNDEFINED;
}
static JSValue _log_info(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
return _log(ctx, this_val, argc, argv, QJS_LOG_INFO);
}
static JSValue _log_error(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
return _log(ctx, this_val, argc, argv, QJS_LOG_ERROR);
}
static JSValue _log_debug(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
return _log(ctx, this_val, argc, argv, QJS_LOG_DEBUG);
}
int qjs_log_api_init()
{
qjs_register_c_api("_log_info", _log_info, 1);
qjs_register_c_api("_log_error", _log_error, 1);
qjs_register_c_api("_log_debug", _log_debug, 1);
return 0;
}

View File

@@ -1,267 +0,0 @@
/*
* 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 <json-c/json.h>
#include <quickjs/quickjs-libc.h>
#include <quickjs/quickjs.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "dm_log.h"
#include "qjs.h"
#include "qjs_api.h"
#include "ubus_client.h"
#include "dm_apply.h"
struct ubus_event_data {
struct uloop_timeout tm;
struct ubus_event_handler ev;
struct blob_attr *msg;
int res;
};
struct invoke_cb_arg {
JSContext *ctx;
JSValue res;
};
static void ubus_invoke_cb(struct ubus_request *req, int type, struct blob_attr *msg)
{
struct invoke_cb_arg *arg = (struct invoke_cb_arg *)req->priv;
if (!msg)
return;
char *json_str = blobmsg_format_json(msg, true);
if (json_str == NULL) {
dmlog_error("blobmsg_format_json failed");
return;
}
// dmlog_debug("ubus_invoke_cb: %s", json_str);
arg->res = JS_ParseJSON(arg->ctx, json_str, strlen(json_str), "ubus_invoke_cb");
if (JS_IsException(arg->res)) {
dmlog_error("JS_ParseJSON failed %s", json_str);
}
free(json_str);
}
static JSValue _ubus_call(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
int ret = -1;
const char *path = JS_ToCString(ctx, argv[0]);
const char *method = JS_ToCString(ctx, argv[1]);
struct invoke_cb_arg arg;
arg.ctx = ctx;
arg.res = JS_UNDEFINED;
// dmlog_debug("ubus %s: %s, argc: %d", path, method, argc);
if (argc > 2) {
struct blob_buf bb = {};
if (!JS_IsObject(argv[2])) {
dmlog_error("_ubus_call, object is expected as ubus arguments");
goto end;
}
JSValue json = JS_JSONStringify(ctx, argv[2], JS_UNDEFINED, JS_UNDEFINED);
if (JS_IsException(json)) {
dmlog_error("JS_ParseJSON failed");
goto end;
}
blob_buf_init(&bb, 0);
const char *str = JS_ToCString(ctx, json);
if (!blobmsg_add_json_from_string(&bb, str)) {
dmlog_error("blobmsg_add_json_from_string failed");
JS_FreeCString(ctx, str);
JS_FreeValue(ctx, json);
goto end;
}
ret = ubus_client_call(path, method, bb.head, ubus_invoke_cb, &arg);
blob_buf_free(&bb);
if (strcmp(path, "uci") == 0 &&
(strcmp(method, "set") == 0 || strcmp(method, "add") == 0 || strcmp(method, "delete") == 0)) {
dmlog_debug("ubus uci %s: args: %s", method, str);
if (ret == 0) {
JSValue val = JS_GetPropertyStr(ctx, argv[2], "config");
if (JS_IsString(val)) {
const char *config = JS_ToCString(ctx, val);
add_apply_package(strdup(config));
JS_FreeCString(ctx, config);
}
JS_FreeValue(ctx, val);
}
}
JS_FreeCString(ctx, str);
JS_FreeValue(ctx, json);
} else {
ret = ubus_client_call(path, method, NULL, ubus_invoke_cb, &arg);
}
if (ret != 0 || JS_IsException(arg.res)) {
ret = -1;
}
end:
JS_FreeCString(ctx, path);
JS_FreeCString(ctx, method);
JSValue arr = JS_NewArray(ctx);
JS_SetPropertyUint32(ctx, arr, 0, JS_NewInt32(ctx, ret));
JS_SetPropertyUint32(ctx, arr, 1, arg.res);
return arr;
}
static void ubus_listen_timeout(struct uloop_timeout *timeout)
{
uloop_end();
}
static bool compare_blob_msg(struct blob_attr *src_attr, struct blob_attr *dst_attr)
{
if (!src_attr || !dst_attr)
return false;
int src_type = blob_id(src_attr);
int dst_type = blob_id(dst_attr);
if (src_type != dst_type)
return false;
void *src_val = blobmsg_data(src_attr);
void *dst_val = blobmsg_data(dst_attr);
switch (src_type) {
case BLOBMSG_TYPE_STRING:
if (src_val == NULL && dst_val == NULL)
return true;
if (src_val && dst_val && strcmp((char *)src_val, (char*)dst_val) == 0)
return true;
break;
default:
break;
}
return false;
}
static bool validate_blob_message(struct blob_attr *src, struct blob_attr *dst)
{
if (!src || !dst)
return false;
size_t src_len = (size_t)blobmsg_data_len(src);
size_t dst_len = (size_t)blobmsg_data_len(dst);
if (dst_len < src_len)
return false;
bool res = true;
struct blob_attr *src_attr, *dst_attr;
__blob_for_each_attr(src_attr, blobmsg_data(src), src_len) {
bool matched = false;
__blob_for_each_attr(dst_attr, blobmsg_data(dst), dst_len) {
if (strcmp(blobmsg_name(src_attr), blobmsg_name(dst_attr)) != 0) {
continue;
}
matched = compare_blob_msg(src_attr, dst_attr);
break;
}
if (matched == false) {
res = false;
break;
}
}
return res;
}
static void ubus_receive_event(struct ubus_context *ctx, struct ubus_event_handler *ev,
const char *type, struct blob_attr *msg)
{
struct ubus_event_data *data;
if (!msg || !ev)
return;
data = container_of(ev, struct ubus_event_data, ev);
// skip the check if the content of event to check (data->msg) is empty.
if (data->msg == NULL || validate_blob_message(data->msg, msg) == true) {
data->res = 0;
uloop_end();
}
return;
}
static JSValue _ubus_wait_event(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
if (argc < 2) {
dmlog_info("_ubus_wait_event, missing argument");
return JS_NewInt32(ctx, -1);
}
unsigned int timeout = 100;
struct blob_attr *msg = NULL;
JS_ToUint32(ctx, &timeout, argv[1]);
struct blob_buf b;
memset(&b, 0, sizeof(b));
struct ubus_context *ubus_ctx = ubus_connect(NULL);
if (!ubus_ctx) {
return JS_NewInt32(ctx, -1);
}
const char *event = JS_ToCString(ctx, argv[0]);
blob_buf_init(&b, 0);
if (argc > 2) {
JSValue json_val = JS_JSONStringify(ctx, argv[2], JS_UNDEFINED, JS_UNDEFINED);
const char *json_str = JS_ToCString(ctx, json_val);
blobmsg_add_json_from_string(&b, json_str);
JS_FreeCString(ctx, json_str);
msg = b.head;
}
struct ubus_event_data data = {
.tm.cb = ubus_listen_timeout,
.ev.cb = ubus_receive_event,
.msg = msg,
.res = -1,
};
uloop_init();
ubus_add_uloop(ubus_ctx);
if (ubus_register_event_handler(ubus_ctx, &data.ev, event) == 0) {
uloop_timeout_set(&data.tm, timeout * 1000);
uloop_run();
uloop_done();
ubus_unregister_event_handler(ubus_ctx, &data.ev);
} else {
dmlog_error("_ubus_wait_event, failed to register event");
}
JS_FreeCString(ctx, event);
blob_buf_free(&b);
ubus_free(ubus_ctx);
return JS_NewInt32(ctx, data.res);
}
int qjs_ubus_api_init()
{
ubus_client_init();
qjs_register_c_api("_ubus_call", _ubus_call, 2);
qjs_register_c_api("_ubus_wait_event", _ubus_wait_event, 2);
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,157 +0,0 @@
/*
* 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 <string.h>
#include <stdlib.h>
#include "dm_list.h"
#include "dm_log.h"
#define DEFAULT_LIST_BUF_SIZE 128
#define MAX_LIST_BUF_SIZE 1024 * 256
struct dm_list {
unsigned int cnt;
unsigned int buf_size;
void **mem_ptr;
list_item_cmp cmp;
};
// default compare for string.
static int list_str_cmp(const void *item1, const void *item2)
{
if (strcmp((const char*)item1, (const char*)item2) == 0) {
return 0;
}
return 1;
}
dm_list_h dm_list_create(list_item_cmp cmp_cb)
{
struct dm_list *list = calloc(1, sizeof(struct dm_list));
if (list == NULL)
return NULL;
if (cmp_cb == NULL) {
list->cmp = list_str_cmp;
} else {
list->cmp = cmp_cb;
}
return (dm_list_h)list;
}
int dm_list_append(dm_list_h list, void *item)
{
if (list == NULL)
return -1;
if (list->buf_size == 0) {
list->buf_size = DEFAULT_LIST_BUF_SIZE;
list->mem_ptr = (void **)calloc(DEFAULT_LIST_BUF_SIZE, sizeof(void *));
if (list->mem_ptr == NULL)
return -1;
} else if (list->buf_size <= list->cnt) {
// Check if the memory required to allocate is not out of bounds.
if (list->buf_size > MAX_LIST_BUF_SIZE / 2)
return -1;
else {
// double buffer
void *new_mem = realloc((void *)list->mem_ptr, 2 * (list->buf_size) * sizeof(void *));
if (new_mem == NULL)
return -1;
list->buf_size *= 2;
list->mem_ptr = (void **)new_mem;
}
}
list->mem_ptr[list->cnt] = item;
list->cnt++;
return 0;
}
int dm_list_cnt(dm_list_h list)
{
if (list == NULL)
return 0;
return list->cnt;
}
void *dm_list_get(dm_list_h list, int i)
{
if (list == NULL || i >= list->cnt)
return NULL;
return list->mem_ptr[i];
}
int dm_list_contains(dm_list_h list, const void *item)
{
int cnt = dm_list_cnt(list);
for (int i = 0; i < cnt; i++) {
void *val = dm_list_get(list, i);
if (val && list->cmp(val, item) == 0) {
return 1;
}
}
return 0;
}
int dm_list_remove(dm_list_h list, void *item)
{
int cnt = dm_list_cnt(list);
for (int i = 0; i < cnt; i++) {
void *val = dm_list_get(list, i);
if (val && list->cmp(val, item) == 0) {
free(val);
list->mem_ptr[i] = NULL;
return 0;
}
}
return -1;
}
void dm_list_free(dm_list_h list)
{
if (list == NULL)
return;
int i;
for (i = 0; i < list->cnt; i++)
if (list->mem_ptr[i])
free(list->mem_ptr[i]);
if (list->mem_ptr)
free(list->mem_ptr);
free(list);
}
void dm_list_dump(dm_list_h list)
{
int cnt = dm_list_cnt(list);
for (int i = 0; i < cnt; i++) {
char *val = dm_list_get(list, i);
if (val) {
dmlog_debug("dm-list val: %s", val);
}
}
}

View File

@@ -1,77 +0,0 @@
/*
* 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.
*
*/
#ifndef DM_LIST_H
#define DM_LIST_H
struct dm_list;
typedef struct dm_list *dm_list_h;
// return 0 if equal, otherwise 1
typedef int (*list_item_cmp)(const void *item1, const void *item2);
/**
* Create a list
* @param cmp_cb item compare callback (optional if dm_list_contains will not be called)
* @return a valid handle if successful, otherwise return NULL
*/
dm_list_h dm_list_create(list_item_cmp cmp_cb);
/**
* Append an item to the list
* @param list handle create by dm_list_create
* @item pointer of item, the memory must be allocated by user using malloc.
* memory of item will be not free'd until dm_list_free or dm_list_del(not implemented yet) is called.
* @return 0 if successful, otherwise return -1
*/
int dm_list_append(dm_list_h list, void *item);
/**
* Get count of items in the list
* @param list handle create by dm_list_create
* @return number of items
*/
int dm_list_cnt(dm_list_h list);
/**
* Get item in the list by index
* @param list handle create by dm_list_create
* @param i, index of item to get, valid scope is [0, cnt-1]
* @return pointer of item if index is valid, otherwise return NULL
*/
void *dm_list_get(dm_list_h list, int i);
/**
* check if a item is already in the list
* @param list handle create by dm_list_create
* @param item, item to check
* @return 1 if exist, otherwise return 0
*/
int dm_list_contains(dm_list_h list, const void *item);
/**
* remove a item from the list
* @param list handle create by dm_list_create
* @param item, item to remove
* @return 0 if successful, otherwise return -1
*/
int dm_list_remove(dm_list_h list, void *item);
/**
* Free the list, including all items in the list
* @param list handle create by dm_list_create
* @return none
*/
void dm_list_free(dm_list_h list);
// only works when the value is string type
void dm_list_dump(dm_list_h list);
#endif

View File

@@ -1,54 +0,0 @@
/*
* 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 <dm_log.h>
#include <stdarg.h>
#include <stdio.h>
#include <syslog.h>
void dmlog_init(const char *name, int log_level)
{
// todo : implement the filter level
openlog(name, LOG_NOWAIT | LOG_ODELAY, LOG_LOCAL0);
}
void dmlog_info(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsyslog(LOG_INFO, fmt, ap);
va_end(ap);
}
void dmlog_warn(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsyslog(LOG_WARNING, fmt, ap);
va_end(ap);
}
void dmlog_error(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsyslog(LOG_ERR, fmt, ap);
va_end(ap);
}
void dmlog_debug(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsyslog(LOG_DEBUG, fmt, ap);
va_end(ap);
}
void dmlog_close()
{
closelog();
}

View File

@@ -1,45 +0,0 @@
/*
* 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 "ubus_client.h"
#include "dm_log.h"
#define DEFAULT_UBUS_TIMEOUT 10000 // in ms
static struct ubus_context *ubus_ctx_g = NULL;
void ubus_client_init()
{
ubus_ctx_g = ubus_connect(NULL);
}
int ubus_client_call(const char *path, const char *method, struct blob_attr *msg,
ubus_data_handler_t cb, void *priv)
{
uint32_t id;
if (ubus_lookup_id(ubus_ctx_g, path, &id)) {
// dmlog_error("ubus_lookup_id failed, object:%s", path);
return -1;
}
int ret = ubus_invoke(ubus_ctx_g, id, method, msg, cb, priv, DEFAULT_UBUS_TIMEOUT);
if (ret != 0) {
dmlog_error("ubus_invoke failed: object:%s, method:%s, %d", path, method, ret);
if (msg) {
char *json_str = blobmsg_format_json(msg, true);
dmlog_error("ubus_invoke mesg: %s", json_str);
free(json_str);
}
return -1;
}
return 0;
}

View File

@@ -1,21 +0,0 @@
/*
* 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.
*
*/
#ifndef UBUS_CLIENT_H
#define UBUS_CLIENT_H
#include <libubox/blobmsg_json.h>
#include <libubus.h>
#include <json-c/json.h>
void ubus_client_init();
int ubus_client_call(const char *path, const char *method, struct blob_attr *msg,
ubus_data_handler_t cb, void *priv);
#endif

View File

@@ -1,84 +0,0 @@
/*
* 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 <sys/types.h>
#include <sys/time.h>
#include <stdint.h>
#include <time.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <unistd.h>
#include "utils.h"
#include "dm_log.h"
int copy_file(const char *source, const char *dest)
{
int source_fd = open(source, O_RDONLY, 0);
if (source_fd < 0) {
dmlog_error("%s, failed to open %s", __FUNCTION__, source);
return -1;
}
struct stat stat_source;
if (fstat(source_fd, &stat_source) < 0) {
close(source_fd);
dmlog_error("%s, failed to fstat %s", __FUNCTION__, source);
return -1;
}
int dest_fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (dest_fd < 0) {
close(source_fd);
dmlog_error("%s, failed to open %s", __FUNCTION__, dest);
return -1;
}
ssize_t ret = sendfile(dest_fd, source_fd, 0, stat_source.st_size);
if (ret != stat_source.st_size) {
close(source_fd);
close(dest_fd);
remove(dest);
dmlog_error("%s, failed to sendfile from %s to %s", __FUNCTION__, source, dest);
return -1;
}
if (0 != fsync(dest_fd)) {
dmlog_error("%s, fsync fails", __FUNCTION__);
close(source_fd);
close(dest_fd);
remove(dest);
return -1;
}
sync();
close(source_fd);
close(dest_fd);
return 0;
}
unsigned int get_uptime_msecs(void)
{
time_t t;
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
t = ((time_t)(ts.tv_sec * 1000) + (time_t)(ts.tv_nsec / 1000000));
return (uint32_t)t;
}

View File

@@ -1,17 +0,0 @@
/*
* 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.
*
*/
#ifndef UTILS_H
#define UTILS_H
int copy_file(const char *source, const char *dest);
unsigned int get_uptime_msecs(void);
#endif

View File

@@ -8,13 +8,13 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=dslmngr
PKG_VERSION:=1.2.9
PKG_VERSION:=1.2.10
LOCAL_DEV=0
ifneq ($(LOCAL_DEV),1)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://dev.iopsys.eu/hal/dslmngr.git
PKG_SOURCE_VERSION:=5340cb31f759301f5aca3fd848fc3a63b0b4663f
PKG_SOURCE_VERSION:=8fb4093b4d26b3cb06603e110d424005e33cf5d6
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
PKG_MAINTAINER:=Rahul Thakur <rahul.thakur@iopsys.eu>
PKG_MIRROR_HASH:=skip

View File

@@ -5,6 +5,8 @@ source "/lib/functions/network.sh"
source "/lib/functions/system.sh"
PREVLINK=""
LINK=""
LINKSPEED=""
PREVWANMODE=""
WANMODE=""
CONFIGURED=0
@@ -60,7 +62,7 @@ create_atm_devices() {
}
configure_line() {
local mode profile bitswap sra us0 sesdrop sos ginp mod prof
local mode profile bitswap sra us0 sesdrop sos roc ginp gvector mod prof
local adsl1_flag=0 issue2_flag=0 Glite_flag=0 adsl2_flag=0 adsl2p_flag=0 vdsl2_flag=0
local pro_8a_flag=0 pro_8b_flag=0 pro_8c_flag=0 pro_8d_flag=0 pro_12a_flag=0 pro_12b_flag=0 pro_17a_flag=0 pro_30a_flag=0 pro_35b_flag=0
@@ -70,8 +72,9 @@ configure_line() {
config_get sra $1 sra "1"
config_get us0 $1 us0 "1"
config_get sos $1 sos "0"
config_get sos $1 roc "0"
config_get sos $1 ginp "0"
config_get roc $1 roc "0"
config_get ginp $1 ginp "1"
config_get gvector $1 gvector "1"
for mod in $mode; do
[ "$mod" = "gdmt" ] && adsl1_flag=1
@@ -96,6 +99,7 @@ configure_line() {
/userfs/bin/blapi_cmd xdsl set_adsl_profile "$pro_8a_flag" "$pro_8b_flag" "$pro_8c_flag" "$pro_8d_flag" "$pro_12a_flag" "$pro_12b_flag" "$pro_17a_flag" "$pro_30a_flag" "$pro_35b_flag"
/userfs/bin/blapi_cmd xdsl set_adsl_mode "$adsl1_flag" "$issue2_flag" "$Glite_flag" "$adsl2_flag" "$adsl2p_flag" "$vdsl2_flag"
/userfs/bin/blapi_cmd xdsl set_adsl_gvector "$((!gvector))"
/userfs/bin/blapi_cmd xdsl set_adsl_ginp "$((!ginp))"
/userfs/bin/blapi_cmd xdsl set_adsl_sos_roc "$((!sos))" "$((!roc))"
/userfs/bin/blapi_cmd xdsl set_adsl_us0 "$((!us0))"
@@ -148,6 +152,12 @@ while [ true ]; do
if [ "$LINK" != "$PREVLINK" -a \( "$LINK" = "down" -o "$LINK" = "up" \) ]; then
if [ "$LINK" = "down" ]; then
if [ ! -s /tmp/qos/wan_link_shape_rate ]; then
rm -rf /tmp/qos/wan_link_shape_rate
rm -rf /tmp/qos/wan_link_speed
/usr/sbin/qos-uplink-bandwidth
fi
[ "$CONFIGURED" -eq 0 ] && configure_lines # Needs to be done once the slave SoC is in down state and we've not been able to auto-sync.
if [ -n "$WANMODE" ]; then
if [ "$WANMODE" = "PTM" ]; then
@@ -224,6 +234,26 @@ while [ true ]; do
call_wan_hotplug "up" "$WANPORT"
PREVWANMODE="$WANMODE"
if [ ! -s /tmp/qos/wan_link_shape_rate ]; then
LINKSPEED="$(awk '/far-end interleaved channel bit rate/{print $6}' /proc/tc3162/adsl_stats)"
LINKSPEED=$((LINKSPEED))
if [ "$LINKSPEED" -eq 0 ]; then
LINKSPEED="$(awk '/far-end fast channel bit rate/{print $6}' /proc/tc3162/adsl_stats)"
LINKSPEED=$((LINKSPEED))
fi
if [ "$LINKSPEED" -ne 0 ]; then
mkdir -p /tmp/qos
touch /tmp/qos/wan_link_shape_rate
/userfs/bin/qosrule discpline Rate uplink-bandwidth ${LINKSPEED}
hw_nat -! > /dev/null 2>&1
else
rm -rf /tmp/qos/wan_link_speed
/usr/sbin/qos-uplink-bandwidth
fi
fi
fi
# Toggle link state

View File

@@ -5,13 +5,13 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=ethmngr
PKG_VERSION:=3.0.8
PKG_VERSION:=3.1.3
LOCAL_DEV:=0
ifneq ($(LOCAL_DEV),1)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://dev.iopsys.eu/hal/ethmngr.git
PKG_SOURCE_VERSION:=c73e5b15718ca40b2740bbe6151dfbb2bcca16df
PKG_SOURCE_VERSION:=7bc8297e1a74adb522f7635bab4f93a1a2620216
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)_$(PKG_SOURCE_VERSION).tar.xz
PKG_MIRROR_HASH:=skip
endif

View File

@@ -10,19 +10,14 @@ PKG_NAME:=fdtextract
PKG_RELEASE:=1
PKG_VERSION:=1.0
PKG_SOURCE_URL:=https://dev.iopsys.eu/iopsys/fdtextract.git
PKG_SOURCE_URL:=https://dev.iopsys.eu/system/fdtextract.git
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=e3cefda3b26c9aea3021b20725ce7b31b33eebc4
PKG_SOURCE_VERSION:=7917dbcb29724476cd46164eec29848df1e5fb67
PKG_MIRROR_HASH:=skip
PKG_LICENSE:=GPLv2
PKG_LICENSE_FILES:=LICENSE
RSTRIP:=true
export BUILD_DIR
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
PKG_BUILD_PARALLEL:=1
@@ -40,9 +35,7 @@ endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/fdtextract $(1)/usr/sbin/
$(STRIP) $(1)/usr/sbin/fdtextract
endef
$(eval $(call BuildPackage,$(PKG_NAME)))

View File

@@ -5,13 +5,13 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=firewallmngr
PKG_VERSION:=1.0.9
PKG_VERSION:=1.0.10
LOCAL_DEV:=0
ifneq ($(LOCAL_DEV),1)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://dev.iopsys.eu/network/firewallmngr.git
PKG_SOURCE_VERSION:=77ad8425b73a3ac63f6160dc217635394ac87907
PKG_SOURCE_VERSION:=05ad0d6f7f21520eecd05429c14d1963de2a8463
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
PKG_MIRROR_HASH:=skip
endif

View File

@@ -5,15 +5,16 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=fluent-bit
PKG_VERSION:=4.0.2
PKG_VERSION:=4.0.4
PKG_RELEASE:=$(AUTORELEASE)
LOCAL_DEV:=0
ifneq ($(LOCAL_DEV),1)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/fluent/fluent-bit.git
PKG_SOURCE_VERSION=v$(PKG_VERSION)
PKG_SOURCE:=$(PKG_NAME)-v$(PKG_VERSION).tar.gz
PKG_SOURCE_URL_FILE:=v$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://github.com/fluent/fluent-bit/archive/refs/tags/
PKG_HASH:=aa0577ba7251081c8d5398b2a905b5b0585bb657ca13b39a5e12931437516f08
PKG_MIRROR_HASH:=skip
endif
PKG_LICENSE:=Apache-2.0
@@ -65,9 +66,9 @@ CMAKE_OPTIONS += \
-DFLB_IN_DISK=Yes \
-DFLB_IN_EXEC=Yes \
-DFLB_IN_HEAD=Yes \
-DFLB_IN_KMSG=Yes \
-DFLB_IN_TAIL=Yes \
-DFLB_IN_FORWARD=No \
-DFLB_IN_KMSG=No \
-DFLB_IN_PROC=No \
-DFLB_IN_RANDOM=No \
-DFLB_IN_SERIAL=No \

View File

@@ -9,6 +9,10 @@
tag syslog
path /dev/log
[INPUT]
name kmsg
tag kernel
[OUTPUT]
name null
match *

View File

@@ -1,45 +0,0 @@
diff --git a/plugins/out_file/file.c b/plugins/out_file/file.c
index 2e47c9666..95d28e438 100644
--- a/plugins/out_file/file.c
+++ b/plugins/out_file/file.c
@@ -27,6 +27,7 @@
#include <msgpack.h>
#include <stdio.h>
+#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -55,6 +56,7 @@ struct flb_file_conf {
int csv_column_names;
int mkdir;
struct flb_output_instance *ins;
+ char hostname[256];
};
static char *check_delimiter(const char *str)
@@ -141,6 +143,9 @@ static int cb_file_init(struct flb_output_instance *ins,
}
}
+ if (gethostname(ctx->hostname, sizeof(ctx->hostname)) != 0)
+ snprintf(ctx->hostname, sizeof(ctx->hostname), "%s", "localhost");
+
tmp = flb_output_get_property("delimiter", ins);
ret_str = check_delimiter(tmp);
if (ret_str != NULL) {
@@ -233,12 +238,8 @@ static int template_output_write(struct flb_file_conf *ctx,
int i;
msgpack_object_kv *kv;
- /*
- * Right now we treat "{time}" specially and fill the placeholder
- * with the metadata timestamp (formatted as float).
- */
- if (!strncmp(key, "time", size)) {
- fprintf(fp, "%f", flb_time_to_double(tm));
+ if (!strncmp(key, "hostname", size)) {
+ fprintf(fp, "%s", ctx->hostname);
return 0;
}

View File

@@ -0,0 +1,27 @@
diff --git a/plugins/out_file/file.c b/plugins/out_file/file.c
index 77baf6be8..04c519d5a 100644
--- a/plugins/out_file/file.c
+++ b/plugins/out_file/file.c
@@ -238,10 +238,20 @@ static int template_output_write(struct flb_file_conf *ctx,
/*
* Right now we treat "{time}" specially and fill the placeholder
- * with the metadata timestamp (formatted as float).
+ * with the metadata timestamp.
*/
if (!strncmp(key, "time", size)) {
- fprintf(fp, "%f", flb_time_to_double(tm));
+ struct tm tm_local;
+ char buf[32];
+ if (localtime_r(&tm->tm.tv_sec, &tm_local) == NULL) {
+ flb_plg_error(ctx->ins, "localtime_r failed");
+ return -1;
+ }
+ if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", &tm_local) == 0) {
+ flb_plg_error(ctx->ins, "strftime failed");
+ return -1;
+ }
+ fputs(buf, fp);
return 0;
}

View File

@@ -0,0 +1,73 @@
diff --git a/plugins/in_kmsg/in_kmsg.c b/plugins/in_kmsg/in_kmsg.c
index cd5c4cd17..15f105451 100644
--- a/plugins/in_kmsg/in_kmsg.c
+++ b/plugins/in_kmsg/in_kmsg.c
@@ -36,7 +36,6 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <inttypes.h>
-#include <time.h>
#include "in_kmsg.h"
@@ -123,12 +122,17 @@ static inline int process_line(const char *line,
ctx->buffer_id++;
errno = 0;
- val = strtol(p, &end, 10);
- if ((errno == ERANGE && (val == INT_MAX || val == INT_MIN))
+ val = strtoul(p, &end, 10);
+ if ((errno == ERANGE && val == ULONG_MAX)
|| (errno != 0 && val == 0)) {
goto fail;
}
+ /* ensure something was consumed */
+ if (end == p) {
+ goto fail;
+ }
+
/* Priority */
priority = FLB_KLOG_PRI(val);
@@ -144,24 +148,35 @@ static inline int process_line(const char *line,
}
p++;
- val = strtoul(p, &end, 10);
- if ((errno == ERANGE && (val == INT_MAX || val == INT_MIN))
+ val = strtoull(p, &end, 10);
+ if ((errno == ERANGE && val == ULLONG_MAX)
|| (errno != 0 && val == 0)) {
goto fail;
}
+ /* make sure strtoull consumed something */
+ /* after the sequence number, the next char must be ',' */
+ if (end == p || *end != ',') {
+ goto fail;
+ }
+
sequence = val;
p = ++end;
/* Timestamp */
- val = strtoul(p, &end, 10);
- if ((errno == ERANGE && (val == INT_MAX || val == INT_MIN))
+ val = strtoull(p, &end, 10);
+ if ((errno == ERANGE && val == ULLONG_MAX)
|| (errno != 0 && val == 0)) {
goto fail;
}
+ /* ensure something was consumed */
+ if (end == p) {
+ goto fail;
+ }
+
tv.tv_sec = val/1000000;
- tv.tv_usec = val - (tv.tv_sec * 1000000);
+ tv.tv_usec = val - ((uint64_t)tv.tv_sec * 1000000);
flb_time_set(&ts, ctx->boot_time.tv_sec + tv.tv_sec, tv.tv_usec * 1000);

View File

@@ -40,22 +40,22 @@ get_vivsoi() {
#hex-string 2 character=1 Byte
# length in hex string will be twice of actual Byte length
[ "$len" -gt "8" ] || return
[ "${len}" -gt 8 ] || return
data="${opt125}"
rem_len="${len}"
while [ $rem_len -gt 0 ]; do
while [ "${rem_len}" -gt 0 ]; do
ent_id=${data:0:8}
ent_id=$(printf "%d\n" "0x$ent_id")
if [ $ent_id -ne 3561 ]; then
if [ "${ent_id}" -ne 3561 ]; then
len_val=${data:8:2}
data_len=$(printf "%d\n" "0x$len_val")
# add 4 byte for ent_id and 1 byte for len
data_len=$(( data_len * 2 + 10 ))
# move ahead data to next enterprise id
data=${data:"${data_len}":"${rem_len}"}
rem_len=$(( rem_len - $data_len ))
rem_len=$(( rem_len - data_len ))
continue
fi
@@ -66,7 +66,7 @@ get_vivsoi() {
data_len=$(( data_len * 2 + 10 ))
opt_len=$(printf "%d\n" "0x$len_val")
[ $opt_len -eq 0 ] && return
[ "${opt_len}" -eq 0 ] && return
# populate the option data of enterprise id
sub_data_len=$(( opt_len * 2))
@@ -74,7 +74,7 @@ get_vivsoi() {
sub_data=${data:10:"${sub_data_len}"}
# parsing of suboption of option 125
while [ $sub_data_len -gt 0 ]; do
while [ "${sub_data_len}" -gt 0 ]; do
# get the suboption id
sub_opt_id=${sub_data:0:2}
sub_opt_id=$(printf "%d\n" "0x$sub_opt_id")
@@ -85,20 +85,20 @@ get_vivsoi() {
sub_opt_len=$(( sub_opt_len * 2 ))
# get the value of sub option starting 4 means starting after length
sub_opt_val=${sub_data:4:${sub_opt_len}}
sub_opt_val=${sub_data:4:"${sub_opt_len}"}
# assign the value found in sub option
case "${sub_opt_id}" in
"4")
OUI=$(echo -n $sub_opt_val | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf && echo '')
OUI=$(echo -n "${sub_opt_val}" | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf && echo '')
GW_DISCOVERED=1
;;
"5")
SERIAL=$(echo -n $sub_opt_val | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf && echo '')
SERIAL=$(echo -n "${sub_opt_val}" | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf && echo '')
GW_DISCOVERED=1
;;
"6")
CLASS=$(echo -n $sub_opt_val | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf && echo '')
CLASS=$(echo -n "${sub_opt_val}" | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf && echo '')
GW_DISCOVERED=1
;;
esac
@@ -110,7 +110,7 @@ get_vivsoi() {
sub_data_len=$((sub_data_len - sub_opt_end))
# fetch next sub option hex string
sub_data=${sub_data:${sub_opt_end}:${sub_data_len}}
sub_data=${sub_data:"${sub_opt_end}":"${sub_data_len}"}
done
# move ahead data to next enterprise id
@@ -131,15 +131,13 @@ send_host_query() {
sleep 5
json_load "$(ubus call umdns browse)"
json_select discovered_services
if [ "${?}" -ne 0 ]; then
if ! json_select discovered_services; then
json_cleanup
loop=$(( loop - 1 ))
continue
fi
json_select _usp-agt-mqtt._tcp
if [ "${?}" -ne 0 ]; then
if ! json_select _usp-agt-mqtt._tcp; then
json_cleanup
loop=$(( loop - 1 ))
continue
@@ -156,7 +154,7 @@ send_host_query() {
json_get_keys keys
for key in $keys; do
json_select $key
json_select "${key}"
json_get_var _host host ""
if [ -z "${_host}" ] || [[ "${sent_host}" =~ " ${_host}" ]]; then
@@ -166,9 +164,10 @@ send_host_query() {
sent_host="${sent_host} ${_host}"
cmd="ubus call umdns query '{\"question\":\"$_host\",\"interface\":\"$intf\"}'"
eval $cmd
sh -c "${cmd}"
resp=0
json_select ..
sleep 2 # umdns query sometime takes time to resolve so adding some sleep
done
json_cleanup
@@ -185,32 +184,29 @@ get_usp_agent_id() {
fi
json_load "$(ubus call umdns browse)"
json_select discovered_services
if [ "${?}" -ne 0 ]; then
if ! json_select discovered_services; then
json_cleanup
echo ${ID}
echo "${ID}"
return 0
fi
json_select _usp-agt-mqtt._tcp
if [ "${?}" -ne 0 ]; then
if ! json_select _usp-agt-mqtt._tcp; then
json_cleanup
echo ${ID}
echo "${ID}"
return 0
fi
json_get_keys keys
for key in $keys; do
json_select $key
json_select $family
if [ "${?}" -ne 0 ]; then
json_select "${key}"
if ! json_select "${family}"; then
json_select ..
continue
fi
json_get_keys ips
for ip in $ips; do
json_get_var ip_val $ip
json_get_var ip_val "${ip}"
if [ "${ip_val}" != "${dhcp_ip}" ]; then
continue
fi
@@ -219,8 +215,8 @@ get_usp_agent_id() {
json_select txt
json_get_keys txts
for _txt in $txts; do
json_get_var text_val $_txt
if [[ "${text_val:0:3}" == "ID=" ]]; then
json_get_var text_val "${_txt}"
if [[ "${text_val:0:3}" = "ID=" ]]; then
ID="${text_val:3}"
break
fi
@@ -238,16 +234,16 @@ get_usp_agent_id() {
done
json_cleanup
echo ${ID}
echo "${ID}"
}
get_mac_address() {
ip="${1}"
device="${2}"
mac="$(cat /proc/net/arp | grep $ip | awk '{print $4}')"
mac=$(grep "${ip}" /proc/net/arp | awk '{print $4}')
if [ -z "${mac}" ]; then
arp_resp="$(arping -b -f -c 5 -I $device $ip | grep 'Unicast reply from' | awk '{print $5}')"
arp_resp=$(arping -b -f -c 5 -I "${device}" "${ip}" | grep 'Unicast reply from' | awk '{print $5}')
if [ -n "${arp_resp}" ]; then
mac=${arp_resp:1:-1}
fi
@@ -260,7 +256,7 @@ send_unknown_gw_event() {
mac="${1}"
cmd="ubus -t 5 send gateway-info.gateway.unknown '{\"hwaddr\":\"$mac\"}'"
eval $cmd
sh -c "${cmd}"
}
send_cwmp_gw_event() {
@@ -269,14 +265,14 @@ send_cwmp_gw_event() {
serial="${3}"
cmd="ubus -t 5 send gateway-info.gateway.cwmp '{\"oui\":\"$oui\",\"class\":\"$class\",\"serial\":\"$serial\"}'"
eval $cmd
sh -c "${cmd}"
}
send_usp_gw_event() {
endpoint="${1}"
cmd="ubus -t 5 send gateway-info.gateway.usp '{\"endpoint\":\"$endpoint\"}'"
eval $cmd
sh -c "${cmd}"
}
config_load gateway
@@ -287,13 +283,13 @@ if [ "${enable}" -eq 0 ]; then
return 0
fi
if [ "${wan_intf}" == "${INTERFACE}" ]; then
if [ "${1}" == "deconfig" ]; then
if [ "${wan_intf}" = "${INTERFACE}" ]; then
if [ "${1}" = "deconfig" ]; then
rm -rf /var/state/gwinfo
return 0
fi
json_load "$(ifstatus ${INTERFACE})"
json_load "$(ifstatus "${INTERFACE}")"
json_get_var dev_name device ""
json_select data
json_get_var dhcp_ip dhcpserver ""
@@ -303,7 +299,7 @@ if [ "${wan_intf}" == "${INTERFACE}" ]; then
return 0
fi
MAC="$(get_mac_address $dhcp_ip $dev_name)"
MAC=$(get_mac_address "${dhcp_ip}" "${dev_name}")
mkdir -p /var/state
touch /var/state/gwinfo
@@ -326,8 +322,8 @@ if [ "${wan_intf}" == "${INTERFACE}" ]; then
return 0
fi
len=$(printf "$opt125"|wc -c)
get_vivsoi "$opt125" "$len"
len=$(echo -n "${opt125}" | wc -c)
get_vivsoi "${opt125}" "${len}"
if [ "${GW_DISCOVERED}" -eq 0 ]; then
send_unknown_gw_event "${MAC}"
@@ -341,19 +337,18 @@ if [ "${wan_intf}" == "${INTERFACE}" ]; then
uci -q -c /var/state commit gwinfo
# Check for USP parameters
ubus -t 15 wait_for umdns
if [ "${?}" -ne 0 ]; then
if ! ubus -t 15 wait_for umdns; then
send_cwmp_gw_event "${OUI}" "${CLASS}" "${SERIAL}"
return 0
fi
resp=$(send_host_query $dev_name)
resp=$(send_host_query "${dev_name}")
if [ "${resp}" -ne 0 ]; then
send_cwmp_gw_event "${OUI}" "${CLASS}" "${SERIAL}"
return 0
fi
ID="$(get_usp_agent_id $dhcp_ip)"
ID=$(get_usp_agent_id "${dhcp_ip}")
if [ -z "${ID}" ]; then
send_cwmp_gw_event "${OUI}" "${CLASS}" "${SERIAL}"
return 0

View File

@@ -5,12 +5,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=hostmngr
PKG_VERSION:=1.3.1
PKG_VERSION:=1.4.0
LOCAL_DEV=0
ifneq ($(LOCAL_DEV),1)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=3663ca4d001508509774115d6797b932f9ed4f69
PKG_SOURCE_VERSION:=230d55ae6769e1ebde02cef3f718e6c4cf1b1962
PKG_SOURCE_URL:=https://dev.iopsys.eu/iopsys/hostmngr.git
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)_$(PKG_SOURCE_VERSION).tar.xz
PKG_MIRROR_HASH:=skip

View File

@@ -8,13 +8,13 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=icwmp
PKG_VERSION:=9.9.9
PKG_VERSION:=9.10.5
LOCAL_DEV:=0
ifneq ($(LOCAL_DEV),1)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://dev.iopsys.eu/bbf/icwmp.git
PKG_SOURCE_VERSION:=070e812e1bfb81a35a95a9c16cc20e8ffa6e30e4
PKG_SOURCE_VERSION:=7f4a159f6ff49584655e57bb801218eb083fba67
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
PKG_MIRROR_HASH:=skip
endif
@@ -88,6 +88,7 @@ define Package/icwmp/install
$(INSTALL_BIN) ./files/etc/uci-defaults/90-cwmpfirewall $(1)/etc/uci-defaults/
$(INSTALL_BIN) ./files/etc/uci-defaults/95-set-random-inform-time $(1)/etc/uci-defaults/
$(INSTALL_BIN) ./files/etc/uci-defaults/85-migrate-gw-info $(1)/etc/uci-defaults/
$(INSTALL_BIN) ./files/etc/uci-defaults/999-cwmp-conn-config $(1)/etc/uci-defaults/
$(INSTALL_BIN) ./files/etc/icwmpd/vendor_log.sh $(1)/etc/icwmpd/vendor_log.sh
$(INSTALL_BIN) ./files/etc/icwmpd/firewall.cwmp $(1)/etc/icwmpd/firewall.cwmp
$(INSTALL_DATA) ./files/lib/upgrade/keep.d/icwmp $(1)/lib/upgrade/keep.d/icwmp

View File

@@ -28,9 +28,9 @@ config cpe 'cpe'
option log_severity 'WARNING'
option log_file_name '/var/log/icwmpd.log'
option log_max_size '102400'
option bind_retries '5'
option userid '' #$OUI-$SER
option passwd ''
option port '7547'
option provisioning_code ''
option amd_version '5'
# compression possible configs: InstanceNumber, InstanceAlias

View File

@@ -133,9 +133,56 @@ add_firewall_rule() {
fi
}
remove_port_protection() {
local enabled chain rule rule_num
config_get enabled "${1}" "${2}"
if [ "${enabled}" -eq 1 ]; then
config_get zonename "$1" name
[ -n "$zonename" ] || return 0
chain='prerouting_'$zonename'_rule'
while rule=$(iptables -w -t nat -nL "$chain" --line-numbers | grep -m 1 -w CWMP_Port_protection); do
rule_num=${rule%%[$' \t']*}
iptables -w -t nat -D "$chain" "$rule_num"
done
fi
}
cleanup_port_protection() {
config_load firewall
config_foreach remove_port_protection zone masq
}
install_port_protection() {
local PORT="${3}"
local enabled zonename chain
config_get enabled "${1}" "${2}"
if [ "${enabled}" -eq 1 ]; then
config_get zonename "${1}" name
[ -n "$zonename" ] || return 0
chain='prerouting_'$zonename'_rule'
iptables -w -t nat -I "$chain" -p tcp --dport "$PORT" -j ACCEPT -m comment --comment=CWMP_Port_protection
iptables -w -t nat -I "$chain" -p udp --dport "$PORT" -j ACCEPT -m comment --comment=CWMP_Port_protection
fi
}
add_port_protection() {
config_load firewall
config_foreach install_port_protection zone masq "${1}"
}
configure_connection_req_rules() {
app="${1}"
cleanup_port_protection
wan="$(uci -q get cwmp.cpe.default_wan_interface)"
wan="${wan:-wan}"
@@ -175,8 +222,11 @@ configure_connection_req_rules() {
fi
fi
port=$(uci -q get cwmp.cpe.port)
port="${port:-7547}"
port=$(uci -q -c /var/state get icwmp.cpe.port)
if [ -z "${port}" ]; then
log "cwmp cpe port not configured"
exit 0
fi
ipaddr=$(uci -q get cwmp.cpe.allowed_cr_ip)
if [ -n "${ipaddr}" ]; then
@@ -197,6 +247,8 @@ configure_connection_req_rules() {
# Close the ACS port at Lan side
close_downstream_acs_port "${lan}" "${port}"
fi
add_port_protection "${port}"
}
load_zone_names

View File

@@ -16,79 +16,6 @@ log() {
echo "${@}"|logger -t cwmp.init -p info
}
regenerate_ssl_link() {
local cert_dir
cert_dir="${1%/}"
if [ -f "${cert_dir}" ]; then
return 0
fi
# do not generate the c_rehash if its system default cert path
# ca-certificate package already generates c_rehash on compilation
[ ! -d "${cert_dir}" ] || [ "${cert_dir}" = "/etc/ssl/certs" ] && return 0
generate_links() {
local file_type="$1"
local files="${cert_dir}"/*."${file_type}"
for cfile in ${files}; do
if [ -f "${cfile}" ]; then
rehash="$(openssl x509 -hash -noout -in "${cfile}")"
if [ ! -f "${cert_dir}/${rehash}.0" ]; then
log "Generating c_rehash for ${cfile}=>${rehash}.0"
ln -s "${cfile}" "${cert_dir}/${rehash}.0"
fi
fi
done
}
generate_links "pem"
}
enable_dhcp_option43() {
local wan="${1}"
### Ask for DHCP Option 43 only if CWMP is enabled ###
local reqopts="$(uci -q get network."${wan}".reqopts)"
local proto="$(uci -q get network."${wan}".proto)"
local newreqopts=""
local option43_present=0
for ropt in $reqopts; do
case $ropt in
43) option43_present=1 ;;
*) ;;
esac
done
if [ ${option43_present} -eq 1 ]; then
return;
fi
newreqopts="$reqopts 43"
if [ "${proto}" = "dhcp" ]; then
uci -q set network."${wan}".reqopts="$newreqopts"
uci commit network
ubus call network reload
fi
}
set_vendor_id() {
local wan="${1}"
local proto="$(uci -q get network."${wan}".proto)"
if [ "${proto}" = "dhcp" ]; then
vendorid="$(uci -q get network."${wan}".vendorid)"
if [ -z "${vendorid}" ]; then
uci -q set network."${wan}".vendorid="dslforum.org"
ubus call uci commit '{"config":"network"}'
elif [[ $vendorid != *"dslforum.org"* ]]; then
uci -q set network."${wan}".vendorid="${vendorid},dslforum.org"
ubus call uci commit '{"config":"network"}'
fi
fi
}
wait_for_resolvfile() {
local time=$1
local tm=1
@@ -211,28 +138,6 @@ validate_defaults() {
}
boot() {
local dhcp_discovery wan_interface skip_dhcp_boot_options
config_load cwmp
config_get wan_interface cpe default_wan_interface "wan"
config_get dhcp_discovery acs dhcp_discovery "0"
config_get skip_dhcp_boot_options acs skip_dhcp_boot_options "0"
if [ "${dhcp_discovery}" = "enable" ] || [ "${dhcp_discovery}" = "1" ]; then
if [ "${skip_dhcp_boot_options}" -ne 1 ]; then
# Set dhcp option 43 if not already configured
enable_dhcp_option43 "${wan_interface}"
# Set dhcp option 60
set_vendor_id "${wan_interface}"
fi
fi
config_get ssl_capath acs ssl_capath
if [ -n "${ssl_capath}" ]; then
regenerate_ssl_link "${ssl_capath}"
fi
# Copy backup data so that if it restart latter on, it gets the info
copy_cwmp_etc_files_to_varstate
mkdir -p /var/run/icwmpd/

View File

@@ -5,7 +5,6 @@ uci -q batch <<-EOT
set firewall.cwmp=include
set firewall.cwmp.path=/etc/icwmpd/firewall.cwmp
set firewall.cwmp.reload=1
commit firewall
EOT
exit 0

View File

@@ -0,0 +1,107 @@
#!/bin/sh
. /lib/functions.sh
log() {
echo "${@}"|logger -t cwmp.defaults -p info
}
set_vendor_id() {
local wan="${1}"
local proto="$(uci -q get network."${wan}".proto)"
if [ "${proto}" = "dhcp" ]; then
vendorid="$(uci -q get network."${wan}".vendorid)"
if [ -z "${vendorid}" ]; then
uci -q set network."${wan}".vendorid="dslforum.org"
elif [[ $vendorid != *"dslforum.org"* ]]; then
uci -q set network."${wan}".vendorid="${vendorid},dslforum.org"
fi
fi
}
enable_dhcp_option43() {
local wan="${1}"
local reqopts="$(uci -q get network."${wan}".reqopts)"
local proto="$(uci -q get network."${wan}".proto)"
local newreqopts=""
local option43_present=0
for ropt in $reqopts; do
case $ropt in
43) option43_present=1 ;;
*) ;;
esac
done
if [ ${option43_present} -eq 1 ]; then
return;
fi
newreqopts="$reqopts 43"
if [ "${proto}" = "dhcp" ]; then
uci -q set network."${wan}".reqopts="$newreqopts"
fi
}
regenerate_ssl_link() {
local cert_dir
cert_dir="${1%/}"
if [ -f "${cert_dir}" ]; then
return 0
fi
# do not generate the c_rehash if its system default cert path
# ca-certificate package already generates c_rehash on compilation
[ ! -d "${cert_dir}" ] || [ "${cert_dir}" = "/etc/ssl/certs" ] && return 0
generate_links() {
local file_type="$1"
local files="${cert_dir}"/*."${file_type}"
for cfile in ${files}; do
if [ -f "${cfile}" ]; then
rehash="$(openssl x509 -hash -noout -in "${cfile}")"
if [ ! -f "${cert_dir}/${rehash}.0" ]; then
log "Generating c_rehash for ${cfile}=>${rehash}.0"
ln -s "${cfile}" "${cert_dir}/${rehash}.0"
fi
fi
done
}
generate_links "pem"
}
configure_dhcp_discovery() {
local dhcp_discovery wan_interface skip_dhcp_boot_options
config_load cwmp
config_get wan_interface cpe default_wan_interface "wan"
config_get dhcp_discovery acs dhcp_discovery "0"
config_get skip_dhcp_boot_options acs skip_dhcp_boot_options "0"
if [ "${dhcp_discovery}" = "enable" ] || [ "${dhcp_discovery}" = "1" ]; then
if [ "${skip_dhcp_boot_options}" -ne 1 ]; then
# Set dhcp option 43 if not already configured
enable_dhcp_option43 "${wan_interface}"
# Set dhcp option 60
set_vendor_id "${wan_interface}"
fi
fi
}
configure_ssl_path() {
local ssl_capath
config_load cwmp
config_get ssl_capath acs ssl_capath
if [ -n "${ssl_capath}" ]; then
regenerate_ssl_link "${ssl_capath}"
fi
}
configure_dhcp_discovery
configure_ssl_path

View File

@@ -16,12 +16,12 @@ get_opt43() {
local opt43="$1"
local len="$2"
[ "$len" -gt "2" ] || return
[ "${len}" -gt 2 ] || return
first_byte=${opt43:0:2}
first_byte=$(printf "%d\n" "0x$first_byte")
if [ $len -ge 4 ] && [ $first_byte -ge 1 ] && [ $first_byte -le 4 ]; then
if [ "${len}" -ge 4 ] && [ "${first_byte}" -ge 1 ] && [ "${first_byte}" -le 4 ]; then
# it is in encapsulated form
# opt43 encapsulated vendor-specific option has data in below format
# Code Len Data item Code Len Data item Code
@@ -35,7 +35,7 @@ get_opt43() {
data="${opt43}"
rem_len="${len}"
# parsing of suboption of option 43
while [ $rem_len -gt 0 ]; do
while [ "${rem_len}" -gt 0 ]; do
# get the suboption id
sub_opt_id=${data:0:2}
sub_opt_id=$(printf "%d\n" "0x$sub_opt_id")
@@ -50,13 +50,13 @@ get_opt43() {
# assign the value found in sub option
case "${sub_opt_id}" in
"1") DHCP_ACS_URL=$(echo -n $sub_opt_val | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf && echo '')
"1") DHCP_ACS_URL=$(echo -n "${sub_opt_val}" | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf && echo '')
;;
"2") DHCP_PROV_CODE=$(echo -n $sub_opt_val | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf && echo '')
"2") DHCP_PROV_CODE=$(echo -n "${sub_opt_val}" | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf && echo '')
;;
"3") MIN_WAIT_INVL=$(echo -n $sub_opt_val | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf && echo '')
"3") MIN_WAIT_INVL=$(echo -n "${sub_opt_val}" | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf && echo '')
;;
"4") INVL_MULTIPLIER=$(echo -n $sub_opt_val | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf && echo '')
"4") INVL_MULTIPLIER=$(echo -n "${sub_opt_val}" | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf && echo '')
;;
esac
@@ -70,13 +70,14 @@ get_opt43() {
rem_len=$((rem_len - sub_opt_end))
done
else
DHCP_ACS_URL=$(echo -n $opt43 | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf && echo '')
DHCP_ACS_URL=$(echo -n "${opt43}" | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf && echo '')
fi
}
config_load cwmp
config_get wan_intf cpe default_wan_interface "wan"
config_get dhcp_discovery acs dhcp_discovery "0"
config_get_bool insecure_enable acs insecure_enable "0"
config_get dhcp_url acs dhcp_url ""
config_get min_wait_intvl acs dhcp_retry_min_wait_interval "0"
config_get intvl_multi acs dhcp_retry_interval_multiplier "0"
@@ -92,9 +93,9 @@ if [ "$discovery_enable" = "0" ]; then
return 0
fi
if [ "${wan_intf}" == "${INTERFACE}" ]; then
if [ "${wan_intf}" = "${INTERFACE}" ]; then
if [ -n "$opt43" ]; then
len=$(printf "$opt43"|wc -c)
len=$(echo -n "$opt43"|wc -c)
get_opt43 "$opt43" "$len"
fi
@@ -102,6 +103,17 @@ if [ "${wan_intf}" == "${INTERFACE}" ]; then
return 0
fi
if [ "${insecure_enable}" -eq "0" ]; then
case $DHCP_ACS_URL in
https://*)
log "ACS url $DHCP_ACS_URL has https"
;;
*)
return 0
;;
esac
fi
sec=$(uci -q get cwmp.acs)
if [ -z "${sec}" ]; then

View File

@@ -6,12 +6,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=ieee1905
PKG_VERSION:=8.7.32
PKG_VERSION:=8.7.39
LOCAL_DEV=0
ifneq ($(LOCAL_DEV),1)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=f1f653c0b7b53a243af889a4c8594aca42589045
PKG_SOURCE_VERSION:=85fa0fe16d6a5a3452422b72186f6bbb16a13c62
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
@@ -116,7 +116,7 @@ MAKE_PATH:=src
define Package/ieee1905/install
$(CP) ./files/* $(1)/
$(CP) ./files/etc $(1)/
$(INSTALL_DIR) $(1)/usr/lib
$(INSTALL_DIR) $(1)/usr/lib/ieee1905
$(INSTALL_DIR) $(1)/usr/sbin

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