diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..51d6ec435651afc9a9187fffed3f3addca1d8ba5 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,15 @@ +include: + - project: 'iopsys/gitlab-ci-pipeline' + file: '/static-code-analysis.yml' + ref: '0.32' + +stages: + - static_code_analysis + +variables: + DEBUG: 'TRUE' + SOURCE_FOLDER: "./src" + FLAWFINDER_OPTIONS: "-m 4 --error-level=5" + CPPCHECK_OPTIONS: "--enable=all --error-exitcode=1" + COMPILE: "./gitlab-ci/compile.sh" + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..8c4663c1ba7fd1d0f8012ea49b2132f57beea937 --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2023, IOPSYS +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/docs/guide/libbbfdm_GRE.md b/docs/guide/libbbfdm_GRE.md new file mode 100644 index 0000000000000000000000000000000000000000..fdbed3ceec6e1e5e734e78de660e6a3812717bb1 --- /dev/null +++ b/docs/guide/libbbfdm_GRE.md @@ -0,0 +1,158 @@ +# TR181 GRE datamodel + +Aim of this document is to explain how the Device.GRE.Tunnel.{i}. and Device.GRE.Tunnel.{i}.Interface.{i}. datamodel objects are mapped to network UCI. + +As per the definition in TR-181: + +- Device.GRE.Tunnel.{i}. allows configuration of a tunnel with respect to a certain remote IP Address. +- Device.GRE.Tunnel.{i}.Interface.{i}. allows configuration of a tunnel interface, which will have to be LowerLayer of a Device.IP.Interface.{i}. object. + +## Configuration +A tunnel can be set up in five broad steps: +- Add a Device.GRE.Tunnel. object. +- Set its Device.GRE.Tunnel.{i}.RemoteEndpoints parameter. +- Add a Device.GRE.Tunnel.{i}.Interface. object. +- Set Device.GRE.Tunnel.{i}.Interface.{i}.LowerLayers to the interface with whose address we want to bind this tunnel (default is wan). +- Set up a Device.IP.Interface object. +- Set appropriate Device.IP.Interface.{i}.LowerLayers to point to above added Device.GRE.Tunnel.{i}.Interface. object. + +Please compare the data model values with *ip addr* state below for a clearer picture. + +### Example data model configuration + +```bash +# add IP.Interface +obuspa -c add Device.IP.Interface. +obuspa -c add Device.IP.Interface.3.IPv4Address. +obuspa -c set Device.IP.Interface.3.IPv4Address.1.IPAddress 172.17.0.5 +obuspa -c set Device.IP.Interface.3.IPv4Address.1.SubnetMask 255.255.255.0 +obuspa -c set Device.IP.Interface.3.IPv4Address.1.Enable 1 +obuspa -c set Device.IP.Interface.3.Enable 1 + +# add GRE. +obuspa -c add Device.GRE.Tunnel. +obuspa -c set Device.GRE.Tunnel.1.RemoteEndpoints 10.101.52.1 +obuspa -c add Device.GRE.Tunnel.1.Interface. +obuspa -c set Device.GRE.Tunnel.1.Interface.1.LowerLayers Device.IP.Interface.2. + +# set IP.Interface LowerLayer +obuspa -c set Device.IP.Interface.3.LowerLayers Device.GRE.Tunnel.1.Interface.1. + +``` + +after the above config, the object should should look as follows: + +```bash +root@iopsys:~# obuspa -c get Device.GRE. +Device.GRE.TunnelNumberOfEntries => 1 +Device.GRE.Tunnel.1.Enable => 1 +Device.GRE.Tunnel.1.Status => Enabled +Device.GRE.Tunnel.1.Alias => cpe-1 +Device.GRE.Tunnel.1.RemoteEndpoints => 10.101.52.1 +Device.GRE.Tunnel.1.DeliveryHeaderProtocol => IPv4 +Device.GRE.Tunnel.1.ConnectedRemoteEndpoint => 10.101.52.1 +Device.GRE.Tunnel.1.InterfaceNumberOfEntries => 1 +Device.GRE.Tunnel.1.Interface.1.Enable => 1 +Device.GRE.Tunnel.1.Interface.1.Status => Unknown +Device.GRE.Tunnel.1.Interface.1.Alias => cpe-1 +Device.GRE.Tunnel.1.Interface.1.Name => gre_d1i1 +Device.GRE.Tunnel.1.Interface.1.LastChange => 227 +Device.GRE.Tunnel.1.Interface.1.LowerLayers => Device.IP.Interface.2 +Device.GRE.Tunnel.1.Interface.1.UseChecksum => 0 +Device.GRE.Tunnel.1.Interface.1.UseSequenceNumber => 0 +Device.GRE.Tunnel.1.Interface.1.Stats.BytesSent => 84 +Device.GRE.Tunnel.1.Interface.1.Stats.BytesReceived => 84 +Device.GRE.Tunnel.1.Interface.1.Stats.PacketsSent => 1 +Device.GRE.Tunnel.1.Interface.1.Stats.PacketsReceived => 1 +Device.GRE.Tunnel.1.Interface.1.Stats.ErrorsSent => 0 +Device.GRE.Tunnel.1.Interface.1.Stats.ErrorsReceived => 0 +``` + +```bash +root@iopsys:~# obuspa -c get Device.IP.Interface.3. +Device.IP.Interface.3.Enable => 1 +Device.IP.Interface.3.IPv6Enable => 1 +Device.IP.Interface.3.ULAEnable => 1 +Device.IP.Interface.3.Status => Down +Device.IP.Interface.3.Alias => cpe-3 +Device.IP.Interface.3.Name => iface3 +Device.IP.Interface.3.LastChange => 0 +Device.IP.Interface.3.LowerLayers => Device.GRE.Tunnel.1.Interface.1 +Device.IP.Interface.3.Router => Device.Routing.Router.1 +Device.IP.Interface.3.Reset => 0 +Device.IP.Interface.3.MaxMTUSize => 1500 +Device.IP.Interface.3.Type => Normal +Device.IP.Interface.3.Loopback => 0 +Device.IP.Interface.3.IPv4AddressNumberOfEntries => 1 +Device.IP.Interface.3.IPv6AddressNumberOfEntries => 0 +Device.IP.Interface.3.IPv6PrefixNumberOfEntries => 0 +Device.IP.Interface.3.IPv4Address.1.Enable => 1 +Device.IP.Interface.3.IPv4Address.1.Status => Enabled +Device.IP.Interface.3.IPv4Address.1.Alias => cpe-1 +Device.IP.Interface.3.IPv4Address.1.IPAddress => 172.17.0.5 +Device.IP.Interface.3.IPv4Address.1.SubnetMask => 255.255.255.0 +Device.IP.Interface.3.IPv4Address.1.AddressingType => Static +Device.IP.Interface.3.Stats.BytesSent => 0 +Device.IP.Interface.3.Stats.BytesReceived => 0 +Device.IP.Interface.3.Stats.PacketsSent => 0 +Device.IP.Interface.3.Stats.PacketsReceived => 0 +Device.IP.Interface.3.Stats.ErrorsSent => 0 +Device.IP.Interface.3.Stats.ErrorsReceived => 0 +Device.IP.Interface.3.Stats.DiscardPacketsSent => 0 +Device.IP.Interface.3.Stats.DiscardPacketsReceived => 0 +Device.IP.Interface.3.Stats.MulticastPacketsReceived => 0 +``` + +NOTE: The status might be down for *Device.IP.Interface.3.Status* but the IP will be assigned properly in ifconfig output. + +```bash +gre4-gre_d1i1 Link encap:UNSPEC HWaddr 0A-65-34-64-00-00-00-00-00-00-00-00-00-00-00-00 + inet addr:172.17.0.5 P-t-P:172.17.0.5 Mask:255.255.255.0 + inet6 addr: fe80::5efe:a65:3464/64 Scope:Link + UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1280 Metric:1 + RX packets:1 errors:0 dropped:0 overruns:0 frame:0 + TX packets:1 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:1000 + RX bytes:84 (84.0 B) TX bytes:84 (84.0 B) +``` + +## Network UCI with added new section for GRE Tunnel + +```bash +config device 'gre_dev_1' + option name 'gre_dev_1' + option type 'tunnel' + option mode 'greip' + option remote '10.101.52.1' + +config interface 'gre_d1i1' + option proto 'gre' + option device 'gre_dev_1' + option disabled '0' + option tunlink 'wan' + option peeraddr '10.101.52.1' + +config interface 'gre_ll_1' + option proto 'static' + option ipaddr '172.17.0.5' + option netmask '255.255.255.0' + option device 'gre4-gre_d1i1' + +``` + +### IP addr state + +```bash +23: gre4-gre_d1i1@eth0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1280 qdisc noqueue state UNKNOWN group default qlen 1000 + link/gre 10.101.52.100 peer 10.101.52.1 + inet 172.17.0.5/24 brd 172.17.0.255 scope global gre4-gre_d1i1 + valid_lft forever preferred_lft forever + inet6 fe80::5efe:c0a8:101/64 scope link + valid_lft forever preferred_lft forever +``` + +## Limitations +- Current system expects one to one mapping between Device.Tunnel.{i}. and Device.Tunnel.{i}.Interface and Device.IP.Interface.{i}.LowerLayer at a time, that is, +at the moment, we can only functionally support single value in Device.GRE.Tunnel.1.Interface.1.LowerLayers and not comma separated list of values. +- When Device.IP.Interface.{i}.LowerLayer is set to Device.GRE.Tunnel.{i}.Interface.{i}., the system finds the Linux generated tunnel name for the Tunnel and sets it to option device in the Device.IP.Interface.{i}. interface section, this is to avoid using "@" notation of referring to interfaces, which causes problems in processing of interfaces in the data model implementation. +- The lowerlayer of the GRE.Tunnel.Interface object maps to option tunlink in the UCI. If not specified, openwrt by default picks wan interface as tunlink. That means if you have a config interface 'wan' section in your UCI, then the IP.Interface object corresponding to this will automatically become the lowerlayer of Tunnel.Interface object. It is strongly recommended that you do not rely on this however, and for clarity, always specify the value of Tunnel.Interface.Lowerlayer parameter, even though, functionally, your tunnel may even be setup if you leave it as blank provided a config interface wan section exists in your network UCI. In such a scenario, even though you have left the Lowerlayer value as blank, the "wan" interface will be used internally as the default value for option tunlink. diff --git a/docs/guide/libbbfdm_IP_Interface.md b/docs/guide/libbbfdm_IP_Interface.md new file mode 100644 index 0000000000000000000000000000000000000000..7e7aaf7239c26a1bbf133a3d844b66d885f2f000 --- /dev/null +++ b/docs/guide/libbbfdm_IP_Interface.md @@ -0,0 +1,55 @@ +# TR181 IP.Interface. Object + +The purpose of this document is to describe what are the problems and limitation we have in managing IP.Interface. with their sub-objects and what is the best way for the customer to avoid these problems/limitations and can easily configure IP.Interface. with different IPv4/v6 addresses using static or dhcp server. + +In fact, many TR181 objects are not mapped 1-to-1 with uci config which makes managing these objects so difficult and one of the important objects is IP.Interface. + +# Problematics: + +Actually, we find a lot of problems with the current implementation of IP.Interface object such as: + + - If IP.Interface instance and IP.Interface.X.IPv4Address instance map to the same interface section, so there is no way to disable IPv4Address instance without affecting IP.Interface since both maps to the same interface section. + +``` +config interface 'wan' ---> used by Device.IP.Interface.X. and Device.IP.Interface.X.IPv4Address.X. instances + option disabled '0' ---> Disabling this IPv4Address.X. instance using Enable parameter(Device.IP.Interface.X.IPv4Address.X.Enable) will impact on IP.Interface.X. instance + option device 'ethx' + option proto 'static' + option ipaddr '10.100.17.39' + option netmask '255.255.255.0' + +``` + + - If someone try to create a static route and bind it to an IP.Interface. instance which has an IPv4Address instance defined there so disabling IPv4Addres will cause IP.Interface instance to be disabled and therefore the static route will be automatically disabled from the system. + +``` +config interface 'wan' ---> used by Device.IP.Interface.1. and Device.IP.Interface.1.IPv4Address.1. instances + option disabled '1' ---> Disabling this IPv4Address.1. instance using Enable parameter(Device.IP.Interface.1.IPv4Address.1.Enable) will disable IP.Interface.1. and route section even if there are others section use the same device(wan_2) + option device 'ethx' + option proto 'dhcp' + +config interface 'wan_2' ---> used by Device.IP.Interface.1.IPv4Address.2. instance + option disabled '0' + option device 'ethx' + option proto 'static' + option ipaddr '10.100.17.39' + option netmask '255.255.255.0' + +config route + option interface 'wan' + option target '0.0.0.0/0' + option gateway '10.72.197.110' + +``` + +# Solution: + +To fix the above issues, we have updated our IP.Interface.X.IPv4Address implementation to store everything in dmmap, then based on each uci section, we decide how to manage their IP.Interface.X.IPv4Address parameters. but unfortunately, with this approach, the customer has to be aware of some limitations such as: + + - If Data Model shows IP.Interface.{i}.IPv4Address.{i}. instance with DHCP type, then it's not allowed to disable this IP.Interface.{i}.IPv4Address.{i}. instance and the only way to disable it is to set their DHCPv4.Client.X.Interface parameter to empty. + + - If Data Model shows IP.Interface.{i}.IPv6Address.{i}. instance with DHCP type, then it's not allowed to disable this IP.Interface.{i}.IPv6Address.{i}. instance and the only way to disable it is to set their DHCPv6.Client.X.Interface parameter to empty + + - If the network uci defines an interface section which used by both IP.Interface.{i}. instance and DHCPv4.Client.{i}. instance, then it's not allowed to disable this DHCPv4.Client.{i}. instance using Enable parameter and the only way to disable it is to set their IP.Interface.X.Enable parameter to 0. + +>Note: In future we might optimise it further to simplify the mapping between data model objects and uci, that might forgo some limitations. diff --git a/docs/guide/network_depoyment_scenarios.md b/docs/guide/network_depoyment_scenarios.md new file mode 100644 index 0000000000000000000000000000000000000000..0da1d87b993dcc8bdbefa0964bbcc638f7931ab0 --- /dev/null +++ b/docs/guide/network_depoyment_scenarios.md @@ -0,0 +1,2744 @@ +# Network Deployment Scenarios using TR-181 Data Model + +The purpose of this document is to explain the different deployment scenarios supported by our devices and how to configure each scenario using TR-181 data model. + +## Deployment scenarios + +### 1. Transparent Bridge + +- **TR-181 Commands** + +```bash +obuspa -c del Device.DHCPv4.Client.* +obuspa -c del Device.DHCPv6.Client.* +obuspa -c del Device.Ethernet.Link.* +obuspa -c del Device.Bridging.Bridge.* +obuspa -c del Device.IP.Interface.* + +obuspa -c add Device.IP.Interface. +obuspa -c add Device.DHCPv4.Client. +obuspa -c add Device.Ethernet.Link. +obuspa -c add Device.Bridging.Bridge. +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c add Device.Bridging.Bridge.1.Port. + +obuspa -c set Device.IP.Interface.1.Enable 1 +obuspa -c set Device.IP.Interface.1.LowerLayers Device.Ethernet.Link.1 + +obuspa -c set Device.DHCPv4.Client.1.Enable 1 +obuspa -c set Device.DHCPv4.Client.1.Interface Device.IP.Interface.1 + +obuspa -c set Device.Ethernet.Link.1.LowerLayers Device.Bridging.Bridge.1.Port.1 + +obuspa -c set Device.Bridging.Bridge.1.Port.1.Enable 1 +obuspa -c set Device.Bridging.Bridge.1.Port.2.Enable 1 +obuspa -c set Device.Bridging.Bridge.1.Port.3.Enable 1 +obuspa -c set Device.Bridging.Bridge.1.Port.4.Enable 1 + +obuspa -c set Device.Bridging.Bridge.1.Port.1.ManagementPort 1 +obuspa -c set Device.Bridging.Bridge.1.Port.2.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.1.Port.3.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.1.Port.4.ManagementPort 0 + +obuspa -c set Device.Bridging.Bridge.1.Port.2.LowerLayers Device.Ethernet.Interface.1 +obuspa -c set Device.Bridging.Bridge.1.Port.3.LowerLayers Device.Ethernet.Interface.2 +obuspa -c set Device.Bridging.Bridge.1.Port.4.LowerLayers Device.Ethernet.Interface.3 +``` + +- **Network UCI Config** + +```bash +$ cat /etc/config/network + +config interface 'loopback' + option device 'lo' + option proto 'static' + option ipaddr '127.0.0.1' + option netmask '255.0.0.0' + +config globals 'globals' + option ula_prefix 'fdec:6076:a3d3::/48' + +config device 'dev_eth1' + option enabled '1' + option ifname 'eth1' + option name 'eth1' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:53' + +config device 'dev_eth3' + option enabled '1' + option ifname 'eth3' + option name 'eth3' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:53' + +config device 'dev_eth4' + option enabled '1' + option ifname 'eth4' + option name 'eth4' + option eee '0' + option pause '1' + option macaddr '44:D4:37:71:B5:53' + +config interface 'iface1' + option proto 'dhcp' + option disabled '0' + option device 'br-dev1' + option macaddr '44:D4:37:71:B5:53' + +config device 'dev_br1' + option name 'br-dev1' + option type 'bridge' + option bridge_empty '1' + list ports 'eth1' + list ports 'eth3' + list ports 'eth4' + option macaddr '44:D4:37:71:B5:53' + +``` + +- **TR-181 Data Model** + +```bash +$ obuspa -c get Device.IP.Interface.*.LowerLayers +Device.IP.Interface.1.LowerLayers => Device.Ethernet.Link.1 +$ obuspa -c get Device.Ethernet.Link.*.LowerLayers +Device.Ethernet.Link.1.LowerLayers => Device.Bridging.Bridge.1.Port.1 +$ obuspa -c get Device.DHCPv4.Client.*.Interface +Device.DHCPv4.Client.1.Interface => Device.IP.Interface.1 +$ obuspa -c get Device.Bridging.Bridge.*.Port.*.LowerLayers +Device.Bridging.Bridge.1.Port.1.LowerLayers => Device.Bridging.Bridge.1.Port.2,Device.Bridging.Bridge.1.Port.3,Device.Bridging.Bridge.1.Port.4 +Device.Bridging.Bridge.1.Port.2.LowerLayers => Device.Ethernet.Interface.1 +Device.Bridging.Bridge.1.Port.3.LowerLayers => Device.Ethernet.Interface.2 +Device.Bridging.Bridge.1.Port.4.LowerLayers => Device.Ethernet.Interface.3 +$ obuspa -c get Device.Bridging.Bridge.*.VLANPort. +$ obuspa -c get Device.Bridging.Bridge.*.VLAN. +``` + +### 2. One VLAN per Service (Bridge mode) + +- **TR-181 Commands** + +```bash +obuspa -c del Device.DHCPv4.Client.* +obuspa -c del Device.DHCPv6.Client.* +obuspa -c del Device.Ethernet.Link.* +obuspa -c del Device.Bridging.Bridge.* +obuspa -c del Device.IP.Interface.* + +obuspa -c add Device.IP.Interface. +obuspa -c add Device.IP.Interface. +obuspa -c add Device.IP.Interface. +obuspa -c add Device.DHCPv4.Client. +obuspa -c add Device.Ethernet.Link. +obuspa -c add Device.Ethernet.Link. +obuspa -c add Device.Ethernet.Link. +obuspa -c add Device.Bridging.Bridge. +obuspa -c add Device.Bridging.Bridge. +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c add Device.Bridging.Bridge.1.VLAN. +obuspa -c add Device.Bridging.Bridge.1.VLANPort. +obuspa -c add Device.Bridging.Bridge.1.VLANPort. +obuspa -c add Device.Bridging.Bridge.2.Port. +obuspa -c add Device.Bridging.Bridge.2.Port. +obuspa -c add Device.Bridging.Bridge.2.Port. +obuspa -c add Device.Bridging.Bridge.2.VLAN. +obuspa -c add Device.Bridging.Bridge.2.VLANPort. +obuspa -c add Device.Bridging.Bridge.2.VLANPort. + +obuspa -c set Device.IP.Interface.1.Enable 1 +obuspa -c set Device.IP.Interface.2.Enable 1 +obuspa -c set Device.IP.Interface.3.Enable 1 + +obuspa -c set Device.IP.Interface.1.LowerLayers Device.Ethernet.Link.1 +obuspa -c set Device.IP.Interface.2.LowerLayers Device.Ethernet.Link.2 +obuspa -c set Device.IP.Interface.3.LowerLayers Device.Ethernet.Link.3 + +obuspa -c set Device.DHCPv4.Client.1.Enable 1 +obuspa -c set Device.DHCPv4.Client.1.Interface Device.IP.Interface.3 + +obuspa -c set Device.Ethernet.Link.1.LowerLayers Device.Bridging.Bridge.1.Port.1 +obuspa -c set Device.Ethernet.Link.2.LowerLayers Device.Bridging.Bridge.2.Port.1 +obuspa -c set Device.Ethernet.Link.3.LowerLayers Device.Ethernet.Interface.3 + +obuspa -c set Device.Bridging.Bridge.1.VLANPort.1.Enable 1 +obuspa -c set Device.Bridging.Bridge.1.VLANPort.2.Enable 1 + +obuspa -c set Device.Bridging.Bridge.1.VLANPort.1.VLAN Device.Bridging.Bridge.1.VLAN.1 +obuspa -c set Device.Bridging.Bridge.1.VLANPort.2.VLAN Device.Bridging.Bridge.1.VLAN.1 + +obuspa -c set Device.Bridging.Bridge.1.VLANPort.1.Port Device.Bridging.Bridge.1.Port.2 +obuspa -c set Device.Bridging.Bridge.1.VLANPort.2.Port Device.Bridging.Bridge.1.Port.3 + +obuspa -c set Device.Bridging.Bridge.1.Port.2.LowerLayers Device.Ethernet.Interface.1 +obuspa -c set Device.Bridging.Bridge.1.Port.3.LowerLayers Device.Ethernet.Interface.3 + +obuspa -c set Device.Bridging.Bridge.1.VLAN.1.VLANID 100 + +obuspa -c set Device.Bridging.Bridge.1.Port.1.ManagementPort 1 +obuspa -c set Device.Bridging.Bridge.1.Port.2.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.1.Port.3.ManagementPort 0 + +obuspa -c set Device.Bridging.Bridge.1.Port.1.Enable 1 +obuspa -c set Device.Bridging.Bridge.1.Port.2.Enable 1 +obuspa -c set Device.Bridging.Bridge.1.Port.3.Enable 1 + +obuspa -c set Device.Bridging.Bridge.2.Port.1.ManagementPort 1 +obuspa -c set Device.Bridging.Bridge.2.Port.2.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.2.Port.3.ManagementPort 0 + +obuspa -c set Device.Bridging.Bridge.2.VLANPort.1.VLAN Device.Bridging.Bridge.2.VLAN.1 +obuspa -c set Device.Bridging.Bridge.2.VLANPort.2.VLAN Device.Bridging.Bridge.2.VLAN.1 + +obuspa -c set Device.Bridging.Bridge.2.VLANPort.1.Port Device.Bridging.Bridge.2.Port.2 +obuspa -c set Device.Bridging.Bridge.2.VLANPort.2.Port Device.Bridging.Bridge.2.Port.3 + +obuspa -c set Device.Bridging.Bridge.2.VLAN.1.VLANID 200 + +obuspa -c set Device.Bridging.Bridge.2.Port.1.Enable 1 +obuspa -c set Device.Bridging.Bridge.2.Port.2.Enable 1 +obuspa -c set Device.Bridging.Bridge.2.Port.3.Enable 1 + +obuspa -c set Device.Bridging.Bridge.2.Port.2.LowerLayers Device.Ethernet.Interface.2 +obuspa -c set Device.Bridging.Bridge.2.Port.3.LowerLayers Device.Ethernet.Interface.3 + +obuspa -c set Device.Bridging.Bridge.2.VLANPort.1.Enable 1 +obuspa -c set Device.Bridging.Bridge.2.VLANPort.2.Enable 1 +``` + +- **Network UCI Config** + +```bash +$ cat /etc/config/network + +config interface 'loopback' + option device 'lo' + option proto 'static' + option ipaddr '127.0.0.1' + option netmask '255.0.0.0' + +config globals 'globals' + option ula_prefix 'fddd:90b7:d9ec::/48' + +config device 'dev_eth1' + option enabled '1' + option ifname 'eth1' + option name 'eth1' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth3' + option enabled '1' + option ifname 'eth3' + option name 'eth3' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth4' + option enabled '1' + option ifname 'eth4' + option name 'eth4' + option eee '0' + option pause '1' + option macaddr '44:D4:37:71:B5:55' + +config interface 'iface1' + option proto 'none' + option disabled '0' + option device 'br-dev1' + option macaddr '44:D4:37:71:B5:53' + +config interface 'iface2' + option proto 'none' + option disabled '0' + option device 'br-dev2' + option macaddr '44:D4:37:71:B5:54' + +config interface 'iface3' + option proto 'dhcp' + option disabled '0' + option device 'eth4' + option macaddr '44:D4:37:71:B5:55' + +config device 'dev_br1' + option name 'br-dev1' + option type 'bridge' + option bridge_empty '1' + option macaddr '44:D4:37:71:B5:53' + list ports 'eth1.100' + list ports 'eth4.100' + +config device 'dev_br2' + option name 'br-dev2' + option type 'bridge' + option bridge_empty '1' + option macaddr '44:D4:37:71:B5:54' + list ports 'eth3.200' + list ports 'eth4.200' + +config device 'br_1_port_1' + option type '8021q' + option enabled '1' + option vid '100' + option ifname 'eth1' + option name 'eth1.100' + option macaddr '44:D4:37:71:B5:53' + +config device 'br_1_port_2' + option type '8021q' + option enabled '1' + option vid '100' + option ifname 'eth4' + option name 'eth4.100' + option macaddr '44:D4:37:71:B5:53' + +config device 'br_2_port_1' + option type '8021q' + option enabled '1' + option vid '200' + option ifname 'eth3' + option name 'eth3.200' + option macaddr '44:D4:37:71:B5:54' + +config device 'br_2_port_2' + option type '8021q' + option enabled '1' + option vid '200' + option ifname 'eth4' + option name 'eth4.200' + option macaddr '44:D4:37:71:B5:54' + +``` + +- **TR-181 Data Model** + +```bash +$ obuspa -c get Device.IP.Interface.*.LowerLayers +Device.IP.Interface.1.LowerLayers => Device.Ethernet.Link.1 +Device.IP.Interface.2.LowerLayers => Device.Ethernet.Link.2 +Device.IP.Interface.3.LowerLayers => Device.Ethernet.Link.3 +$ obuspa -c get Device.Ethernet.Link.*.LowerLayers +Device.Ethernet.Link.1.LowerLayers => Device.Bridging.Bridge.1.Port.1 +Device.Ethernet.Link.2.LowerLayers => Device.Bridging.Bridge.2.Port.1 +Device.Ethernet.Link.3.LowerLayers => Device.Ethernet.Interface.3 +$ obuspa -c get Device.Ethernet.VLANTermination.*.LowerLayers +$ obuspa -c get Device.Bridging.Bridge.*.Port.*.LowerLayers +Device.Bridging.Bridge.1.Port.1.LowerLayers => Device.Bridging.Bridge.1.Port.2,Device.Bridging.Bridge.1.Port.3 +Device.Bridging.Bridge.1.Port.2.LowerLayers => Device.Ethernet.Interface.1 +Device.Bridging.Bridge.1.Port.3.LowerLayers => Device.Ethernet.Interface.3 +Device.Bridging.Bridge.2.Port.1.LowerLayers => Device.Bridging.Bridge.2.Port.2,Device.Bridging.Bridge.2.Port.3 +Device.Bridging.Bridge.2.Port.2.LowerLayers => Device.Ethernet.Interface.2 +Device.Bridging.Bridge.2.Port.3.LowerLayers => Device.Ethernet.Interface.3 +$ obuspa -c get Device.Bridging.Bridge.*.VLANPort. +Device.Bridging.Bridge.1.VLANPort.1.Enable => 1 +Device.Bridging.Bridge.1.VLANPort.1.Alias => cpe-1 +Device.Bridging.Bridge.1.VLANPort.1.VLAN => Device.Bridging.Bridge.1.VLAN.1 +Device.Bridging.Bridge.1.VLANPort.1.Port => Device.Bridging.Bridge.1.Port.2 +Device.Bridging.Bridge.1.VLANPort.1.Untagged => 0 +Device.Bridging.Bridge.1.VLANPort.2.Enable => 1 +Device.Bridging.Bridge.1.VLANPort.2.Alias => cpe-2 +Device.Bridging.Bridge.1.VLANPort.2.VLAN => Device.Bridging.Bridge.1.VLAN.1 +Device.Bridging.Bridge.1.VLANPort.2.Port => Device.Bridging.Bridge.1.Port.3 +Device.Bridging.Bridge.1.VLANPort.2.Untagged => 0 +Device.Bridging.Bridge.2.VLANPort.1.Enable => 1 +Device.Bridging.Bridge.2.VLANPort.1.Alias => cpe-1 +Device.Bridging.Bridge.2.VLANPort.1.VLAN => Device.Bridging.Bridge.2.VLAN.1 +Device.Bridging.Bridge.2.VLANPort.1.Port => Device.Bridging.Bridge.2.Port.2 +Device.Bridging.Bridge.2.VLANPort.1.Untagged => 0 +Device.Bridging.Bridge.2.VLANPort.2.Enable => 1 +Device.Bridging.Bridge.2.VLANPort.2.Alias => cpe-2 +Device.Bridging.Bridge.2.VLANPort.2.VLAN => Device.Bridging.Bridge.2.VLAN.1 +Device.Bridging.Bridge.2.VLANPort.2.Port => Device.Bridging.Bridge.2.Port.3 +Device.Bridging.Bridge.2.VLANPort.2.Untagged => 0 +$ obuspa -c get Device.Bridging.Bridge.*.VLAN. +Device.Bridging.Bridge.1.VLAN.1.Enable => 1 +Device.Bridging.Bridge.1.VLAN.1.Alias => cpe-1 +Device.Bridging.Bridge.1.VLAN.1.Name => br_1_vlan_1 +Device.Bridging.Bridge.1.VLAN.1.VLANID => 100 +Device.Bridging.Bridge.2.VLAN.1.Enable => 1 +Device.Bridging.Bridge.2.VLAN.1.Alias => cpe-1 +Device.Bridging.Bridge.2.VLAN.1.Name => br_2_vlan_1 +Device.Bridging.Bridge.2.VLAN.1.VLANID => 200 +$ obuspa -c get Device.DHCPv4.Client.*.Interface +Device.DHCPv4.Client.1.Interface => Device.IP.Interface.3 +``` + +### 3. One VLAN per Service (Route mode) + +- **TR-181 Commands** + +```bash +obuspa -c del Device.DHCPv4.Client.* +obuspa -c del Device.DHCPv6.Client.* +obuspa -c del Device.Ethernet.Link.* +obuspa -c del Device.Bridging.Bridge.* +obuspa -c del Device.IP.Interface.* + +obuspa -c add Device.IP.Interface. +obuspa -c add Device.IP.Interface. +obuspa -c add Device.IP.Interface. +obuspa -c add Device.IP.Interface. +obuspa -c add Device.DHCPv4.Client. +obuspa -c add Device.Ethernet.VLANTermination. +obuspa -c add Device.Ethernet.VLANTermination. +obuspa -c add Device.Ethernet.Link. +obuspa -c add Device.Ethernet.Link. +obuspa -c add Device.Bridging.Bridge. +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c add Device.Bridging.Bridge.1.Port. + +obuspa -c set Device.IP.Interface.1.Enable 1 +obuspa -c set Device.IP.Interface.2.Enable 1 +obuspa -c set Device.IP.Interface.3.Enable 1 +obuspa -c set Device.IP.Interface.4.Enable 1 + +obuspa -c set Device.IP.Interface.1.LowerLayers Device.Ethernet.Link.1 +obuspa -c set Device.IP.Interface.2.LowerLayers Device.Ethernet.VLANTermination.1 +obuspa -c set Device.IP.Interface.3.LowerLayers Device.Ethernet.VLANTermination.2 +obuspa -c set Device.IP.Interface.4.LowerLayers Device.Ethernet.Link.2 + +obuspa -c set Device.DHCPv4.Client.1.Enable 1 +obuspa -c set Device.DHCPv4.Client.1.Interface Device.IP.Interface.4 + +obuspa -c set Device.Ethernet.VLANTermination.1.LowerLayers Device.Ethernet.Link.2 +obuspa -c set Device.Ethernet.VLANTermination.2.LowerLayers Device.Ethernet.Link.2 + +obuspa -c set Device.Ethernet.VLANTermination.1.VLANID 100 +obuspa -c set Device.Ethernet.VLANTermination.2.VLANID 200 + +obuspa -c set Device.Ethernet.Link.1.LowerLayers Device.Bridging.Bridge.1.Port.1 +obuspa -c set Device.Ethernet.Link.2.LowerLayers Device.Ethernet.Interface.3 + +obuspa -c set Device.Bridging.Bridge.1.Port.1.Enable 1 +obuspa -c set Device.Bridging.Bridge.1.Port.2.Enable 1 +obuspa -c set Device.Bridging.Bridge.1.Port.3.Enable 1 + +obuspa -c set Device.Bridging.Bridge.1.Port.1.ManagementPort 1 +obuspa -c set Device.Bridging.Bridge.1.Port.2.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.1.Port.3.ManagementPort 0 + +obuspa -c set Device.Bridging.Bridge.1.Port.2.LowerLayers Device.Ethernet.Interface.1 +obuspa -c set Device.Bridging.Bridge.1.Port.3.LowerLayers Device.Ethernet.Interface.2 +``` + +- **Network UCI Config** + +```bash +$ cat /etc/config/network + +config interface 'loopback' + option device 'lo' + option proto 'static' + option ipaddr '127.0.0.1' + option netmask '255.0.0.0' + +config globals 'globals' + option ula_prefix 'fd9b:03aa:df0a::/48' + +config device 'dev_eth1' + option enabled '1' + option ifname 'eth1' + option name 'eth1' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:53' + +config device 'dev_eth3' + option enabled '1' + option ifname 'eth3' + option name 'eth3' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:53' + +config device 'dev_eth4' + option enabled '1' + option ifname 'eth4' + option name 'eth4' + option eee '0' + option pause '1' + option macaddr '44:D4:37:71:B5:56' + +config interface 'iface1' + option proto 'none' + option disabled '0' + option device 'br-dev1' + option macaddr '44:D4:37:71:B5:53' + +config interface 'iface2' + option proto 'none' + option disabled '0' + option device 'eth4.100' + option macaddr '44:D4:37:71:B5:54' + +config interface 'iface3' + option proto 'none' + option disabled '0' + option device 'eth4.200' + option macaddr '44:D4:37:71:B5:55' + +config interface 'iface4' + option proto 'dhcp' + option disabled '0' + option device 'eth4' + option macaddr '44:D4:37:71:B5:56' + +config device 'vlan_ter_1' + option type '8021q' + option vid '100' + option ifname 'eth4' + option name 'eth4.100' + option macaddr '44:D4:37:71:B5:54' + +config device 'vlan_ter_2' + option type '8021q' + option vid '200' + option ifname 'eth4' + option name 'eth4.200' + option macaddr '44:D4:37:71:B5:55' + +config device 'dev_br1' + option name 'br-dev1' + option type 'bridge' + option bridge_empty '1' + option macaddr '44:D4:37:71:B5:53' + list ports 'eth1' + list ports 'eth3' + +``` + +- **TR-181 Data Model** + +```bash +$ obuspa -c get Device.IP.Interface.*.LowerLayers +Device.IP.Interface.1.LowerLayers => Device.Ethernet.Link.1 +Device.IP.Interface.2.LowerLayers => Device.Ethernet.VLANTermination.1 +Device.IP.Interface.3.LowerLayers => Device.Ethernet.VLANTermination.2 +Device.IP.Interface.4.LowerLayers => Device.Ethernet.Link.2 +$ obuspa -c get Device.Ethernet.VLANTermination.*.LowerLayers +Device.Ethernet.VLANTermination.1.LowerLayers => Device.Ethernet.Link.2 +Device.Ethernet.VLANTermination.2.LowerLayers => Device.Ethernet.Link.2 +$ obuspa -c get Device.Ethernet.Link.*.LowerLayers +Device.Ethernet.Link.1.LowerLayers => Device.Bridging.Bridge.1.Port.1 +Device.Ethernet.Link.2.LowerLayers => Device.Ethernet.Interface.3 +$ obuspa -c get Device.Bridging.Bridge.*.Port.*.LowerLayers +Device.Bridging.Bridge.1.Port.1.LowerLayers => Device.Bridging.Bridge.1.Port.2,Device.Bridging.Bridge.1.Port.3 +Device.Bridging.Bridge.1.Port.2.LowerLayers => Device.Ethernet.Interface.1 +Device.Bridging.Bridge.1.Port.3.LowerLayers => Device.Ethernet.Interface.2 +$ obuspa -c get Device.Bridging.Bridge.*.VLANPort. +$ obuspa -c get Device.Bridging.Bridge.*.VLAN. +$ obuspa -c get Device.DHCPv4.Client.*.Interface +Device.DHCPv4.Client.1.Interface => Device.IP.Interface.4 +``` + +### 4. VLAN Trunking + +- **TR-181 Commands** + +```bash +obuspa -c del Device.DHCPv4.Client.* +obuspa -c del Device.DHCPv6.Client.* +obuspa -c del Device.Ethernet.Link.* +obuspa -c del Device.Bridging.Bridge.* +obuspa -c del Device.IP.Interface.* + +obuspa -c add Device.Bridging.Bridge. + +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c set Device.Bridging.Bridge.1.Port.1.ManagementPort 1 + +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c set Device.Bridging.Bridge.1.Port.2.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.1.Port.2.LowerLayers Device.Ethernet.Interface.1 +obuspa -c set Device.Bridging.Bridge.1.Port.2.Enable 1 + +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c set Device.Bridging.Bridge.1.Port.3.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.1.Port.3.LowerLayers Device.Ethernet.Interface.2 +obuspa -c set Device.Bridging.Bridge.1.Port.3.Enable 1 + +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c set Device.Bridging.Bridge.1.Port.4.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.1.Port.4.LowerLayers Device.Ethernet.Interface.3 +obuspa -c set Device.Bridging.Bridge.1.Port.4.Enable 1 + +obuspa -c add Device.Bridging.Bridge.1.VLAN. +obuspa -c set Device.Bridging.Bridge.1.VLAN.1.VLANID 100 + +obuspa -c add Device.Bridging.Bridge.1.VLANPort. +obuspa -c set Device.Bridging.Bridge.1.VLANPort.1.Enable 1 +obuspa -c set Device.Bridging.Bridge.1.VLANPort.1.VLAN Device.Bridging.Bridge.1.VLAN.1 +obuspa -c set Device.Bridging.Bridge.1.VLANPort.1.Port Device.Bridging.Bridge.1.Port.2 + +obuspa -c add Device.Bridging.Bridge.1.VLANPort. +obuspa -c set Device.Bridging.Bridge.1.VLANPort.2.Enable 1 +obuspa -c set Device.Bridging.Bridge.1.VLANPort.2.VLAN Device.Bridging.Bridge.1.VLAN.1 +obuspa -c set Device.Bridging.Bridge.1.VLANPort.2.Port Device.Bridging.Bridge.1.Port.3 + +obuspa -c add Device.Bridging.Bridge.1.VLANPort. +obuspa -c set Device.Bridging.Bridge.1.VLANPort.3.Enable 1 +obuspa -c set Device.Bridging.Bridge.1.VLANPort.3.VLAN Device.Bridging.Bridge.1.VLAN.1 +obuspa -c set Device.Bridging.Bridge.1.VLANPort.3.Port Device.Bridging.Bridge.1.Port.4 + +obuspa -c add Device.Bridging.Bridge. + +obuspa -c add Device.Bridging.Bridge.2.Port. +obuspa -c set Device.Bridging.Bridge.2.Port.1.ManagementPort 1 + +obuspa -c add Device.Bridging.Bridge.2.Port. +obuspa -c set Device.Bridging.Bridge.2.Port.2.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.2.Port.2.LowerLayers Device.Ethernet.Interface.1 +obuspa -c set Device.Bridging.Bridge.2.Port.2.Enable 1 + +obuspa -c add Device.Bridging.Bridge.2.Port. +obuspa -c set Device.Bridging.Bridge.2.Port.3.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.2.Port.3.LowerLayers Device.Ethernet.Interface.2 +obuspa -c set Device.Bridging.Bridge.2.Port.3.Enable 1 + +obuspa -c add Device.Bridging.Bridge.2.Port. +obuspa -c set Device.Bridging.Bridge.2.Port.4.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.2.Port.4.LowerLayers Device.Ethernet.Interface.3 +obuspa -c set Device.Bridging.Bridge.2.Port.4.Enable 1 + +obuspa -c add Device.Bridging.Bridge.2.VLAN. +obuspa -c set Device.Bridging.Bridge.2.VLAN.1.VLANID 200 + +obuspa -c add Device.Bridging.Bridge.2.VLANPort. +obuspa -c set Device.Bridging.Bridge.2.VLANPort.1.Enable 1 +obuspa -c set Device.Bridging.Bridge.2.VLANPort.1.VLAN Device.Bridging.Bridge.2.VLAN.1 +obuspa -c set Device.Bridging.Bridge.2.VLANPort.1.Port Device.Bridging.Bridge.2.Port.2 + +obuspa -c add Device.Bridging.Bridge.2.VLANPort. +obuspa -c set Device.Bridging.Bridge.2.VLANPort.2.Enable 1 +obuspa -c set Device.Bridging.Bridge.2.VLANPort.2.VLAN Device.Bridging.Bridge.2.VLAN.1 +obuspa -c set Device.Bridging.Bridge.2.VLANPort.2.Port Device.Bridging.Bridge.2.Port.3 + +obuspa -c add Device.Bridging.Bridge.2.VLANPort. +obuspa -c set Device.Bridging.Bridge.2.VLANPort.3.Enable 1 +obuspa -c set Device.Bridging.Bridge.2.VLANPort.3.VLAN Device.Bridging.Bridge.2.VLAN.1 +obuspa -c set Device.Bridging.Bridge.2.VLANPort.3.Port Device.Bridging.Bridge.2.Port.4 + +obuspa -c add Device.Ethernet.Link. +obuspa -c set Device.Ethernet.Link.1.LowerLayers Device.Bridging.Bridge.1.Port.1 + +obuspa -c add Device.Ethernet.Link. +obuspa -c set Device.Ethernet.Link.2.LowerLayers Device.Bridging.Bridge.2.Port.1 + +obuspa -c add Device.Ethernet.Link. +obuspa -c set Device.Ethernet.Link.3.LowerLayers Device.Ethernet.Interface.3 + +obuspa -c add Device.Ethernet.VLANTermination +obuspa -c set Device.Ethernet.VLANTermination.1.VLANID 300 +obuspa -c set Device.Ethernet.VLANTermination.1.LowerLayers Device.Ethernet.Link.3 + +obuspa -c add Device.IP.Interface. +obuspa -c set Device.IP.Interface.1.Enable 1 +obuspa -c set Device.IP.Interface.1.LowerLayers Device.Ethernet.Link.1 + +obuspa -c add Device.IP.Interface. +obuspa -c set Device.IP.Interface.2.Enable 1 +obuspa -c set Device.IP.Interface.2.LowerLayers Device.Ethernet.Link.2 + +obuspa -c add Device.IP.Interface. +obuspa -c set Device.IP.Interface.3.Enable 1 +obuspa -c set Device.IP.Interface.3.LowerLayers Device.Ethernet.VLANTermination.1 + +obuspa -c add Device.DHCPv4.Client. +obuspa -c set Device.DHCPv4.Client.1.Enable 1 +obuspa -c set Device.DHCPv4.Client.1.Interface Device.IP.Interface.3 +``` + +- **Network UCI Config** + +```bash +$ cat /etc/config/network + +config interface 'loopback' + option device 'lo' + option proto 'static' + option ipaddr '127.0.0.1' + option netmask '255.0.0.0' + +config globals 'globals' + option ula_prefix 'fdd6:db34:8106::/48' + +config device 'dev_eth1' + option enabled '1' + option ifname 'eth1' + option name 'eth1' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth3' + option enabled '1' + option ifname 'eth3' + option name 'eth3' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth4' + option enabled '1' + option ifname 'eth4' + option name 'eth4' + option eee '0' + option pause '1' + option macaddr '44:D4:37:71:B5:52' + +config device 'dev_br1' + option name 'br-dev1' + option type 'bridge' + option bridge_empty '1' + list ports 'eth1.100' + list ports 'eth3.100' + list ports 'eth4.100' + option macaddr '44:D4:37:71:B5:53' + +config device 'br_1_port_1' + option type '8021q' + option enabled '1' + option vid '100' + option ifname 'eth1' + option name 'eth1.100' + option macaddr '44:D4:37:71:B5:53' + +config device 'br_1_port_2' + option type '8021q' + option enabled '1' + option vid '100' + option ifname 'eth3' + option name 'eth3.100' + option macaddr '44:D4:37:71:B5:53' + +config device 'br_1_port_3' + option type '8021q' + option enabled '1' + option vid '100' + option ifname 'eth4' + option name 'eth4.100' + option macaddr '44:D4:37:71:B5:53' + +config device 'dev_br2' + option name 'br-dev2' + option type 'bridge' + option bridge_empty '1' + list ports 'eth1.200' + list ports 'eth3.200' + list ports 'eth4.200' + option macaddr '44:D4:37:71:B5:54' + +config device 'br_2_port_1' + option type '8021q' + option enabled '1' + option vid '200' + option ifname 'eth1' + option name 'eth1.200' + option macaddr '44:D4:37:71:B5:54' + +config device 'br_2_port_2' + option type '8021q' + option enabled '1' + option vid '200' + option ifname 'eth3' + option name 'eth3.200' + option macaddr '44:D4:37:71:B5:54' + +config device 'br_2_port_3' + option type '8021q' + option enabled '1' + option vid '200' + option ifname 'eth4' + option name 'eth4.200' + option macaddr '44:D4:37:71:B5:54' + +config device 'vlan_ter_1' + option type '8021q' + option vid '300' + option ifname 'eth4' + option name 'eth4.300' + option macaddr '44:D4:37:71:B5:55' + +config interface 'iface1' + option proto 'none' + option disabled '0' + option device 'br-dev1' + option macaddr '44:D4:37:71:B5:53' + +config interface 'iface2' + option proto 'none' + option disabled '0' + option device 'br-dev2' + option macaddr '44:D4:37:71:B5:54' + +config interface 'iface3' + option proto 'dhcp' + option disabled '0' + option device 'eth4.300' + option macaddr '44:D4:37:71:B5:55' + +``` + +- **TR-181 Data Model** + +```bash +$ obuspa -c get Device.IP.Interface.*.LowerLayers +Device.IP.Interface.1.LowerLayers => Device.Ethernet.Link.1 +Device.IP.Interface.2.LowerLayers => Device.Ethernet.Link.2 +Device.IP.Interface.3.LowerLayers => Device.Ethernet.VLANTermination.1 +$ obuspa -c get Device.Ethernet.VLANTermination.*.LowerLayers +Device.Ethernet.VLANTermination.1.LowerLayers => Device.Ethernet.Link.3 +$ obuspa -c get Device.Ethernet.Link.*.LowerLayers +Device.Ethernet.Link.1.LowerLayers => Device.Bridging.Bridge.1.Port.1 +Device.Ethernet.Link.2.LowerLayers => Device.Bridging.Bridge.2.Port.1 +Device.Ethernet.Link.3.LowerLayers => Device.Ethernet.Interface.3 +$ obuspa -c get Device.DHCPv4.Client.*.Interface +Device.DHCPv4.Client.1.Interface => Device.IP.Interface.3 +$ obuspa -c get Device.Bridging.Bridge.*.Port.*.LowerLayers +Device.Bridging.Bridge.1.Port.1.LowerLayers => Device.Bridging.Bridge.1.Port.2,Device.Bridging.Bridge.1.Port.3,Device.Bridging.Bridge.1.Port.4 +Device.Bridging.Bridge.1.Port.2.LowerLayers => Device.Ethernet.Interface.1 +Device.Bridging.Bridge.1.Port.3.LowerLayers => Device.Ethernet.Interface.2 +Device.Bridging.Bridge.1.Port.4.LowerLayers => Device.Ethernet.Interface.3 +Device.Bridging.Bridge.2.Port.1.LowerLayers => Device.Bridging.Bridge.2.Port.2,Device.Bridging.Bridge.2.Port.3,Device.Bridging.Bridge.2.Port.4 +Device.Bridging.Bridge.2.Port.2.LowerLayers => Device.Ethernet.Interface.1 +Device.Bridging.Bridge.2.Port.3.LowerLayers => Device.Ethernet.Interface.2 +Device.Bridging.Bridge.2.Port.4.LowerLayers => Device.Ethernet.Interface.3 +$ obuspa -c get Device.Bridging.Bridge.*.VLANPort. +Device.Bridging.Bridge.1.VLANPort.1.Enable => 1 +Device.Bridging.Bridge.1.VLANPort.1.Alias => cpe-1 +Device.Bridging.Bridge.1.VLANPort.1.VLAN => Device.Bridging.Bridge.1.VLAN.1 +Device.Bridging.Bridge.1.VLANPort.1.Port => Device.Bridging.Bridge.1.Port.2 +Device.Bridging.Bridge.1.VLANPort.1.Untagged => 0 +Device.Bridging.Bridge.1.VLANPort.2.Enable => 1 +Device.Bridging.Bridge.1.VLANPort.2.Alias => cpe-2 +Device.Bridging.Bridge.1.VLANPort.2.VLAN => Device.Bridging.Bridge.1.VLAN.1 +Device.Bridging.Bridge.1.VLANPort.2.Port => Device.Bridging.Bridge.1.Port.3 +Device.Bridging.Bridge.1.VLANPort.2.Untagged => 0 +Device.Bridging.Bridge.1.VLANPort.3.Enable => 1 +Device.Bridging.Bridge.1.VLANPort.3.Alias => cpe-3 +Device.Bridging.Bridge.1.VLANPort.3.VLAN => Device.Bridging.Bridge.1.VLAN.1 +Device.Bridging.Bridge.1.VLANPort.3.Port => Device.Bridging.Bridge.1.Port.4 +Device.Bridging.Bridge.1.VLANPort.3.Untagged => 0 +Device.Bridging.Bridge.2.VLANPort.1.Enable => 1 +Device.Bridging.Bridge.2.VLANPort.1.Alias => cpe-1 +Device.Bridging.Bridge.2.VLANPort.1.VLAN => Device.Bridging.Bridge.2.VLAN.1 +Device.Bridging.Bridge.2.VLANPort.1.Port => Device.Bridging.Bridge.2.Port.2 +Device.Bridging.Bridge.2.VLANPort.1.Untagged => 0 +Device.Bridging.Bridge.2.VLANPort.2.Enable => 1 +Device.Bridging.Bridge.2.VLANPort.2.Alias => cpe-2 +Device.Bridging.Bridge.2.VLANPort.2.VLAN => Device.Bridging.Bridge.2.VLAN.1 +Device.Bridging.Bridge.2.VLANPort.2.Port => Device.Bridging.Bridge.2.Port.3 +Device.Bridging.Bridge.2.VLANPort.2.Untagged => 0 +Device.Bridging.Bridge.2.VLANPort.3.Enable => 1 +Device.Bridging.Bridge.2.VLANPort.3.Alias => cpe-3 +Device.Bridging.Bridge.2.VLANPort.3.VLAN => Device.Bridging.Bridge.2.VLAN.1 +Device.Bridging.Bridge.2.VLANPort.3.Port => Device.Bridging.Bridge.2.Port.4 +Device.Bridging.Bridge.2.VLANPort.3.Untagged => 0 +$ obuspa -c get Device.Bridging.Bridge.*.VLAN. +Device.Bridging.Bridge.1.VLAN.1.Enable => 1 +Device.Bridging.Bridge.1.VLAN.1.Alias => cpe-1 +Device.Bridging.Bridge.1.VLAN.1.Name => br_1_vlan_1 +Device.Bridging.Bridge.1.VLAN.1.VLANID => 100 +Device.Bridging.Bridge.2.VLAN.1.Enable => 1 +Device.Bridging.Bridge.2.VLAN.1.Alias => cpe-1 +Device.Bridging.Bridge.2.VLAN.1.Name => br_2_vlan_1 +Device.Bridging.Bridge.2.VLAN.1.VLANID => 200 +``` + +### 5. One VLAN per Customer(MACVLAN over tagged interface) + +- **TR-181 Commands** + +```bash +obuspa -c del Device.DHCPv4.Client.* +obuspa -c del Device.DHCPv6.Client.* +obuspa -c del Device.Ethernet.Link.* +obuspa -c del Device.Bridging.Bridge.* +obuspa -c del Device.IP.Interface.* + +obuspa -c add Device.IP.Interface. +obuspa -c add Device.IP.Interface. +obuspa -c add Device.DHCPv4.Client. +obuspa -c add Device.DHCPv4.Client. +obuspa -c add Device.Ethernet.X_IOPSYS_EU_MACVLAN. +obuspa -c add Device.Ethernet.X_IOPSYS_EU_MACVLAN. +obuspa -c add Device.Ethernet.VLANTermination. +obuspa -c add Device.Ethernet.Link. + +obuspa -c set Device.IP.Interface.1.Enable 1 +obuspa -c set Device.IP.Interface.2.Enable 1 + +obuspa -c set Device.IP.Interface.1.LowerLayers Device.Ethernet.X_IOPSYS_EU_MACVLAN.1 +obuspa -c set Device.IP.Interface.2.LowerLayers Device.Ethernet.X_IOPSYS_EU_MACVLAN.2 + +obuspa -c set Device.DHCPv4.Client.1.Enable 1 +obuspa -c set Device.DHCPv4.Client.2.Enable 1 + +obuspa -c set Device.DHCPv4.Client.1.Interface Device.IP.Interface.1 +obuspa -c set Device.DHCPv4.Client.2.Interface Device.IP.Interface.2 + +obuspa -c set Device.Ethernet.X_IOPSYS_EU_MACVLAN.1.LowerLayers Device.Ethernet.VLANTermination.1 +obuspa -c set Device.Ethernet.X_IOPSYS_EU_MACVLAN.2.LowerLayers Device.Ethernet.VLANTermination.1 + +obuspa -c set Device.Ethernet.VLANTermination.1.VLANID 100 +obuspa -c set Device.Ethernet.VLANTermination.1.LowerLayers Device.Ethernet.Link.1 + +obuspa -c set Device.Ethernet.Link.1.LowerLayers Device.Ethernet.Interface.3 +``` + +- **Network UCI Config** + +```bash +$ cat /etc/config/network + +config interface 'loopback' + option device 'lo' + option proto 'static' + option ipaddr '127.0.0.1' + option netmask '255.0.0.0' + +config globals 'globals' + option ula_prefix 'fde7:715b:fb50::/48' + +config device 'dev_eth1' + option enabled '1' + option ifname 'eth1' + option name 'eth1' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth3' + option enabled '1' + option ifname 'eth3' + option name 'eth3' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth4' + option enabled '1' + option ifname 'eth4' + option name 'eth4' + option eee '0' + option pause '1' + option macaddr '44:D4:37:71:B5:52' + +config interface 'iface1' + option proto 'dhcp' + option disabled '0' + option device 'eth4_1' + option macaddr '44:D4:37:71:B5:53' + +config interface 'iface2' + option proto 'dhcp' + option disabled '0' + option device 'eth4_2' + option macaddr '44:D4:37:71:B5:54' + +config device 'mac_vlan_1' + option type 'macvlan' + option ifname 'eth4.100' + option name 'eth4_1' + option macaddr '44:D4:37:71:B5:53' + +config device 'mac_vlan_2' + option type 'macvlan' + option ifname 'eth4.100' + option name 'eth4_2' + option macaddr '44:D4:37:71:B5:54' + +config device 'vlan_ter_1' + option type '8021q' + option vid '100' + option ifname 'eth4' + option name 'eth4.100' + +``` + +- **TR-181 Data Model** + +```bash +$ obuspa -c get Device.IP.Interface.*.LowerLayers +Device.IP.Interface.1.LowerLayers => Device.Ethernet.X_IOPSYS_EU_MACVLAN.1 +Device.IP.Interface.2.LowerLayers => Device.Ethernet.X_IOPSYS_EU_MACVLAN.2 +$ obuspa -c get Device.Ethernet.X_IOPSYS_EU_MACVLAN.*.LowerLayers +Device.Ethernet.X_IOPSYS_EU_MACVLAN.1.LowerLayers => Device.Ethernet.VLANTermination.1 +Device.Ethernet.X_IOPSYS_EU_MACVLAN.2.LowerLayers => Device.Ethernet.VLANTermination.1 +$ obuspa -c get Device.Ethernet.VLANTermination.*.LowerLayers +Device.Ethernet.VLANTermination.1.LowerLayers => Device.Ethernet.Link.1 +$ obuspa -c get Device.Ethernet.Link.*.LowerLayers +Device.Ethernet.Link.1.LowerLayers => Device.Ethernet.Interface.3 +$ obuspa -c get Device.DHCPv4.Client.*.Interface +Device.DHCPv4.Client.1.Interface => Device.IP.Interface.1 +Device.DHCPv4.Client.2.Interface => Device.IP.Interface.2 +$ obuspa -c get Device.Bridging.Bridge.*.Port.*.LowerLayers +$ obuspa -c get Device.Bridging.Bridge.*.VLAN. +$ obuspa -c get Device.Bridging.Bridge.*.VLANPort. +``` + +### 6. One VLAN per Customer(MACVLAN over untagged interface) + +- **TR-181 Commands** + +```bash +obuspa -c del Device.DHCPv4.Client.* +obuspa -c del Device.DHCPv6.Client.* +obuspa -c del Device.Ethernet.Link.* +obuspa -c del Device.Bridging.Bridge.* +obuspa -c del Device.IP.Interface.* + +obuspa -c add Device.IP.Interface. +obuspa -c add Device.IP.Interface. +obuspa -c add Device.Ethernet.X_IOPSYS_EU_MACVLAN. +obuspa -c add Device.Ethernet.X_IOPSYS_EU_MACVLAN. +obuspa -c add Device.Ethernet.Link. + +obuspa -c set Device.IP.Interface.1.Enable 1 +obuspa -c set Device.IP.Interface.2.Enable 1 + +obuspa -c set Device.IP.Interface.1.LowerLayers Device.Ethernet.X_IOPSYS_EU_MACVLAN.1 +obuspa -c set Device.IP.Interface.2.LowerLayers Device.Ethernet.X_IOPSYS_EU_MACVLAN.2 + +obuspa -c set Device.Ethernet.X_IOPSYS_EU_MACVLAN.1.LowerLayers Device.Ethernet.Link.1 +obuspa -c set Device.Ethernet.X_IOPSYS_EU_MACVLAN.2.LowerLayers Device.Ethernet.Link.1 + +obuspa -c set Device.Ethernet.Link.1.LowerLayers Device.Ethernet.Interface.3 + +obuspa -c add Device.DHCPv4.Client. +obuspa -c set Device.DHCPv4.Client.1.Enable 1 +obuspa -c set Device.DHCPv4.Client.1.Interface Device.IP.Interface.1 + +obuspa -c add Device.DHCPv4.Client. +obuspa -c set Device.DHCPv4.Client.2.Enable 1 +obuspa -c set Device.DHCPv4.Client.2.Interface Device.IP.Interface.2 +``` + +- **Network UCI Config** + +```bash +$ cat /etc/config/network + +config interface 'loopback' + option device 'lo' + option proto 'static' + option ipaddr '127.0.0.1' + option netmask '255.0.0.0' + +config globals 'globals' + option ula_prefix 'fd75:d87a:791b::/48' + +config device 'dev_eth1' + option enabled '1' + option ifname 'eth1' + option name 'eth1' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth3' + option enabled '1' + option ifname 'eth3' + option name 'eth3' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth4' + option enabled '1' + option ifname 'eth4' + option name 'eth4' + option eee '0' + option pause '1' + option macaddr '44:D4:37:71:B5:52' + +config interface 'iface1' + option proto 'dhcp' + option disabled '0' + option device 'eth4_1' + option macaddr '44:D4:37:71:B5:53' + +config interface 'iface2' + option proto 'dhcp' + option disabled '0' + option device 'eth4_2' + option macaddr '44:D4:37:71:B5:54' + +config device 'mac_vlan_1' + option type 'macvlan' + option ifname 'eth4' + option name 'eth4_1' + option macaddr '44:D4:37:71:B5:53' + +config device 'mac_vlan_2' + option type 'macvlan' + option ifname 'eth4' + option name 'eth4_2' + option macaddr '44:D4:37:71:B5:54' + +``` + +- **TR-181 Data Model** + +```bash +$ obuspa -c get Device.IP.Interface.*.LowerLayers +Device.IP.Interface.1.LowerLayers => Device.Ethernet.X_IOPSYS_EU_MACVLAN.1 +Device.IP.Interface.2.LowerLayers => Device.Ethernet.X_IOPSYS_EU_MACVLAN.2 +$ obuspa -c get Device.Ethernet.X_IOPSYS_EU_MACVLAN.*.LowerLayers +Device.Ethernet.X_IOPSYS_EU_MACVLAN.1.LowerLayers => Device.Ethernet.Link.1 +Device.Ethernet.X_IOPSYS_EU_MACVLAN.2.LowerLayers => Device.Ethernet.Link.1 +$ obuspa -c get Device.Ethernet.VLANTermination.*.LowerLayers +$ obuspa -c get Device.Ethernet.Link.*.LowerLayers +Device.Ethernet.Link.1.LowerLayers => Device.Ethernet.Interface.3 +$ obuspa -c get Device.DHCPv4.Client.*.Interface +Device.DHCPv4.Client.1.Interface => Device.IP.Interface.1 +Device.DHCPv4.Client.2.Interface => Device.IP.Interface.2 +$ obuspa -c get Device.Bridging.Bridge.*.Port.*.LowerLayers +$ obuspa -c get Device.Bridging.Bridge.*.VLAN. +$ obuspa -c get Device.Bridging.Bridge.*.VLANPort. +``` + +### 7. VLAN Translation + +- **TR-181 Commands** + +```bash +obuspa -c del Device.DHCPv4.Client.* +obuspa -c del Device.DHCPv6.Client.* +obuspa -c del Device.Ethernet.Link.* +obuspa -c del Device.Bridging.Bridge.* +obuspa -c del Device.IP.Interface.* + +obuspa -c add Device.IP.Interface. +obuspa -c add Device.IP.Interface. +obuspa -c add Device.DHCPv4.Client. +obuspa -c add Device.Ethernet.Link. +obuspa -c add Device.Ethernet.Link. +obuspa -c add Device.Bridging.Bridge. +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c add Device.Bridging.Bridge.1.VLAN. +obuspa -c add Device.Bridging.Bridge.1.VLAN. +obuspa -c add Device.Bridging.Bridge.1.VLANPort. +obuspa -c add Device.Bridging.Bridge.1.VLANPort. +obuspa -c add Device.Bridging.Bridge.1.VLANPort. + +obuspa -c set Device.IP.Interface.1.Enable 1 +obuspa -c set Device.IP.Interface.1.LowerLayers Device.Ethernet.Link.1 + +obuspa -c set Device.IP.Interface.2.Enable 1 +obuspa -c set Device.IP.Interface.2.LowerLayers Device.Ethernet.Link.2 + +obuspa -c set Device.DHCPv4.Client.1.Enable 1 +obuspa -c set Device.DHCPv4.Client.1.Interface Device.IP.Interface.2 + +obuspa -c set Device.Bridging.Bridge.1.Port.2.Enable 1 +obuspa -c set Device.Bridging.Bridge.1.Port.3.Enable 1 +obuspa -c set Device.Bridging.Bridge.1.Port.4.Enable 1 + +obuspa -c set Device.Bridging.Bridge.1.Port.1.ManagementPort 1 +obuspa -c set Device.Bridging.Bridge.1.Port.2.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.1.Port.3.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.1.Port.4.ManagementPort 0 + +obuspa -c set Device.Bridging.Bridge.1.VLANPort.1.Enable 1 +obuspa -c set Device.Bridging.Bridge.1.VLANPort.2.Enable 1 +obuspa -c set Device.Bridging.Bridge.1.VLANPort.3.Enable 1 + +obuspa -c set Device.Bridging.Bridge.1.VLANPort.1.VLAN Device.Bridging.Bridge.1.VLAN.1 +obuspa -c set Device.Bridging.Bridge.1.VLANPort.1.Port Device.Bridging.Bridge.1.Port.2 + + +obuspa -c set Device.Bridging.Bridge.1.VLANPort.2.VLAN Device.Bridging.Bridge.1.VLAN.1 +obuspa -c set Device.Bridging.Bridge.1.VLANPort.2.Port Device.Bridging.Bridge.1.Port.3 + +obuspa -c set Device.Bridging.Bridge.1.VLANPort.3.VLAN Device.Bridging.Bridge.1.VLAN.2 +obuspa -c set Device.Bridging.Bridge.1.VLANPort.3.Port Device.Bridging.Bridge.1.Port.4 + +obuspa -c set Device.Bridging.Bridge.1.VLAN.1.VLANID 100 +obuspa -c set Device.Bridging.Bridge.1.VLAN.2.VLANID 200 + +obuspa -c set Device.Bridging.Bridge.1.Port.2.LowerLayers Device.Ethernet.Interface.1 +obuspa -c set Device.Bridging.Bridge.1.Port.3.LowerLayers Device.Ethernet.Interface.2 +obuspa -c set Device.Bridging.Bridge.1.Port.4.LowerLayers Device.Ethernet.Interface.3 + +obuspa -c set Device.Ethernet.Link.1.LowerLayers Device.Bridging.Bridge.1.Port.1 +obuspa -c set Device.Ethernet.Link.2.LowerLayers Device.Ethernet.Interface.3 +``` + +- **Network UCI Config** + +```bash +$ cat /etc/config/network + +config interface 'loopback' + option device 'lo' + option proto 'static' + option ipaddr '127.0.0.1' + option netmask '255.0.0.0' + +config globals 'globals' + option ula_prefix 'fd07:a062:db26::/48' + +config device 'dev_eth1' + option enabled '1' + option ifname 'eth1' + option name 'eth1' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth3' + option enabled '1' + option ifname 'eth3' + option name 'eth3' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth4' + option enabled '1' + option ifname 'eth4' + option name 'eth4' + option eee '0' + option pause '1' + option macaddr '44:D4:37:71:B5:52' + +config interface 'iface1' + option proto 'none' + option disabled '0' + option device 'br-dev1' + option macaddr '44:D4:37:71:B5:53' + +config interface 'iface2' + option proto 'dhcp' + option disabled '0' + option device 'eth4' + option macaddr '44:D4:37:71:B5:54' + +config device 'dev_br1' + option name 'br-dev1' + option type 'bridge' + option bridge_empty '1' + option macaddr '44:D4:37:71:B5:53' + list ports 'eth1.100' + list ports 'eth3.100' + list ports 'eth4.200' + +config device 'br_1_port_1' + option type '8021q' + option enabled '1' + option vid '100' + option ifname 'eth1' + option name 'eth1.100' + option macaddr '44:D4:37:71:B5:53' + +config device 'br_1_port_2' + option type '8021q' + option enabled '1' + option vid '100' + option ifname 'eth3' + option name 'eth3.100' + option macaddr '44:D4:37:71:B5:53' + +config device 'br_1_port_3' + option type '8021q' + option enabled '1' + option vid '200' + option ifname 'eth4' + option name 'eth4.200' + option macaddr '44:D4:37:71:B5:53' + +``` + +- **TR-181 Data Model** + +```bash +$ obuspa -c get Device.IP.Interface.*.LowerLayers +Device.IP.Interface.1.LowerLayers => Device.Ethernet.Link.1 +Device.IP.Interface.2.LowerLayers => Device.Ethernet.Link.2 +$ obuspa -c get Device.Ethernet.Link.*.LowerLayers +Device.Ethernet.Link.1.LowerLayers => Device.Bridging.Bridge.1.Port.1 +Device.Ethernet.Link.2.LowerLayers => Device.Ethernet.Interface.3 +$ obuspa -c get Device.Ethernet.VLANTermination.*.LowerLayers +$ obuspa -c get Device.Bridging.Bridge.*.Port.*.LowerLayers +Device.Bridging.Bridge.1.Port.1.LowerLayers => Device.Bridging.Bridge.1.Port.2,Device.Bridging.Bridge.1.Port.3,Device.Bridging.Bridge.1.Port.4 +Device.Bridging.Bridge.1.Port.2.LowerLayers => Device.Ethernet.Interface.1 +Device.Bridging.Bridge.1.Port.3.LowerLayers => Device.Ethernet.Interface.2 +Device.Bridging.Bridge.1.Port.4.LowerLayers => Device.Ethernet.Interface.3 +$ obuspa -c get Device.Bridging.Bridge.*.VLAN. +Device.Bridging.Bridge.1.VLAN.1.Enable => 1 +Device.Bridging.Bridge.1.VLAN.1.Alias => cpe-1 +Device.Bridging.Bridge.1.VLAN.1.Name => br_1_vlan_1 +Device.Bridging.Bridge.1.VLAN.1.VLANID => 100 +Device.Bridging.Bridge.1.VLAN.2.Enable => 1 +Device.Bridging.Bridge.1.VLAN.2.Alias => cpe-2 +Device.Bridging.Bridge.1.VLAN.2.Name => br_1_vlan_2 +Device.Bridging.Bridge.1.VLAN.2.VLANID => 200 +$ obuspa -c get Device.Bridging.Bridge.*.VLANPort. +Device.Bridging.Bridge.1.VLANPort.1.Enable => 1 +Device.Bridging.Bridge.1.VLANPort.1.Alias => cpe-1 +Device.Bridging.Bridge.1.VLANPort.1.VLAN => Device.Bridging.Bridge.1.VLAN.1 +Device.Bridging.Bridge.1.VLANPort.1.Port => Device.Bridging.Bridge.1.Port.2 +Device.Bridging.Bridge.1.VLANPort.1.Untagged => 0 +Device.Bridging.Bridge.1.VLANPort.2.Enable => 1 +Device.Bridging.Bridge.1.VLANPort.2.Alias => cpe-2 +Device.Bridging.Bridge.1.VLANPort.2.VLAN => Device.Bridging.Bridge.1.VLAN.1 +Device.Bridging.Bridge.1.VLANPort.2.Port => Device.Bridging.Bridge.1.Port.3 +Device.Bridging.Bridge.1.VLANPort.2.Untagged => 0 +Device.Bridging.Bridge.1.VLANPort.3.Enable => 1 +Device.Bridging.Bridge.1.VLANPort.3.Alias => cpe-3 +Device.Bridging.Bridge.1.VLANPort.3.VLAN => Device.Bridging.Bridge.1.VLAN.2 +Device.Bridging.Bridge.1.VLANPort.3.Port => Device.Bridging.Bridge.1.Port.4 +Device.Bridging.Bridge.1.VLANPort.3.Untagged => 0 +$ obuspa -c get Device.DHCPv4.Client.*.Interface +Device.DHCPv4.Client.1.Interface => Device.IP.Interface.2 +``` + +### 8. Managed Bridge + +- **TR-181 Commands** + +```bash +obuspa -c del Device.DHCPv4.Client.* +obuspa -c del Device.DHCPv6.Client.* +obuspa -c del Device.Ethernet.Link.* +obuspa -c del Device.Bridging.Bridge.* +obuspa -c del Device.IP.Interface.* + +obuspa -c add Device.Bridging.Bridge. + +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c set Device.Bridging.Bridge.1.Port.1.ManagementPort 1 + +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c set Device.Bridging.Bridge.1.Port.2.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.1.Port.2.LowerLayers Device.Ethernet.Interface.1 +obuspa -c set Device.Bridging.Bridge.1.Port.2.Enable 1 + +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c set Device.Bridging.Bridge.1.Port.3.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.1.Port.3.LowerLayers Device.Ethernet.Interface.2 +obuspa -c set Device.Bridging.Bridge.1.Port.3.Enable 1 + +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c set Device.Bridging.Bridge.1.Port.4.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.1.Port.4.LowerLayers Device.Ethernet.Interface.3 +obuspa -c set Device.Bridging.Bridge.1.Port.4.Enable 1 + +obuspa -c add Device.Bridging.Bridge.1.VLAN. +obuspa -c set Device.Bridging.Bridge.1.VLAN.1.VLANID 100 + +obuspa -c add Device.Bridging.Bridge.1.VLANPort. +obuspa -c set Device.Bridging.Bridge.1.VLANPort.1.Enable 1 +obuspa -c set Device.Bridging.Bridge.1.VLANPort.1.Port Device.Bridging.Bridge.1.Port.2 +obuspa -c set Device.Bridging.Bridge.1.VLANPort.1.VLAN Device.Bridging.Bridge.1.VLAN.1 + +obuspa -c add Device.Bridging.Bridge.1.VLANPort. +obuspa -c set Device.Bridging.Bridge.1.VLANPort.2.Enable 1 +obuspa -c set Device.Bridging.Bridge.1.VLANPort.2.Port Device.Bridging.Bridge.1.Port.3 +obuspa -c set Device.Bridging.Bridge.1.VLANPort.2.VLAN Device.Bridging.Bridge.1.VLAN.1 + +obuspa -c add Device.Bridging.Bridge.1.VLANPort. +obuspa -c set Device.Bridging.Bridge.1.VLANPort.3.Enable 1 +obuspa -c set Device.Bridging.Bridge.1.VLANPort.3.VLAN Device.Bridging.Bridge.1.VLAN.1 +obuspa -c set Device.Bridging.Bridge.1.VLANPort.3.Port Device.Bridging.Bridge.1.Port.4 + +obuspa -c add Device.Ethernet.Link. +obuspa -c set Device.Ethernet.Link.1.LowerLayers Device.Bridging.Bridge.1.Port.1 + +obuspa -c add Device.IP.Interface. +obuspa -c set Device.IP.Interface.1.Enable 1 +obuspa -c set Device.IP.Interface.1.LowerLayers Device.Ethernet.Link.1 + +obuspa -c add Device.DHCPv4.Client. +obuspa -c set Device.DHCPv4.Client.1.Enable 1 +obuspa -c set Device.DHCPv4.Client.1.Interface Device.IP.Interface.1 +``` + +- **Network UCI Config** + +```bash +$ cat /etc/config/network + +config interface 'loopback' + option device 'lo' + option proto 'static' + option ipaddr '127.0.0.1' + option netmask '255.0.0.0' + +config globals 'globals' + option ula_prefix 'fde2:72a7:da9d::/48' + +config device 'dev_eth1' + option enabled '1' + option ifname 'eth1' + option name 'eth1' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth3' + option enabled '1' + option ifname 'eth3' + option name 'eth3' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth4' + option enabled '1' + option ifname 'eth4' + option name 'eth4' + option eee '0' + option pause '1' + option macaddr '44:D4:37:71:B5:52' + +config device 'dev_br1' + option name 'br-dev1' + option type 'bridge' + option bridge_empty '1' + list ports 'eth1.100' + list ports 'eth3.100' + list ports 'eth4.100' + option macaddr '44:D4:37:71:B5:53' + +config device 'br_1_port_1' + option type '8021q' + option enabled '1' + option ifname 'eth1' + option name 'eth1.100' + option vid '100' + option macaddr '44:D4:37:71:B5:53' + +config device 'br_1_port_2' + option type '8021q' + option enabled '1' + option ifname 'eth3' + option name 'eth3.100' + option vid '100' + option macaddr '44:D4:37:71:B5:53' + +config device 'br_1_port_3' + option type '8021q' + option enabled '1' + option vid '100' + option ifname 'eth4' + option name 'eth4.100' + option macaddr '44:D4:37:71:B5:53' + +config interface 'iface1' + option proto 'dhcp' + option disabled '0' + option device 'br-dev1' + option macaddr '44:D4:37:71:B5:53' + +``` + +- **TR-181 Data Model** + +```bash +$ obuspa -c get Device.IP.Interface.*.LowerLayers +Device.IP.Interface.1.LowerLayers => Device.Ethernet.Link.1 +$ obuspa -c get Device.Ethernet.Link.*.LowerLayers +Device.Ethernet.Link.1.LowerLayers => Device.Bridging.Bridge.1.Port.1 +$ obuspa -c get Device.Ethernet.VLANTermination.*.LowerLayers +$ obuspa -c get Device.Bridging.Bridge.*.Port.*.LowerLayers +Device.Bridging.Bridge.1.Port.1.LowerLayers => Device.Bridging.Bridge.1.Port.2,Device.Bridging.Bridge.1.Port.3,Device.Bridging.Bridge.1.Port.4 +Device.Bridging.Bridge.1.Port.2.LowerLayers => Device.Ethernet.Interface.1 +Device.Bridging.Bridge.1.Port.3.LowerLayers => Device.Ethernet.Interface.2 +Device.Bridging.Bridge.1.Port.4.LowerLayers => Device.Ethernet.Interface.3 +$ obuspa -c get Device.Bridging.Bridge.*.VLANPort. +Device.Bridging.Bridge.1.VLANPort.1.Enable => 1 +Device.Bridging.Bridge.1.VLANPort.1.Alias => cpe-1 +Device.Bridging.Bridge.1.VLANPort.1.VLAN => Device.Bridging.Bridge.1.VLAN.1 +Device.Bridging.Bridge.1.VLANPort.1.Port => Device.Bridging.Bridge.1.Port.2 +Device.Bridging.Bridge.1.VLANPort.1.Untagged => 0 +Device.Bridging.Bridge.1.VLANPort.2.Enable => 1 +Device.Bridging.Bridge.1.VLANPort.2.Alias => cpe-2 +Device.Bridging.Bridge.1.VLANPort.2.VLAN => Device.Bridging.Bridge.1.VLAN.1 +Device.Bridging.Bridge.1.VLANPort.2.Port => Device.Bridging.Bridge.1.Port.3 +Device.Bridging.Bridge.1.VLANPort.2.Untagged => 0 +Device.Bridging.Bridge.1.VLANPort.3.Enable => 1 +Device.Bridging.Bridge.1.VLANPort.3.Alias => cpe-3 +Device.Bridging.Bridge.1.VLANPort.3.VLAN => Device.Bridging.Bridge.1.VLAN.1 +Device.Bridging.Bridge.1.VLANPort.3.Port => Device.Bridging.Bridge.1.Port.4 +Device.Bridging.Bridge.1.VLANPort.3.Untagged => 0 +$ obuspa -c get Device.Bridging.Bridge.*.VLAN. +Device.Bridging.Bridge.1.VLAN.1.Enable => 1 +Device.Bridging.Bridge.1.VLAN.1.Alias => cpe-1 +Device.Bridging.Bridge.1.VLAN.1.Name => br_1_vlan_1 +Device.Bridging.Bridge.1.VLAN.1.VLANID => 100 +$ obuspa -c get Device.DHCPv4.Client.*.Interface +Device.DHCPv4.Client.1.Interface => Device.IP.Interface.1 +``` + +### 9. QinQ lan untagged to wan double tagged (Bridge mode) + +- **TR-181 Commands** + +```bash +obuspa -c del Device.DHCPv4.Client.* +obuspa -c del Device.DHCPv6.Client.* +obuspa -c del Device.Ethernet.Link.* +obuspa -c del Device.Bridging.Bridge.* +obuspa -c del Device.IP.Interface.* + +obuspa -c add Device.Bridging.Bridge. +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c set Device.Bridging.Bridge.1.Port.1.ManagementPort 1 +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c set Device.Bridging.Bridge.1.Port.2.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.1.Port.2.LowerLayers Device.Ethernet.Interface.1 +obuspa -c set Device.Bridging.Bridge.1.Port.2.Enable 1 + +obuspa -c add Device.Bridging.Bridge. +obuspa -c add Device.Bridging.Bridge.2.Port. +obuspa -c set Device.Bridging.Bridge.2.Port.1.ManagementPort 1 +obuspa -c add Device.Bridging.Bridge.2.Port. +obuspa -c set Device.Bridging.Bridge.2.Port.2.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.2.Port.2.LowerLayers Device.Ethernet.Interface.2 +obuspa -c set Device.Bridging.Bridge.2.Port.2.Enable 1 + +obuspa -c add Device.Bridging.Bridge. +obuspa -c add Device.Bridging.Bridge.3.Port. +obuspa -c set Device.Bridging.Bridge.3.Port.1.ManagementPort 1 +obuspa -c add Device.Bridging.Bridge.3.Port. +obuspa -c set Device.Bridging.Bridge.3.Port.2.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.3.Port.2.LowerLayers Device.Ethernet.Interface.3 +obuspa -c set Device.Bridging.Bridge.3.Port.2.Enable 1 + +obuspa -c add Device.Bridging.Bridge.3.VLAN. +obuspa -c set Device.Bridging.Bridge.3.VLAN.1.VLANID 100 + +obuspa -c add Device.Bridging.Bridge.3.VLANPort. +obuspa -c set Device.Bridging.Bridge.3.VLANPort.1.Enable 1 +obuspa -c set Device.Bridging.Bridge.3.VLANPort.1.VLAN Device.Bridging.Bridge.3.VLAN.1 +obuspa -c set Device.Bridging.Bridge.3.VLANPort.1.Port Device.Bridging.Bridge.3.Port.2 + +obuspa -c add Device.Bridging.Bridge. +obuspa -c add Device.Bridging.Bridge.4.Port. +obuspa -c set Device.Bridging.Bridge.4.Port.1.ManagementPort 1 +obuspa -c add Device.Bridging.Bridge.4.Port. +obuspa -c set Device.Bridging.Bridge.4.Port.2.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.4.Port.2.TPID 34984 +obuspa -c set Device.Bridging.Bridge.4.Port.2.LowerLayers Device.Bridging.Bridge.3.Port.2 +obuspa -c set Device.Bridging.Bridge.4.Port.2.Enable 1 + +obuspa -c add Device.Bridging.Bridge.4.VLAN. +obuspa -c set Device.Bridging.Bridge.4.VLAN.1.VLANID 300 + +obuspa -c add Device.Bridging.Bridge.4.VLANPort. +obuspa -c set Device.Bridging.Bridge.4.VLANPort.1.Enable 1 +obuspa -c set Device.Bridging.Bridge.4.VLANPort.1.VLAN Device.Bridging.Bridge.4.VLAN.1 +obuspa -c set Device.Bridging.Bridge.4.VLANPort.1.Port Device.Bridging.Bridge.4.Port.2 + +obuspa -c add Device.Bridging.ProviderBridge. + +obuspa -c set Device.Bridging.ProviderBridge.1.CVLANcomponents Device.Bridging.Bridge.1,Device.Bridging.Bridge.2 +obuspa -c set Device.Bridging.ProviderBridge.1.SVLANcomponent Device.Bridging.Bridge.4 +``` + +- **Network UCI Config** + +```bash +$ cat /etc/config/network + +config interface 'loopback' + option device 'lo' + option proto 'static' + option ipaddr '127.0.0.1' + option netmask '255.0.0.0' + +config globals 'globals' + option ula_prefix 'fdf8:6c90:1a98::/48' + +config device 'dev_eth1' + option enabled '1' + option ifname 'eth1' + option name 'eth1' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:53' + +config device 'dev_eth3' + option enabled '1' + option ifname 'eth3' + option name 'eth3' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:53' + +config device 'dev_eth4' + option enabled '1' + option ifname 'eth4' + option name 'eth4' + option eee '0' + option pause '1' + option macaddr '44:D4:37:71:B5:52' + +config interface 'iface_br1' + option device 'br-dev1' + option macaddr '44:D4:37:71:B5:53' + +config device 'pr_br_1' + option name 'br-dev1' + option type 'bridge' + option bridge_empty '1' + list ports 'eth1' + list ports 'eth3' + list ports 'eth4.100.300' + option macaddr '44:D4:37:71:B5:53' + +config device 'br_3_port_1' + option type '8021q' + option enabled '1' + option vid '100' + option ifname 'eth4' + option name 'eth4.100' + option macaddr '44:D4:37:71:B5:54' + +config device 'br_4_port_1' + option type '8021ad' + option enabled '1' + option vid '300' + option ifname 'eth4.100' + option name 'eth4.100.300' + option macaddr '44:D4:37:71:B5:55' + +``` + +- **TR-181 Data Model** + +```bash +$ obuspa -c get Device.Bridging.Bridge.*.Port.*.LowerLayers +Device.Bridging.Bridge.1.Port.1.LowerLayers => Device.Bridging.Bridge.1.Port.2 +Device.Bridging.Bridge.1.Port.2.LowerLayers => Device.Ethernet.Interface.1 +Device.Bridging.Bridge.2.Port.1.LowerLayers => Device.Bridging.Bridge.2.Port.2 +Device.Bridging.Bridge.2.Port.2.LowerLayers => Device.Ethernet.Interface.2 +Device.Bridging.Bridge.3.Port.1.LowerLayers => Device.Bridging.Bridge.3.Port.2 +Device.Bridging.Bridge.3.Port.2.LowerLayers => Device.Ethernet.Interface.3 +Device.Bridging.Bridge.4.Port.1.LowerLayers => Device.Bridging.Bridge.4.Port.2 +Device.Bridging.Bridge.4.Port.2.LowerLayers => Device.Bridging.Bridge.3.Port.2 +$ obuspa -c get Device.Bridging.Bridge.*.VLANPort. +Device.Bridging.Bridge.3.VLANPort.1.Enable => 1 +Device.Bridging.Bridge.3.VLANPort.1.Alias => cpe-1 +Device.Bridging.Bridge.3.VLANPort.1.VLAN => Device.Bridging.Bridge.3.VLAN.1 +Device.Bridging.Bridge.3.VLANPort.1.Port => Device.Bridging.Bridge.3.Port.2 +Device.Bridging.Bridge.3.VLANPort.1.Untagged => 0 +Device.Bridging.Bridge.4.VLANPort.1.Enable => 1 +Device.Bridging.Bridge.4.VLANPort.1.Alias => cpe-1 +Device.Bridging.Bridge.4.VLANPort.1.VLAN => Device.Bridging.Bridge.4.VLAN.1 +Device.Bridging.Bridge.4.VLANPort.1.Port => Device.Bridging.Bridge.4.Port.2 +Device.Bridging.Bridge.4.VLANPort.1.Untagged => 0 +$ obuspa -c get Device.Bridging.Bridge.*.VLAN. +Device.Bridging.Bridge.3.VLAN.1.Enable => 1 +Device.Bridging.Bridge.3.VLAN.1.Alias => cpe-1 +Device.Bridging.Bridge.3.VLAN.1.Name => br_3_vlan_1 +Device.Bridging.Bridge.3.VLAN.1.VLANID => 100 +Device.Bridging.Bridge.4.VLAN.1.Enable => 1 +Device.Bridging.Bridge.4.VLAN.1.Alias => cpe-1 +Device.Bridging.Bridge.4.VLAN.1.Name => br_4_vlan_1 +Device.Bridging.Bridge.4.VLAN.1.VLANID => 300 +$ obuspa -c get Device.Bridging.ProviderBridge. +Device.Bridging.ProviderBridge.1.Enable => 1 +Device.Bridging.ProviderBridge.1.Status => Enabled +Device.Bridging.ProviderBridge.1.Alias => cpe-1 +Device.Bridging.ProviderBridge.1.SVLANcomponent => Device.Bridging.Bridge.4 +Device.Bridging.ProviderBridge.1.CVLANcomponents => Device.Bridging.Bridge.1,Device.Bridging.Bridge.2 +``` + +### 10. QinQ lan single tagged to wan double tagged (Bridge mode) + +- **TR-181 Commands** + +```bash +obuspa -c del Device.DHCPv4.Client.* +obuspa -c del Device.DHCPv6.Client.* +obuspa -c del Device.Ethernet.Link.* +obuspa -c del Device.Bridging.Bridge.* +obuspa -c del Device.IP.Interface.* + +obuspa -c add Device.Bridging.Bridge. +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c set Device.Bridging.Bridge.1.Port.1.ManagementPort 1 +obuspa -c add Device.Bridging.Bridge.1.Port. +obuspa -c set Device.Bridging.Bridge.1.Port.2.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.1.Port.2.LowerLayers Device.Ethernet.Interface.1 +obuspa -c set Device.Bridging.Bridge.1.Port.2.Enable 1 + +obuspa -c add Device.Bridging.Bridge.1.VLAN. +obuspa -c set Device.Bridging.Bridge.1.VLAN.1.VLANID 100 + +obuspa -c add Device.Bridging.Bridge.1.VLANPort. +obuspa -c set Device.Bridging.Bridge.1.VLANPort.1.Enable 1 +obuspa -c set Device.Bridging.Bridge.1.VLANPort.1.VLAN Device.Bridging.Bridge.1.VLAN.1 +obuspa -c set Device.Bridging.Bridge.1.VLANPort.1.Port Device.Bridging.Bridge.1.Port.2 + +obuspa -c add Device.Bridging.Bridge. +obuspa -c add Device.Bridging.Bridge.2.Port. +obuspa -c set Device.Bridging.Bridge.2.Port.1.ManagementPort 1 +obuspa -c add Device.Bridging.Bridge.2.Port. +obuspa -c set Device.Bridging.Bridge.2.Port.2.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.2.Port.2.LowerLayers Device.Ethernet.Interface.2 +obuspa -c set Device.Bridging.Bridge.2.Port.2.Enable 1 + +obuspa -c add Device.Bridging.Bridge.2.VLAN. +obuspa -c set Device.Bridging.Bridge.2.VLAN.1.VLANID 100 + +obuspa -c add Device.Bridging.Bridge.2.VLANPort. +obuspa -c set Device.Bridging.Bridge.2.VLANPort.1.Enable 1 +obuspa -c set Device.Bridging.Bridge.2.VLANPort.1.VLAN Device.Bridging.Bridge.2.VLAN.1 +obuspa -c set Device.Bridging.Bridge.2.VLANPort.1.Port Device.Bridging.Bridge.2.Port.2 + +obuspa -c add Device.Bridging.Bridge. +obuspa -c add Device.Bridging.Bridge.3.Port. +obuspa -c set Device.Bridging.Bridge.3.Port.1.ManagementPort 1 +obuspa -c add Device.Bridging.Bridge.3.Port. +obuspa -c set Device.Bridging.Bridge.3.Port.2.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.3.Port.2.LowerLayers Device.Ethernet.Interface.3 +obuspa -c set Device.Bridging.Bridge.3.Port.2.Enable 1 + +obuspa -c add Device.Bridging.Bridge.3.VLAN. +obuspa -c set Device.Bridging.Bridge.3.VLAN.1.VLANID 100 + +obuspa -c add Device.Bridging.Bridge.3.VLANPort. +obuspa -c set Device.Bridging.Bridge.3.VLANPort.1.Enable 1 +obuspa -c set Device.Bridging.Bridge.3.VLANPort.1.VLAN Device.Bridging.Bridge.3.VLAN.1 +obuspa -c set Device.Bridging.Bridge.3.VLANPort.1.Port Device.Bridging.Bridge.3.Port.2 + +obuspa -c add Device.Bridging.Bridge. +obuspa -c add Device.Bridging.Bridge.4.Port. +obuspa -c set Device.Bridging.Bridge.4.Port.1.ManagementPort 1 +obuspa -c add Device.Bridging.Bridge.4.Port. +obuspa -c set Device.Bridging.Bridge.4.Port.2.ManagementPort 0 +obuspa -c set Device.Bridging.Bridge.4.Port.2.TPID 34984 +obuspa -c set Device.Bridging.Bridge.4.Port.2.LowerLayers Device.Bridging.Bridge.3.Port.2 +obuspa -c set Device.Bridging.Bridge.4.Port.2.Enable 1 + +obuspa -c add Device.Bridging.Bridge.4.VLAN. +obuspa -c set Device.Bridging.Bridge.4.VLAN.1.VLANID 300 + +obuspa -c add Device.Bridging.Bridge.4.VLANPort. +obuspa -c set Device.Bridging.Bridge.4.VLANPort.1.Enable 1 +obuspa -c set Device.Bridging.Bridge.4.VLANPort.1.VLAN Device.Bridging.Bridge.4.VLAN.1 +obuspa -c set Device.Bridging.Bridge.4.VLANPort.1.Port Device.Bridging.Bridge.4.Port.2 + +obuspa -c add Device.Bridging.ProviderBridge. + +obuspa -c set Device.Bridging.ProviderBridge.1.CVLANcomponents Device.Bridging.Bridge.1,Device.Bridging.Bridge.2 +obuspa -c set Device.Bridging.ProviderBridge.1.SVLANcomponent Device.Bridging.Bridge.4 +``` + +- **Network UCI Config** + +```bash +$ cat /etc/config/network + +config interface 'loopback' + option device 'lo' + option proto 'static' + option ipaddr '127.0.0.1' + option netmask '255.0.0.0' + +config globals 'globals' + option ula_prefix 'fde7:6307:3a39::/48' + +config device 'dev_eth1' + option enabled '1' + option ifname 'eth1' + option name 'eth1' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth3' + option enabled '1' + option ifname 'eth3' + option name 'eth3' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth4' + option enabled '1' + option ifname 'eth4' + option name 'eth4' + option eee '0' + option pause '1' + option macaddr '44:D4:37:71:B5:52' + +config interface 'iface_br1' + option device 'br-dev1' + option macaddr '44:D4:37:71:B5:53' + +config device 'pr_br_1' + option name 'br-dev1' + option type 'bridge' + option bridge_empty '1' + list ports 'eth1.100' + list ports 'eth3.100' + list ports 'eth4.100.300' + option macaddr '44:D4:37:71:B5:53' + +config device 'br_1_port_1' + option type '8021q' + option enabled '1' + option vid '100' + option ifname 'eth1' + option name 'eth1.100' + option macaddr '44:D4:37:71:B5:53' + +config device 'br_2_port_1' + option type '8021q' + option enabled '1' + option vid '100' + option ifname 'eth3' + option name 'eth3.100' + option macaddr '44:D4:37:71:B5:53' + +config device 'br_3_port_1' + option type '8021q' + option enabled '1' + option vid '100' + option ifname 'eth4' + option name 'eth4.100' + option macaddr '44:D4:37:71:B5:55' + +config device 'br_4_port_1' + option type '8021ad' + option enabled '1' + option vid '300' + option ifname 'eth4.100' + option name 'eth4.100.300' + option macaddr '44:D4:37:71:B5:53' + +``` + +- **TR-181 Data Model** + +```bash +$ obuspa -c get Device.Bridging.Bridge.*.Port.*.LowerLayers +Device.Bridging.Bridge.1.Port.1.LowerLayers => Device.Bridging.Bridge.1.Port.2 +Device.Bridging.Bridge.1.Port.2.LowerLayers => Device.Ethernet.Interface.1 +Device.Bridging.Bridge.2.Port.1.LowerLayers => Device.Bridging.Bridge.2.Port.2 +Device.Bridging.Bridge.2.Port.2.LowerLayers => Device.Ethernet.Interface.2 +Device.Bridging.Bridge.3.Port.1.LowerLayers => Device.Bridging.Bridge.3.Port.2 +Device.Bridging.Bridge.3.Port.2.LowerLayers => Device.Ethernet.Interface.3 +Device.Bridging.Bridge.4.Port.1.LowerLayers => Device.Bridging.Bridge.4.Port.2 +Device.Bridging.Bridge.4.Port.2.LowerLayers => Device.Bridging.Bridge.3.Port.2 +$ obuspa -c get Device.Bridging.Bridge.*.VLANPort. +Device.Bridging.Bridge.1.VLANPort.1.Enable => 1 +Device.Bridging.Bridge.1.VLANPort.1.Alias => cpe-1 +Device.Bridging.Bridge.1.VLANPort.1.VLAN => Device.Bridging.Bridge.1.VLAN.1 +Device.Bridging.Bridge.1.VLANPort.1.Port => Device.Bridging.Bridge.1.Port.2 +Device.Bridging.Bridge.1.VLANPort.1.Untagged => 0 +Device.Bridging.Bridge.2.VLANPort.1.Enable => 1 +Device.Bridging.Bridge.2.VLANPort.1.Alias => cpe-1 +Device.Bridging.Bridge.2.VLANPort.1.VLAN => Device.Bridging.Bridge.2.VLAN.1 +Device.Bridging.Bridge.2.VLANPort.1.Port => Device.Bridging.Bridge.2.Port.2 +Device.Bridging.Bridge.2.VLANPort.1.Untagged => 0 +Device.Bridging.Bridge.3.VLANPort.1.Enable => 1 +Device.Bridging.Bridge.3.VLANPort.1.Alias => cpe-1 +Device.Bridging.Bridge.3.VLANPort.1.VLAN => Device.Bridging.Bridge.3.VLAN.1 +Device.Bridging.Bridge.3.VLANPort.1.Port => Device.Bridging.Bridge.3.Port.2 +Device.Bridging.Bridge.3.VLANPort.1.Untagged => 0 +Device.Bridging.Bridge.4.VLANPort.1.Enable => 1 +Device.Bridging.Bridge.4.VLANPort.1.Alias => cpe-1 +Device.Bridging.Bridge.4.VLANPort.1.VLAN => Device.Bridging.Bridge.4.VLAN.1 +Device.Bridging.Bridge.4.VLANPort.1.Port => Device.Bridging.Bridge.4.Port.2 +Device.Bridging.Bridge.4.VLANPort.1.Untagged => 0 +$ obuspa -c get Device.Bridging.Bridge.*.VLAN. +Device.Bridging.Bridge.1.VLAN.1.Enable => 1 +Device.Bridging.Bridge.1.VLAN.1.Alias => cpe-1 +Device.Bridging.Bridge.1.VLAN.1.Name => br_1_vlan_1 +Device.Bridging.Bridge.1.VLAN.1.VLANID => 100 +Device.Bridging.Bridge.2.VLAN.1.Enable => 1 +Device.Bridging.Bridge.2.VLAN.1.Alias => cpe-1 +Device.Bridging.Bridge.2.VLAN.1.Name => br_2_vlan_1 +Device.Bridging.Bridge.2.VLAN.1.VLANID => 100 +Device.Bridging.Bridge.3.VLAN.1.Enable => 1 +Device.Bridging.Bridge.3.VLAN.1.Alias => cpe-1 +Device.Bridging.Bridge.3.VLAN.1.Name => br_3_vlan_1 +Device.Bridging.Bridge.3.VLAN.1.VLANID => 100 +Device.Bridging.Bridge.4.VLAN.1.Enable => 1 +Device.Bridging.Bridge.4.VLAN.1.Alias => cpe-1 +Device.Bridging.Bridge.4.VLAN.1.Name => br_4_vlan_1 +Device.Bridging.Bridge.4.VLAN.1.VLANID => 300 +$ obuspa -c get Device.Bridging.ProviderBridge. +Device.Bridging.ProviderBridge.1.Enable => 1 +Device.Bridging.ProviderBridge.1.Status => Enabled +Device.Bridging.ProviderBridge.1.Alias => cpe-1 +Device.Bridging.ProviderBridge.1.SVLANcomponent => Device.Bridging.Bridge.4 +Device.Bridging.ProviderBridge.1.CVLANcomponents => Device.Bridging.Bridge.1,Device.Bridging.Bridge.2 +``` + +### 11. QinQ (Route mode) + +- **TR-181 Commands** + +```bash +obuspa -c del Device.DHCPv4.Client.* +obuspa -c del Device.DHCPv6.Client.* +obuspa -c del Device.Ethernet.Link.* +obuspa -c del Device.Bridging.Bridge.* +obuspa -c del Device.IP.Interface.* + +obuspa -c add Device.IP.Interface. +obuspa -c add Device.DHCPv4.Client. +obuspa -c add Device.Ethernet.VLANTermination. +obuspa -c add Device.Ethernet.VLANTermination. +obuspa -c add Device.Ethernet.Link. + +obuspa -c set Device.IP.Interface.1.Enable 1 +obuspa -c set Device.IP.Interface.1.LowerLayers Device.Ethernet.VLANTermination.2 + +obuspa -c set Device.DHCPv4.Client.1.Enable 1 +obuspa -c set Device.DHCPv4.Client.1.Interface Device.IP.Interface.1 + +obuspa -c set Device.Ethernet.VLANTermination.1.VLANID 100 +obuspa -c set Device.Ethernet.VLANTermination.1.LowerLayers Device.Ethernet.Link.1 + +obuspa -c set Device.Ethernet.VLANTermination.2.TPID 34984 +obuspa -c set Device.Ethernet.VLANTermination.2.VLANID 200 +obuspa -c set Device.Ethernet.VLANTermination.2.LowerLayers Device.Ethernet.VLANTermination.1 + +obuspa -c set Device.Ethernet.Link.1.LowerLayers Device.Ethernet.Interface.3 +``` + +- **Network UCI Config** + +```bash +$ cat /etc/config/network + +config interface 'loopback' + option device 'lo' + option proto 'static' + option ipaddr '127.0.0.1' + option netmask '255.0.0.0' + +config globals 'globals' + option ula_prefix 'fde6:fba3:37bb::/48' + +config device 'dev_eth1' + option enabled '1' + option ifname 'eth1' + option name 'eth1' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth3' + option enabled '1' + option ifname 'eth3' + option name 'eth3' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth4' + option enabled '1' + option ifname 'eth4' + option name 'eth4' + option eee '0' + option pause '1' + option macaddr '44:D4:37:71:B5:52' + +config interface 'iface1' + option proto 'dhcp' + option disabled '0' + option device 'eth4.100.200' + option macaddr '44:D4:37:71:B5:53' + +config device 'vlan_ter_1' + option type '8021q' + option vid '100' + option ifname 'eth4' + option name 'eth4.100' + +config device 'vlan_ter_2' + option type '8021ad' + option vid '200' + option ifname 'eth4.100' + option name 'eth4.100.200' + option macaddr '44:D4:37:71:B5:53' + +``` + +- **TR-181 Data Model** + +```bash +$ obuspa -c get Device.IP.Interface.*.LowerLayers +Device.IP.Interface.1.LowerLayers => Device.Ethernet.VLANTermination.2 +$ obuspa -c get Device.Ethernet.VLANTermination.*.LowerLayers +Device.Ethernet.VLANTermination.1.LowerLayers => Device.Ethernet.Link.1 +Device.Ethernet.VLANTermination.2.LowerLayers => Device.Ethernet.VLANTermination.1 +$ obuspa -c get Device.Ethernet.Link.*.LowerLayers +Device.Ethernet.Link.1.LowerLayers => Device.Ethernet.Interface.3 +$ obuspa -c get Device.DHCPv4.Client.*.Interface +Device.DHCPv4.Client.1.Interface => Device.IP.Interface.1 +$ obuspa -c get Device.Bridging.Bridge.*.Port.*.LowerLayers +``` + +### 12. PPPoE WAN connection + +- **TR-181 Commands** + +```bash +obuspa -c del Device.DHCPv4.Client.* +obuspa -c del Device.DHCPv6.Client.* +obuspa -c del Device.Ethernet.Link.* +obuspa -c del Device.Bridging.Bridge.* +obuspa -c del Device.IP.Interface.* + +obuspa -c add Device.IP.Interface. +obuspa -c add Device.PPP.Interface. +obuspa -c add Device.Ethernet.Link. + +obuspa -c set Device.IP.Interface.1.Enable 1 +obuspa -c set Device.IP.Interface.1.LowerLayers Device.PPP.Interface.1 + +obuspa -c set Device.PPP.Interface.1.LowerLayers Device.Ethernet.Link.1 +obuspa -c set Device.PPP.Interface.1.Username test +obuspa -c set Device.PPP.Interface.1.Password test +obuspa -c set Device.PPP.Interface.1.Enable 1 + +obuspa -c set Device.Ethernet.Link.1.LowerLayers Device.Ethernet.Interface.3 +``` + +- **Network UCI Config** + +```bash +$ cat /etc/config/network + +config interface 'loopback' + option device 'lo' + option proto 'static' + option ipaddr '127.0.0.1' + option netmask '255.0.0.0' + +config globals 'globals' + option ula_prefix 'fd8d:6e8e:444f::/48' + +config device 'dev_eth1' + option enabled '1' + option ifname 'eth1' + option name 'eth1' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth3' + option enabled '1' + option ifname 'eth3' + option name 'eth3' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth4' + option enabled '1' + option ifname 'eth4' + option name 'eth4' + option eee '0' + option pause '1' + option macaddr '44:D4:37:71:B5:52' + +config interface 'iface1' + option proto 'pppoe' + option disabled '0' + option device 'eth4' + option macaddr '44:D4:37:71:B5:53' + option username 'test' + option password 'test' + +``` + +- **TR-181 Data Model** + +```bash +$ obuspa -c get Device.IP.Interface.*.LowerLayers +Device.IP.Interface.1.LowerLayers => Device.PPP.Interface.1 +$ obuspa -c get Device.PPP.Interface.*.LowerLayers +Device.PPP.Interface.1.LowerLayers => Device.Ethernet.Link.1 +$ obuspa -c get Device.Ethernet.VLANTermination.*.LowerLayers +$ obuspa -c get Device.Ethernet.Link.*.LowerLayers +Device.Ethernet.Link.1.LowerLayers => Device.Ethernet.Interface.3 +$ obuspa -c get Device.DHCPv4.Client.*.Interface +$ obuspa -c get Device.Bridging.Bridge.*.Port.*.LowerLayers +``` + +### 13. Switch WAN connection from DHCP to PPP + +- **TR-181 Commands** + +```bash +obuspa -c set Device.DHCPv4.Client.1.Interface "" +obuspa -c set Device.DHCPv6.Client.1.Interface "" +obuspa -c set Device.IP.Interface.2.LowerLayers "" + +obuspa -c add Device.PPP.Interface. +obuspa -c set Device.PPP.Interface.1.LowerLayers Device.Ethernet.Link.2 +obuspa -c set Device.PPP.Interface.1.Username test +obuspa -c set Device.PPP.Interface.1.Password test +obuspa -c set Device.PPP.Interface.1.Enable 1 + +obuspa -c set Device.IP.Interface.2.LowerLayers Device.PPP.Interface.1 +``` + +- **Network UCI Config** + +```bash +$ cat /etc/config/network + +config interface 'loopback' + option device 'lo' + option proto 'static' + option ipaddr '127.0.0.1' + option netmask '255.0.0.0' + +config globals 'globals' + option ula_prefix 'fd7c:b8d8:8e46::/48' + +config device 'br_lan' + option name 'br-lan' + option type 'bridge' + list ports 'eth1' + list ports 'eth3' + option multicast_to_unicast '0' + option macaddr '44:D4:37:71:B5:51' + +config interface 'lan' + option device 'br-lan' + option proto 'static' + option ipaddr '192.168.1.1' + option netmask '255.255.255.0' + option ip6assign '60' + option is_lan '1' + option macaddr '44:D4:37:71:B5:51' + +config interface 'wan' + option device 'eth4' + option proto 'pppoe' + option macaddr '44:D4:37:71:B5:52' + option username 'test' + option password 'test' + +config device 'dev_eth1' + option enabled '1' + option ifname 'eth1' + option name 'eth1' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth3' + option enabled '1' + option ifname 'eth3' + option name 'eth3' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth4' + option enabled '1' + option ifname 'eth4' + option name 'eth4' + option eee '0' + option pause '1' + option macaddr '44:D4:37:71:B5:52' + +``` + +- **TR-181 Data Model** + +```bash +$ obuspa -c get Device.IP.Interface.*.LowerLayers +Device.IP.Interface.1.LowerLayers => Device.Ethernet.Link.1 +Device.IP.Interface.2.LowerLayers => Device.PPP.Interface.1 +$ obuspa -c get Device.PPP.Interface.*.LowerLayers +Device.PPP.Interface.1.LowerLayers => Device.Ethernet.Link.2 +$ obuspa -c get Device.DHCPv4.Client.*.Interface +Device.DHCPv4.Client.1.Interface => +$ obuspa -c get Device.DHCPv6.Client.*.Interface +Device.DHCPv6.Client.1.Interface => +$ obuspa -c get Device.Ethernet.Link.*.LowerLayers +Device.Ethernet.Link.1.LowerLayers => Device.Bridging.Bridge.1.Port.1 +Device.Ethernet.Link.2.LowerLayers => Device.Ethernet.Interface.3 +``` + +### 14. Switch WAN connection from PPP to Static + +- **TR-181 Commands** + +```bash +obuspa -c set Device.IP.Interface.2.LowerLayers "" + +obuspa -c del Device.PPP.Interface.1 + +obuspa -c set Device.IP.Interface.2.LowerLayers Device.Ethernet.Link.2 +obuspa -c set Device.IP.Interface.2.Enable 1 + +obuspa -c add Device.IP.Interface.2.IPv4Address. +obuspa -c set Device.IP.Interface.2.IPv4Address.1.Enable 1 +obuspa -c set Device.IP.Interface.2.IPv4Address.1.IPAddress 10.100.1.222 +obuspa -c set Device.IP.Interface.2.IPv4Address.1.SubnetMask 255.255.255.0 + +obuspa -c add Device.IP.Interface.2.IPv4Address. +obuspa -c set Device.IP.Interface.2.IPv4Address.2.Enable 1 +obuspa -c set Device.IP.Interface.2.IPv4Address.2.IPAddress 10.100.10.222 +obuspa -c set Device.IP.Interface.2.IPv4Address.2.SubnetMask 255.255.255.0 +``` + +- **Network UCI Config** + +```bash +$ cat /etc/config/network + +config interface 'loopback' + option device 'lo' + option proto 'static' + option ipaddr '127.0.0.1' + option netmask '255.0.0.0' + +config globals 'globals' + option ula_prefix 'fd7c:b8d8:8e46::/48' + +config device 'br_lan' + option name 'br-lan' + option type 'bridge' + list ports 'eth1' + list ports 'eth3' + option multicast_to_unicast '0' + option macaddr '44:D4:37:71:B5:51' + +config interface 'lan' + option device 'br-lan' + option proto 'static' + option ipaddr '192.168.1.1' + option netmask '255.255.255.0' + option ip6assign '60' + option is_lan '1' + option macaddr '44:D4:37:71:B5:51' + +config interface 'wan' + option device 'eth4' + option proto 'none' + option macaddr '44:D4:37:71:B5:52' + +config device 'dev_eth1' + option enabled '1' + option ifname 'eth1' + option name 'eth1' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth3' + option enabled '1' + option ifname 'eth3' + option name 'eth3' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth4' + option enabled '1' + option ifname 'eth4' + option name 'eth4' + option eee '0' + option pause '1' + option macaddr '44:D4:37:71:B5:54' + +config interface 'iface2_ipv4_1' + option device 'eth4' + option proto 'static' + option disabled '0' + option ipaddr '10.100.1.222' + option netmask '255.255.255.0' + option macaddr '44:D4:37:71:B5:53' + +config interface 'iface2_ipv4_2' + option device 'eth4' + option proto 'static' + option disabled '0' + option ipaddr '10.100.10.222' + option netmask '255.255.255.0' + option macaddr '44:D4:37:71:B5:54' + +``` + +- **TR-181 Data Model** + +```bash +$ obuspa -c get Device.IP.Interface.*.LowerLayers +Device.IP.Interface.1.LowerLayers => Device.Ethernet.Link.1 +Device.IP.Interface.2.LowerLayers => Device.Ethernet.Link.2 +$ obuspa -c get Device.PPP.Interface.*.LowerLayers +$ obuspa -c get Device.DHCPv4.Client.*.Interface +Device.DHCPv4.Client.1.Interface => +$ obuspa -c get Device.DHCPv6.Client.*.Interface +Device.DHCPv6.Client.1.Interface => +$ obuspa -c get Device.Ethernet.Link.*.LowerLayers +Device.Ethernet.Link.1.LowerLayers => Device.Bridging.Bridge.1.Port.1 +Device.Ethernet.Link.2.LowerLayers => Device.Ethernet.Interface.3 +$ obuspa -c get Device.IP.Interface.2.IPv4Address. +Device.IP.Interface.2.IPv4Address.1.Enable => 1 +Device.IP.Interface.2.IPv4Address.1.Status => Enabled +Device.IP.Interface.2.IPv4Address.1.Alias => cpe-1 +Device.IP.Interface.2.IPv4Address.1.IPAddress => 10.100.1.222 +Device.IP.Interface.2.IPv4Address.1.SubnetMask => 255.255.255.0 +Device.IP.Interface.2.IPv4Address.1.AddressingType => Static +Device.IP.Interface.2.IPv4Address.2.Enable => 1 +Device.IP.Interface.2.IPv4Address.2.Status => Enabled +Device.IP.Interface.2.IPv4Address.2.Alias => cpe-2 +Device.IP.Interface.2.IPv4Address.2.IPAddress => 10.100.10.222 +Device.IP.Interface.2.IPv4Address.2.SubnetMask => 255.255.255.0 +Device.IP.Interface.2.IPv4Address.2.AddressingType => Static +``` + +### 15. Switch WAN connection from Static to DHCP + +- **TR-181 Commands** + +```bash +obuspa -c del Device.IP.Interface.2.IPv4Address.1 +obuspa -c del Device.IP.Interface.2.IPv4Address.2 + +obuspa -c set Device.DHCPv4.Client.1.Interface Device.IP.Interface.2 +obuspa -c set Device.DHCPv6.Client.1.Interface Device.IP.Interface.2 +``` + +- **Network UCI Config** + +```bash +$ cat /etc/config/network + +config interface 'loopback' + option device 'lo' + option proto 'static' + option ipaddr '127.0.0.1' + option netmask '255.0.0.0' + +config globals 'globals' + option ula_prefix 'fd7c:b8d8:8e46::/48' + +config device 'br_lan' + option name 'br-lan' + option type 'bridge' + list ports 'eth1' + list ports 'eth3' + option multicast_to_unicast '0' + option macaddr '44:D4:37:71:B5:51' + +config interface 'lan' + option device 'br-lan' + option proto 'static' + option ipaddr '192.168.1.1' + option netmask '255.255.255.0' + option ip6assign '60' + option is_lan '1' + option macaddr '44:D4:37:71:B5:51' + +config interface 'wan' + option device 'eth4' + option proto 'dhcp' + option macaddr '44:D4:37:71:B5:52' + option hostname 'eagle-44d43771b550' + option vendorid 'dslforum.org' + option sendopts '124:00000DE90403757370 125:00000DE91C0106343444343337020B593037323131343030383603054541474C45' + option reqopts '125 43' + +config device 'dev_eth1' + option enabled '1' + option ifname 'eth1' + option name 'eth1' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth3' + option enabled '1' + option ifname 'eth3' + option name 'eth3' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth4' + option enabled '1' + option ifname 'eth4' + option name 'eth4' + option eee '0' + option pause '1' + option macaddr '44:D4:37:71:B5:52' + +config interface 'wan6' + option device 'eth4' + option proto 'dhcpv6' + option macaddr '44:D4:37:71:B5:52' + +``` + +- **TR-181 Data Model** + +```bash +$ obuspa -c get Device.IP.Interface.*.LowerLayers +Device.IP.Interface.1.LowerLayers => Device.Ethernet.Link.1 +Device.IP.Interface.2.LowerLayers => Device.Ethernet.Link.2 +$ obuspa -c get Device.PPP.Interface.*.LowerLayers +$ obuspa -c get Device.DHCPv4.Client.*.Interface +Device.DHCPv4.Client.1.Interface => Device.IP.Interface.2 +$ obuspa -c get Device.DHCPv6.Client.*.Interface +Device.DHCPv6.Client.1.Interface => Device.IP.Interface.2 +$ obuspa -c get Device.Ethernet.Link.*.LowerLayers +Device.Ethernet.Link.1.LowerLayers => Device.Bridging.Bridge.1.Port.1 +Device.Ethernet.Link.2.LowerLayers => Device.Ethernet.Interface.3 +``` + +### 16. Switch WAN connection from DHCP to Static + +- **TR-181 Commands** + +```bash +obuspa -c set Device.DHCPv4.Client.1.Interface "" +obuspa -c set Device.DHCPv6.Client.1.Interface "" + +obuspa -c add Device.IP.Interface.2.IPv4Address. +obuspa -c set Device.IP.Interface.2.IPv4Address.1.Enable 1 +obuspa -c set Device.IP.Interface.2.IPv4Address.1.IPAddress 10.100.1.222 +obuspa -c set Device.IP.Interface.2.IPv4Address.1.SubnetMask 255.255.255.0 + +obuspa -c add Device.IP.Interface.2.IPv4Address. +obuspa -c set Device.IP.Interface.2.IPv4Address.2.Enable 1 +obuspa -c set Device.IP.Interface.2.IPv4Address.2.IPAddress 10.100.10.222 +obuspa -c set Device.IP.Interface.2.IPv4Address.2.SubnetMask 255.255.255.0 +``` + +- **Network UCI Config** + +```bash +$ cat /etc/config/network + +config interface 'loopback' + option device 'lo' + option proto 'static' + option ipaddr '127.0.0.1' + option netmask '255.0.0.0' + +config globals 'globals' + option ula_prefix 'fd7c:b8d8:8e46::/48' + +config device 'br_lan' + option name 'br-lan' + option type 'bridge' + list ports 'eth1' + list ports 'eth3' + option multicast_to_unicast '0' + option macaddr '44:D4:37:71:B5:51' + +config interface 'lan' + option device 'br-lan' + option proto 'static' + option ipaddr '192.168.1.1' + option netmask '255.255.255.0' + option ip6assign '60' + option is_lan '1' + option macaddr '44:D4:37:71:B5:51' + +config interface 'wan' + option device 'eth4' + option proto 'none' + option macaddr '44:D4:37:71:B5:52' + +config device 'dev_eth1' + option enabled '1' + option ifname 'eth1' + option name 'eth1' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth3' + option enabled '1' + option ifname 'eth3' + option name 'eth3' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth4' + option enabled '1' + option ifname 'eth4' + option name 'eth4' + option eee '0' + option pause '1' + option macaddr '44:D4:37:71:B5:53' + +config interface 'iface2_ipv4_1' + option device 'eth4' + option proto 'static' + option disabled '0' + option ipaddr '10.100.1.222' + option netmask '255.255.255.0' + option macaddr '44:D4:37:71:B5:53' + +config interface 'iface2_ipv4_2' + option device 'eth4' + option proto 'static' + option disabled '0' + option ipaddr '10.100.10.222' + option netmask '255.255.255.0' + option macaddr '44:D4:37:71:B5:54' + +``` + +- **TR-181 Data Model** + +```bash +$ obuspa -c get Device.IP.Interface.*.LowerLayers +Device.IP.Interface.1.LowerLayers => Device.Ethernet.Link.1 +Device.IP.Interface.2.LowerLayers => Device.Ethernet.Link.2 +$ obuspa -c get Device.PPP.Interface.*.LowerLayers +$ obuspa -c get Device.DHCPv4.Client.*.Interface +Device.DHCPv4.Client.1.Interface => +$ obuspa -c get Device.DHCPv6.Client.*.Interface +Device.DHCPv6.Client.1.Interface => +$ obuspa -c get Device.Ethernet.Link.*.LowerLayers +Device.Ethernet.Link.1.LowerLayers => Device.Bridging.Bridge.1.Port.1 +Device.Ethernet.Link.2.LowerLayers => Device.Ethernet.Interface.3 +$ obuspa -c get Device.IP.Interface.2.IPv4Address. +Device.IP.Interface.2.IPv4Address.1.Enable => 1 +Device.IP.Interface.2.IPv4Address.1.Status => Enabled +Device.IP.Interface.2.IPv4Address.1.Alias => cpe-1 +Device.IP.Interface.2.IPv4Address.1.IPAddress => 10.100.1.222 +Device.IP.Interface.2.IPv4Address.1.SubnetMask => 255.255.255.0 +Device.IP.Interface.2.IPv4Address.1.AddressingType => Static +Device.IP.Interface.2.IPv4Address.2.Enable => 1 +Device.IP.Interface.2.IPv4Address.2.Status => Enabled +Device.IP.Interface.2.IPv4Address.2.Alias => cpe-2 +Device.IP.Interface.2.IPv4Address.2.IPAddress => 10.100.10.222 +Device.IP.Interface.2.IPv4Address.2.SubnetMask => 255.255.255.0 +Device.IP.Interface.2.IPv4Address.2.AddressingType => Static +``` + +### 17. Switch WAN connection from Static to PPP + +- **TR-181 Commands** + +```bash +obuspa -c del Device.IP.Interface.2.IPv4Address.1 +obuspa -c del Device.IP.Interface.2.IPv4Address.2 + +obuspa -c set Device.IP.Interface.2.LowerLayers "" + +obuspa -c add Device.PPP.Interface. +obuspa -c set Device.PPP.Interface.1.LowerLayers Device.Ethernet.Link.2 +obuspa -c set Device.PPP.Interface.1.Username test +obuspa -c set Device.PPP.Interface.1.Password test +obuspa -c set Device.PPP.Interface.1.Enable 1 + +obuspa -c set Device.IP.Interface.2.LowerLayers Device.PPP.Interface.1 +``` + +- **Network UCI Config** + +```bash +$ cat /etc/config/network + +config interface 'loopback' + option device 'lo' + option proto 'static' + option ipaddr '127.0.0.1' + option netmask '255.0.0.0' + +config globals 'globals' + option ula_prefix 'fd7c:b8d8:8e46::/48' + +config device 'br_lan' + option name 'br-lan' + option type 'bridge' + list ports 'eth1' + list ports 'eth3' + option multicast_to_unicast '0' + option macaddr '44:D4:37:71:B5:51' + +config interface 'lan' + option device 'br-lan' + option proto 'static' + option ipaddr '192.168.1.1' + option netmask '255.255.255.0' + option ip6assign '60' + option is_lan '1' + option macaddr '44:D4:37:71:B5:51' + +config interface 'wan' + option device 'eth4' + option proto 'pppoe' + option macaddr '44:D4:37:71:B5:52' + option username 'test' + option password 'test' + +config device 'dev_eth1' + option enabled '1' + option ifname 'eth1' + option name 'eth1' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth3' + option enabled '1' + option ifname 'eth3' + option name 'eth3' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth4' + option enabled '1' + option ifname 'eth4' + option name 'eth4' + option eee '0' + option pause '1' + option macaddr '44:D4:37:71:B5:52' + +``` + +- **TR-181 Data Model** + +```bash +$ obuspa -c get Device.IP.Interface.*.LowerLayers +Device.IP.Interface.1.LowerLayers => Device.Ethernet.Link.1 +Device.IP.Interface.2.LowerLayers => Device.PPP.Interface.1 +$ obuspa -c get Device.PPP.Interface.*.LowerLayers +Device.PPP.Interface.1.LowerLayers => Device.Ethernet.Link.2 +$ obuspa -c get Device.DHCPv4.Client.*.Interface +Device.DHCPv4.Client.1.Interface => +$ obuspa -c get Device.DHCPv6.Client.*.Interface +Device.DHCPv6.Client.1.Interface => +$ obuspa -c get Device.Ethernet.Link.*.LowerLayers +Device.Ethernet.Link.1.LowerLayers => Device.Bridging.Bridge.1.Port.1 +Device.Ethernet.Link.2.LowerLayers => Device.Ethernet.Interface.3 +``` + +### 18. Switch WAN connection from PPP to DHCP + +- **TR-181 Commands** + +```bash +obuspa -c set Device.IP.Interface.2.LowerLayers "" + +obuspa -c del Device.PPP.Interface.1 + +obuspa -c set Device.IP.Interface.2.LowerLayers Device.Ethernet.Link.2 + +obuspa -c set Device.DHCPv4.Client.1.Interface Device.IP.Interface.2 +obuspa -c set Device.DHCPv6.Client.1.Interface Device.IP.Interface.2 +``` + +- **Network UCI Config** + +```bash +$ cat /etc/config/network + +config interface 'loopback' + option device 'lo' + option proto 'static' + option ipaddr '127.0.0.1' + option netmask '255.0.0.0' + +config globals 'globals' + option ula_prefix 'fd7c:b8d8:8e46::/48' + +config device 'br_lan' + option name 'br-lan' + option type 'bridge' + list ports 'eth1' + list ports 'eth3' + option multicast_to_unicast '0' + option macaddr '44:D4:37:71:B5:51' + +config interface 'lan' + option device 'br-lan' + option proto 'static' + option ipaddr '192.168.1.1' + option netmask '255.255.255.0' + option ip6assign '60' + option is_lan '1' + option macaddr '44:D4:37:71:B5:51' + +config interface 'wan' + option device 'eth4' + option proto 'dhcp' + option macaddr '44:D4:37:71:B5:52' + option hostname 'eagle-44d43771b550' + option vendorid 'dslforum.org' + option sendopts '124:00000DE90403757370 125:00000DE91C0106343444343337020B593037323131343030383603054541474C45' + option reqopts '125 43' + +config device 'dev_eth1' + option enabled '1' + option ifname 'eth1' + option name 'eth1' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth3' + option enabled '1' + option ifname 'eth3' + option name 'eth3' + option eee '0' + option pause '0' + option macaddr '44:D4:37:71:B5:51' + +config device 'dev_eth4' + option enabled '1' + option ifname 'eth4' + option name 'eth4' + option eee '0' + option pause '1' + option macaddr '44:D4:37:71:B5:52' + +config interface 'wan6' + option device 'eth4' + option proto 'dhcpv6' + option macaddr '44:D4:37:71:B5:52' + +``` + +- **TR-181 Data Model** + +```bash +$ obuspa -c get Device.IP.Interface.*.LowerLayers +Device.IP.Interface.1.LowerLayers => Device.Ethernet.Link.1 +Device.IP.Interface.2.LowerLayers => Device.Ethernet.Link.2 +$ obuspa -c get Device.PPP.Interface.*.LowerLayers +$ obuspa -c get Device.DHCPv4.Client.*.Interface +Device.DHCPv4.Client.1.Interface => Device.IP.Interface.2 +$ obuspa -c get Device.DHCPv6.Client.*.Interface +Device.DHCPv6.Client.1.Interface => Device.IP.Interface.2 +$ obuspa -c get Device.Ethernet.Link.*.LowerLayers +Device.Ethernet.Link.1.LowerLayers => Device.Bridging.Bridge.1.Port.1 +Device.Ethernet.Link.2.LowerLayers => Device.Ethernet.Interface.3 +``` + +## Limitations + +- Device.Bridging.Bridge.{i}.Port.{i}.LowerLayers: its value will be generated automatically when user defines **'ManagementPort'** parameter as **1** +- If user forgets to define a Bridge.{i}.Port. instance as management port, then there is no way to assign that Bridge.{i}.Port.{i}. for any interface(Device.Ethernet.Link.{i}.) +- Only one device port(ethx) is allowed for each Bridge{i}.Port. instance +- There are other deployment scenarios that can be configured by our devices using TR-181 data model, but we describe only the most important ones above diff --git a/gitlab-ci/compile.sh b/gitlab-ci/compile.sh new file mode 100755 index 0000000000000000000000000000000000000000..06b73c60ce685b607bd2d95eee90330776691e4e --- /dev/null +++ b/gitlab-ci/compile.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +echo "Install dependencies" +ROOT="${PWD}" + +source ./gitlab-ci/shared.sh + +# install bbfdm +install_bbfdm + +# compile +echo "build stage" +cd ${ROOT}/src/ + +make all diff --git a/gitlab-ci/shared.sh b/gitlab-ci/shared.sh new file mode 100644 index 0000000000000000000000000000000000000000..f098751729cd67463d6d4912bc1bf7ffab42ee40 --- /dev/null +++ b/gitlab-ci/shared.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +function exec_cmd() +{ + echo "executing $@" + $@ >/dev/null 2>&1 + + if [ $? -ne 0 ]; then + echo "Failed to execute $@" + exit 1 + fi +} + +function install_bbfdm() +{ + [ -d "/opt/dev/bbfdm" ] && rm -rf /opt/dev/bbfdm + + if [ -n "${BBFDM_BRANCH}" ]; then + exec_cmd git clone -b ${BBFDM_BRANCH} https://dev.iopsys.eu/bbf/bbfdm.git /opt/dev/bbfdm + else + exec_cmd git clone https://dev.iopsys.eu/bbf/bbfdm.git /opt/dev/bbfdm + fi + + cd /opt/dev/bbfdm + ./gitlab-ci/install-dependencies.sh install + ./gitlab-ci/setup.sh install +} diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a60218dd97c14267131ee2ed9edbf449c10603ed --- /dev/null +++ b/src/Makefile @@ -0,0 +1,33 @@ +LIBNETMNGR := libnetmngr.so +LIBIFACESTACK := libinterface_stack.so + +LIBNETMNGROBJS := net_plugin.o \ + gre.o \ + ip.o \ + routing.o \ + ppp.o \ + routeradvertisement.o \ + common.o + +LIBIFACESTACKOBJS := interfacestack.o + +LIB_CFLAGS = $(CFLAGS) -Wall -Werror -fstrict-aliasing -g -DBBF_VENDOR_PREFIX=\"X_IOPSYS_EU_\" +LIB_LDFLAGS = $(LDFLAGS) +FPIC := -fPIC + +.PHONY: all + +%.o: %.c + $(CC) $(LIB_CFLAGS) $(FPIC) -c -o $@ $< + +all: $(LIBNETMNGR) $(LIBIFACESTACK) + +$(LIBNETMNGR): $(LIBNETMNGROBJS) + $(CC) $(LIB_CFLAGS) $(LIB_LDFLAGS) -shared -o $@ $^ + +$(LIBIFACESTACK): $(LIBIFACESTACKOBJS) + $(CC) $(LIB_CFLAGS) $(LIB_LDFLAGS) -shared -o $@ $^ + +clean: + rm -f *.o $(LIBNETMNGR) $(LIBIFACESTACK) + diff --git a/src/common.c b/src/common.c new file mode 100644 index 0000000000000000000000000000000000000000..07dd6bfa4e72cc41924909f54c74e289e6f92f56 --- /dev/null +++ b/src/common.c @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2023 iopsys Software Solutions AB + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> + * + */ + +#include "common.h" + +void ppp___update_sections(struct uci_section *s_from, struct uci_section *s_to) +{ + char *proto = NULL; + char *device = NULL; + char *username = NULL; + char *password = NULL; + char *pppd_options = NULL; + char *service = NULL; + char *ac = NULL; + + dmuci_get_value_by_section_string(s_from, "proto", &proto); + dmuci_get_value_by_section_string(s_from, "device", &device); + dmuci_get_value_by_section_string(s_from, "username", &username); + dmuci_get_value_by_section_string(s_from, "password", &password); + dmuci_get_value_by_section_string(s_from, "pppd_options", &pppd_options); + dmuci_get_value_by_section_string(s_from, "service", &service); + dmuci_get_value_by_section_string(s_from, "ac", &ac); + + dmuci_set_value_by_section(s_to, "proto", proto); + dmuci_set_value_by_section(s_to, "device", DM_STRLEN(device) ? device : section_name(s_to)); + dmuci_set_value_by_section(s_to, "username", username); + dmuci_set_value_by_section(s_to, "password", password); + dmuci_set_value_by_section(s_to, "pppd_options", pppd_options); + dmuci_set_value_by_section(s_to, "service", service); + dmuci_set_value_by_section(s_to, "ac", ac); +} + +void ppp___reset_options(struct uci_section *ppp_s) +{ + dmuci_set_value_by_section(ppp_s, "device", section_name(ppp_s)); + dmuci_set_value_by_section(ppp_s, "username", ""); + dmuci_set_value_by_section(ppp_s, "password", ""); + dmuci_set_value_by_section(ppp_s, "pppd_options", ""); + dmuci_set_value_by_section(ppp_s, "service", ""); + dmuci_set_value_by_section(ppp_s, "ac", ""); +} + +void firewall__create_zone_section(char *s_name) +{ + struct uci_section *s = NULL; + char *input = NULL; + char *output = NULL; + char *forward = NULL; + + dmuci_get_option_value_string("firewall", "@defaults[0]", "input", &input); + dmuci_get_option_value_string("firewall", "@defaults[0]", "output", &output); + dmuci_get_option_value_string("firewall", "@defaults[0]", "forward", &forward); + + dmuci_add_section("firewall", "zone", &s); + dmuci_rename_section_by_section(s, s_name); + dmuci_set_value_by_section(s, "name", s_name); + dmuci_set_value_by_section(s, "input", input); + dmuci_set_value_by_section(s, "output", output); + dmuci_set_value_by_section(s, "forward", forward); + + dmuci_add_list_value_by_section(s, "network", s_name); +} + +/* get the name that linux generates based on ifname of tunnel */ +void gre___get_tunnel_system_name(struct uci_section *iface_section, char *device_str, size_t device_str_size) +{ + char *proto = NULL; + + if (!iface_section || !device_str_size) + return; + + dmuci_get_value_by_section_string(iface_section, "proto", &proto); + + // to generate appropriate device name + if (proto && !DM_LSTRCMP(proto, "grev6")) { + snprintf(device_str, device_str_size, "gre6-%s", section_name(iface_section)); + } else { + snprintf(device_str, device_str_size, "gre4-%s", section_name(iface_section)); + } +} + +bool ip___is_gre_protocols(const char *proto) +{ + if (!DM_LSTRCMP(proto, "gre")) + return true; + + if (!DM_LSTRCMP(proto, "grev6")) + return true; + + if (!DM_LSTRCMP(proto, "gretap")) + return true; + + if (!DM_LSTRCMP(proto, "grev6tap")) + return true; + + return false; +} + +bool ip___is_ip_interface_instance_exists(const char *sec_name, const char *device) +{ + struct uci_section *s = NULL; + char *curr_dev = NULL; + + if (DM_STRLEN(sec_name) == 0 || + DM_STRLEN(device) == 0) + return false; + + uci_foreach_sections("network", "interface", s) { + + dmuci_get_value_by_section_string(s, "device", &curr_dev); + if (DM_STRLEN(curr_dev) == 0 || + DM_STRCMP(curr_dev, device) != 0) + continue; + + struct uci_section *dmmap_s = NULL; + char *ip_inst = NULL; + + if ((dmmap_s = get_dup_section_in_dmmap("dmmap_network", "interface", section_name(s))) != NULL) { + dmuci_get_value_by_section_string(dmmap_s, "ip_int_instance", &ip_inst); + + if (strcmp(sec_name, section_name(s)) != 0 && + DM_STRLEN(ip_inst) != 0) + return true; + } + } + + return false; +} + +void ip___update_child_interfaces(char *device, char *option_name, char *option_value) +{ + struct uci_section *s = NULL; + + if (DM_STRLEN(device) == 0) + return; + + uci_foreach_option_eq("network", "interface", "device", device, s) { + dmuci_set_value_by_section(s, option_name, option_value); + } +} + +static void ip___Update_IP_Interface_Layer(char *path, char *linker) +{ + struct uci_section *dmmap_s = NULL; + + uci_path_foreach_option_eq(bbfdm, "dmmap_network", "interface", "LowerLayers", path, dmmap_s) { + struct uci_section *iface_s = NULL; + char *sec_name = NULL; + char *instance = NULL; + char *curr_device = NULL; + + dmuci_get_value_by_section_string(dmmap_s, "ip_int_instance", &instance); + if (!DM_STRLEN(instance)) + continue; + + dmuci_get_value_by_section_string(dmmap_s, "section_name", &sec_name); + if (!DM_STRLEN(sec_name)) + continue; + + iface_s = get_origin_section_from_config("network", "interface", sec_name); + if (!iface_s) + continue; + + dmuci_get_value_by_section_string(iface_s, "device", &curr_device); + + ip___update_child_interfaces(curr_device, "device", DM_STRLEN(linker) ? linker : section_name(iface_s)); + } +} + +void ppp___Update_PPP_Interface_Top_Layers(char *path, char *linker) +{ + char *p = DM_STRRCHR(path, '.'); + if (p) *p = 0; + + // Update IP Interface instance if exists + ip___Update_IP_Interface_Layer(path, linker); +} diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000000000000000000000000000000000000..c6cc50dedd2564344f20c563a6285b91e8a96242 --- /dev/null +++ b/src/common.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2023 iopsys Software Solutions AB + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> + * + */ + +#ifndef __DMLAYER_H__ +#define __DMLAYER_H__ + +#include "libbbfdm-api/dmcommon.h" + +void gre___get_tunnel_system_name(struct uci_section *iface_section, char *device_str, size_t device_str_size); + +bool ip___is_gre_protocols(const char *proto); +bool ip___is_ip_interface_instance_exists(const char *sec_name, const char *device); +void ip___update_child_interfaces(char *device, char *option_name, char *option_value); + +void ppp___update_sections(struct uci_section *s_from, struct uci_section *s_to); +void ppp___reset_options(struct uci_section *ppp_s); +void ppp___Update_PPP_Interface_Top_Layers(char *path, char *linker); + +void firewall__create_zone_section(char *s_name); + +#endif //__DMLAYER_H__ diff --git a/src/gre.c b/src/gre.c new file mode 100644 index 0000000000000000000000000000000000000000..28ce8baca09b0a186d45ec2aa08bfd4a48590f3b --- /dev/null +++ b/src/gre.c @@ -0,0 +1,886 @@ +/* + * Copyright (C) 2024 iopsys Software Solutions AB + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * Author: Omar Kallel <omar.kallel@pivasoftware.com> + * Author: Mohd Husaam Mehdi <husaam.mehdi@iopsys.eu> + */ + +#include "gre.h" +#include "common.h" + +/************************************************************* +* UTILITY METHODS +**************************************************************/ +/* wrapper to avoid long lines */ +static char *get_tunnel_name(struct uci_section *tunnel_section) +{ + return dmuci_get_value_by_section_fallback_def(tunnel_section, "name", ""); +} + + +/* different family tunnels have different option proto */ +static char *get_tunnel_dev_proto_family(struct uci_section *tunnel_section) +{ + if (!tunnel_section) { + return ""; + } + + char *tunnel_dev_mode = dmuci_get_value_by_section_fallback_def(tunnel_section, "mode", ""); + + if (!DM_LSTRCMP(tunnel_dev_mode, "greip6")) { + return "grev6"; + } else { + return "gre"; + } +} + +/* delete sections from both main UCI and dmmap UCI */ +static void delete_all_sections_with_opt_eq(char *package, char *section_type, char *option, char *value) +{ + struct uci_section *s = NULL, *stmp = NULL, *dmmap_section = NULL; + + if (!package || !section_type || !option || !value) { + return; + } + + uci_foreach_option_eq_safe(package, section_type, option, value, stmp, s) { + dmmap_section = NULL; + + get_dmmap_section_of_config_section("dmmap_gre", section_type, section_name(s), &dmmap_section); + + dmuci_delete_by_section(dmmap_section, NULL, NULL); + dmuci_delete_by_section(s, NULL, NULL); + } +} + +/* set value in all sections in main UCI */ +static void set_all_sections_with_opt_eq(char *package, char *section_type, char *option, char *value, char *set_option, char *set_value) +{ + struct uci_section *s = NULL; + + if (!package || !section_type || !option || !value || !set_option || !set_value) { + return; + } + + uci_foreach_option_eq(package, section_type, option, value, s) { + // do not remove device of interface section + if (!DM_LSTRCMP(set_option, "device") && !DM_LSTRCMP(set_value, "")) { + dmuci_set_value_by_section(s, set_option, section_name(s)); + } else { + dmuci_set_value_by_section(s, set_option, set_value); + } + } +} + +/* update interface sections corresponding to Tunnel.Interface.LowerLayer, as changed proto leads to changed dev name*/ +static void update_all_interface_upper_layers(char *tunnel_dev_name, bool is_current_ipv6) +{ + struct uci_section *s = NULL, *s_lower = NULL; + + if (!tunnel_dev_name || !DM_STRLEN(tunnel_dev_name)) { + return; + } + + // for all interfaces that have this tunnel_dev + uci_foreach_option_eq("network", "interface", "device", tunnel_dev_name, s) { + s_lower = NULL; + // get the interface name + char *if_section_name = section_name(s); + char current_lower_layer_device[32] = {0}; + char new_lower_layer_device[32] = {0}; + + if (is_current_ipv6) { + snprintf(current_lower_layer_device, sizeof(current_lower_layer_device), "gre6-%s", if_section_name); + snprintf(new_lower_layer_device, sizeof(new_lower_layer_device), "gre4-%s", if_section_name); + } else { + snprintf(current_lower_layer_device, sizeof(current_lower_layer_device), "gre4-%s", if_section_name); + snprintf(new_lower_layer_device, sizeof(new_lower_layer_device), "gre6-%s", if_section_name); + } + + // for all interfaces that have device set to the name generated from current tunnel.interface + uci_foreach_option_eq("network", "interface", "device", current_lower_layer_device, s_lower) { + // update device + dmuci_set_value_by_section(s_lower, "device", new_lower_layer_device); + } + } +} + +static char *get_gre_tunnel_interface_statistics(json_object *json_stats, char *key) +{ + char *value = NULL; + if (!json_stats || !key) { + return "0"; + } + + value = dmjson_get_value(json_stats, 2, "statistics", key); + return value ? value : "0"; +} + +/* remove device section of interface sections corresponding to lowerlayer */ +static void empty_all_upper_layers_of_interface(struct uci_section *iface_section) +{ + char tunnel_system_name[32] = {0}; + + if (!iface_section) + return; + + gre___get_tunnel_system_name(iface_section, &tunnel_system_name[0], sizeof(tunnel_system_name)); + + // remove tunnel system name from option device of the interface section of lower layers + // otherwise tunnel interface is not removed from the system + set_all_sections_with_opt_eq("network", "interface", "device", tunnel_system_name, "device", ""); +} + +static void remove_all_interfaces_of_tunnel(char *tunnel_dev_name) +{ + if (!tunnel_dev_name || !DM_STRLEN(tunnel_dev_name)) { + return; + } + + struct uci_section *s = NULL; + + // for all interfaces of this tunnel + uci_foreach_option_eq("network", "interface", "device", tunnel_dev_name, s) { + empty_all_upper_layers_of_interface(s); + } + + // delete all sections corresponding to tunnel.interface + delete_all_sections_with_opt_eq("network", "interface", "device", tunnel_dev_name); +} + +static void remove_tunnel(struct uci_section *tunnel_section, struct uci_section *tunnel_dmmap_section) +{ + if (!tunnel_section) + return; + + char *tunnel_dev_name = NULL; + + tunnel_dev_name = dmuci_get_value_by_section_fallback_def(tunnel_section, "name", ""); + + // delete all sections corresponding to Tunnel.Interface + remove_all_interfaces_of_tunnel(tunnel_dev_name); + + // remove the tunnel dmmap section + if (tunnel_dmmap_section == NULL) { + struct uci_section *dmmap_section = NULL; + get_dmmap_section_of_config_section("dmmap_gre", "interface", section_name(tunnel_section), &dmmap_section); + dmuci_delete_by_section(dmmap_section, NULL, NULL); + } else { + dmuci_delete_by_section(tunnel_dmmap_section, NULL, NULL); + } + + // remove tunnel network UCI section + dmuci_delete_by_section(tunnel_section, NULL, NULL); +} + +static void remove_all_tunnels(void) +{ + struct uci_section *s = NULL, *stmp = NULL; + + uci_foreach_option_eq_safe("network", "device", "mode", "greip", stmp, s) { + remove_tunnel(s, NULL); + } + + s = NULL, stmp = NULL; + uci_foreach_option_eq_safe("network", "device", "mode", "greip6", stmp, s) { + remove_tunnel(s, NULL); + } +} +/************************************************************* +* ENTRY METHOD +*************************************************************/ +static int browseGRETunnelInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +{ + char *inst = NULL; + struct dm_data *curr_data = NULL; + LIST_HEAD(dup_list); + + synchronize_specific_config_sections_with_dmmap_cont("network", "device", "dmmap_gre", "mode", "greip", &dup_list); + list_for_each_entry(curr_data, &dup_list, list) { + + inst = handle_instance(dmctx, parent_node, curr_data->dmmap_section, "gre_tunnel_instance", "gre_tunnel_alias"); + + if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)curr_data, inst) == DM_STOP) + break; + } + free_dmmap_config_dup_list(&dup_list); + return 0; +} + +static int browseGRETunnelInterfaceInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +{ + json_object *res = NULL; + char *inst = NULL; + struct dm_data *curr_data = NULL; + char *tunnel_dev_name = NULL; + char *tunnel_instance = NULL; + LIST_HEAD(dup_list); + + tunnel_dev_name = dmuci_get_value_by_section_fallback_def(((struct dm_data *)prev_data)->config_section, "name", ""); + if (!DM_STRLEN(tunnel_dev_name)) + return 0; + + tunnel_instance = dmuci_get_value_by_section_fallback_def(((struct dm_data *)prev_data)->dmmap_section, "gre_tunnel_instance", ""); + + dmubus_call("network.device", "status", UBUS_ARGS{0}, 0, &res); + + synchronize_specific_config_sections_with_dmmap_eq("network", "interface", "dmmap_gre", "device", tunnel_dev_name, &dup_list); + list_for_each_entry(curr_data, &dup_list, list) { + // get system name for this interface + char tunnel_system_name[32] = {0}; + gre___get_tunnel_system_name(curr_data->config_section, &tunnel_system_name[0], sizeof(tunnel_system_name)); + + // loop over all objects of network.device status + json_object_object_foreach(res, key, val) { + if (DM_LSTRCMP(key, tunnel_system_name) == 0) { + curr_data->json_object = json_object_get(val); + break; + } + } + + // set tunnel instance in dmmap gre interface section, needed for interfacestack + dmuci_set_value_by_section(curr_data->dmmap_section, "tunnel_instance", tunnel_instance); + + inst = handle_instance(dmctx, parent_node, curr_data->dmmap_section, "gre_iface_instance", "gre_iface_alias"); + + if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)curr_data, inst) == DM_STOP) + break; + } + free_dmmap_config_dup_list(&dup_list); + + return 0; +} + +/************************************************************* +* ADD & DEL OBJ +*************************************************************/ +static int addObjGRETunnel(char *refparam, struct dmctx *ctx, void *data, char **instance) +{ + struct uci_section *dev_sec = NULL, *dmmap_sec = NULL; + char buf[32] = {0}; + + snprintf(buf, sizeof(buf), "gre_dev_%s", *instance); + + dmuci_add_section("network", "device", &dev_sec); + dmuci_rename_section_by_section(dev_sec, buf); + dmuci_set_value_by_section(dev_sec, "name", buf); + dmuci_set_value_by_section(dev_sec, "type", "tunnel"); + dmuci_set_value_by_section(dev_sec, "mode", "greip"); + + dmuci_add_section_bbfdm("dmmap_gre", "device", &dmmap_sec); + dmuci_set_value_by_section(dmmap_sec, "section_name", buf); + dmuci_set_value_by_section(dmmap_sec, "gre_tunnel_instance", *instance); + return 0; +} + +static int delObjGRETunnel(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action) +{ + switch (del_action) { + case DEL_INST: + remove_tunnel(((struct dm_data *)data)->config_section, ((struct dm_data *)data)->dmmap_section); + break; + case DEL_ALL: + remove_all_tunnels(); + break; + } + return 0; +} + +static int addObjGRETunnelInterface(char *refparam, struct dmctx *ctx, void *data, char **instance) +{ + struct uci_section *if_sec = NULL, *dmmap_sec = NULL; + char buf[32] = {0}; + struct uci_section *tunnel_section = ((struct dm_data *)data)->config_section; + char *tunnel_instance = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->dmmap_section, "gre_tunnel_instance", ""); + + char *proto = get_tunnel_dev_proto_family(tunnel_section); + char *disabled = dmuci_get_value_by_section_fallback_def(tunnel_section, "disabled", "0"); + char *remote = dmuci_get_value_by_section_fallback_def(tunnel_section, "remote", ""); + + // name is derived from tunnel number and intf number + snprintf(buf, sizeof(buf), "gre_d%si%s", tunnel_instance, *instance); + + dmuci_add_section("network", "interface", &if_sec); + dmuci_rename_section_by_section(if_sec, buf); + dmuci_set_value_by_section(if_sec, "proto", proto); + dmuci_set_value_by_section(if_sec, "device", get_tunnel_name(tunnel_section)); + dmuci_set_value_by_section(if_sec, "disabled", disabled); + + if (DM_STRLEN(remote)) { + if (!DM_LSTRCMP(proto, "grev6")) { + dmuci_set_value_by_section(if_sec, "peer6addr", remote); + } else { + dmuci_set_value_by_section(if_sec, "peeraddr", remote); + } + } + + dmuci_add_section_bbfdm("dmmap_gre", "interface", &dmmap_sec); + dmuci_set_value_by_section(dmmap_sec, "section_name", buf); + dmuci_set_value_by_section(dmmap_sec, "gre_iface_instance", *instance); + return 0; +} + +static int delObjGRETunnelInterface(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action) +{ + char *tunnel_dev_name = NULL; + + switch (del_action) { + case DEL_INST: + empty_all_upper_layers_of_interface(((struct dm_data *)data)->config_section); + // Remove interface section in network UCI + dmuci_delete_by_section(((struct dm_data *)data)->config_section, NULL, NULL); + // Remove interface section in dmmap_gre + dmuci_delete_by_section(((struct dm_data *)data)->dmmap_section, NULL, NULL); + + break; + case DEL_ALL: + tunnel_dev_name = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "name", ""); + remove_all_interfaces_of_tunnel(tunnel_dev_name); + break; + } + return 0; +} + +/************************************************************* +* GET & SET PARAM +*************************************************************/ + +static int get_GRE_TunnelNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + int cnt = get_number_of_entries(ctx, data, instance, browseGRETunnelInst); + dmasprintf(value, "%d", cnt); + return 0; +} + +static int get_GRETunnel_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *disabled = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "disabled", "0"); + + if (!DM_STRCMP(disabled, "0") || !DM_STRCMP(disabled, "false")) + *value = "1"; + else + *value = "0"; + + return 0; +} + +static int set_GRETunnel_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct uci_section *tunnel_section = ((struct dm_data *)data)->config_section; + bool b = true; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + char *disabled = b ? "0" : "1"; + + dmuci_set_value_by_section(tunnel_section, "disabled", disabled); + // disabling the device will have no effect so apply to all interfaces + set_all_sections_with_opt_eq("network", "interface", "device", get_tunnel_name(tunnel_section), "disabled", disabled ); + break; + } + return 0; +} + +static int get_GRETunnel_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *disabled = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "disabled", "0"); + + if (!DM_STRCMP(disabled, "0") || !DM_STRCMP(disabled, "false")) { + *value = "Enabled"; + } else { + *value = "Disabled"; + } + + return 0; +} + +/*#Device.GRE.Tunnel.{i}.Alias!UCI:dmmap_gre/interface,@i-1/gre_tunnel_alias*/ +static int get_GRETunnel_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return bbf_get_alias(ctx, ((struct dm_data *)data)->dmmap_section, "gre_tunnel_alias", instance, value); +} + +static int set_GRETunnel_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + return bbf_set_alias(ctx, ((struct dm_data *)data)->dmmap_section, "gre_tunnel_alias", instance, value); +} + +static int get_GRETunnel_DeliveryHeaderProtocol(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *proto = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "mode", &proto); + + if (proto && !DM_LSTRCMP(proto, "greip6")) { + *value = "IPv6"; + } else { + *value = "IPv4"; + } + return 0; +} + +static int set_GRETunnel_DeliveryHeaderProtocol(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char *DeliveryHeaderProtocol[] = {"IPv4", "IPv6", NULL}; + char *current_delivery_header = NULL; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, -1, DeliveryHeaderProtocol, NULL)) + return FAULT_9007; + break; + case VALUESET: + get_GRETunnel_DeliveryHeaderProtocol(refparam, ctx, data, instance, ¤t_delivery_header); + + // if current delivery header and new delivery header are same, do nothing + // if different, find the device name for this tunnel + // for every interface that has device as this device name, update device name there + // delete current peeraddr or peer6addr as applicable + // and set a new empty one + // finally update the proto + if (DM_LSTRCMP(current_delivery_header, value)) { + struct uci_section *tunnel_section = ((struct dm_data *)data)->config_section; + char *current_proto = get_tunnel_dev_proto_family(tunnel_section); + char *tunnel_dev_name = get_tunnel_name(tunnel_section); + + // changing from grev6 to gre + if (!DM_LSTRCMP(current_proto, "grev6")) { + // update mode in tunnel device section + dmuci_set_value_by_section(tunnel_section, "mode", "greip"); + // remove remote because now we need different family's address + dmuci_set_value_by_section(tunnel_section, "remote", ""); + + // update proto to gre in all sections belonging to tunnel.interface + set_all_sections_with_opt_eq("network", "interface", "device", tunnel_dev_name, "proto", "gre"); + // remove peer6addr because now we need peeraddr + set_all_sections_with_opt_eq("network", "interface", "device", tunnel_dev_name, "peer6addr", ""); + // update device in all sections which have this tunnel.interface as lower layer + bool is_current_ipv6 = true; + update_all_interface_upper_layers(tunnel_dev_name, is_current_ipv6); + // changing from gre to grev6 + } else { + // current is greip, new is greip6 + // update mode in tunnel device section + dmuci_set_value_by_section(tunnel_section, "mode", "greip6"); + // remove remote because now we need different family's address + dmuci_set_value_by_section(tunnel_section, "remote", ""); + + // update proto to grev6 in all sections belonging to tunnel.interface + set_all_sections_with_opt_eq("network", "interface", "device", tunnel_dev_name, "proto", "grev6"); + // remove peeraddr because now we need peer6addr + set_all_sections_with_opt_eq("network", "interface", "device", tunnel_dev_name, "peeraddr", ""); + // update device in all sections which have this tunnel.interface as lower layer + bool is_current_ipv6 = false; + update_all_interface_upper_layers(tunnel_dev_name, is_current_ipv6); + } + } + break; + } + return 0; +} + +static int get_GRETunnel_RemoteEndpoints(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *tunnel_section = ((struct dm_data *)data)->config_section; + + *value = dmuci_get_value_by_section_fallback_def(tunnel_section, "remote", ""); + + return 0; +} + +static int set_GRETunnel_RemoteEndpoints(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct uci_section *tunnel_section = ((struct dm_data *)data)->config_section; + char *proto = NULL, *tunnel_dev_name = NULL; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, 45, NULL, IPAddress)) + return FAULT_9007; + break; + case VALUESET: + proto = get_tunnel_dev_proto_family(tunnel_section); + tunnel_dev_name = get_tunnel_name(tunnel_section); + + // set the option remote in tunnel device section + dmuci_set_value_by_section(tunnel_section, "remote", value); + + if (!DM_LSTRCMP(proto, "grev6")) { + // set the peer6addr in all interfaces of this tunnel + set_all_sections_with_opt_eq("network", "interface", "device", tunnel_dev_name, "peer6addr", value); + } else { + set_all_sections_with_opt_eq("network", "interface", "device", tunnel_dev_name, "peeraddr", value); + } + + break; + } + return 0; +} + +static int get_GRETunnel_ConnectedRemoteEndpoint(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + // current implementation restricts us to only have one possible value for peer address + // ConnectedRemoteEndpoint is same as RemoteEndpoint + get_GRETunnel_RemoteEndpoints(refparam, ctx, data, instance, value); + return 0; +} + +static int get_GRETunnel_InterfaceNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + int cnt = get_number_of_entries(ctx, data, instance, browseGRETunnelInterfaceInst); + dmasprintf(value, "%d", cnt); + return 0; +} + +static int get_GRETunnelInterface_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *disabled = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "disabled", "0"); + + if (!DM_STRCMP(disabled, "0") || !DM_STRCMP(disabled, "false")) { + *value = "1"; + } else { + *value = "0"; + } + + return 0; +} + +static int set_GRETunnelInterface_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct uci_section *tunnel_intf_section = ((struct dm_data *)data)->config_section; + bool b = true; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + char *disabled = b ? "0" : "1"; + + dmuci_set_value_by_section(tunnel_intf_section, "disabled", disabled); + break; + } + return 0; +} + +static int get_GRETunnelInterface_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *disabled = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "disabled", "0"); + + if (!DM_STRCMP(disabled, "1") || !DM_STRCMP(disabled, "true")) { + *value = "Down"; + return 0; + } + + char tunnel_system_name[32] = {0}; + gre___get_tunnel_system_name(((struct dm_data *)data)->config_section, &tunnel_system_name[0], sizeof(tunnel_system_name)); + + return get_net_device_status(tunnel_system_name, value); +} + +/*#Device.GRE.Tunnel.{i}.Interface.{i}.Alias!UCI:dmmap_gre/interface,@i-1/gre_iface_alias*/ +static int get_GRETunnelInterface_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return bbf_get_alias(ctx, ((struct dm_data *)data)->dmmap_section, "gre_iface_alias", instance, value); +} + +static int set_GRETunnelInterface_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + return bbf_set_alias(ctx, ((struct dm_data *)data)->dmmap_section, "gre_iface_alias", instance, value); +} + +static int get_GRETunnelInterface_Name(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmstrdup(section_name(((struct dm_data *)data)->config_section)); + return 0; +} + +static int get_GRETunnelInterface_LastChange(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + json_object *res = NULL; + + char *if_name = section_name(((struct dm_data *)data)->config_section); + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", if_name, String}}, 1, &res); + DM_ASSERT(res, *value = "0"); + *value = dmjson_get_value(res, 1, "uptime"); + return 0; +} + + +static int get_GRETunnelInterface_LowerLayers(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "LowerLayers", value); + + if ((*value)[0] == '\0') { + char *tunlink = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "tunlink", &tunlink); + + _bbfdm_get_references(ctx, "Device.IP.Interface.", "Name", tunlink, value); + + // Store LowerLayers value + dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "LowerLayers", *value); + } + + return 0; +} + +static int set_GRETunnelInterface_LowerLayers(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char *allowed_objects[] = {"Device.IP.Interface.", NULL}; + struct dm_reference reference = {0}; + + bbfdm_get_reference_linker(ctx, value, &reference); + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, reference.path, -1, -1, NULL, NULL)) + return FAULT_9007; + + if (dm_validate_allowed_objects(ctx, &reference, allowed_objects)) + return FAULT_9007; + break; + case VALUESET: + // Store LowerLayers value under dmmap section + dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "LowerLayers", reference.path); + + // Update tunlink option + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "tunlink", reference.value); + break; + } + return 0; +} + +static int get_GRETunnelInterface_UseChecksum(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *iface_section = ((struct dm_data *)data)->config_section; + char *ocsum = NULL; + + dmuci_get_value_by_section_string(iface_section, "ocsum", &ocsum); + if (ocsum) { + if (!DM_STRCMP(ocsum, "1") || !DM_STRCMP(ocsum, "true")) + *value = "1"; + else + *value = "0"; + } + + return 0; +} + +static int set_GRETunnelInterface_UseChecksum(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct uci_section *iface_section = ((struct dm_data *)data)->config_section; + bool b = true; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + dmuci_set_value_by_section(iface_section, "ocsum", b ? "1" : "0"); + break; + } + return 0; +} + +static int get_GRETunnelInterface_UseSequenceNumber(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *iface_section = ((struct dm_data *)data)->config_section; + char *oseqno = NULL; + + dmuci_get_value_by_section_string(iface_section, "oseqno", &oseqno); + if (oseqno) { + if (!DM_STRCMP(oseqno, "1") || !DM_STRCMP(oseqno, "true")) + *value = "1"; + else + *value = "0"; + } + + return 0; +} + +static int set_GRETunnelInterface_UseSequenceNumber(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct uci_section *iface_section = ((struct dm_data *)data)->config_section; + bool b = false; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + dmuci_set_value_by_section(iface_section, "oseqno", b ? "1" : "0"); + break; + } + return 0; +} + +static int get_GRETunnelInterfaceStats_BytesSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = get_gre_tunnel_interface_statistics(((struct dm_data *)data)->json_object, "tx_bytes"); + return 0; +} + +static int get_GRETunnelInterfaceStats_BytesReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = get_gre_tunnel_interface_statistics(((struct dm_data *)data)->json_object, "rx_bytes"); + return 0; +} + +static int get_GRETunnelInterfaceStats_PacketsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = get_gre_tunnel_interface_statistics(((struct dm_data *)data)->json_object, "tx_packets"); + return 0; +} + +static int get_GRETunnelInterfaceStats_PacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = get_gre_tunnel_interface_statistics(((struct dm_data *)data)->json_object, "rx_packets"); + return 0; +} + +static int get_GRETunnelInterfaceStats_ErrorsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = get_gre_tunnel_interface_statistics(((struct dm_data *)data)->json_object, "tx_errors"); + return 0; +} + +static int get_GRETunnelInterfaceStats_ErrorsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = get_gre_tunnel_interface_statistics(((struct dm_data *)data)->json_object, "rx_errors"); + return 0; +} + +/********************************************************************************************************************************** +* OBJ & PARAM DEFINITION +***********************************************************************************************************************************/ +/* *** Device. *** */ +DMOBJ tDeviceGREObj[] = { +/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/ +{"GRE", &DMREAD, NULL, NULL, "file:/lib/netifd/proto/gre.sh,/etc/config/network", NULL, NULL, NULL, tGREObj, tGREParams, NULL, BBFDM_BOTH, NULL}, +{0} +}; + +/* *** Device.GRE. *** */ +DMOBJ tGREObj[] = { +/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/ +{"Tunnel", &DMWRITE, addObjGRETunnel, delObjGRETunnel, NULL, browseGRETunnelInst, NULL, NULL, tGRETunnelObj, tGRETunnelParams, NULL, BBFDM_BOTH, NULL}, +//{"Filter", &DMWRITE, addObjGREFilter, delObjGREFilter, NULL, browseGREFilterInst, NULL, NULL, NULL, tGREFilterParams, NULL, BBFDM_BOTH, NULL}, +{0} +}; + +DMLEAF tGREParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version, version*/ +{"TunnelNumberOfEntries", &DMREAD, DMT_UNINT, get_GRE_TunnelNumberOfEntries, NULL, BBFDM_BOTH}, +//{"FilterNumberOfEntries", &DMREAD, DMT_UNINT, get_GRE_FilterNumberOfEntries, NULL, BBFDM_BOTH}, +{0} +}; + +/* *** Device.GRE.Tunnel.{i}. *** */ +DMOBJ tGRETunnelObj[] = { +/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/ +{"Stats", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tGRETunnelStatsParams, NULL, BBFDM_BOTH, NULL}, +{"Interface", &DMWRITE, addObjGRETunnelInterface, delObjGRETunnelInterface, NULL, browseGRETunnelInterfaceInst, NULL, NULL, tGRETunnelInterfaceObj, tGRETunnelInterfaceParams, NULL, BBFDM_BOTH, NULL}, +{0} +}; + +DMLEAF tGRETunnelParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"Enable", &DMWRITE, DMT_BOOL, get_GRETunnel_Enable, set_GRETunnel_Enable, BBFDM_BOTH}, +{"Status", &DMREAD, DMT_STRING, get_GRETunnel_Status, NULL, BBFDM_BOTH}, +{"Alias", &DMWRITE, DMT_STRING, get_GRETunnel_Alias, set_GRETunnel_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"RemoteEndpoints", &DMWRITE, DMT_STRING, get_GRETunnel_RemoteEndpoints, set_GRETunnel_RemoteEndpoints, BBFDM_BOTH}, +//{"KeepAlivePolicy", &DMWRITE, DMT_STRING, get_GRETunnel_KeepAlivePolicy, set_GRETunnel_KeepAlivePolicy, BBFDM_BOTH}, +//{"KeepAliveTimeout", &DMWRITE, DMT_UNINT, get_GRETunnel_KeepAliveTimeout, set_GRETunnel_KeepAliveTimeout, BBFDM_BOTH}, +//{"KeepAliveThreshold", &DMWRITE, DMT_UNINT, get_GRETunnel_KeepAliveThreshold, set_GRETunnel_KeepAliveThreshold, BBFDM_BOTH}, +{"DeliveryHeaderProtocol", &DMWRITE, DMT_STRING, get_GRETunnel_DeliveryHeaderProtocol, set_GRETunnel_DeliveryHeaderProtocol, BBFDM_BOTH}, +//{"DefaultDSCPMark", &DMWRITE, DMT_UNINT, get_GRETunnel_DefaultDSCPMark, set_GRETunnel_DefaultDSCPMark, BBFDM_BOTH}, +{"ConnectedRemoteEndpoint", &DMREAD, DMT_STRING, get_GRETunnel_ConnectedRemoteEndpoint, NULL, BBFDM_BOTH}, +{"InterfaceNumberOfEntries", &DMREAD, DMT_UNINT, get_GRETunnel_InterfaceNumberOfEntries, NULL, BBFDM_BOTH}, +{0} +}; + +/* + * no tunnel stats because there is no separate device section for tunnel + * and currently we only support only one interface per tunnel at a time + */ +/* *** Device.GRE.Tunnel.{i}.Stats. *** */ +DMLEAF tGRETunnelStatsParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +//{"KeepAliveSent", &DMREAD, DMT_UNINT, get_GRETunnelStats_KeepAliveSent, NULL, BBFDM_BOTH}, +//{"KeepAliveReceived", &DMREAD, DMT_UNINT, get_GRETunnelStats_KeepAliveReceived, NULL, BBFDM_BOTH}, +//{"BytesSent", &DMREAD, DMT_UNINT, get_GRETunnelStats_BytesSent, NULL, BBFDM_BOTH}, +//{"BytesReceived", &DMREAD, DMT_UNINT, get_GRETunnelStats_BytesReceived, NULL, BBFDM_BOTH}, +//{"PacketsSent", &DMREAD, DMT_UNINT, get_GRETunnelStats_PacketsSent, NULL, BBFDM_BOTH}, +//{"PacketsReceived", &DMREAD, DMT_UNINT, get_GRETunnelStats_PacketsReceived, NULL, BBFDM_BOTH}, +//{"ErrorsSent", &DMREAD, DMT_UNINT, get_GRETunnelStats_ErrorsSent, NULL, BBFDM_BOTH}, +//{"ErrorsReceived", &DMREAD, DMT_UNINT, get_GRETunnelStats_ErrorsReceived, NULL, BBFDM_BOTH}, +{0} +}; + +/* *** Device.GRE.Tunnel.{i}.Interface.{i}. *** */ +DMOBJ tGRETunnelInterfaceObj[] = { +/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/ +{"Stats", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tGRETunnelInterfaceStatsParams, NULL, BBFDM_BOTH, NULL}, +{0} +}; + +DMLEAF tGRETunnelInterfaceParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"Enable", &DMWRITE, DMT_BOOL, get_GRETunnelInterface_Enable, set_GRETunnelInterface_Enable, BBFDM_BOTH}, +{"Status", &DMREAD, DMT_STRING, get_GRETunnelInterface_Status, NULL, BBFDM_BOTH}, +{"Alias", &DMWRITE, DMT_STRING, get_GRETunnelInterface_Alias, set_GRETunnelInterface_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"Name", &DMREAD, DMT_STRING, get_GRETunnelInterface_Name, NULL, BBFDM_BOTH, DM_FLAG_UNIQUE|DM_FLAG_LINKER}, +{"LastChange", &DMREAD, DMT_UNINT, get_GRETunnelInterface_LastChange, NULL, BBFDM_BOTH}, +{"LowerLayers", &DMWRITE, DMT_STRING, get_GRETunnelInterface_LowerLayers, set_GRETunnelInterface_LowerLayers, BBFDM_BOTH, DM_FLAG_REFERENCE}, +//{"ProtocolIdOverride", &DMWRITE, DMT_UNINT, get_GRETunnelInterface_ProtocolIdOverride, set_GRETunnelInterface_ProtocolIdOverride, BBFDM_BOTH}, +{"UseChecksum", &DMWRITE, DMT_BOOL, get_GRETunnelInterface_UseChecksum, set_GRETunnelInterface_UseChecksum, BBFDM_BOTH}, +//{"KeyIdentifierGenerationPolicy", &DMWRITE, DMT_STRING, get_GRETunnelInterface_KeyIdentifierGenerationPolicy, set_GRETunnelInterface_KeyIdentifierGenerationPolicy, BBFDM_BOTH}, +//{"KeyIdentifier", &DMWRITE, DMT_UNINT, get_GRETunnelInterface_KeyIdentifier, set_GRETunnelInterface_KeyIdentifier, BBFDM_BOTH}, +{"UseSequenceNumber", &DMWRITE, DMT_BOOL, get_GRETunnelInterface_UseSequenceNumber, set_GRETunnelInterface_UseSequenceNumber, BBFDM_BOTH}, +{0} +}; + +/* *** Device.GRE.Tunnel.{i}.Interface.{i}.Stats. *** */ +DMLEAF tGRETunnelInterfaceStatsParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"BytesSent", &DMREAD, DMT_UNINT, get_GRETunnelInterfaceStats_BytesSent, NULL, BBFDM_BOTH}, +{"BytesReceived", &DMREAD, DMT_UNINT, get_GRETunnelInterfaceStats_BytesReceived, NULL, BBFDM_BOTH}, +{"PacketsSent", &DMREAD, DMT_UNINT, get_GRETunnelInterfaceStats_PacketsSent, NULL, BBFDM_BOTH}, +{"PacketsReceived", &DMREAD, DMT_UNINT, get_GRETunnelInterfaceStats_PacketsReceived, NULL, BBFDM_BOTH}, +{"ErrorsSent", &DMREAD, DMT_UNINT, get_GRETunnelInterfaceStats_ErrorsSent, NULL, BBFDM_BOTH}, +{"ErrorsReceived", &DMREAD, DMT_UNINT, get_GRETunnelInterfaceStats_ErrorsReceived, NULL, BBFDM_BOTH}, +//{"DiscardChecksumReceived", &DMREAD, DMT_UNINT, get_GRETunnelInterfaceStats_DiscardChecksumReceived, NULL, BBFDM_BOTH}, +//{"DiscardSequenceNumberReceived", &DMREAD, DMT_UNINT, get_GRETunnelInterfaceStats_DiscardSequenceNumberReceived, NULL, BBFDM_BOTH}, +{0} +}; + +/* *** Device.GRE.Filter.{i}. *** */ +DMLEAF tGREFilterParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +//{"Enable", &DMWRITE, DMT_BOOL, get_GREFilter_Enable, set_GREFilter_Enable, BBFDM_BOTH}, +//{"Status", &DMREAD, DMT_STRING, get_GREFilter_Status, NULL, BBFDM_BOTH}, +//{"Order", &DMWRITE, DMT_UNINT, get_GREFilter_Order, set_GREFilter_Order, BBFDM_BOTH}, +//{"Alias", &DMWRITE, DMT_STRING, get_GREFilter_Alias, set_GREFilter_Alias, BBFDM_BOTH}, +//{"Interface", &DMWRITE, DMT_STRING, get_GREFilter_Interface, set_GREFilter_Interface, BBFDM_BOTH}, +//{"AllInterfaces", &DMWRITE, DMT_BOOL, get_GREFilter_AllInterfaces, set_GREFilter_AllInterfaces, BBFDM_BOTH}, +//{"VLANIDCheck", &DMWRITE, DMT_INT, get_GREFilter_VLANIDCheck, set_GREFilter_VLANIDCheck, BBFDM_BOTH}, +//{"VLANIDExclude", &DMWRITE, DMT_BOOL, get_GREFilter_VLANIDExclude, set_GREFilter_VLANIDExclude, BBFDM_BOTH}, +//{"DSCPMarkPolicy", &DMWRITE, DMT_INT, get_GREFilter_DSCPMarkPolicy, set_GREFilter_DSCPMarkPolicy, BBFDM_BOTH}, +{0} +}; diff --git a/src/gre.h b/src/gre.h new file mode 100644 index 0000000000000000000000000000000000000000..c75092a2f51d8b75a42db98db4444d2062389a5a --- /dev/null +++ b/src/gre.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2024 iopsys Software Solutions AB + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * Author: Omar Kallel <omar.kallel@pivasoftware.com> + * Author: Mohd Husaam Mehdi <husaam.mehdi@iopsys.eu> + */ + +#ifndef __GRE_H +#define __GRE_H + +#include "libbbfdm-api/dmcommon.h" + +extern DMOBJ tDeviceGREObj[]; +extern DMOBJ tGREObj[]; +extern DMLEAF tGREParams[]; +extern DMOBJ tGRETunnelObj[]; +extern DMLEAF tGRETunnelParams[]; +extern DMLEAF tGRETunnelStatsParams[]; +extern DMOBJ tGRETunnelInterfaceObj[]; +extern DMLEAF tGRETunnelInterfaceParams[]; +extern DMLEAF tGRETunnelInterfaceStatsParams[]; +extern DMLEAF tGREFilterParams[]; + +#endif //__GRE_H + diff --git a/src/interfacestack.c b/src/interfacestack.c new file mode 100644 index 0000000000000000000000000000000000000000..ff633dd336f934057ec518fae16b68ba0387201a --- /dev/null +++ b/src/interfacestack.c @@ -0,0 +1,355 @@ +/* + * Copyright (C) 2023-2024 iopsys Software Solutions AB + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> + */ + +#include "interfacestack.h" + +struct interfacestack_data +{ + char *HigherLayer; + char *LowerLayer; + char *HigherAlias; + char *LowerAlias; +}; + +/************************************************************* +* COMMON FUNCTIONS +**************************************************************/ +static struct uci_section *get_bridge_management_port_section(char *instance) +{ + struct uci_section *s = NULL; + char *management = NULL; + + uci_path_foreach_option_eq(bbfdm, "dmmap_bridge_port", "bridge_port", "br_inst", instance, s) { + + dmuci_get_value_by_section_string(s, "management", &management); + if (DM_STRCMP(management, "1") == 0) + return s; + } + + return NULL; +} + +static char *get_lower_alias_value(const char *path) +{ + struct uci_section *s = NULL; + char *alias_value = ""; + + if (DM_STRLEN(path) == 0) + return ""; + + char *instance = DM_STRRCHR(path, '.'); + if (!instance) + return ""; + + if (DM_STRNCMP(path, "Device.IP.Interface.", strlen("Device.IP.Interface.")) == 0) { + get_dmmap_section_of_config_section_eq("dmmap_network", "interface", "ip_int_instance", instance + 1, &s); + dmuci_get_value_by_section_string(s, "ip_int_alias", &alias_value); + } else if (DM_STRNCMP(path, "Device.Ethernet.Link.", strlen("Device.Ethernet.Link.")) == 0) { + get_dmmap_section_of_config_section_eq("dmmap_ethernet", "link", "link_instance", instance + 1, &s); + dmuci_get_value_by_section_string(s, "link_alias", &alias_value); + } else if (DM_STRNCMP(path, "Device.Ethernet.Interface.", strlen("Device.Ethernet.Interface.")) == 0) { + get_dmmap_section_of_config_section_eq("dmmap_ethernet", "device", "eth_iface_instance", instance + 1, &s); + dmuci_get_value_by_section_string(s, "eth_iface_alias", &alias_value); + } else if (DM_STRNCMP(path, "Device.Bridging.Bridge.", strlen("Device.Bridging.Bridge.")) == 0 || + DM_STRNCMP(path, "Device.GRE.Tunnel.", strlen("Device.GRE.Tunnel.")) == 0) { + regmatch_t pmatch[1] = {0}; + + bool res = match(path, "([0-9]+)", 1, pmatch); + if (res) { + char first_inst[8] = {0}; + char *second_inst = NULL; + + DM_STRNCPY(first_inst, &path[pmatch[0].rm_so], pmatch[0].rm_eo - pmatch[0].rm_so + 1); + if (DM_STRLEN(first_inst) == 0) + return ""; + + if (DM_STRNCMP(path, "Device.Bridging.Bridge.", strlen("Device.Bridging.Bridge.")) == 0) { + uci_path_foreach_option_eq(bbfdm, "dmmap_bridge_port", "bridge_port", "br_inst", first_inst, s) { + dmuci_get_value_by_section_string(s, "bridge_port_instance", &second_inst); + if (DM_STRCMP(second_inst, instance + 1) == 0) { + dmuci_get_value_by_section_string(s, "bridge_port_alias", &alias_value); + break; + } + } + } else if (DM_STRNCMP(path, "Device.GRE.Tunnel.", strlen("Device.GRE.Tunnel.")) == 0) { + uci_path_foreach_option_eq(bbfdm, "dmmap_gre", "interface", "tunnel_instance", first_inst, s) { + dmuci_get_value_by_section_string(s, "gre_iface_instance", &second_inst); + if (DM_STRCMP(second_inst, instance + 1) == 0) { + dmuci_get_value_by_section_string(s, "gre_iface_alias", &alias_value); + break; + } + } + } + } + } else if (DM_STRNCMP(path, "Device.WiFi.SSID.", strlen("Device.WiFi.SSID.")) == 0) { + get_dmmap_section_of_config_section_eq("dmmap_wireless", "ssid", "ssid_instance", instance + 1, &s); + dmuci_get_value_by_section_string(s, "ssid_alias", &alias_value); + } else if (DM_STRNCMP(path, "Device.WiFi.Radio.", strlen("Device.WiFi.Radio.")) == 0) { + get_dmmap_section_of_config_section_eq("dmmap_wireless", "wifi-device", "radioinstance", instance + 1, &s); + dmuci_get_value_by_section_string(s, "radioalias", &alias_value); + } else if (DM_STRNCMP(path, "Device.Ethernet.VLANTermination.", strlen("Device.Ethernet.VLANTermination.")) == 0) { + get_dmmap_section_of_config_section_eq("dmmap_network", "device", "vlan_term_instance", instance + 1, &s); + dmuci_get_value_by_section_string(s, "vlan_term_alias", &alias_value); + } else if (DM_STRNCMP(path, "Device.PPP.Interface.", strlen("Device.PPP.Interface.")) == 0) { + get_dmmap_section_of_config_section_eq("dmmap_ppp", "interface", "ppp_int_instance", instance + 1, &s); + dmuci_get_value_by_section_string(s, "ppp_int_alias", &alias_value); + } else if (DM_STRNCMP(path, "Device.Ethernet."BBF_VENDOR_PREFIX"MACVLAN.", strlen("Device.Ethernet."BBF_VENDOR_PREFIX"MACVLAN.")) == 0) { + get_dmmap_section_of_config_section_eq("dmmap_network", "device", "mac_vlan_instance", instance + 1, &s); + dmuci_get_value_by_section_string(s, "mac_vlan_alias", &alias_value); + } + + return alias_value; +} + +static int create_interface_stack_instance(struct dmctx *dmctx, DMNODE *parent_node, + struct interfacestack_data *data, struct uci_section *s, + char *path, char *inst_number, char *inst_alias, int *curr_inst) +{ + struct dm_data curr_data = {0}; + char *instance = NULL, *inst = NULL; + char *LowerLayer = NULL; + + if (!s || !data || !path || !inst_number || !inst_alias) + goto end; + + dmuci_get_value_by_section_string(s, inst_number, &instance); + if (DM_STRLEN(instance) == 0) + goto end; + + dmasprintf(&data->HigherLayer, "%s%s", path, instance); + dmuci_get_value_by_section_string(s, inst_alias, &data->HigherAlias); + dmuci_get_value_by_section_string(s, "LowerLayers", &LowerLayer); + + data->LowerLayer = get_value_by_reference(dmctx, LowerLayer); + data->LowerAlias = get_lower_alias_value(data->LowerLayer); + + inst = handle_instance_without_section(dmctx, parent_node, ++(*curr_inst)); + + curr_data.additional_data = (void *)data; + + if (DM_LINK_INST_OBJ(dmctx, parent_node, &curr_data, inst) == DM_STOP) + return -1; + +end: + return 0; +} + +/************************************************************* +* ENTRY METHOD +**************************************************************/ +static int browseInterfaceStackInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +{ + struct interfacestack_data curr_interfacestack_data = {0}; + struct uci_section *s = NULL; + int idx = 0; + + /* Higher Layer is Device.IP.Interface.{i}. */ + uci_path_foreach_sections(bbfdm, "dmmap_network", "interface", s) { + + if (create_interface_stack_instance(dmctx, parent_node, &curr_interfacestack_data, s, + "Device.IP.Interface.", "ip_int_instance", "ip_int_alias", &idx)) + goto end; + } + + /* Higher Layer is Device.GRE.Tunnel.{i}.Interface.{i}. */ + uci_path_foreach_sections(bbfdm, "dmmap_gre", "interface", s) { + char *tunnel_inst = NULL; + char path[128] = {0}; + + dmuci_get_value_by_section_string(s, "tunnel_instance", &tunnel_inst); + + snprintf(path, sizeof(path), "Device.GRE.Tunnel.%s.Interface.", tunnel_inst); + + if (create_interface_stack_instance(dmctx, parent_node, &curr_interfacestack_data, s, + path, "gre_iface_instance", "gre_iface_alias", &idx)) + goto end; + } + + /* Higher Layer is Device.PPP.Interface.{i}. */ + uci_path_foreach_sections(bbfdm, "dmmap_ppp", "interface", s) { + + if (create_interface_stack_instance(dmctx, parent_node, &curr_interfacestack_data, s, + "Device.PPP.Interface.", "ppp_int_instance", "ppp_int_alias", &idx)) + goto end; + } + + /* Higher Layer is Device.Ethernet.X_IOPSYS_EU_MACVLAN.{i}. */ + uci_path_foreach_sections(bbfdm, "dmmap_network", "device", s) { + + if (create_interface_stack_instance(dmctx, parent_node, &curr_interfacestack_data, s, + "Device.Ethernet."BBF_VENDOR_PREFIX"MACVLAN.", "mac_vlan_instance", "mac_vlan_alias", &idx)) + goto end; + } + + /* Higher Layer is Device.Ethernet.VLANTermination.{i}. */ + uci_path_foreach_sections(bbfdm, "dmmap_network", "device", s) { + + if (create_interface_stack_instance(dmctx, parent_node, &curr_interfacestack_data, s, + "Device.Ethernet.VLANTermination.", "vlan_term_instance", "vlan_term_alias", &idx)) + goto end; + } + + /* Higher Layer is Device.Ethernet.Link.{i}. */ + uci_path_foreach_sections(bbfdm, "dmmap_ethernet", "link", s) { + + if (create_interface_stack_instance(dmctx, parent_node, &curr_interfacestack_data, s, + "Device.Ethernet.Link.", "link_instance", "link_alias", &idx)) + goto end; + } + + /* Higher Layer is Device.Bridging.Bridge.{i}.Port.{i}.*/ + uci_path_foreach_sections(bbfdm, "dmmap_bridge", "device", s) { + struct uci_section *port_s = NULL; + char *br_instance = NULL; + char *mg_port_instnace = NULL; + char *mg_port_alias = NULL; + char *inst = NULL; + + dmuci_get_value_by_section_string(s, "bridge_instance", &br_instance); + if (DM_STRLEN(br_instance) == 0) + continue; + + struct uci_section *mg_port_s = get_bridge_management_port_section(br_instance); + if (!mg_port_s) + continue; + + dmuci_get_value_by_section_string(mg_port_s, "bridge_port_instance", &mg_port_instnace); + dmuci_get_value_by_section_string(mg_port_s, "bridge_port_alias", &mg_port_alias); + + uci_path_foreach_option_eq(bbfdm, "dmmap_bridge_port", "bridge_port", "br_inst", br_instance, port_s) { + struct dm_data curr_data = {0}; + char *management = NULL; + char *instance_value = NULL; + char *alias_value = NULL; + char *config = NULL; + char path[128] = {0}; + + dmuci_get_value_by_section_string(port_s, "management", &management); + if (DM_STRCMP(management, "1") == 0) + continue; + + dmuci_get_value_by_section_string(port_s, "bridge_port_instance", &instance_value); + dmuci_get_value_by_section_string(port_s, "bridge_port_alias", &alias_value); + + dmasprintf(&curr_interfacestack_data.HigherLayer, "Device.Bridging.Bridge.%s.Port.%s", br_instance, mg_port_instnace); + curr_interfacestack_data.HigherAlias = mg_port_alias; + dmasprintf(&curr_interfacestack_data.LowerLayer, "Device.Bridging.Bridge.%s.Port.%s", br_instance, instance_value); + curr_interfacestack_data.LowerAlias = alias_value; + + inst = handle_instance_without_section(dmctx, parent_node, ++idx); + curr_data.additional_data = (void *)&curr_interfacestack_data; + if (DM_LINK_INST_OBJ(dmctx, parent_node, &curr_data, inst) == DM_STOP) + goto end; + + /* Higher Layer is Device.Bridging.Bridge.{i}.Port.{i}.*/ + snprintf(path, sizeof(path), "Device.Bridging.Bridge.%s.Port.", br_instance); + + if (create_interface_stack_instance(dmctx, parent_node, &curr_interfacestack_data, port_s, + path, "bridge_port_instance", "bridge_port_alias", &idx)) + goto end; + + /* Higher Layer is Device.WiFi.SSID.{i}.*/ + dmuci_get_value_by_section_string(port_s, "config", &config); + if (DM_STRCMP(config, "wireless") == 0) { + struct uci_section *wl_s = NULL; + char *port = NULL; + + dmuci_get_value_by_section_string(port_s, "port", &port); + wl_s = get_dup_section_in_config_opt("wireless", "wifi-iface", "ifname", port); + wl_s = get_dup_section_in_dmmap_opt("dmmap_wireless", "ssid", "ap_section_name", section_name(wl_s)); + + if (create_interface_stack_instance(dmctx, parent_node, &curr_interfacestack_data, wl_s, + "Device.WiFi.SSID.", "ssid_instance", "ssid_alias", &idx)) + goto end; + } + } + } + +end: + return 0; +} + +/************************************************************* +* GET & SET PARAM +**************************************************************/ +static int get_Device_InterfaceStackNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + int cnt = get_number_of_entries(ctx, data, instance, browseInterfaceStackInst); + dmasprintf(value, "%d", cnt); + return 0; +} + +static int get_InterfaceStack_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmasprintf(value, "cpe-%s", instance); + return 0; +} + +static int set_InterfaceStack_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + return 0; +} + +static int get_InterfaceStack_HigherLayer(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = ((struct interfacestack_data *)((struct dm_data *)data)->additional_data)->HigherLayer; + return 0; +} + +static int get_InterfaceStack_LowerLayer(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = ((struct interfacestack_data *)((struct dm_data *)data)->additional_data)->LowerLayer; + return 0; +} + +static int get_InterfaceStack_HigherAlias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = ((struct interfacestack_data *)((struct dm_data *)data)->additional_data)->HigherAlias; + return 0; +} + +static int get_InterfaceStack_LowerAlias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = ((struct interfacestack_data *)((struct dm_data *)data)->additional_data)->LowerAlias; + return 0; +} + +/********************************************************************************************************************************** +* OBJ & PARAM DEFINITION +***********************************************************************************************************************************/ +DM_MAP_OBJ tDynamicObj[] = { +/* parentobj, nextobject, parameter */ +{"Device.", tDeviceInterfaceStackObj, tDeviceInterfaceStackParams}, +{0} +}; + +/* *** Device. *** */ +DMOBJ tDeviceInterfaceStackObj[] = { +/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/ +{"InterfaceStack", &DMREAD, NULL, NULL, "file:/etc/config/network", browseInterfaceStackInst, NULL, NULL, NULL, tInterfaceStackParams, NULL, BBFDM_BOTH, NULL}, +{0} +}; + +DMLEAF tDeviceInterfaceStackParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"InterfaceStackNumberOfEntries", &DMREAD, DMT_UNINT, get_Device_InterfaceStackNumberOfEntries, NULL, BBFDM_BOTH}, +{0} +}; + +/* *** Device.InterfaceStack.{i}. *** */ +DMLEAF tInterfaceStackParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"Alias", &DMWRITE, DMT_STRING, get_InterfaceStack_Alias, set_InterfaceStack_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"HigherLayer", &DMREAD, DMT_STRING, get_InterfaceStack_HigherLayer, NULL, BBFDM_BOTH}, +{"LowerLayer", &DMREAD, DMT_STRING, get_InterfaceStack_LowerLayer, NULL, BBFDM_BOTH}, +{"HigherAlias", &DMREAD, DMT_STRING, get_InterfaceStack_HigherAlias, NULL, BBFDM_BOTH}, +{"LowerAlias", &DMREAD, DMT_STRING, get_InterfaceStack_LowerAlias, NULL, BBFDM_BOTH}, +{0} +}; diff --git a/src/interfacestack.h b/src/interfacestack.h new file mode 100644 index 0000000000000000000000000000000000000000..b9158dd3c51e13a2d514327a1c4f723005d1d4db --- /dev/null +++ b/src/interfacestack.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2023-2024 iopsys Software Solutions AB + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> + */ + +#ifndef __INTERFACESTACK_H +#define __INTERFACESTACK_H + +#include "libbbfdm-api/dmcommon.h" + +extern DMOBJ tDeviceInterfaceStackObj[]; +extern DMLEAF tDeviceInterfaceStackParams[]; +extern DMLEAF tInterfaceStackParams[]; + + +#endif //__INTERFACESTACK_H diff --git a/src/ip.c b/src/ip.c new file mode 100644 index 0000000000000000000000000000000000000000..565ae98fb2b38ef1ad76296d9a930479713deeae --- /dev/null +++ b/src/ip.c @@ -0,0 +1,2464 @@ +/* + * Copyright (C) 2020-2024 iopsys Software Solutions AB + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> + * Author: Mohd Husaam Mehdi <husaam.mehdi@iopsys.eu> + * + */ + +#include "common.h" +#include "ip.h" + +#define STATUS_SIZE 16 + +typedef struct { + char local_ip[INET6_ADDRSTRLEN]; + uint16_t local_port; + char remote_ip[INET6_ADDRSTRLEN]; + uint16_t remote_port; + unsigned int state; +} ActivePort; + +/************************************************************* +* INIT +**************************************************************/ +static void format_ipv6_address(const char *hex_str_ip, char *ipv6_addr) +{ + struct in6_addr addr = {}; + + sscanf(hex_str_ip, "%08X%08X%08X%08X", + &addr.s6_addr32[0], &addr.s6_addr32[1], + &addr.s6_addr32[2], &addr.s6_addr32[3]); + + // Convert the address to the standard IPv6 format + inet_ntop(AF_INET6, &addr, ipv6_addr, INET6_ADDRSTRLEN); +} + +static void parse_tcp_line(const char* line, int is_ipv6, ActivePort* port) +{ + unsigned int local_port, remote_port; + unsigned int state; + char local_ip[INET6_ADDRSTRLEN] = {0}; + char remote_ip[INET6_ADDRSTRLEN] = {0}; + + if (is_ipv6) { + char local_ip6[33] = {0}, remote_ip6[33] = {0}; + sscanf(line, "%*d: %32s:%4X %32s:%4X %2X", local_ip6, &local_port, remote_ip6, &remote_port, &state); + format_ipv6_address(local_ip6, local_ip); + format_ipv6_address(remote_ip6, remote_ip); + } else { + unsigned int local_ip_num, remote_ip_num; + sscanf(line, "%*d: %8X:%4X %8X:%4X %2X", &local_ip_num, &local_port, &remote_ip_num, &remote_port, &state); + + struct in_addr local_addr = { local_ip_num }; + struct in_addr remote_addr = { remote_ip_num }; + + inet_ntop(AF_INET, &local_addr, local_ip, INET_ADDRSTRLEN); + inet_ntop(AF_INET, &remote_addr, remote_ip, INET_ADDRSTRLEN); + } + + DM_STRNCPY(port->local_ip, local_ip, INET6_ADDRSTRLEN); + port->local_port = local_port; + DM_STRNCPY(port->remote_ip, remote_ip, INET6_ADDRSTRLEN); + port->remote_port = remote_port; + port->state = state; +} + +static void browse_ip_port(struct dmctx *dmctx, DMNODE *parent_node, bool is_ipv6, const char *proc_path, int *id, char *inst) +{ + if (proc_path == NULL || DM_STRLEN(proc_path) == 0) + return; + + FILE* fp = fopen(proc_path, "r"); + if (fp == NULL) { + return; + } + + char line[256] = {0}; + fgets(line, sizeof(line), fp); // Skip header line + + while (fgets(line, sizeof(line), fp)) { + struct dm_data curr_data = {0}; + + ActivePort port; + memset(&port, 0, sizeof(port)); + parse_tcp_line(line, is_ipv6, &port); + + // only display LISTEN or ESTABLISHED + if (port.state != 1 && port.state != 10) + continue; + + curr_data.additional_data = (void *)(&port); + inst = handle_instance_without_section(dmctx, parent_node, ++(*id)); + + if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)&curr_data, inst) == DM_STOP) + break; + } + + fclose(fp); +} + +static int init_interface_ip_args(struct dm_data *args, struct uci_section *iface_sec, struct uci_section *dmmap_sec, json_object *json_obj) +{ + args->config_section = iface_sec; + args->dmmap_section = dmmap_sec; + args->json_object = json_obj; + return 0; +} + +/************************************************************* +* COMMON Functions +**************************************************************/ +static int get_sysctl_disable_ipv6_per_device(const char *device, char **value) +{ + char file[256]; + char val[32] = {0}; + + *value = "0"; + + if (DM_STRLEN(device) == 0) + return -1; + + snprintf(file, sizeof(file), "/proc/sys/net/ipv6/conf/%s/disable_ipv6", device); + dm_read_sysfs_file(file, val, sizeof(val)); + *value = dmstrdup(val); + + return 0; +} + +static int set_sysctl_disable_ipv6_per_device(const char *device, bool value) +{ + FILE *fp = NULL; + char cmd[128] = {0}; + char path[64] = {0}; + + fp = fopen("/etc/bbfdm/sysctl.conf", "r+"); + if (!fp) + return -1; + + int path_len = snprintf(path, sizeof(path), "net.ipv6.conf.%s.disable_ipv6", device); + int cmd_len = snprintf(cmd, sizeof(cmd), "%s=%d", path, value ? 0 : 1); + + dmcmd("sysctl", 2, "-w", cmd); + + fseek(fp, 0, SEEK_END); + long length = ftell(fp); + + char *buf = (char *)dmcalloc(1, length + 1); + if (buf == NULL) { + fclose(fp); + return -1; + } + + + fseek(fp, 0, SEEK_SET); + size_t len = fread(buf, 1, length, fp); + if (len != length) { + dmfree(buf); + fclose(fp); + return -1; + } + + char *ptr = DM_STRSTR(buf, path); + if (ptr) { + *(ptr + path_len + 1) = (value) ? '0' : '1'; + fseek(fp, 0, SEEK_SET); + fwrite(buf, sizeof(char), strlen(buf), fp); + } else { + cmd[cmd_len] = '\n'; + cmd[cmd_len + 1] = 0; + fputs(cmd, fp); + } + + dmfree(buf); + fclose(fp); + + return 0; +} + +static int get_ip_iface_sysfs(const struct uci_section *data, const char *name, char **value) +{ + return get_net_iface_sysfs(section_name(((struct dm_data *)data)->config_section), name, value); +} + +static bool is_main_interface_sec(void *data) +{ + char *parent_section = NULL; + char *current_section = NULL; + char *link_local = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "link_local", &link_local); + if (DM_LSTRCMP(link_local, "1") == 0) + return true; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "parent_section", &parent_section); + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "section_name", ¤t_section); + + return !DM_STRCMP(parent_section, current_section); +} + +static void add_network_to_firewall_zone_network_list(char *zone_name, char *interface_name) +{ + struct uci_section *s = NULL; + + uci_foreach_option_eq("firewall", "zone", "name", zone_name, s) { + dmuci_add_list_value_by_section(s, "network", interface_name); + break; + } +} + +static bool proc_intf6_line_exists(char *parent_section, char *address) +{ + struct uci_section *s = NULL; + + uci_path_foreach_sections(bbfdm, "dmmap_network_ipv6", "intf_ipv6", s) { + char *parent_s = NULL, *addr = NULL; + + dmuci_get_value_by_section_string(s, "parent_section", &parent_s); + dmuci_get_value_by_section_string(s, "address", &addr); + + if (parent_s && DM_STRCMP(parent_s, parent_section) == 0 && + addr && DM_STRCMP(addr, address) == 0) + return true; + } + return false; +} + +static void dmmap_synchronize_ipv6_address_link_local(char *parent_section) +{ + struct uci_section *s = NULL, *stmp = NULL; + char buf[512] = {0}, ipstr[64] = {0}; + FILE *fp = NULL; + + char *device = get_device(parent_section); + + uci_path_foreach_sections_safe(bbfdm, "dmmap_network_ipv6", "intf_ipv6", stmp, s) { + char *link_local = NULL, *parent_s = NULL, *address = NULL; + + dmuci_get_value_by_section_string(s, "parent_section", &parent_s); + dmuci_get_value_by_section_string(s, "link_local", &link_local); + + if ((parent_s && DM_STRCMP(parent_s, parent_section) != 0) || + (link_local && DM_LSTRCMP(link_local, "1") != 0)) + continue; + + dmuci_get_value_by_section_string(s, "address", &address); + + fp = fopen(PROC_INTF6, "r"); + if (fp == NULL) + return; + + bool found = false; + while (fgets(buf, 512, fp) != NULL) { + + if (parse_proc_intf6_line(buf, device, ipstr, sizeof(ipstr))) + continue; + + if (address && DM_STRCMP(address, ipstr) == 0) { + found = true; + break; + } + } + fclose(fp); + + if (!found) + dmuci_delete_by_section(s, NULL, NULL); + } + + fp = fopen(PROC_INTF6, "r"); + if (fp == NULL) + return; + + while (fgets(buf , 512 , fp) != NULL) { + + if (parse_proc_intf6_line(buf, device, ipstr, sizeof(ipstr))) + continue; + + if (proc_intf6_line_exists(parent_section, ipstr)) + continue; + + dmuci_add_section_bbfdm("dmmap_network_ipv6", "intf_ipv6", &s); + dmuci_set_value_by_section(s, "parent_section", parent_section); + dmuci_set_value_by_section(s, "section_name", parent_section); + dmuci_set_value_by_section(s, "link_local", "1"); + dmuci_set_value_by_section(s, "address", ipstr); + } + fclose(fp); +} + +static struct uci_section *check_dmmap_network_interface_ipv4(char *dmmap_file_name, char *dmmap_sec_name, char *parent_section, char *section_name) +{ + struct uci_section *dmmap_section = NULL; + char *sec_name; + + uci_path_foreach_option_eq(bbfdm, dmmap_file_name, dmmap_sec_name, "parent_section", parent_section, dmmap_section) { + dmuci_get_value_by_section_string(dmmap_section, "section_name", &sec_name); + if (DM_STRCMP(sec_name, section_name) == 0) + return dmmap_section; + } + + return NULL; +} + +static struct uci_section *add_dmmap_network_interface_ipv4(char *dmmap_file_name, char *dmmap_sec_name, char *parent_section, char *section_name, char *addr, char *mask, const char *disabled) +{ + struct uci_section *dmmap_section = NULL; + + dmuci_add_section_bbfdm(dmmap_file_name, dmmap_sec_name, &dmmap_section); + dmuci_set_value_by_section_bbfdm(dmmap_section, "parent_section", parent_section); + dmuci_set_value_by_section_bbfdm(dmmap_section, "section_name", section_name); + dmuci_set_value_by_section_bbfdm(dmmap_section, "address", addr); + dmuci_set_value_by_section_bbfdm(dmmap_section, "mask", mask); + dmuci_set_value_by_section_bbfdm(dmmap_section, "enable", (disabled && *disabled == '1') ? "0" : "1"); + + return dmmap_section; +} + +static struct uci_section *update_dmmap_network_interface(char *dmmap_file_name, char *dmmap_sec_name, char *parent_section, char *section_name, char *option, char *value, bool assign) +{ + struct uci_section *dmmap_section = NULL; + char *sec_name, *opt_value; + + uci_path_foreach_option_eq(bbfdm, dmmap_file_name, dmmap_sec_name, "parent_section", parent_section, dmmap_section) { + dmuci_get_value_by_section_string(dmmap_section, "section_name", &sec_name); + dmuci_get_value_by_section_string(dmmap_section, option, &opt_value); + if (DM_STRCMP(sec_name, section_name) == 0 && DM_STRCMP(opt_value, value) == 0) + return dmmap_section; + } + + if (!dmmap_section) { + dmuci_add_section_bbfdm(dmmap_file_name, dmmap_sec_name, &dmmap_section); + dmuci_set_value_by_section_bbfdm(dmmap_section, "parent_section", parent_section); + dmuci_set_value_by_section_bbfdm(dmmap_section, "section_name", section_name); + dmuci_set_value_by_section_bbfdm(dmmap_section, option, value); + dmuci_set_value_by_section_bbfdm(dmmap_section, "assign", assign ? "1" : "0"); + } + + return dmmap_section; +} + +static void synchronize_intf_ipv4_sections_with_dmmap(void) +{ + json_object *res = NULL, *ipv4_obj = NULL, *arrobj = NULL; + struct uci_section *s = NULL, *ss = NULL, *stmp = NULL; + char *dmmap_intf_s = NULL, *enable = NULL, *ipaddr = NULL; + char *added_by_controller = NULL, *dmmap_address = NULL; + int i = 0; + + uci_path_foreach_sections_safe(bbfdm, "dmmap_network_ipv4", "intf_ipv4", stmp, s) { + bool found = false; + dmuci_get_value_by_section_string(s, "section_name", &dmmap_intf_s); + dmuci_get_value_by_section_string(s, "address", &dmmap_address); + dmuci_get_value_by_section_string(s, "added_by_controller", &added_by_controller); + dmuci_get_value_by_section_string(s, "enable", &enable); + + if (DM_LSTRCMP(added_by_controller, "1") == 0) + continue; + + ss = get_origin_section_from_config("network", "interface", dmmap_intf_s); + + if (DM_STRCMP(enable, "0") == 0 && ss != NULL) + continue; + + dmuci_get_value_by_section_string(ss, "ipaddr", &ipaddr); + + if (DM_STRLEN(ipaddr) && DM_STRCMP(ipaddr, dmmap_address) == 0) + continue; + + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", dmmap_intf_s, String}}, 1, &res); + + dmjson_foreach_obj_in_array(res, arrobj, ipv4_obj, i, 1, "ipv4-address") { + + char *address = dmjson_get_value(ipv4_obj, 1, "address"); + if (DM_STRLEN(address) && DM_STRCMP(address, dmmap_address) == 0) { + found = true; + break; + } + } + + if (found) + continue; + + dmuci_delete_by_section(s, NULL, NULL); + } +} + +static void synchronize_intf_ipv6_sections_with_dmmap(void) +{ + json_object *res = NULL, *ipv6_obj = NULL, *arrobj = NULL; + struct uci_section *s = NULL, *ss = NULL, *stmp = NULL; + char *dmmap_intf_s, *dmmap_address, *link_local = NULL, *ip6addr = NULL; + bool found = false; + int i = 0; + + uci_path_foreach_sections_safe(bbfdm, "dmmap_network_ipv6", "intf_ipv6", stmp, s) { + dmuci_get_value_by_section_string(s, "link_local", &link_local); + if (link_local && *link_local != '\0' && DM_LSTRCMP(link_local, "1") == 0) + continue; + + dmuci_get_value_by_section_string(s, "section_name", &dmmap_intf_s); + dmuci_get_value_by_section_string(s, "address", &dmmap_address); + found = false; + + ss = get_origin_section_from_config("network", "interface", dmmap_intf_s); + dmuci_get_value_by_section_string(ss, "ip6addr", &ip6addr); + + if (ip6addr && *ip6addr != '\0' && DM_STRCMP(ip6addr, dmmap_address) == 0) + continue; + + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", dmmap_intf_s, String}}, 1, &res); + + dmjson_foreach_obj_in_array(res, arrobj, ipv6_obj, i, 1, "ipv6-address") { + + char *address = dmjson_get_value(ipv6_obj, 1, "address"); + if (address && *address && DM_STRCMP(address, dmmap_address) == 0) { + found = true; + break; + } + + } + + if (found) + continue; + + dmjson_foreach_obj_in_array(res, arrobj, ipv6_obj, i, 1, "ipv6-prefix-assignment") { + + char *address = dmjson_get_value(ipv6_obj, 2, "local-address", "address"); + if (address && *address && DM_STRCMP(address, dmmap_address) == 0) { + found = true; + break; + } + + } + + if (!found) + dmuci_delete_by_section(s, NULL, NULL); + } +} + +static void synchronize_intf_ipv6_prefix_sections_with_dmmap(void) +{ + json_object *res = NULL, *ipv6_prefix_obj = NULL, *arrobj = NULL; + struct uci_section *s = NULL, *ss = NULL, *stmp = NULL; + char *dmmap_intf_s, *dmmap_address, *ip6prefix = NULL, ipv6_prefix[256] = {0}; + int i = 0; + + uci_path_foreach_sections_safe(bbfdm, "dmmap_network_ipv6_prefix", "intf_ipv6_prefix", stmp, s) { + dmuci_get_value_by_section_string(s, "section_name", &dmmap_intf_s); + dmuci_get_value_by_section_string(s, "address", &dmmap_address); + bool found = false; + + ss = get_origin_section_from_config("network", "interface", dmmap_intf_s); + dmuci_get_value_by_section_string(ss, "ip6prefix", &ip6prefix); + + if (ip6prefix && *ip6prefix != '\0' && DM_STRCMP(ip6prefix, dmmap_address) == 0) + continue; + + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", dmmap_intf_s, String}}, 1, &res); + + dmjson_foreach_obj_in_array(res, arrobj, ipv6_prefix_obj, i, 1, "ipv6-prefix") { + + char *address = dmjson_get_value(ipv6_prefix_obj, 1, "address"); + char *mask = dmjson_get_value(ipv6_prefix_obj, 1, "mask"); + if (*address == '\0' || *mask == '\0') + continue; + + snprintf(ipv6_prefix, sizeof(ipv6_prefix), "%s/%s", address, mask); + if (DM_STRCMP(ipv6_prefix, dmmap_address) == 0) { + found = true; + break; + } + + } + + if (found) + continue; + + dmjson_foreach_obj_in_array(res, arrobj, ipv6_prefix_obj, i, 1, "ipv6-prefix-assignment") { + + char *address = dmjson_get_value(ipv6_prefix_obj, 1, "address"); + char *mask = dmjson_get_value(ipv6_prefix_obj, 1, "mask"); + if (*address == '\0' || *mask == '\0') + continue; + + snprintf(ipv6_prefix, sizeof(ipv6_prefix), "%s/%s", address, mask); + if (DM_STRCMP(ipv6_prefix, dmmap_address) == 0) { + found = true; + break; + } + + } + + if (!found) + dmuci_delete_by_section(s, NULL, NULL); + } +} + +static void delete_ip_intertace_instance(struct uci_section *s) +{ + struct uci_section *int_ss = NULL, *int_stmp = NULL; + char *iface_dev = NULL; + + dmuci_get_value_by_section_string(s, "device", &iface_dev); + if (DM_STRLEN(iface_dev) == 0) + return; + + uci_foreach_sections_safe("network", "interface", int_stmp, int_ss) { + struct uci_section *ss = NULL; + struct uci_section *stmp = NULL; + char *int_device = NULL; + char *proto = NULL; + + dmuci_get_value_by_section_string(int_ss, "device", &int_device); + if (strcmp(section_name(int_ss), section_name(s)) != 0 && DM_STRCMP(int_device, iface_dev) != 0) + continue; + + /* remove dmmap section related to this interface */ + get_dmmap_section_of_config_section("dmmap_network", "interface", section_name(int_ss), &ss); + dmuci_delete_by_section(ss, NULL, NULL); + + /* Remove "IPv4Address" child section related to this "IP.Interface." object */ + uci_path_foreach_option_eq_safe(bbfdm, "dmmap_network_ipv4", "intf_ipv4", "parent_section", section_name(int_ss), stmp, ss) { + dmuci_delete_by_section(ss, NULL, NULL); + } + + /* Remove "IPv6Address" child section related to this "IP.Interface." object */ + uci_path_foreach_option_eq_safe(bbfdm, "dmmap_network_ipv6", "intf_ipv6", "parent_section", section_name(int_ss), stmp, ss) { + dmuci_delete_by_section(ss, NULL, NULL); + } + + /* Remove "IPv6PrefixAddress" child section related to this "IP.Interface." object */ + uci_path_foreach_option_eq_safe(bbfdm, "dmmap_network_ipv6_prefix", "intf_ipv6_prefix", "parent_section", section_name(int_ss), stmp, ss) { + dmuci_delete_by_section(ss, NULL, NULL); + } + + dmuci_get_value_by_section_string(int_ss, "proto", &proto); + + if (DM_LSTRCMP(proto, "dhcp") == 0) { + struct uci_section *dhcpv4_client_s = get_dup_section_in_dmmap_opt("dmmap_dhcp_client", "interface", "iface_name", section_name(int_ss)); + + if (dhcpv4_client_s) { + dmuci_set_value_by_section_bbfdm(dhcpv4_client_s, "iface_name", ""); + } + } + + if (DM_LSTRCMP(proto, "dhcpv6") == 0) { + struct uci_section *dhcpv6_client_s = get_dup_section_in_dmmap_opt("dmmap_dhcpv6", "interface", "iface_name", section_name(int_ss)); + + if (dhcpv6_client_s) { + dmuci_set_value_by_section_bbfdm(dhcpv6_client_s, "iface_name", ""); + } + } + + if (DM_LSTRNCMP(proto, "ppp", 3) == 0) { + struct uci_section *ppp_s = get_dup_section_in_dmmap_opt("dmmap_ppp", "interface", "iface_name", section_name(int_ss)); + + if (ppp_s) { + dmuci_set_value_by_section_bbfdm(ppp_s, "iface_name", ""); + } + } + + /* Remove Firewall zone section related to this "IP.Interface." object */ + uci_foreach_option_eq_safe("firewall", "zone", "name", section_name(int_ss), stmp, ss) { + dmuci_delete_by_section(ss, NULL, NULL); + } + + /* remove interface section */ + dmuci_delete_by_section(int_ss, NULL, NULL); + } +} + +static int delObjIPInterfaceIPv6(void *data, unsigned char del_action, char *dmmap_file_name, char *section_type, char *option_name) +{ + struct uci_section *s = NULL, *stmp = NULL, *dmmap_s = NULL; + char *proto = NULL, *assign = NULL, *link_local = NULL, *device = NULL, *iface_dev = NULL; + + switch (del_action) { + case DEL_INST: + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "assign", &assign); + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "link_local", &link_local); + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "proto", &proto); + + if ((DM_LSTRCMP(assign, "1") == 0) || (DM_LSTRCMP(link_local, "1") == 0) || DM_LSTRCMP(proto, "static") != 0) + return FAULT_9001; + + if (!is_main_interface_sec(data)) { + dmuci_delete_by_section(((struct dm_data *)data)->config_section, NULL, NULL); + } else { + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, option_name, ""); + } + + dmuci_delete_by_section(((struct dm_data *)data)->dmmap_section, NULL, NULL); + break; + case DEL_ALL: + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "proto", &proto); + if (DM_LSTRCMP(proto, "static") != 0) + return FAULT_9001; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "device", &iface_dev); + + uci_foreach_sections_safe("network", "interface", stmp, s) { + + dmuci_get_value_by_section_string(s, "device", &device); + + if (strcmp(section_name(s), section_name(((struct dm_data *)data)->config_section)) == 0) { + dmuci_set_value_by_section(s, option_name, ""); + + get_dmmap_section_of_config_section(dmmap_file_name, section_type, section_name(s), &dmmap_s); + dmuci_delete_by_section(dmmap_s, NULL, NULL); + } else if (DM_STRCMP(device, iface_dev) == 0) { + get_dmmap_section_of_config_section(dmmap_file_name, section_type, section_name(s), &dmmap_s); + dmuci_delete_by_section(dmmap_s, NULL, NULL); + + dmuci_delete_by_section(s, NULL, NULL); + } else { + continue; + } + } + break; + } + return 0; +} + +/************************************************************* +* ENTRY METHOD +**************************************************************/ +/*#Device.IP.Interface.{i}.!UCI:network/interface/dmmap_network*/ +static int browseIPInterfaceInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +{ + char *proto = NULL, *device = NULL, *inst = NULL; + struct dm_data *curr_data = NULL; + LIST_HEAD(dup_list); + + synchronize_specific_config_sections_with_dmmap("network", "interface", "dmmap_network", &dup_list); + list_for_each_entry(curr_data, &dup_list, list) { + + dmuci_get_value_by_section_string(curr_data->config_section, "proto", &proto); + dmuci_get_value_by_section_string(curr_data->config_section, "device", &device); + + if (strcmp(section_name(curr_data->config_section), "loopback") == 0 || + DM_STRLEN(proto) == 0 || + ip___is_gre_protocols(proto) || + DM_STRCHR(device, '@') || + ip___is_ip_interface_instance_exists(section_name(curr_data->config_section), device)) + continue; + + inst = handle_instance(dmctx, parent_node, curr_data->dmmap_section, "ip_int_instance", "ip_int_alias"); + + if (DM_LINK_INST_OBJ(dmctx, parent_node, curr_data, inst) == DM_STOP) + break; + } + free_dmmap_config_dup_list(&dup_list); + return 0; +} + +static int browseIPInterfaceIPv4AddressInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +{ + struct uci_section *parent_sec = ((struct dm_data *)prev_data)->config_section, *intf_s = NULL, *dmmap_s = NULL; + struct dm_data curr_data = {0}; + char *inst = NULL, *iface_dev = NULL; + + dmuci_get_value_by_section_string(parent_sec, "device", &iface_dev); + + synchronize_intf_ipv4_sections_with_dmmap(); + uci_foreach_sections("network", "interface", intf_s) { + char *ipaddr = NULL, *mask = NULL, *added_by_controller = NULL, *device = NULL, *disabled; + json_object *res = NULL; + + dmuci_get_value_by_section_string(intf_s, "device", &device); + if (strcmp(section_name(intf_s), section_name(parent_sec)) != 0 && DM_STRCMP(device, iface_dev) != 0) + continue; + + dmuci_get_value_by_section_string(intf_s, "disabled", &disabled); + dmuci_get_value_by_section_string(intf_s, "netmask", &mask); + + dmmap_s = check_dmmap_network_interface_ipv4("dmmap_network_ipv4", "intf_ipv4", section_name(parent_sec), section_name(intf_s)); + dmuci_get_value_by_section_string(dmmap_s, "added_by_controller", &added_by_controller); + + dmuci_get_value_by_section_string(intf_s, "ipaddr", &ipaddr); + if (*ipaddr == '\0') { + json_object *ipv4_obj = NULL; + char *if_name = section_name(intf_s); + + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", if_name, String}}, 1, &res); + ipv4_obj = dmjson_select_obj_in_array_idx(res, 0, 1, "ipv4-address"); + ipaddr = dmjson_get_value(ipv4_obj, 1, "address"); + mask = dmjson_get_value(ipv4_obj, 1, "mask"); + mask = DM_STRLEN(mask) ? cidr2netmask(DM_STRTOL(mask)) : ""; + } + + if (*ipaddr == '\0' && dmmap_s) + dmuci_get_value_by_section_string(dmmap_s, "address", &ipaddr); + + if (*ipaddr == '\0' && DM_LSTRCMP(added_by_controller, "1") != 0) + continue; + + if (dmmap_s == NULL) + dmmap_s = add_dmmap_network_interface_ipv4("dmmap_network_ipv4", "intf_ipv4", section_name(parent_sec), section_name(intf_s), ipaddr, mask, disabled); + + init_interface_ip_args(&curr_data, intf_s, dmmap_s, res); + + inst = handle_instance(dmctx, parent_node, dmmap_s, "ipv4_instance", "ipv4_alias"); + + if (DM_LINK_INST_OBJ(dmctx, parent_node, &curr_data, inst) == DM_STOP) + break; + } + return 0; +} + +static int browseIPInterfaceIPv6AddressInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +{ + struct uci_section *parent_sec = ((struct dm_data *)prev_data)->config_section, *intf_s = NULL, *dmmap_s = NULL; + char *inst = NULL, *device, *ip6addr; + char *iface_dev = NULL; + json_object *res = NULL, *ipv6_obj = NULL, *arrobj = NULL; + struct dm_data curr_data = {0}; + int i = 0; + + dmuci_get_value_by_section_string(parent_sec, "device", &iface_dev); + + synchronize_intf_ipv6_sections_with_dmmap(); + uci_foreach_sections("network", "interface", intf_s) { + + dmuci_get_value_by_section_string(intf_s, "device", &device); + if (strcmp(section_name(intf_s), section_name(parent_sec)) != 0 && DM_STRCMP(device, iface_dev) != 0) + continue; + + dmuci_get_value_by_section_string(intf_s, "ip6addr", &ip6addr); + + char *if_name = section_name(intf_s); + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", if_name, String}}, 1, &res); + + if (*ip6addr == '\0') { + + dmjson_foreach_obj_in_array(res, arrobj, ipv6_obj, i, 1, "ipv6-address") { + + char *address = dmjson_get_value(ipv6_obj, 1, "address"); + if (*address == '\0') + continue; + + dmmap_s = update_dmmap_network_interface("dmmap_network_ipv6", "intf_ipv6", section_name(parent_sec), section_name(intf_s), "address", address, false); + + init_interface_ip_args(&curr_data, intf_s, dmmap_s, ipv6_obj); + + inst = handle_instance(dmctx, parent_node, dmmap_s, "ipv6_instance", "ipv6_alias"); + + if (DM_LINK_INST_OBJ(dmctx, parent_node, &curr_data, inst) == DM_STOP) + goto end; + } + + } else { + + dmmap_s = update_dmmap_network_interface("dmmap_network_ipv6", "intf_ipv6", section_name(parent_sec), section_name(intf_s), "address", ip6addr, false); + + init_interface_ip_args(&curr_data, intf_s, dmmap_s, NULL); + + inst = handle_instance(dmctx, parent_node, dmmap_s, "ipv6_instance", "ipv6_alias"); + + if (DM_LINK_INST_OBJ(dmctx, parent_node, &curr_data, inst) == DM_STOP) + goto end; + + } + + dmjson_foreach_obj_in_array(res, arrobj, ipv6_obj, i, 1, "ipv6-prefix-assignment") { + + char *address = dmjson_get_value(ipv6_obj, 2, "local-address", "address"); + if (*address == '\0') + continue; + + dmmap_s = update_dmmap_network_interface("dmmap_network_ipv6", "intf_ipv6", section_name(parent_sec), section_name(intf_s), "address", address, true); + + init_interface_ip_args(&curr_data, intf_s, dmmap_s, ipv6_obj); + + inst = handle_instance(dmctx, parent_node, dmmap_s, "ipv6_instance", "ipv6_alias"); + + if (DM_LINK_INST_OBJ(dmctx, parent_node, &curr_data, inst) == DM_STOP) + goto end; + } + + // Get ipv6 LinkLocal address + if (strcmp(section_name(intf_s), section_name(parent_sec)) == 0) { + + dmmap_synchronize_ipv6_address_link_local(section_name(parent_sec)); + + uci_path_foreach_option_eq(bbfdm, "dmmap_network_ipv6", "intf_ipv6", "parent_section", section_name(parent_sec), dmmap_s) { + char *link_local = NULL; + + dmuci_get_value_by_section_string(dmmap_s, "link_local", &link_local); + if (link_local && DM_LSTRCMP(link_local, "1") != 0) + continue; + + init_interface_ip_args(&curr_data, NULL, dmmap_s, NULL); + + inst = handle_instance(dmctx, parent_node, dmmap_s, "ipv6_instance", "ipv6_alias"); + + if (DM_LINK_INST_OBJ(dmctx, parent_node, &curr_data, inst) == DM_STOP) + goto end; + } + } + } + +end: + return 0; +} + +static int browseIPInterfaceIPv6PrefixInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +{ + struct uci_section *parent_sec = ((struct dm_data *)prev_data)->config_section, *intf_s = NULL, *dmmap_s = NULL; + char *inst = NULL, *device, *ip6prefix, ipv6_prefix[256] = {0}; + char *iface_dev = NULL; + json_object *res = NULL, *ipv6_prefix_obj = NULL, *arrobj = NULL; + struct dm_data curr_data = {0}; + int i = 0; + + dmuci_get_value_by_section_string(parent_sec, "device", &iface_dev); + + synchronize_intf_ipv6_prefix_sections_with_dmmap(); + uci_foreach_sections("network", "interface", intf_s) { + + dmuci_get_value_by_section_string(intf_s, "device", &device); + if (strcmp(section_name(intf_s), section_name(parent_sec)) != 0 && DM_STRCMP(device, iface_dev) != 0) + continue; + + dmuci_get_value_by_section_string(intf_s, "ip6prefix", &ip6prefix); + + char *if_name = section_name(intf_s); + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", if_name, String}}, 1, &res); + + if (*ip6prefix == '\0') { + + dmjson_foreach_obj_in_array(res, arrobj, ipv6_prefix_obj, i, 1, "ipv6-prefix") { + + char *address = dmjson_get_value(ipv6_prefix_obj, 1, "address"); + char *mask = dmjson_get_value(ipv6_prefix_obj, 1, "mask"); + if (*address == '\0' || *mask == '\0') + continue; + + snprintf(ipv6_prefix, sizeof(ipv6_prefix), "%s/%s", address, mask); + dmmap_s = update_dmmap_network_interface("dmmap_network_ipv6_prefix","intf_ipv6_prefix", section_name(parent_sec), section_name(intf_s), "address", ipv6_prefix, false); + + init_interface_ip_args(&curr_data, intf_s, dmmap_s, ipv6_prefix_obj); + + inst = handle_instance(dmctx, parent_node, dmmap_s, "ipv6_prefix_instance", "ipv6_prefix_alias"); + + if (DM_LINK_INST_OBJ(dmctx, parent_node, &curr_data, inst) == DM_STOP) + goto end; + } + + } else { + + dmjson_foreach_obj_in_array(res, arrobj, ipv6_prefix_obj, i, 1, "ipv6-prefix") { + char *address = dmjson_get_value(ipv6_prefix_obj, 1, "address"); + char *mask = dmjson_get_value(ipv6_prefix_obj, 1, "mask"); + if (*address == '\0' || *mask == '\0') + continue; + + snprintf(ipv6_prefix, sizeof(ipv6_prefix), "%s/%s", address, mask); + + if (DM_STRCMP(ipv6_prefix, ip6prefix) == 0) + break; + } + + dmmap_s = update_dmmap_network_interface("dmmap_network_ipv6_prefix","intf_ipv6_prefix", section_name(parent_sec), section_name(intf_s), "address", ip6prefix, false); + + init_interface_ip_args(&curr_data, intf_s, dmmap_s, ipv6_prefix_obj); + + inst = handle_instance(dmctx, parent_node, dmmap_s, "ipv6_prefix_instance", "ipv6_prefix_alias"); + + if (DM_LINK_INST_OBJ(dmctx, parent_node, &curr_data, inst) == DM_STOP) + goto end; + + } + + dmjson_foreach_obj_in_array(res, arrobj, ipv6_prefix_obj, i, 1, "ipv6-prefix-assignment") { + + char *address = dmjson_get_value(ipv6_prefix_obj, 1, "address"); + char *mask = dmjson_get_value(ipv6_prefix_obj, 1, "mask"); + if (*address == '\0' || *mask == '\0') + continue; + + snprintf(ipv6_prefix, sizeof(ipv6_prefix), "%s/%s", address, mask); + dmmap_s = update_dmmap_network_interface("dmmap_network_ipv6_prefix", "intf_ipv6_prefix", section_name(parent_sec), section_name(intf_s), "address", ipv6_prefix, true); + + init_interface_ip_args(&curr_data, intf_s, dmmap_s, ipv6_prefix_obj); + + inst = handle_instance(dmctx, parent_node, dmmap_s, "ipv6_prefix_instance", "ipv6_prefix_alias"); + + if (DM_LINK_INST_OBJ(dmctx, parent_node, &curr_data, inst) == DM_STOP) + goto end; + } + } + +end: + return 0; +} + +static int browseIPActivePortInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +{ + char *inst = NULL; + int id = 0; + + browse_ip_port(dmctx, parent_node, 0, "/proc/net/tcp", &id, inst); + browse_ip_port(dmctx, parent_node, 1, "/proc/net/tcp6", &id, inst); + + return 0; +} + +/************************************************************* +* ADD & DEL OBJ +**************************************************************/ +static int addObjIPInterface(char *refparam, struct dmctx *ctx, void *data, char **instance) +{ + struct uci_section *dmmap_ip_interface; + char ip_name[32] = {0}; + + snprintf(ip_name, sizeof(ip_name), "iface%s", *instance); + + // Network interface section + dmuci_set_value("network", ip_name, "", "interface"); + dmuci_set_value("network", ip_name, "proto", "none"); + dmuci_set_value("network", ip_name, "disabled", "1"); + dmuci_set_value("network", ip_name, "device", ip_name); + + // Firewall zone section + firewall__create_zone_section(ip_name); + + dmuci_add_section_bbfdm("dmmap_network", "interface", &dmmap_ip_interface); + dmuci_set_value_by_section(dmmap_ip_interface, "section_name", ip_name); + dmuci_set_value_by_section(dmmap_ip_interface, "ip_int_instance", *instance); + return 0; +} + +static int delObjIPInterface(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action) +{ + struct uci_section *s = NULL, *stmp = NULL; + + switch (del_action) { + case DEL_INST: + delete_ip_intertace_instance(((struct dm_data *)data)->config_section); + break; + case DEL_ALL: + uci_foreach_sections_safe("network", "interface", stmp, s) { + char *proto, *device; + dmuci_get_value_by_section_string(s, "proto", &proto); + dmuci_get_value_by_section_string(s, "device", &device); + + if (strcmp(section_name(s), "loopback") == 0 || + DM_STRLEN(proto) == 0 || + ip___is_gre_protocols(proto) || + DM_STRCHR(device, '@') || + ip___is_ip_interface_instance_exists(section_name(s), device)) + continue; + + delete_ip_intertace_instance(s); + } + break; + } + return 0; +} + +static int addObjIPInterfaceIPv4Address(char *refparam, struct dmctx *ctx, void *data, char **instance) +{ + char *ip_inst = NULL, *device = NULL, ipv4_name[64] = {0}; + struct uci_section *dmmap_ip_interface_ipv4 = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "ip_int_instance", &ip_inst); + + snprintf(ipv4_name, sizeof(ipv4_name), "iface%s_ipv4_%s", ip_inst, *instance); + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "device", &device); + + dmuci_set_value("network", ipv4_name, "", "interface"); + dmuci_set_value("network", ipv4_name, "device", device); + dmuci_set_value("network", ipv4_name, "proto", "static"); + dmuci_set_value("network", ipv4_name, "disabled", "1"); + + // Firewall : add this new interface to zone->network list + add_network_to_firewall_zone_network_list(section_name(((struct dm_data *)data)->config_section), ipv4_name); + + dmuci_add_section_bbfdm("dmmap_network_ipv4", "intf_ipv4", &dmmap_ip_interface_ipv4); + dmuci_set_value_by_section(dmmap_ip_interface_ipv4, "parent_section", section_name(((struct dm_data *)data)->config_section)); + dmuci_set_value_by_section(dmmap_ip_interface_ipv4, "section_name", ipv4_name); + dmuci_set_value_by_section(dmmap_ip_interface_ipv4, "enable", "0"); + dmuci_set_value_by_section(dmmap_ip_interface_ipv4, "added_by_controller", "1"); + dmuci_set_value_by_section(dmmap_ip_interface_ipv4, "ipv4_instance", *instance); + return 0; +} + +static int delObjIPInterfaceIPv4Address(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action) +{ + struct uci_section *s = NULL, *stmp = NULL, *dmmap_s = NULL; + char *proto, *device, *iface_dev; + + switch (del_action) { + case DEL_INST: + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "proto", &proto); + if (DM_LSTRCMP(proto, "static") != 0) + return FAULT_9001; + + if (!is_main_interface_sec(data)) { + dmuci_delete_by_section(((struct dm_data *)data)->config_section, NULL, NULL); + } else { + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ipaddr", ""); + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "netmask", ""); + } + + dmuci_delete_by_section(((struct dm_data *)data)->dmmap_section, NULL, NULL); + break; + case DEL_ALL: + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "proto", &proto); + if (DM_LSTRCMP(proto, "static") != 0) + return FAULT_9001; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "device", &iface_dev); + + uci_foreach_sections_safe("network", "interface", stmp, s) { + + dmuci_get_value_by_section_string(s, "device", &device); + + if (strcmp(section_name(s), section_name(((struct dm_data *)data)->config_section)) == 0) { + dmuci_set_value_by_section(s, "ipaddr", ""); + dmuci_set_value_by_section(s, "netmask", ""); + + get_dmmap_section_of_config_section("dmmap_network_ipv4", "intf_ipv4", section_name(s), &dmmap_s); + dmuci_delete_by_section(dmmap_s, NULL, NULL); + } else if (DM_STRCMP(device, iface_dev) == 0) { + get_dmmap_section_of_config_section("dmmap_network_ipv4", "intf_ipv4", section_name(s), &dmmap_s); + dmuci_delete_by_section(dmmap_s, NULL, NULL); + + dmuci_delete_by_section(s, NULL, NULL); + } else { + continue; + } + } + break; + } + return 0; +} + +static int addObjIPInterfaceIPv6Address(char *refparam, struct dmctx *ctx, void *data, char **instance) +{ + char *ip_inst = NULL, *device = NULL, ipv6_name[64] = {0}; + struct uci_section *dmmap_ip_interface_ipv6 = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "ip_int_instance", &ip_inst); + + snprintf(ipv6_name, sizeof(ipv6_name), "iface%s_ipv6_%s", ip_inst, *instance); + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "device", &device); + + dmuci_set_value("network", ipv6_name, "", "interface"); + dmuci_set_value("network", ipv6_name, "device", device); + dmuci_set_value("network", ipv6_name, "proto", "static"); + dmuci_set_value("network", ipv6_name, "ip6addr", "::"); + dmuci_set_value("network", ipv6_name, "disabled", "1"); + + // Firewall : add this new interface to zone->network list + add_network_to_firewall_zone_network_list(section_name(((struct dm_data *)data)->config_section), ipv6_name); + + dmuci_add_section_bbfdm("dmmap_network_ipv6", "intf_ipv6", &dmmap_ip_interface_ipv6); + dmuci_set_value_by_section(dmmap_ip_interface_ipv6, "parent_section", section_name(((struct dm_data *)data)->config_section)); + dmuci_set_value_by_section(dmmap_ip_interface_ipv6, "section_name", ipv6_name); + dmuci_set_value_by_section(dmmap_ip_interface_ipv6, "address", "::"); + dmuci_set_value_by_section(dmmap_ip_interface_ipv6, "ipv6_instance", *instance); + return 0; +} + +static int delObjIPInterfaceIPv6Address(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action) +{ + return delObjIPInterfaceIPv6(data, del_action, "dmmap_network_ipv6", "intf_ipv6", "ip6addr"); +} + +static int addObjIPInterfaceIPv6Prefix(char *refparam, struct dmctx *ctx, void *data, char **instance) +{ + char *ip_inst = NULL, *device = NULL, ipv6_prefix_name[64] = {0}; + struct uci_section *dmmap_ip_interface_ipv6_prefix = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "ip_int_instance", &ip_inst); + + snprintf(ipv6_prefix_name, sizeof(ipv6_prefix_name), "iface%s_ipv6_prefix_%s", ip_inst, *instance); + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "device", &device); + + dmuci_set_value("network", ipv6_prefix_name, "", "interface"); + dmuci_set_value("network", ipv6_prefix_name, "device", device); + dmuci_set_value("network", ipv6_prefix_name, "proto", "static"); + dmuci_set_value("network", ipv6_prefix_name, "ip6prefix", "::/64"); + dmuci_set_value("network", ipv6_prefix_name, "disabled", "1"); + + // Firewall : add this new interface to zone->network list + add_network_to_firewall_zone_network_list(section_name(((struct dm_data *)data)->config_section), ipv6_prefix_name); + + dmuci_add_section_bbfdm("dmmap_network_ipv6_prefix", "intf_ipv6_prefix", &dmmap_ip_interface_ipv6_prefix); + dmuci_set_value_by_section(dmmap_ip_interface_ipv6_prefix, "parent_section", section_name(((struct dm_data *)data)->config_section)); + dmuci_set_value_by_section(dmmap_ip_interface_ipv6_prefix, "section_name", ipv6_prefix_name); + dmuci_set_value_by_section(dmmap_ip_interface_ipv6_prefix, "address", "::/64"); + dmuci_set_value_by_section(dmmap_ip_interface_ipv6_prefix, "ipv6_prefix_instance", *instance); + return 0; +} + +static int delObjIPInterfaceIPv6Prefix(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action) +{ + return delObjIPInterfaceIPv6(data, del_action, "dmmap_network_ipv6_prefix", "intf_ipv6_prefix", "ip6prefix"); +} + +/************************************************************* +* GET & SET PARAM +**************************************************************/ +static int get_IP_IPv4Capable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = folder_exists("/proc/sys/net/ipv4") ? "1" : "0"; + return 0; +} + +static int get_IP_IPv4Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "Enabled"; + return 0; +} + +static int get_IP_IPv6Capable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = folder_exists("/proc/sys/net/ipv6") ? "1" : "0"; + return 0; +} + +static int get_IP_IPv6Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *ipv6 = NULL; + + get_sysctl_disable_ipv6_per_device("all", &ipv6); + *value = (DM_LSTRCMP(ipv6, "1") == 0) ? "0" : "1"; + return 0; +} + +static int set_IP_IPv6Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + bool b; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + set_sysctl_disable_ipv6_per_device("all", b); + break; + } + return 0; +} + +static int get_IP_IPv6Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + get_IP_IPv6Enable(refparam, ctx, data, instance, value); + *value = (DM_LSTRCMP(*value, "1") == 0) ? "Enabled" : "Disabled"; + return 0; +} + +/*#Device.IP.ULAPrefix!UCI:network/globals,globals/ula_prefix*/ +static int get_IP_ULAPrefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_option_value_string("network", "globals", "ula_prefix", value); + return 0; +} + +static int set_IP_ULAPrefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, 49, NULL, IPv6Prefix)) + return FAULT_9007; + break; + case VALUESET: + dmuci_set_value("network", "globals", "ula_prefix", value); + break; + } + return 0; +} + +static int get_IP_InterfaceNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + int cnt = get_number_of_entries(ctx, data, instance, browseIPInterfaceInst); + dmasprintf(value, "%d", cnt); + return 0; +} + +static int get_IP_ActivePortNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + int cnt = get_number_of_entries(ctx, data, instance, browseIPActivePortInst); + dmasprintf(value, "%d", cnt); + return 0; +} + +/*#Device.IP.Interface.{i}.Enable!UCI:network/interface,@i-1/disabled*/ +static int get_IPInterface_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *s = NULL; + char *device = NULL; + + *value = "0"; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "device", &device); + + uci_foreach_option_eq("network", "interface", "device", device, s) { + char *disabled = NULL; + + dmuci_get_value_by_section_string(s, "disabled", &disabled); + + if (DM_STRCMP(disabled, "1") != 0) { + *value = "1"; + break; + } + } + + return 0; +} + +static int set_IPInterface_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char *device = NULL; + bool b; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "device", &device); + ip___update_child_interfaces(device, "disabled", b ? "0" : "1"); + break; + } + return 0; +} + +static int get_IPInterface_IPv6Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *device = get_device(section_name(((struct dm_data *)data)->config_section)); + struct uci_section *dev_s = get_dup_section_in_config_opt("network", "device", "name", device); + *value = dmuci_get_value_by_section_fallback_def(dev_s, "ipv6", "1"); + return 0; +} + +static int set_IPInterface_IPv6Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct uci_section *dev_s = NULL; + char *device = NULL; + bool b; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + device = get_device(section_name(((struct dm_data *)data)->config_section)); + dev_s = get_dup_section_in_config_opt("network", "device", "name", device); + dmuci_set_value_by_section(dev_s, "ipv6", b ? "1" : "0"); + break; + } + return 0; +} + +/*#Device.IP.Interface.{i}.ULAEnable!UCI:network/interface,@i-1/ula*/ +static int get_IPInterface_ULAEnable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "ula", "1"); + return 0; +} + +static int set_IPInterface_ULAEnable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + bool b; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ula", b ? "1" : "0"); + break; + } + return 0; +} + +static int get_IPInterface_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *device = get_device(section_name(((struct dm_data *)data)->config_section)); + return get_net_device_status(device, value); +} + +/*#Device.IP.Interface.{i}.Alias!UCI:dmmap_network/interface,@i-1/ip_int_alias*/ +static int get_IPInterface_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return bbf_get_alias(ctx, ((struct dm_data *)data)->dmmap_section, "ip_int_alias", section_name(((struct dm_data *)data)->config_section), value); +} + +static int set_IPInterface_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + return bbf_set_alias(ctx, ((struct dm_data *)data)->dmmap_section, "ip_int_alias", instance, value); +} + +static int get_IPInterface_Name(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmstrdup(section_name(((struct dm_data *)data)->config_section)); + return 0; +} + +/*#Device.IP.Interface.{i}.LastChange!UBUS:network.interface/status/interface,@Name/uptime*/ +static int get_IPInterface_LastChange(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + json_object *res = NULL; + + char *if_name = section_name(((struct dm_data *)data)->config_section); + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", if_name, String}}, 1, &res); + DM_ASSERT(res, *value = "0"); + *value = dmjson_get_value(res, 1, "uptime"); + return 0; +} + +static int get_IPInterface_LowerLayers(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "LowerLayers", value); + + if ((*value)[0] == '\0') { + char buf[1024] = {0}; + + char *device = get_device(section_name(((struct dm_data *)data)->config_section)); + if (DM_STRLEN(device) == 0) { + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "device", &device); + if (DM_STRLEN(device) == 0) + return 0; + } + + bbfdm_get_references(ctx, MATCH_FIRST, "Device.PPP.Interface.", "Name", device, buf, sizeof(buf)); + bbfdm_get_references(ctx, MATCH_FIRST, "Device.Ethernet."BBF_VENDOR_PREFIX"MACVLAN.", "Name", device, buf, sizeof(buf)); + bbfdm_get_references(ctx, MATCH_FIRST, "Device.Ethernet.VLANTermination.", "Name", device, buf, sizeof(buf)); + bbfdm_get_references(ctx, MATCH_FIRST, "Device.Ethernet.Link.", "Name", device, buf, sizeof(buf)); + + if ((DM_STRLEN(device) > 5) && DM_LSTRNCMP(device, "gre", 3) == 0) { + // gre device name is of the form gre4-<iface> or gre6-<iface> + bbfdm_get_references(ctx, MATCH_FIRST, "Device.GRE.Tunnel.*.Interface.", "Name", device + 5, buf, sizeof(buf)); + } + + // Store LowerLayers value + dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "LowerLayers", buf); + + *value = dmstrdup(buf); + } + + return 0; +} + +static int set_IPInterface_LowerLayers(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char eth_mac_vlan[] = "Device.Ethernet."BBF_VENDOR_PREFIX"MACVLAN"; + char *allowed_objects[] = { + "Device.PPP.Interface.", + eth_mac_vlan, + "Device.Ethernet.VLANTermination.", + "Device.Ethernet.Link.", + "Device.GRE.Tunnel.*.Interface.", + NULL}; + char *curr_device = NULL; + struct dm_reference reference = {0}; + + bbfdm_get_reference_linker(ctx, value, &reference); + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string_list(ctx, reference.path, -1, -1, 1024, -1, -1, NULL, NULL)) + return FAULT_9007; + + if (dm_validate_allowed_objects(ctx, &reference, allowed_objects)) + return FAULT_9007; + + break; + case VALUESET: + // Store LowerLayers value under dmmap_network section + dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "LowerLayers", reference.path); + + if (DM_STRLEN(reference.value) == 0) { + char *curr_proto = NULL; + + // Update device option + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "device", section_name(((struct dm_data *)data)->config_section)); + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "proto", &curr_proto); + if (DM_LSTRNCMP(curr_proto, "ppp", 3) == 0) { + struct uci_section *ppp_s = NULL; + + ppp_s = get_dup_section_in_dmmap_opt("dmmap_ppp", "interface", "iface_name", section_name(((struct dm_data *)data)->config_section)); + dmuci_set_value_by_section_bbfdm(ppp_s, "iface_name", ""); + + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "proto", "none"); + ppp___reset_options(((struct dm_data *)data)->config_section); + } + return 0; + } + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "device", &curr_device); + + if (DM_STRNCMP(reference.path, "Device.PPP.Interface.", strlen("Device.PPP.Interface.")) == 0) { + struct uci_section *ppp_s = get_dup_section_in_dmmap_opt("dmmap_ppp", "interface", "name", reference.value); + if (ppp_s) { + char *new_device = NULL; + + dmuci_get_value_by_section_string(ppp_s, "device", &new_device); + if (DM_STRLEN(new_device)) + ip___update_child_interfaces(curr_device, "device", new_device); + + dmuci_set_value_by_section_bbfdm(ppp_s, "iface_name", section_name(((struct dm_data *)data)->config_section)); + ppp___update_sections(ppp_s, ((struct dm_data *)data)->config_section); + } + } else if (DM_STRNCMP(reference.path, "Device.GRE.Tunnel.", strlen("Device.GRE.Tunnel.")) == 0) { + // get gre device name for provided interface in gre_device + struct uci_section *iface_s = get_origin_section_from_config("network", "interface", reference.value); + char gre_device[32] = {0}; + + gre___get_tunnel_system_name(iface_s, &gre_device[0], sizeof(gre_device)); + + if (DM_STRLEN(gre_device) > 0) { + ip___update_child_interfaces(curr_device, "device", gre_device); + } + } else { + ip___update_child_interfaces(curr_device, "device", reference.value); + } + + break; + } + return 0; +} + +static int get_IPInterface_Router(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "Router", value); + + if ((*value)[0] == '\0') { + char *ip4table = NULL; + char linker[32] = {0}; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "ip4table", &ip4table); + + snprintf(linker, sizeof(linker), "route_table-%s", DM_STRLEN(ip4table) ? ip4table : "254"); + _bbfdm_get_references(ctx, "Device.Routing.Router.", "Alias", linker, value); + + // Store LowerLayers value + dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "Router", *value); + } + + return 0; +} + +static int set_IPInterface_Router(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char *allowed_objects[] = {"Device.Routing.Router.", NULL}; + struct dm_reference reference = {0}; + struct uci_section *s = NULL; + char *device = NULL; + + bbfdm_get_reference_linker(ctx, value, &reference); + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, reference.path, -1, 256, NULL, NULL)) + return FAULT_9007; + + if (dm_validate_allowed_objects(ctx, &reference, allowed_objects)) + return FAULT_9007; + + break; + case VALUESET: + if (DM_STRLEN(reference.value) == 0) + return FAULT_9007; + + char *rt_table = DM_STRCHR(reference.value, '-'); // Get rt_table 'X' which is linker from Alias prefix 'route_table-X' + if (!rt_table) + return FAULT_9007; + + // Store LowerLayers value + dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "Router", reference.path); + + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ip4table", rt_table + 1); + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ip6table", rt_table + 1); + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "device", &device); + + uci_foreach_option_eq("network", "interface", "device", device, s) { + dmuci_set_value_by_section(s, "ip4table", rt_table + 1); + dmuci_set_value_by_section(s, "ip6table", rt_table + 1); + } + break; + } + return 0; +} + +static int get_IPInterface_Reset(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "0"; + return 0; +} + +static int set_IPInterface_Reset(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + /* Reset can disrupt on-going cwmp session, so this parameter must be + * taken care by cwmp internally. + */ + break; + } + return 0; +} + +/*#Device.IP.Interface.{i}.MaxMTUSize!SYSFS:/sys/class/net/@Name/mtu*/ +static int get_IPInterface_MaxMTUSize(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + get_ip_iface_sysfs(data, "mtu", value); + if (*value && **value != '0') + return 0; + + *value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "mtu", "1500"); + return 0; +} + +static int set_IPInterface_MaxMTUSize(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char *device = NULL; + struct uci_section *s = NULL; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"64","65535"}}, 1)) + return FAULT_9007; + break; + case VALUESET: + /* find the device section for this interface */ + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "device", &device); + + /* check if device is empty */ + if ((device)[0] == '\0') { + return FAULT_9002; + } + + /* set option MTU in device section */ + uci_foreach_option_eq("network", "device", "name", device, s) { + dmuci_set_value_by_section(s, "mtu", value); + break; + } + break; + } + return 0; +} + +static int get_IPInterface_Type(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "Normal"; + return 0; +} + +static int get_IPInterface_Loopback(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "0"; + return 0; +} + +static int set_IPInterface_Loopback(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + break; + } + return 0; +} + +static int get_IPInterface_IPv4AddressNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + int cnt = get_number_of_entries(ctx, data, instance, browseIPInterfaceIPv4AddressInst); + dmasprintf(value, "%d", cnt); + return 0; +} + +static int get_IPInterface_IPv6AddressNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + int cnt = get_number_of_entries(ctx, data, instance, browseIPInterfaceIPv6AddressInst); + dmasprintf(value, "%d", cnt); + return 0; +} + +static int get_IPInterface_IPv6PrefixNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + int cnt = get_number_of_entries(ctx, data, instance, browseIPInterfaceIPv6PrefixInst); + dmasprintf(value, "%d", cnt); + return 0; +} + +static int get_IPInterfaceIPv4Address_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "enable", value); + return 0; +} + +static int set_IPInterfaceIPv4Address_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char *proto = NULL; + bool b; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "proto", &proto); + if (DM_LSTRCMP(proto, "static") != 0) + return FAULT_9007; + + break; + case VALUESET: + string_to_bool(value, &b); + if (is_main_interface_sec(data)) { + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ipaddr", ""); + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "netmask", ""); + + if (b) { + char *addr = NULL, *mask = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "address", &addr); + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "mask", &mask); + + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ipaddr", addr); + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "netmask", mask); + } + } else { + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "disabled", b ? "0" : "1"); + } + + dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "enable", b ? "1" : "0"); + break; + } + return 0; +} + +/*#Device.IP.Interface.{i}.IPv4Address.{i}.Status!UCI:network/interface,@i-1/disabled*/ +static int get_IPInterfaceIPv4Address_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + get_IPInterfaceIPv4Address_Enable(refparam, ctx, data, instance, value); + *value = ((*value)[0] == '1') ? "Enabled" : "Disabled"; + return 0; +} + +/*#Device.IP.Interface.{i}.IPv4Address.{i}.Alias!UCI:dmmap_network_ipv4/intf_ipv4,@i-1/ipv4_alias*/ +static int get_IPInterfaceIPv4Address_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return bbf_get_alias(ctx, ((struct dm_data *)data)->dmmap_section, "ipv4_alias", instance, value); +} + +static int set_IPInterfaceIPv4Address_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + return bbf_set_alias(ctx, ((struct dm_data *)data)->dmmap_section, "ipv4_alias", instance, value); +} + +static int get_IPInterfaceIPv4Address_IPAddress(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "address", value); + return 0; +} + +static int set_IPInterfaceIPv4Address_IPAddress(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char *proto = NULL; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, 15, NULL, IPv4Address)) + return FAULT_9007; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "proto", &proto); + if (DM_LSTRCMP(proto, "static") != 0) + return FAULT_9007; + + break; + case VALUESET: + if (is_main_interface_sec(data)) { + char *enable = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "enable", &enable); + if (DM_STRCMP(enable, "1") == 0) + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ipaddr", value); + } else { + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ipaddr", value); + } + + dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "address", value); + break; + } + return 0; +} + +static int get_IPInterfaceIPv4Address_SubnetMask(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "mask", value); + return 0; +} + +static int set_IPInterfaceIPv4Address_SubnetMask(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char *proto = NULL; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, 15, NULL, IPv4Address)) + return FAULT_9007; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "proto", &proto); + if (DM_LSTRCMP(proto, "static") != 0) + return FAULT_9007; + + break; + case VALUESET: + if (is_main_interface_sec(data)) { + char *enable = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "enable", &enable); + if (DM_STRCMP(enable, "1") == 0) + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "netmask", value); + } else { + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "netmask", value); + } + + dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "mask", value); + break; + } + return 0; +} + +/*#Device.IP.Interface.{i}.IPv4Address.{i}.AddressingType!UCI:network/interface,@i-1/proto*/ +static int get_IPInterfaceIPv4Address_AddressingType(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *proto = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "proto", &proto); + + if (DM_LSTRCMP(proto, "static") == 0) + *value = "Static"; + else if (DM_LSTRNCMP(proto, "ppp", 3) == 0) + *value = "IPCP"; + else + *value = "DHCP"; + return 0; +} + +/*#Device.IP.Interface.{i}.IPv6Address.{i}.Enable!UCI:network/interface,@i-1/disabled*/ +static int get_IPInterfaceIPv6Address_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *assign = NULL, *link_local = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "assign", &assign); + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "link_local", &link_local); + + if ((DM_LSTRCMP(assign, "1") == 0) || (DM_LSTRCMP(link_local, "1") == 0)) { + *value = "1"; + } else { + char *disabled = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "disabled", &disabled); + *value = (disabled && *disabled == '1') ? "0" : "1"; + } + + return 0; +} + +static int set_IPInterfaceIPv6Address_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char *link_local = NULL, *assign = NULL, *proto = NULL; + bool b; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "assign", &assign); + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "link_local", &link_local); + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "proto", &proto); + + if ((DM_LSTRCMP(assign, "1") == 0) || (DM_LSTRCMP(link_local, "1") == 0) || DM_LSTRCMP(proto, "static") != 0) + return FAULT_9007; + + break; + case VALUESET: + string_to_bool(value, &b); + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "disabled", b ? "0" : "1"); + break; + } + return 0; +} + +/*#Device.IP.Interface.{i}.IPv6Address.{i}.Status!UCI:network/interface,@i-1/ipv6*/ +static int get_IPInterfaceIPv6Address_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + get_IPInterfaceIPv6Address_Enable(refparam, ctx, data, instance, value); + *value = ((*value)[0] == '1') ? "Enabled" : "Disabled"; + return 0; +} + +static int get_IPInterfaceIPv6Address_IPAddressStatus(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *assign = NULL, *preferred = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "assign", &assign); + if (DM_LSTRCMP(assign, "1") == 0) + preferred = dmjson_get_value(((struct dm_data *)data)->json_object, 2, "local-address", "preferred"); + else + preferred = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "preferred"); + + *value = (preferred && *preferred != '\0') ? "Preferred" : "Invalid"; + return 0; +} + +/*#Device.IP.Interface.{i}.IPv6Address.{i}.Alias!UCI:dmmap_network_ipv6/intf_ipv6,@i-1/ipv6_alias*/ +static int get_IPInterfaceIPv6Address_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return bbf_get_alias(ctx, ((struct dm_data *)data)->dmmap_section, "ipv6_alias", instance, value); +} + +static int set_IPInterfaceIPv6Address_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + return bbf_set_alias(ctx, ((struct dm_data *)data)->dmmap_section, "ipv6_alias", instance, value); +} + +/*#Device.IP.Interface.{i}.IPv6Address.{i}.IPAddress!UCI:network/interface,@i-1/ip6addr*/ +static int get_IPInterfaceIPv6Address_IPAddress(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "address", value); + char *mask = DM_STRCHR(*value, '/'); + if (mask) *mask = '\0'; + return 0; +} + +static int set_IPInterfaceIPv6Address_IPAddress(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char *link_local = NULL, *assign = NULL, *proto = NULL; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, 45, NULL, IPv6Address)) + return FAULT_9007; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "assign", &assign); + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "link_local", &link_local); + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "proto", &proto); + + if ((DM_LSTRCMP(assign, "1") == 0) || (DM_LSTRCMP(link_local, "1") == 0) || DM_LSTRCMP(proto, "static") != 0) + return FAULT_9007; + + break; + case VALUESET: + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ip6addr", value); + dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "address", value); + break; + } + return 0; +} + +static int get_IPInterfaceIPv6Address_Origin(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *assign = NULL, *link_local = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "assign", &assign); + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "link_local", &link_local); + + if ((DM_LSTRCMP(assign, "1") == 0) || (DM_LSTRCMP(link_local, "1") == 0)) { + *value = "AutoConfigured"; + } else { + char *proto; + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "proto", &proto); + *value = (DM_LSTRCMP(proto, "dhcpv6") == 0) ? "DHCPv6" : "Static"; + } + return 0; +} + +static int get_IPInterfaceIPv6Address_Prefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *assign = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "assign", &assign); + if (DM_LSTRCMP(assign, "1") == 0) { + struct uci_section *dmmap_section = NULL; + char *ip_inst = NULL, *ipv6_prefix_inst = NULL, *parent_section, *section_name; + char curr_address[64] = {0}, *address = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "parent_section", &parent_section); + get_dmmap_section_of_config_section("dmmap_network", "interface", parent_section, &dmmap_section); + dmuci_get_value_by_section_string(dmmap_section, "ip_int_instance", &ip_inst); + + char *addr = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "address"); + char *mask = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "mask"); + snprintf(curr_address, sizeof(curr_address), "%s/%s", addr, mask); + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "section_name", §ion_name); + uci_path_foreach_option_eq(bbfdm, "dmmap_network_ipv6_prefix", "intf_ipv6_prefix", "section_name", section_name, dmmap_section) { + dmuci_get_value_by_section_string(dmmap_section, "address", &address); + if (address && DM_STRCMP(address, curr_address) == 0) { + dmuci_get_value_by_section_string(dmmap_section, "ipv6_prefix_instance", &ipv6_prefix_inst); + break; + } + } + + if (ip_inst && *ip_inst && ipv6_prefix_inst && *ipv6_prefix_inst) + dmasprintf(value, "Device.IP.Interface.%s.IPv6Prefix.%s", ip_inst, ipv6_prefix_inst); + } + return 0; +} + +static int set_IPInterfaceIPv6Address_Prefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, -1, NULL, NULL)) + return FAULT_9007; + break; + case VALUESET: + break; + } + return 0; +} + +static int get_IPInterfaceIPv6Address_PreferredLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *assign = NULL, *preferred = NULL, local_time[32] = {0}; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "assign", &assign); + if (DM_LSTRCMP(assign, "1") == 0) + preferred = dmjson_get_value(((struct dm_data *)data)->json_object, 2, "local-address", "preferred"); + else + preferred = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "preferred"); + + if (preferred && *preferred && get_shift_utc_time(DM_STRTOL(preferred), local_time, sizeof(local_time)) == -1) + return 0; + + *value = (*local_time) ? dmstrdup(local_time) : "9999-12-31T23:59:59Z"; + return 0; +} + +static int set_IPInterfaceIPv6Address_PreferredLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_dateTime(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + break; + } + return 0; +} + +static int get_IPInterfaceIPv6Address_ValidLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *assign = NULL, *preferred = NULL, local_time[32] = {0}; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "assign", &assign); + if (DM_LSTRCMP(assign, "1") == 0) + preferred = dmjson_get_value(((struct dm_data *)data)->json_object, 2, "local-address", "valid"); + else + preferred = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "valid"); + + if (preferred && *preferred && get_shift_utc_time(DM_STRTOL(preferred), local_time, sizeof(local_time)) == -1) + return 0; + + *value = (*local_time) ? dmstrdup(local_time) : "9999-12-31T23:59:59Z"; + return 0; +} + +static int set_IPInterfaceIPv6Address_ValidLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_dateTime(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + break; + } + return 0; +} + +/*#Device.IP.Interface.{i}.IPv6Prefix.{i}.Enable!UCI:network/interface,@i-1/disabled*/ +static int get_IPInterfaceIPv6Prefix_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *disabled = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "disabled", &disabled); + *value = (disabled && *disabled == '1') ? "0" : "1"; + return 0; +} + +static int set_IPInterfaceIPv6Prefix_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char *proto = NULL, *assign = NULL; + bool b; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "proto", &proto); + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "assign", &assign); + + if (DM_LSTRCMP(proto, "static") != 0 || DM_LSTRCMP(assign, "1") == 0) + return FAULT_9007; + + break; + case VALUESET: + string_to_bool(value, &b); + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "disabled", b ? "0" : "1"); + break; + } + return 0; +} + +/*#Device.IP.Interface.{i}.IPv6Prefix.{i}.Status!UCI:network/interface,@i-1/ipv6*/ +static int get_IPInterfaceIPv6Prefix_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + get_IPInterfaceIPv6Prefix_Enable(refparam, ctx, data, instance, value); + *value = ((*value)[0] == '1') ? "Enabled" : "Disabled"; + return 0; +} + +static int get_IPInterfaceIPv6Prefix_PrefixStatus(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *preferred = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "preferred"); + *value = (preferred && *preferred) ? "Preferred" : "Invalid"; + return 0; +} + +/*#Device.IP.Interface.{i}.IPv6Prefix.{i}.Alias!UCI:dmmap_network_ipv6_prefix/intf_ipv6_prefix,@i-1/ipv6_prefix_alias*/ +static int get_IPInterfaceIPv6Prefix_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return bbf_get_alias(ctx, ((struct dm_data *)data)->dmmap_section, "ipv6_prefix_alias", instance, value); +} + +static int set_IPInterfaceIPv6Prefix_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + return bbf_set_alias(ctx, ((struct dm_data *)data)->dmmap_section, "ipv6_prefix_alias", instance, value); +} + +/*#Device.IP.Interface.{i}.IPv6Prefix.{i}.Prefix!UCI:network/interface,@i-1/ip6prefix*/ +static int get_IPInterfaceIPv6Prefix_Prefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "address", value); + return 0; +} + +static int set_IPInterfaceIPv6Prefix_Prefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char *proto = NULL, *assign = NULL; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, 49, NULL, IPv6Prefix)) + return FAULT_9007; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "proto", &proto); + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "assign", &assign); + + if (DM_LSTRCMP(proto, "static") != 0 || DM_LSTRCMP(assign, "1") == 0) + return FAULT_9007; + + break; + case VALUESET: + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ip6prefix", value); + dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "address", value); + break; + } + return 0; +} + +static int get_IPInterfaceIPv6Prefix_Origin(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *assign = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "assign", &assign); + if (DM_LSTRCMP(assign, "1") == 0) { + *value = "AutoConfigured"; + } else { + char *proto = NULL; + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "proto", &proto); + *value = (DM_LSTRCMP(proto, "dhcpv6") == 0) ? "PrefixDelegation" : "Static"; + } + return 0; +} + +static int get_IPInterfaceIPv6Prefix_ParentPrefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *assign = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "assign", &assign); + if (DM_LSTRCMP(assign, "1") == 0) { + char *linker = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "address", &linker); + _bbfdm_get_references(ctx, "Device.IP.Interface.*.IPv6Prefix.", "ChildPrefixBits", linker, value); + } + return 0; +} + +static int set_IPInterfaceIPv6Prefix_ParentPrefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, -1, NULL, NULL)) + return FAULT_9007; + break; + case VALUESET: + break; + } + return 0; +} + +static int get_IPInterfaceIPv6Prefix_ChildPrefixBits(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *assign = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "assign", &assign); + if (DM_LSTRCMP(assign, "0") == 0) { + char *address = dmjson_get_value(((struct dm_data *)data)->json_object, 3, "assigned", "lan", "address"); + char *mask = dmjson_get_value(((struct dm_data *)data)->json_object, 3, "assigned", "lan", "mask"); + if (address && *address && mask && *mask) + dmasprintf(value, "%s/%s", address, mask); + } + return 0; +} + +static int set_IPInterfaceIPv6Prefix_ChildPrefixBits(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, 49, NULL, IPv6Prefix)) + return FAULT_9007; + break; + case VALUESET: + break; + } + return 0; +} + +static int get_IPInterfaceIPv6Prefix_PreferredLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char local_time[32] = {0}; + + char *preferred = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "preferred"); + if (DM_STRLEN(preferred) && get_shift_utc_time(DM_STRTOL(preferred), local_time, sizeof(local_time)) == -1) + return 0; + + *value = (*local_time) ? dmstrdup(local_time) : "9999-12-31T23:59:59Z"; + return 0; +} + +static int set_IPInterfaceIPv6Prefix_PreferredLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_dateTime(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + break; + } + return 0; +} + +static int get_IPInterfaceIPv6Prefix_ValidLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char local_time[32] = {0}; + + char *valid = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "valid"); + if (DM_STRLEN(valid) && get_shift_time_time(DM_STRTOL(valid), local_time, sizeof(local_time)) == -1) + return 0; + + *value = (*local_time) ? dmstrdup(local_time) : "9999-12-31T23:59:59Z"; + return 0; +} + +static int set_IPInterfaceIPv6Prefix_ValidLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_dateTime(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + break; + } + return 0; +} + +/*#Device.IP.Interface.{i}.Stats.BytesSent!SYSFS:/sys/class/net/@Name/statistics/tx_bytes*/ +static int get_IPInterfaceStats_BytesSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return get_ip_iface_sysfs(data, "statistics/tx_bytes", value); +} + +/*#Device.IP.Interface.{i}.Stats.BytesReceived!SYSFS:/sys/class/net/@Name/statistics/rx_bytes*/ +static int get_IPInterfaceStats_BytesReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return get_ip_iface_sysfs(data, "statistics/rx_bytes", value); +} + +/*#Device.IP.Interface.{i}.Stats.PacketsSent!SYSFS:/sys/class/net/@Name/statistics/tx_packets*/ +static int get_IPInterfaceStats_PacketsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return get_ip_iface_sysfs(data, "statistics/tx_packets", value); +} + +/*#Device.IP.Interface.{i}.Stats.PacketsReceived!SYSFS:/sys/class/net/@Name/statistics/rx_packets*/ +static int get_IPInterfaceStats_PacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return get_ip_iface_sysfs(data, "statistics/rx_packets", value); +} + +/*#Device.IP.Interface.{i}.Stats.ErrorsSent!SYSFS:/sys/class/net/@Name/statistics/tx_errors*/ +static int get_IPInterfaceStats_ErrorsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return get_ip_iface_sysfs(data, "statistics/tx_errors", value); +} + +/*#Device.IP.Interface.{i}.Stats.ErrorsReceived!SYSFS:/sys/class/net/@Name/statistics/rx_errors*/ +static int get_IPInterfaceStats_ErrorsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return get_ip_iface_sysfs(data, "statistics/rx_errors", value); +} + +/*#Device.IP.Interface.{i}.Stats.DiscardPacketsSent!SYSFS:/sys/class/net/@Name/statistics/tx_dropped*/ +static int get_IPInterfaceStats_DiscardPacketsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return get_ip_iface_sysfs(data, "statistics/tx_dropped", value); +} + +/*#Device.IP.Interface.{i}.Stats.DiscardPacketsReceived!SYSFS:/sys/class/net/@Name/statistics/rx_dropped*/ +static int get_IPInterfaceStats_DiscardPacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return get_ip_iface_sysfs(data, "statistics/rx_dropped", value); +} + +/*#Device.IP.Interface.{i}.Stats.MulticastPacketsReceived!SYSFS:/sys/class/net/@Name/statistics/multicast*/ +static int get_IPInterfaceStats_MulticastPacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return get_ip_iface_sysfs(data, "statistics/multicast", value); +} + +static int get_IP_ActivePort_LocalIPAddress(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmstrdup(((ActivePort *)((struct dm_data *)data)->additional_data)->local_ip); + return 0; +} + +static int get_IP_ActivePort_LocalPort(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmasprintf(value, "%u", ((ActivePort *)((struct dm_data *)data)->additional_data)->local_port); + return 0; +} + +static int get_IP_ActivePort_RemoteIPAddress(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmstrdup(((ActivePort *)((struct dm_data *)data)->additional_data)->remote_ip); + return 0; +} + +static int get_IP_ActivePort_RemotePort(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmasprintf(value, "%u", ((ActivePort *)((struct dm_data *)data)->additional_data)->remote_port); + return 0; +} + +static int get_IP_ActivePort_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + unsigned int state = (((ActivePort *)((struct dm_data *)data)->additional_data)->state); + + switch (state) { + case 1: + *value = "ESTABLISHED"; + break; + case 10: + *value = "LISTEN"; + break; + default: + *value = ""; + break; + } + + return 0; +} +/************************************************************* + * OPERATE COMMANDS + *************************************************************/ +static int operate_IPInterface_Reset(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char interface_obj[64] = {0}; + + snprintf(interface_obj, sizeof(interface_obj), "network.interface.%s", section_name((((struct dm_data *)data)->config_section))); + dmubus_call_set(interface_obj, "down", UBUS_ARGS{0}, 0); + dmubus_call_set(interface_obj, "up", UBUS_ARGS{0}, 0); + + return 0; +} + +/********************************************************************************************************************************** +* OBJ & PARAM DEFINITION +***********************************************************************************************************************************/ +/* *** Device. *** */ +DMOBJ tDeviceIPObj[] = { +/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/ +{"IP", &DMREAD, NULL, NULL, "file:/etc/config/network", NULL, NULL, NULL, tIPObj, tIPParams, NULL, BBFDM_BOTH, NULL}, +{0} +}; + +/* *** Device.IP. *** */ +DMOBJ tIPObj[] = { +/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/ +{"Interface", &DMWRITE, addObjIPInterface, delObjIPInterface, NULL, browseIPInterfaceInst, NULL, NULL, tIPInterfaceObj, tIPInterfaceParams, NULL, BBFDM_BOTH, NULL}, +{"ActivePort", &DMREAD, NULL, NULL, NULL, browseIPActivePortInst, NULL, NULL, NULL, tIPActivePortParams, NULL, BBFDM_BOTH, NULL}, +{0} +}; + +DMLEAF tIPParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"IPv4Capable", &DMREAD, DMT_BOOL, get_IP_IPv4Capable, NULL, BBFDM_BOTH}, +//{"IPv4Enable", &DMWRITE, DMT_BOOL, get_IP_IPv4Enable, set_IP_IPv4Enable, BBFDM_BOTH}, +{"IPv4Status", &DMREAD, DMT_STRING, get_IP_IPv4Status, NULL, BBFDM_BOTH}, +{"IPv6Capable", &DMREAD, DMT_BOOL, get_IP_IPv6Capable, NULL, BBFDM_BOTH}, +{"IPv6Enable", &DMWRITE, DMT_BOOL, get_IP_IPv6Enable, set_IP_IPv6Enable, BBFDM_BOTH}, +{"IPv6Status", &DMREAD, DMT_STRING, get_IP_IPv6Status, NULL, BBFDM_BOTH}, +{"ULAPrefix", &DMWRITE, DMT_STRING, get_IP_ULAPrefix, set_IP_ULAPrefix, BBFDM_BOTH}, +{"InterfaceNumberOfEntries", &DMREAD, DMT_UNINT, get_IP_InterfaceNumberOfEntries, NULL, BBFDM_BOTH}, +{"ActivePortNumberOfEntries", &DMREAD, DMT_UNINT, get_IP_ActivePortNumberOfEntries, NULL, BBFDM_BOTH}, +{0} +}; + +/* *** Device.IP.Interface.{i}. *** */ +DMOBJ tIPInterfaceObj[] = { +/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/ +{"IPv4Address", &DMWRITE, addObjIPInterfaceIPv4Address, delObjIPInterfaceIPv4Address, NULL, browseIPInterfaceIPv4AddressInst, NULL, NULL, NULL, tIPInterfaceIPv4AddressParams, NULL, BBFDM_BOTH, NULL}, +{"IPv6Address", &DMWRITE, addObjIPInterfaceIPv6Address, delObjIPInterfaceIPv6Address, NULL, browseIPInterfaceIPv6AddressInst, NULL, NULL, NULL, tIPInterfaceIPv6AddressParams, NULL, BBFDM_BOTH, NULL}, +{"IPv6Prefix", &DMWRITE, addObjIPInterfaceIPv6Prefix, delObjIPInterfaceIPv6Prefix, NULL, browseIPInterfaceIPv6PrefixInst, NULL, NULL, NULL, tIPInterfaceIPv6PrefixParams, NULL, BBFDM_BOTH, NULL}, +{"Stats", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tIPInterfaceStatsParams, NULL, BBFDM_BOTH}, +{0} +}; + +DMLEAF tIPInterfaceParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"Enable", &DMWRITE, DMT_BOOL, get_IPInterface_Enable, set_IPInterface_Enable, BBFDM_BOTH}, +//{"IPv4Enable", &DMWRITE, DMT_BOOL, get_IPInterface_IPv4Enable, set_IPInterface_IPv4Enable, BBFDM_BOTH}, +{"IPv6Enable", &DMWRITE, DMT_BOOL, get_IPInterface_IPv6Enable, set_IPInterface_IPv6Enable, BBFDM_BOTH}, +{"ULAEnable", &DMWRITE, DMT_BOOL, get_IPInterface_ULAEnable, set_IPInterface_ULAEnable, BBFDM_BOTH}, +{"Status", &DMREAD, DMT_STRING, get_IPInterface_Status, NULL, BBFDM_BOTH}, +{"Alias", &DMWRITE, DMT_STRING, get_IPInterface_Alias, set_IPInterface_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"Name", &DMREAD, DMT_STRING, get_IPInterface_Name, NULL, BBFDM_BOTH, DM_FLAG_UNIQUE|DM_FLAG_LINKER}, +{"LastChange", &DMREAD, DMT_UNINT, get_IPInterface_LastChange, NULL, BBFDM_BOTH}, +{"LowerLayers", &DMWRITE, DMT_STRING, get_IPInterface_LowerLayers, set_IPInterface_LowerLayers, BBFDM_BOTH, DM_FLAG_REFERENCE}, +{"Router", &DMWRITE, DMT_STRING, get_IPInterface_Router, set_IPInterface_Router, BBFDM_BOTH, DM_FLAG_REFERENCE}, +{"Reset", &DMWRITE, DMT_BOOL, get_IPInterface_Reset, set_IPInterface_Reset, BBFDM_CWMP}, +{"MaxMTUSize", &DMWRITE, DMT_UNINT, get_IPInterface_MaxMTUSize, set_IPInterface_MaxMTUSize, BBFDM_BOTH}, +{"Type", &DMREAD, DMT_STRING, get_IPInterface_Type, NULL, BBFDM_BOTH}, +{"Loopback", &DMWRITE, DMT_BOOL, get_IPInterface_Loopback, set_IPInterface_Loopback, BBFDM_BOTH}, +{"IPv4AddressNumberOfEntries", &DMREAD, DMT_UNINT, get_IPInterface_IPv4AddressNumberOfEntries, NULL, BBFDM_BOTH}, +{"IPv6AddressNumberOfEntries", &DMREAD, DMT_UNINT, get_IPInterface_IPv6AddressNumberOfEntries, NULL, BBFDM_BOTH}, +{"IPv6PrefixNumberOfEntries", &DMREAD, DMT_UNINT, get_IPInterface_IPv6PrefixNumberOfEntries, NULL, BBFDM_BOTH}, +//{"AutoIPEnable", &DMWRITE, DMT_BOOL, get_IPInterface_AutoIPEnable, set_IPInterface_AutoIPEnable, BBFDM_BOTH}, +{"Reset()", &DMSYNC, DMT_COMMAND, NULL, operate_IPInterface_Reset, BBFDM_USP}, +{0} +}; + +/* *** Device.IP.Interface.{i}.IPv4Address.{i}. *** */ +DMLEAF tIPInterfaceIPv4AddressParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"Enable", &DMWRITE, DMT_BOOL, get_IPInterfaceIPv4Address_Enable, set_IPInterfaceIPv4Address_Enable, BBFDM_BOTH}, +{"Status", &DMREAD, DMT_STRING, get_IPInterfaceIPv4Address_Status, NULL, BBFDM_BOTH}, +{"Alias", &DMWRITE, DMT_STRING, get_IPInterfaceIPv4Address_Alias, set_IPInterfaceIPv4Address_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"IPAddress", &DMWRITE, DMT_STRING, get_IPInterfaceIPv4Address_IPAddress, set_IPInterfaceIPv4Address_IPAddress, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"SubnetMask", &DMWRITE, DMT_STRING, get_IPInterfaceIPv4Address_SubnetMask, set_IPInterfaceIPv4Address_SubnetMask, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"AddressingType", &DMREAD, DMT_STRING, get_IPInterfaceIPv4Address_AddressingType, NULL, BBFDM_BOTH}, +{0} +}; + +/* *** Device.IP.Interface.{i}.IPv6Address.{i}. *** */ +DMLEAF tIPInterfaceIPv6AddressParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"Enable", &DMWRITE, DMT_BOOL, get_IPInterfaceIPv6Address_Enable, set_IPInterfaceIPv6Address_Enable, BBFDM_BOTH}, +{"Status", &DMREAD, DMT_STRING, get_IPInterfaceIPv6Address_Status, NULL, BBFDM_BOTH}, +{"IPAddressStatus", &DMREAD, DMT_STRING, get_IPInterfaceIPv6Address_IPAddressStatus, NULL, BBFDM_BOTH}, +{"Alias", &DMWRITE, DMT_STRING, get_IPInterfaceIPv6Address_Alias, set_IPInterfaceIPv6Address_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"IPAddress", &DMWRITE, DMT_STRING, get_IPInterfaceIPv6Address_IPAddress, set_IPInterfaceIPv6Address_IPAddress, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"Origin", &DMREAD, DMT_STRING, get_IPInterfaceIPv6Address_Origin, NULL, BBFDM_BOTH}, +{"Prefix", &DMWRITE, DMT_STRING, get_IPInterfaceIPv6Address_Prefix, set_IPInterfaceIPv6Address_Prefix, BBFDM_BOTH}, +{"PreferredLifetime", &DMWRITE, DMT_TIME, get_IPInterfaceIPv6Address_PreferredLifetime, set_IPInterfaceIPv6Address_PreferredLifetime, BBFDM_BOTH}, +{"ValidLifetime", &DMWRITE, DMT_TIME, get_IPInterfaceIPv6Address_ValidLifetime, set_IPInterfaceIPv6Address_ValidLifetime, BBFDM_BOTH}, +//{"Anycast", &DMWRITE, DMT_BOOL, get_IPInterfaceIPv6Address_Anycast, set_IPInterfaceIPv6Address_Anycast, BBFDM_BOTH}, +{0} +}; + +/* *** Device.IP.Interface.{i}.IPv6Prefix.{i}. *** */ +DMLEAF tIPInterfaceIPv6PrefixParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/ +{"Enable", &DMWRITE, DMT_BOOL, get_IPInterfaceIPv6Prefix_Enable, set_IPInterfaceIPv6Prefix_Enable, BBFDM_BOTH}, +{"Status", &DMREAD, DMT_STRING, get_IPInterfaceIPv6Prefix_Status, NULL, BBFDM_BOTH}, +{"PrefixStatus", &DMREAD, DMT_STRING, get_IPInterfaceIPv6Prefix_PrefixStatus, NULL, BBFDM_BOTH}, +{"Alias", &DMWRITE, DMT_STRING, get_IPInterfaceIPv6Prefix_Alias, set_IPInterfaceIPv6Prefix_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"Prefix", &DMWRITE, DMT_STRING, get_IPInterfaceIPv6Prefix_Prefix, set_IPInterfaceIPv6Prefix_Prefix, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"Origin", &DMREAD, DMT_STRING, get_IPInterfaceIPv6Prefix_Origin, NULL, BBFDM_BOTH}, +//{"StaticType", &DMWRITE, DMT_STRING, get_IPInterfaceIPv6Prefix_StaticType, set_IPInterfaceIPv6Prefix_StaticType, BBFDM_BOTH}, +{"ParentPrefix", &DMWRITE, DMT_STRING, get_IPInterfaceIPv6Prefix_ParentPrefix, set_IPInterfaceIPv6Prefix_ParentPrefix, BBFDM_BOTH, DM_FLAG_REFERENCE}, +{"ChildPrefixBits", &DMWRITE, DMT_STRING, get_IPInterfaceIPv6Prefix_ChildPrefixBits, set_IPInterfaceIPv6Prefix_ChildPrefixBits, BBFDM_BOTH}, +//{"OnLink", &DMWRITE, DMT_BOOL, get_IPInterfaceIPv6Prefix_OnLink, set_IPInterfaceIPv6Prefix_OnLink, BBFDM_BOTH}, +//{"Autonomous", &DMWRITE, DMT_BOOL, get_IPInterfaceIPv6Prefix_Autonomous, set_IPInterfaceIPv6Prefix_Autonomous, BBFDM_BOTH}, +{"PreferredLifetime", &DMWRITE, DMT_TIME, get_IPInterfaceIPv6Prefix_PreferredLifetime, set_IPInterfaceIPv6Prefix_PreferredLifetime, BBFDM_BOTH}, +{"ValidLifetime", &DMWRITE, DMT_TIME, get_IPInterfaceIPv6Prefix_ValidLifetime, set_IPInterfaceIPv6Prefix_ValidLifetime, BBFDM_BOTH}, +{0} +}; + +/* *** Device.IP.Interface.{i}.Stats. *** */ +DMLEAF tIPInterfaceStatsParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"BytesSent", &DMREAD, DMT_UNLONG, get_IPInterfaceStats_BytesSent, NULL, BBFDM_BOTH}, +{"BytesReceived", &DMREAD, DMT_UNLONG, get_IPInterfaceStats_BytesReceived, NULL, BBFDM_BOTH}, +{"PacketsSent", &DMREAD, DMT_UNLONG, get_IPInterfaceStats_PacketsSent, NULL, BBFDM_BOTH}, +{"PacketsReceived", &DMREAD, DMT_UNLONG, get_IPInterfaceStats_PacketsReceived, NULL, BBFDM_BOTH}, +{"ErrorsSent", &DMREAD, DMT_UNINT, get_IPInterfaceStats_ErrorsSent, NULL, BBFDM_BOTH}, +{"ErrorsReceived", &DMREAD, DMT_UNINT, get_IPInterfaceStats_ErrorsReceived, NULL, BBFDM_BOTH}, +//{"UnicastPacketsSent", &DMREAD, DMT_UNLONG, get_IPInterfaceStats_UnicastPacketsSent, NULL, BBFDM_BOTH}, +//{"UnicastPacketsReceived", &DMREAD, DMT_UNLONG, get_IPInterfaceStats_UnicastPacketsReceived, NULL, BBFDM_BOTH}, +{"DiscardPacketsSent", &DMREAD, DMT_UNINT, get_IPInterfaceStats_DiscardPacketsSent, NULL, BBFDM_BOTH}, +{"DiscardPacketsReceived", &DMREAD, DMT_UNINT, get_IPInterfaceStats_DiscardPacketsReceived, NULL, BBFDM_BOTH}, +//{"MulticastPacketsSent", &DMREAD, DMT_UNLONG, get_IPInterfaceStats_MulticastPacketsSent, NULL, BBFDM_BOTH}, +{"MulticastPacketsReceived", &DMREAD, DMT_UNLONG, get_IPInterfaceStats_MulticastPacketsReceived, NULL, BBFDM_BOTH}, +//{"BroadcastPacketsSent", &DMREAD, DMT_UNLONG, get_IPInterfaceStats_BroadcastPacketsSent, NULL, BBFDM_BOTH}, +//{"BroadcastPacketsReceived", &DMREAD, DMT_UNLONG, get_IPInterfaceStats_BroadcastPacketsReceived, NULL, BBFDM_BOTH}, +//{"UnknownProtoPacketsReceived", &DMREAD, DMT_UNINT, get_IPInterfaceStats_UnknownProtoPacketsReceived, NULL, BBFDM_BOTH}, +{0} +}; + +/* *** Device.IP.ActivePort.{i}. *** */ +DMLEAF tIPActivePortParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type */ +{"LocalIPAddress", &DMREAD, DMT_STRING, get_IP_ActivePort_LocalIPAddress, NULL, BBFDM_BOTH}, +{"LocalPort", &DMREAD, DMT_UNINT, get_IP_ActivePort_LocalPort, NULL, BBFDM_BOTH}, +{"RemoteIPAddress", &DMREAD, DMT_STRING, get_IP_ActivePort_RemoteIPAddress, NULL, BBFDM_BOTH}, +{"RemotePort", &DMREAD, DMT_UNINT, get_IP_ActivePort_RemotePort, NULL, BBFDM_BOTH}, +{"Status", &DMREAD, DMT_STRING, get_IP_ActivePort_Status, NULL, BBFDM_BOTH}, +{0} +}; diff --git a/src/ip.h b/src/ip.h new file mode 100644 index 0000000000000000000000000000000000000000..cc0e2f01983f97d87c2325fb10e791c9f038f9c0 --- /dev/null +++ b/src/ip.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2020-2024 iopsys Software Solutions AB + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> + * Author: Mohd Husaam Mehdi <husaam.mehdi@iopsys.eu> + * + */ + +#ifndef __IP_H +#define __IP_H + +#include "libbbfdm-api/dmcommon.h" + +extern DMOBJ tDeviceIPObj[]; +extern DMOBJ tIPObj[]; +extern DMLEAF tIPParams[]; +extern DMOBJ tIPInterfaceObj[]; +extern DMLEAF tIPInterfaceParams[]; +extern DMLEAF tIPInterfaceIPv4AddressParams[]; +extern DMLEAF tIPInterfaceIPv6AddressParams[]; +extern DMLEAF tIPInterfaceIPv6PrefixParams[]; +extern DMLEAF tIPInterfaceStatsParams[]; +extern DMLEAF tIPActivePortParams[]; + +#endif //__IP_H + diff --git a/src/net_plugin.c b/src/net_plugin.c new file mode 100644 index 0000000000000000000000000000000000000000..fc1aa616d6b775e8200eae01fc26842e5fbf7d57 --- /dev/null +++ b/src/net_plugin.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2024 iopsys Software Solutions AB + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> + */ + +#include "ip.h" +#include "gre.h" +#include "ppp.h" +#include "routing.h" +#include "routeradvertisement.h" + +DM_MAP_OBJ tDynamicObj[] = { +/* parentobj, nextobject, parameter */ +{"Device.", tDeviceIPObj, NULL}, +{"Device.", tDeviceGREObj, NULL}, +{"Device.", tDevicePPPObj, NULL}, +{"Device.", tDeviceRoutingObj, NULL}, +{"Device.", tDeviceRouterAdvertisementObj, NULL}, +{0} +}; diff --git a/src/ppp.c b/src/ppp.c new file mode 100644 index 0000000000000000000000000000000000000000..daab521797021f31bb1329996dc6ee4b1dafe03d --- /dev/null +++ b/src/ppp.c @@ -0,0 +1,1231 @@ +/* + * Copyright (C) 2019-2024 iopsys Software Solutions AB + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> + * + */ + +#include "common.h" +#include "ppp.h" + +#define IPCP 0 +#define IPCPv6 1 + +/************************************************************* +* COMMON FUNCTIONS +**************************************************************/ +static bool is_ppp_section_exist(char *sec_name) +{ + struct uci_section *s = NULL; + + uci_path_foreach_option_eq(bbfdm, "dmmap_ppp", "interface", "iface_name", sec_name, s) { + return true; + } + + return false; +} + +static void dmmap_synchronizePPPInterface(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +{ + struct uci_section *s = NULL, *stmp = NULL; + + uci_path_foreach_sections_safe(bbfdm, "dmmap_ppp", "interface", stmp, s) { + char *added_by_controller = NULL; + char *iface_name = NULL; + + dmuci_get_value_by_section_string(s, "added_by_controller", &added_by_controller); + if (DM_LSTRCMP(added_by_controller, "1") == 0) + continue; + + dmuci_get_value_by_section_string(s, "iface_name", &iface_name); + if (DM_STRLEN(iface_name)) { + struct uci_section *iface_s = NULL; + + get_config_section_of_dmmap_section("network", "interface", iface_name, &iface_s); + + if (!iface_s) + dmuci_delete_by_section(s, NULL, NULL); + } + } + + uci_foreach_sections("network", "interface", s) { + struct uci_section *ppp_s = NULL; + char *proto = NULL; + + dmuci_get_value_by_section_string(s, "proto", &proto); + if (DM_LSTRNCMP(proto, "ppp", 3) != 0) + continue; + + if (is_ppp_section_exist(section_name(s))) + continue; + + dmuci_add_section_bbfdm("dmmap_ppp", "interface", &ppp_s); + dmuci_set_value_by_section(ppp_s, "iface_name", section_name(s)); + ppp___update_sections(s, ppp_s); + } +} + +/************************************************************* +* ENTRY METHOD +**************************************************************/ +static int browseInterfaceInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +{ + struct dm_data curr_data = {0}; + struct uci_section *s = NULL; + char *inst = NULL; + + dmmap_synchronizePPPInterface(dmctx, parent_node, prev_data, prev_instance); + uci_path_foreach_sections(bbfdm, "dmmap_ppp", "interface", s) { + struct uci_section *iface_s = NULL; + char *iface_name = NULL; + char *curr_name = NULL; + + dmuci_get_value_by_section_string(s, "iface_name", &iface_name); + if (DM_STRLEN(iface_name)) + get_config_section_of_dmmap_section("network", "interface", iface_name, &iface_s); + + curr_data.config_section = iface_s; + curr_data.dmmap_section = s; + + inst = handle_instance(dmctx, parent_node, s, "ppp_int_instance", "ppp_int_alias"); + + dmuci_get_value_by_section_string(s, "name", &curr_name); + if (!DM_STRLEN(curr_name)) { + char name[8] = {0}; + + snprintf(name, sizeof(name), "ppp_%s", inst); + dmuci_set_value_by_section(s, "name", name); + } + + if (DM_LINK_INST_OBJ(dmctx, parent_node, &curr_data, inst) == DM_STOP) + break; + } + return 0; +} + +/************************************************************* +* ADD DEL OBJ +**************************************************************/ +static int add_ppp_interface(char *refparam, struct dmctx *ctx, void *data, char **instance) +{ + struct uci_section *dmmap_ppp = NULL; + char name[8] = {0}; + + snprintf(name, sizeof(name), "ppp_%s", *instance); + + dmuci_add_section_bbfdm("dmmap_ppp", "interface", &dmmap_ppp); + dmuci_set_value_by_section(dmmap_ppp, "name", name); + dmuci_set_value_by_section(dmmap_ppp, "proto", "ppp"); + dmuci_set_value_by_section(dmmap_ppp, "disabled", "1"); + dmuci_set_value_by_section(dmmap_ppp, "added_by_controller", "1"); + dmuci_set_value_by_section(dmmap_ppp, "ppp_int_instance", *instance); + return 0; +} + +static int delete_ppp_interface(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action) +{ + switch (del_action) { + case DEL_INST: + if (((struct dm_data *)data)->config_section) { + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "proto", "none"); + ppp___reset_options(((struct dm_data *)data)->config_section); + } + + // Update PPP Interface Top Layers + ppp___Update_PPP_Interface_Top_Layers(refparam, ""); + + // Remove dmmap section + dmuci_delete_by_section(((struct dm_data *)data)->dmmap_section, NULL, NULL); + break; + case DEL_ALL: + break; + } + return 0; +} + +/************************************************************* +* GET & SET PARAM +**************************************************************/ +static int get_ppp_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct dm_data *ppp = (struct dm_data *)data; + char *disabled = NULL; + + dmuci_get_value_by_section_string(ppp->config_section ? ppp->config_section : ppp->dmmap_section, "disabled", &disabled); + *value = (disabled && *disabled == '1') ? "0" : "1"; + return 0; +} + +static int set_ppp_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct dm_data *ppp = (struct dm_data *)data; + bool b; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + dmuci_set_value_by_section(ppp->dmmap_section, "disabled", b ? "0" : "1"); + if (ppp->config_section) + dmuci_set_value_by_section(ppp->config_section, "disabled", b ? "0" : "1"); + break; + } + return 0; +} + +static int get_PPPInterface_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + get_ppp_enable(refparam, ctx, data, instance, value); + *value = (DM_LSTRCMP(*value, "1") == 0) ? "Up" : "Down"; + return 0; +} + +/*#Device.PPP.Interface.{i}.Alias!UCI:dmmap_network/interface,@i-1/ppp_int_alias*/ +static int get_ppp_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return bbf_get_alias(ctx, ((struct dm_data *)data)->dmmap_section, "ppp_int_alias", instance, value); +} + +static int set_ppp_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + return bbf_set_alias(ctx, ((struct dm_data *)data)->dmmap_section, "ppp_int_alias", instance, value); +} + +/*#Device.PPP.Interface.{i}.LastChange!UBUS:network.interface/status/interface,@Name/uptime*/ +static int get_PPPInterface_LastChange(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *ppp_s = ((struct dm_data *)data)->config_section; + + if (ppp_s) { + json_object *res = NULL; + + char *if_name = section_name(ppp_s); + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", if_name, String}}, 1, &res); + DM_ASSERT(res, *value = "0"); + *value = dmjson_get_value(res, 1, "uptime"); + } else { + *value = "0"; + } + return 0; +} + +static int get_PPPInterface_Reset(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "false"; + return 0; +} + +static int set_PPPInterface_Reset(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + /* Reset can disrupt on-going cwmp session, so this parameter must be + * taken care by cwmp internally. + */ + break; + } + return 0; +} + +static int get_ppp_name(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "name", value); + return 0; +} + +/*#Device.PPP.Interface.{i}.ConnectionStatus!UBUS:network.interface/status/interface,@Name/up*/ +static int get_ppp_status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *ppp_s = ((struct dm_data *)data)->config_section; + + if (ppp_s) { + char *status = NULL, *uptime = NULL, *pending = NULL; + json_object *res = NULL, *jobj = NULL; + bool bstatus = false, bpend = false; + + char *if_name = section_name(ppp_s); + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", if_name, String}}, 1, &res); + DM_ASSERT(res, *value = "Unconfigured"); + jobj = dmjson_get_obj(res, 1, "up"); + if (jobj) { + status = dmjson_get_value(res, 1, "up"); + string_to_bool(status, &bstatus); + if (bstatus) { + uptime = dmjson_get_value(res, 1, "uptime"); + pending = dmjson_get_value(res, 1, "pending"); + string_to_bool(pending, &bpend); + } + } + if (uptime && DM_STRTOL(uptime) > 0) + *value = "Connected"; + else if (pending && bpend) + *value = "Pending Disconnect"; + else + *value = "Disconnected"; + } else { + *value = "Unconfigured"; + } + return 0; +} + +static int get_PPPInterface_LastConnectionError(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *ppp_s = ((struct dm_data *)data)->config_section; + + if (ppp_s) { + json_object *res = NULL; + + char *if_name = section_name(ppp_s); + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", if_name, String}}, 1, &res); + DM_ASSERT(res, *value = "ERROR_NONE"); + char *status = dmjson_get_value(res, 2, "data", "lastconnectionerror"); + + switch (DM_STRTOL(status)) { + case 0: + *value = "ERROR_NONE"; + break; + case 1: case 10: case 13: case 14: case 17: case 18: case 20: case 22: + *value = "ERROR_UNKNOWN"; + break; + case 2: case 3: case 4: case 6: case 7: case 9: + *value = "ERROR_COMMAND_ABORTED"; + break; + case 5: case 15: + *value = "ERROR_USER_DISCONNECT"; + break; + case 8: + *value = "ERROR_IP_CONFIGURATION"; + break; + case 11: case 19: case 21: + *value = "ERROR_AUTHENTICATION_FAILURE"; + break; + case 12: + *value = "ERROR_IDLE_DISCONNECT"; + break; + case 16: + *value = "ERROR_ISP_DISCONNECT"; + break; + default: + *value = "ERROR_NONE"; + break; + } + } else { + *value = "ERROR_NONE"; + } + return 0; +} + +/*#Device.PPP.Interface.{i}.Username!UCI:network/interface,@i-1/username*/ +static int get_ppp_username(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct dm_data *ppp = (struct dm_data *)data; + + dmuci_get_value_by_section_string(ppp->config_section ? ppp->config_section : ppp->dmmap_section, "username", value); + return 0; +} + +static int set_ppp_username(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct dm_data *ppp = (struct dm_data *)data; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, 64, NULL, NULL)) + return FAULT_9007; + return 0; + case VALUESET: + dmuci_set_value_by_section(ppp->dmmap_section, "username", value); + if (ppp->config_section) + dmuci_set_value_by_section(ppp->config_section, "username", value); + return 0; + } + return 0; +} + +/*#Device.PPP.Interface.{i}.Password!UCI:network/interface,@i-1/password*/ +static int get_ppp_password(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct dm_data *ppp = (struct dm_data *)data; + + dmuci_get_value_by_section_string(ppp->config_section ? ppp->config_section : ppp->dmmap_section, "password", value); + return 0; +} + +/*#Device.PPP.Interface.{i}.Password!UCI:network/interface,@i-1/password*/ +static int set_ppp_password(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct dm_data *ppp = (struct dm_data *)data; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, 64, NULL, NULL)) + return FAULT_9007; + return 0; + case VALUESET: + dmuci_set_value_by_section(ppp->dmmap_section, "password", value); + if (ppp->config_section) + dmuci_set_value_by_section(ppp->config_section, "password", value); + return 0; + } + return 0; +} + +static int get_PPPInterface_MaxMRUSize(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct dm_data *ppp = (struct dm_data *)data; + char *pppd_opt = NULL; + + dmuci_get_value_by_section_string(ppp->config_section ? ppp->config_section : ppp->dmmap_section, "pppd_options", &pppd_opt); + if (pppd_opt && *pppd_opt == '\0') { + *value = "1500"; + return 0; + } + + char *token = NULL , *end = NULL; + token = strtok_r(pppd_opt, " ", &end); + while (NULL != token) { + if (0 == DM_LSTRCMP(token, "mru")) { + char mru_val[1024] = {0}, mru_str[1024] = {0}; + DM_STRNCPY(mru_val, end, sizeof(mru_val)); + sscanf(mru_val, "%1023s", mru_str); + if ('\0' != mru_str[0]) { + *value = dmstrdup(mru_str); + } + break; + } + token = strtok_r(NULL, " ", &end); + } + + if (*value && (*value)[0] == '\0') { + *value = "1500"; + } + + return 0; +} + +static int configure_pppd_mru(char *pppd_opt, char *mru_str, struct uci_section *sec, char *value) +{ + char *token = NULL, *end = NULL; + char list_options[1024] = {0}, mru_opt[1024] = {0}; + unsigned pos = 0; + bool found = false; + + list_options[0] = 0; + token = strtok_r(pppd_opt, " ", &end); + while (NULL != token) { + if (0 == DM_LSTRCMP(token, "mru")) { + found = true; + pos += snprintf(&list_options[pos], sizeof(list_options) - pos, "%s %s", token, value); + DM_STRNCPY(mru_opt, end, sizeof(mru_opt)); + char *p, *q; + p = strtok_r(mru_opt, " ", &q); + if (p != NULL && q != NULL) { + pos += snprintf(&list_options[pos], sizeof(list_options) - pos, " %s", q); + } + break; + } + pos += snprintf(&list_options[pos], sizeof(list_options) - pos, "%s ", token); + token = strtok_r(NULL, " ", &end); + } + + if (found == false) + snprintf(&list_options[pos], sizeof(list_options) - pos, "%s", mru_str); + + dmuci_set_value_by_section(sec, "pppd_options", list_options); + return 0; +} + +static int set_PPPInterface_MaxMRUSize(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct dm_data *ppp = (struct dm_data *)data; + char mru_str[1024] = {0}; + char *pppd_opt = NULL; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"64","65535"}}, 1)) + return FAULT_9007; + break; + case VALUESET: + snprintf(mru_str, sizeof(mru_str), "%s %s", "mru", value); + dmuci_get_value_by_section_string(ppp->config_section ? ppp->config_section : ppp->dmmap_section, "pppd_options", &pppd_opt); + + if (pppd_opt && *pppd_opt == '\0') { + dmuci_set_value_by_section(ppp->dmmap_section, "pppd_options", mru_str); + if (ppp->config_section) + dmuci_set_value_by_section(ppp->config_section, "pppd_options", mru_str); + } else { + // If mru is specified then we need to replace and keep the rest of the options intact. + configure_pppd_mru(pppd_opt, mru_str, ppp->dmmap_section, value); + if (ppp->config_section) + configure_pppd_mru(pppd_opt, mru_str, ppp->config_section, value); + } + break; + } + return 0; +} + +static int get_PPPInterface_CurrentMRUSize(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *ppp_s = ((struct dm_data *)data)->config_section; + + if (ppp_s) { + char intf[64] = {0}; + + snprintf(intf, sizeof(intf), "%s-%s", "pppoe", section_name(ppp_s)); + get_net_device_sysfs(intf, "mtu", value); + } + + return 0; +} + +static int get_PPPInterface_LCPEcho(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *ppp_s = ((struct dm_data *)data)->config_section; + + if (ppp_s) { + char *lcp_echo = NULL, *token = NULL; + + dmuci_get_value_by_section_string(ppp_s, "keepalive", &lcp_echo); + if (lcp_echo && *lcp_echo == '\0') { + *value = "1"; + return 0; + } + + token = strtok(lcp_echo , " "); + if (NULL != token) { + char echo_val[50] = {0}; + + DM_STRNCPY(echo_val, token, sizeof(echo_val)); + *value = dmstrdup(echo_val); + } + } + return 0; +} + +static int get_PPPInterface_LCPEchoRetry(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *ppp_s = ((struct dm_data *)data)->config_section; + + if (ppp_s) { + char *lcp_retry = NULL, *token = NULL; + + dmuci_get_value_by_section_string(ppp_s, "keepalive", &lcp_retry); + if (!lcp_retry || *lcp_retry == '\0') { + *value = "5"; + } else { + token = DM_STRCHR(lcp_retry , ' '); + if (NULL != token) { + char lcp_interval[50] = {0}; + + DM_STRNCPY(lcp_interval, token + 1, sizeof(lcp_interval)); + *value = dmstrdup(lcp_interval); + } + } + } + return 0; +} + +static int configure_supported_ncp_options(struct uci_section *ss, char *value, char *option) +{ + char *proto, *pppd_opt = NULL; + char list_options[1024] = {0}; + + dmuci_get_value_by_section_string(ss, "proto", &proto); + if (0 == DM_LSTRCMP(proto, "pppoe")) { + dmuci_get_value_by_section_string(ss, "pppd_options", &pppd_opt); + } + + if (pppd_opt && *pppd_opt != '\0') { + char *token = NULL, *end = NULL; + bool found = false; + unsigned pos = 0; + + list_options[0] = 0; + token = strtok_r(pppd_opt, " ", &end); + while (NULL != token) { + char ncp_opt[1024] = {0}; + DM_STRNCPY(ncp_opt, token, sizeof(ncp_opt)); + if (0 == DM_STRNCMP(ncp_opt, option, sizeof(ncp_opt))) { + found = true; + if (0 == DM_LSTRCMP(value, "1") && NULL != end) { + if (pos != 0) + pos += snprintf(&list_options[pos], sizeof(list_options) - pos, "%c", ' '); + + pos += snprintf(&list_options[pos], sizeof(list_options) - pos, "%s", end); + break; + } + } else { + if (pos != 0) + pos += snprintf(&list_options[pos], sizeof(list_options) - pos, "%c", ' '); + + pos += snprintf(&list_options[pos], sizeof(list_options) - pos, "%s", token); + } + token = strtok_r(NULL, " ", &end); + } + + if ((0 == DM_LSTRCMP(value, "0")) && found == false) { + if (pos != 0) + pos += snprintf(&list_options[pos], sizeof(list_options) - pos, "%c", ' '); + + snprintf(&list_options[pos], sizeof(list_options) - pos, "%s", option); + } + + dmuci_set_value_by_section(ss, "pppd_options", list_options); + } else { + if (0 == DM_LSTRCMP(value, "0")) { + dmuci_set_value_by_section(ss, "pppd_options", option); + } + } + + return 0; +} + +static int parse_pppd_options(char *pppd_opt, int option) +{ + int noip = 0, noipv6 = 0; + char *token = NULL, *end = NULL; + + token = strtok_r(pppd_opt, " ", &end); + while (NULL != token) { + char value[50] = {0}; + DM_STRNCPY(value, token, sizeof(value)); + + if ((4 == DM_STRLEN(value)) && 0 == DM_LSTRCMP(value, "noip")) { + noip = 1; + } + + if (0 == DM_LSTRNCMP(value, "noipv6", 6)) { + noipv6 = 1; + } + + token = strtok_r(NULL, " ", &end); + } + + if (option == IPCP) { + return noip; + } else { + return noipv6; + } +} + +static int handle_supported_ncp_options(struct uci_section *s, char *instance, int option) +{ + char *pppd_opt = NULL, *proto = NULL; + + dmuci_get_value_by_section_string(s, "proto", &proto); + if (proto && DM_LSTRCMP(proto, "pppoe") == 0) + dmuci_get_value_by_section_string(s, "pppd_options", &pppd_opt); + + return pppd_opt ? parse_pppd_options(pppd_opt, option) : 0; +} + +static int get_PPPInterface_IPCPEnable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct dm_data *ppp = (struct dm_data *)data; + + int ret = handle_supported_ncp_options(ppp->config_section ? ppp->config_section : ppp->dmmap_section, instance, IPCP); + *value = ret ? "0" : "1"; + return 0; +} + +static int set_PPPInterface_IPCPEnable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct dm_data *ppp = (struct dm_data *)data; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + configure_supported_ncp_options(ppp->dmmap_section, value, "noip"); + if (ppp->config_section) + configure_supported_ncp_options(ppp->config_section, value, "noip"); + + break; + } + return 0; +} + +static int get_PPPInterface_IPv6CPEnable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct dm_data *ppp = (struct dm_data *)data; + + int ret = handle_supported_ncp_options(ppp->config_section ? ppp->config_section : ppp->dmmap_section, instance, IPCPv6); + *value = ret ? "0" : "1"; + return 0; +} + +static int set_PPPInterface_IPv6CPEnable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct dm_data *ppp = (struct dm_data *)data; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + configure_supported_ncp_options(ppp->dmmap_section, value, "noipv6"); + if (ppp->config_section) + configure_supported_ncp_options(ppp->config_section, value, "noipv6"); + break; + } + return 0; +} + +static int get_PPPInterfacePPPoE_SessionID(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + FILE *fp = fopen("/proc/net/pppoe" ,"r"); + if (NULL == fp) { + *value = "1"; + } else { + char session_id[20] = {0}; + char path[1024] = {0}; + int i = 0; + + while (fgets(path, sizeof(path), fp) != NULL) { + i++; + if (2 == i) { + sscanf(path, "%19s", session_id); + int number = (int)strtol(session_id, NULL, 16); + memset(session_id, '\0', sizeof(session_id)); + snprintf(session_id, sizeof(session_id), "%d", number); + if ('\0' == session_id[0]) { + *value = "1"; + } else { + *value = dmstrdup(session_id); + } + break; + } + } + fclose(fp); + } + return 0; +} + +static int get_PPPInterfaceIPCP_LocalIPAddress(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *ppp_s = ((struct dm_data *)data)->config_section; + + if (ppp_s) { + json_object *res = NULL; + + char *if_name = section_name(ppp_s); + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", if_name, String}}, 1, &res); + DM_ASSERT(res, *value = ""); + json_object *ipv4_obj = dmjson_select_obj_in_array_idx(res, 0, 1, "ipv4-address"); + *value = dmjson_get_value(ipv4_obj, 1, "address"); + } + return 0; +} + +static int get_PPPInterfaceIPCP_RemoteIPAddress(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *ppp_s = ((struct dm_data *)data)->config_section; + + if (ppp_s) { + json_object *res = NULL; + + char *if_name = section_name(ppp_s); + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", if_name, String}}, 1, &res); + DM_ASSERT(res, *value = ""); + json_object *ipv4_obj = dmjson_select_obj_in_array_idx(res, 0, 1, "ipv4-address"); + *value = dmjson_get_value(ipv4_obj, 1, "ptpaddress"); + if (**value == '\0') { + json_object *route_obj = dmjson_select_obj_in_array_idx(res, 0, 1, "route"); + *value = dmjson_get_value(route_obj, 1, "nexthop"); + } + } + return 0; +} + +static int get_PPPInterfaceIPCP_DNSServers(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *ppp_s = ((struct dm_data *)data)->config_section; + + if (ppp_s) { + json_object *res = NULL; + + char *if_name = section_name(ppp_s); + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", if_name, String}}, 1, &res); + DM_ASSERT(res, *value = ""); + *value = dmjson_get_value_array_all(res, ",", 1, "dns-server"); + } + return 0; +} + +static int get_PPPInterfaceIPv6CP_LocalInterfaceIdentifier(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *ppp_s = ((struct dm_data *)data)->config_section; + + if (ppp_s) { + json_object *res = NULL; + + char *if_name = section_name(ppp_s); + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", if_name, String}}, 1, &res); + DM_ASSERT(res, *value = ""); + json_object *ipv4_obj = dmjson_select_obj_in_array_idx(res, 0, 1, "ipv6-address"); + *value = dmjson_get_value(ipv4_obj, 1, "address"); + } + return 0; +} + +static int get_PPPInterfaceIPv6CP_RemoteInterfaceIdentifier(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *ppp_s = ((struct dm_data *)data)->config_section; + + if (ppp_s) { + json_object *res = NULL; + + char *if_name = section_name(ppp_s); + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", if_name, String}}, 1, &res); + DM_ASSERT(res, *value = ""); + *value = dmjson_get_value(res, 2, "data", "llremote"); + } + return 0; +} + +static int ppp_read_sysfs(void *data, const char *name, char **value) +{ + struct uci_section *ppp_s = ((struct dm_data *)data)->config_section; + + *value = "0"; + + if (ppp_s) { + char *proto; + + dmuci_get_value_by_section_string(ppp_s, "proto", &proto); + if (!DM_LSTRCMP(proto, "pppoe")) { + char *l3_device = get_l3_device(section_name(ppp_s)); + get_net_device_sysfs(l3_device, name, value); + } + } + + return 0; +} + +static int get_PPPInterfaceStats_MulticastPacketsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ +/* + * Irrespective of underlying media, PPP is multicast incapable. + * The stats pertaining to Multicast recv/xmit are irrelevant to ppp interfaces. + * Hence the value of this stats marked ZERO. + */ + *value = "0"; + return 0; +} + +static int get_PPPInterfaceStats_BroadcastPacketsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ +/* + * Irrespective of underlying media, PPP is broadcast incapable. + * The stats pertaining to broadcast recv/xmit are irrelevant to ppp interfaces. + * Hence the value of this stats marked ZERO. + */ + *value = "0"; + return 0; +} + +static int get_PPPInterfaceStats_BroadcastPacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ +/* + * Irrespective of underlying media, PPP is broadcast incapable. + * The stats pertaining to broadcast recv/xmit are irrelevant to ppp interfaces. + * Hence the value of this stats marked ZERO. + */ + *value = "0"; + return 0; +} + +static int get_PPPInterfaceStats_UnknownProtoPacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return ppp_read_sysfs(data, "statistics/rx_unknown_packets", value); +} + +/*#Device.PPP.Interface.{i}.Stats.MulticastPacketsReceived!SYSFS:/sys/class/net/@Name/statistics/multicast*/ +static int get_PPPInterfaceStats_MulticastPacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ +/* + * Irrespective of underlying media, PPP is multicast incapable. + * The stats pertaining to Multicast recv/xmit are irrelevant for ppp interfaces. + * Hence the value of this stats marked ZERO. + */ + *value = "0"; + return 0; +} + +/*#Device.PPP.Interface.{i}.Stats.BytesReceived!SYSFS:/sys/class/net/@Name/statistics/rx_bytes*/ +static int get_ppp_eth_bytes_received(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return ppp_read_sysfs(data, "statistics/rx_bytes", value); +} + +/*#Device.PPP.Interface.{i}.Stats.BytesSent!SYSFS:/sys/class/net/@Name/statistics/tx_bytes*/ +static int get_ppp_eth_bytes_sent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return ppp_read_sysfs(data, "statistics/tx_bytes", value); +} + +/*#Device.PPP.Interface.{i}.Stats.PacketsReceived!SYSFS:/sys/class/net/@Name/statistics/rx_packets*/ +static int get_ppp_eth_pack_received(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return ppp_read_sysfs(data, "statistics/rx_packets", value); +} + +/*#Device.PPP.Interface.{i}.Stats.PacketsSent!SYSFS:/sys/class/net/@Name/statistics/tx_packets*/ +static int get_ppp_eth_pack_sent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return ppp_read_sysfs(data, "statistics/tx_packets", value); +} + +/*#Device.PPP.Interface.{i}.Stats.ErrorsSent!SYSFS:/sys/class/net/@Name/statistics/tx_errors*/ +static int get_PPPInterfaceStats_ErrorsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return ppp_read_sysfs(data, "statistics/tx_errors", value); +} + +/*#Device.PPP.Interface.{i}.Stats.ErrorsReceived!SYSFS:/sys/class/net/@Name/statistics/rx_errors*/ +static int get_PPPInterfaceStats_ErrorsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return ppp_read_sysfs(data, "statistics/rx_errors", value); +} + +/*#Device.PPP.Interface.{i}.Stats.DiscardPacketsSent!SYSFS:/sys/class/net/@Name/statistics/tx_dropped*/ +static int get_PPPInterfaceStats_DiscardPacketsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return ppp_read_sysfs(data, "statistics/tx_dropped", value); +} + +/*#Device.PPP.Interface.{i}.Stats.DiscardPacketsReceived!SYSFS:/sys/class/net/@Name/statistics/rx_dropped*/ +static int get_PPPInterfaceStats_DiscardPacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return ppp_read_sysfs(data, "statistics/rx_dropped", value); +} + +static int get_PPPInterfaceStats_UnicastPacketsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ +/* By default all the data packets at a ppp end point are Unicast. + * Hence the number of Unicast packets is equal to the tx_packets. + */ + return ppp_read_sysfs(data, "statistics/tx_packets", value); +} + +static int get_PPPInterfaceStats_UnicastPacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ +/* Unicast Packets Received = (Total packets received - Unknown Protocol Packets Received)*/ + + char *rx_other = NULL, *rx_pkts = NULL; + unsigned long other_rcv = 0, total_rcv = 0; + + get_PPPInterfaceStats_UnknownProtoPacketsReceived(refparam, ctx, data, instance, &rx_other); + get_ppp_eth_pack_received(refparam, ctx, data, instance, &rx_pkts); + + other_rcv = DM_STRTOUL(rx_other); + total_rcv = DM_STRTOUL(rx_pkts); + + unsigned long ucast_rcv = total_rcv - other_rcv; + dmasprintf(value, "%lu", ucast_rcv); + return 0; +} + +static int get_ppp_lower_layer(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct dm_data *ppp = (struct dm_data *)data; + + dmuci_get_value_by_section_string(ppp->dmmap_section, "LowerLayers", value); + + if ((*value)[0] == '\0') { + char *device = NULL; + char buf[1024] = {0}; + + if (ppp->config_section) { + device = get_device(section_name(ppp->config_section)); + if (DM_STRLEN(device) == 0) + dmuci_get_value_by_section_string(ppp->config_section, "device", &device); + } else { + dmuci_get_value_by_section_string(ppp->dmmap_section, "device", &device); + } + + if (DM_STRLEN(device) == 0) + return 0; + + bbfdm_get_references(ctx, MATCH_FIRST, "Device.Ethernet."BBF_VENDOR_PREFIX"MACVLAN.", "Name", device, buf, sizeof(buf)); + bbfdm_get_references(ctx, MATCH_FIRST, "Device.Ethernet.VLANTermination.", "Name", device, buf, sizeof(buf)); + bbfdm_get_references(ctx, MATCH_FIRST, "Device.Ethernet.Link.", "Name", device, buf, sizeof(buf)); + + // Store LowerLayers value + dmuci_set_value_by_section(ppp->dmmap_section, "LowerLayers", buf); + + *value = dmstrdup(buf); + } + + return 0; +} + +static int set_ppp_lower_layer(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct dm_data *ppp = (struct dm_data *)data; + char eth_mac_vlan[] = "Device.Ethernet."BBF_VENDOR_PREFIX"MACVLAN"; + char *allowed_objects[] = { + eth_mac_vlan, + "Device.Ethernet.VLANTermination.", + "Device.Ethernet.Link.", + NULL}; + struct dm_reference reference = {0}; + char proto[8] = {0}; + + bbfdm_get_reference_linker(ctx, value, &reference); + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string_list(ctx, reference.path, -1, -1, 1024, -1, -1, NULL, NULL)) + return FAULT_9007; + + if (dm_validate_allowed_objects(ctx, &reference, allowed_objects)) + return FAULT_9007; + + return 0; + case VALUESET: + // Store LowerLayers value under dmmap_ppp section + dmuci_set_value_by_section(ppp->dmmap_section, "LowerLayers", reference.path); + + snprintf(proto, sizeof(proto), "ppp%s", (DM_STRLEN(reference.value)) ? (!DM_LSTRNCMP(reference.value, "atm", 3) || !DM_LSTRNCMP(reference.value, "ptm", 3)) ? "oa" : "oe" : ""); + + // Update proto option + dmuci_set_value_by_section(ppp->dmmap_section, "proto", proto); + if (ppp->config_section) dmuci_set_value_by_section(ppp->config_section, "proto", proto); + + // Update device option + dmuci_set_value_by_section(ppp->dmmap_section, "device", reference.value); + if (ppp->config_section) dmuci_set_value_by_section(ppp->config_section, "device", DM_STRLEN(reference.value) ? reference.value : section_name(ppp->config_section)); + + // Update PPP Interface Top Layers + ppp___Update_PPP_Interface_Top_Layers(refparam, reference.value); + return 0; + } + return 0; +} + +static int get_PPP_InterfaceNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + int cnt = get_number_of_entries(ctx, data, instance, browseInterfaceInst); + dmasprintf(value, "%d", cnt); + return 0; +} + +static int get_PPP_SupportedNCPs(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "IPCP,IPv6CP"; + return 0; +} + +/*#Device.PPP.Interface.{i}.PPPoE.ACName!UCI:network/interface,@i-1/ac*/ +static int get_PPPInterfacePPPoE_ACName(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct dm_data *ppp = (struct dm_data *)data; + char *proto; + + dmuci_get_value_by_section_string(ppp->config_section ? ppp->config_section : ppp->dmmap_section, "proto", &proto); + if (DM_LSTRCMP(proto, "pppoe") == 0) { + dmuci_get_value_by_section_string(ppp->config_section ? ppp->config_section : ppp->dmmap_section, "ac", value); + return 0; + } + return 0; +} + +static int set_PPPInterfacePPPoE_ACName(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct dm_data *ppp = (struct dm_data *)data; + char *proto_intf; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, 256, NULL, NULL)) + return FAULT_9007; + + dmuci_get_value_by_section_string(ppp->config_section ? ppp->config_section : ppp->dmmap_section, "proto", &proto_intf); + if (DM_LSTRCMP(proto_intf, "pppoe") != 0) + return FAULT_9001; + break; + case VALUESET: + dmuci_set_value_by_section(ppp->dmmap_section, "ac", value); + if (ppp->config_section) + dmuci_set_value_by_section(ppp->config_section, "ac", value); + break; + } + return 0; +} + +/*#Device.PPP.Interface.{i}.PPPoE.ServiceName!UCI:network/interface,@i-1/service*/ +static int get_PPPInterfacePPPoE_ServiceName(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct dm_data *ppp = (struct dm_data *)data; + char *proto; + + dmuci_get_value_by_section_string(ppp->config_section ? ppp->config_section : ppp->dmmap_section, "proto", &proto); + if (DM_LSTRCMP(proto, "pppoe") == 0) { + dmuci_get_value_by_section_string(ppp->config_section ? ppp->config_section : ppp->dmmap_section, "service", value); + return 0; + } + return 0; +} + +static int set_PPPInterfacePPPoE_ServiceName(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct dm_data *ppp = (struct dm_data *)data; + char *proto; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, 256, NULL, NULL)) + return FAULT_9007; + + dmuci_get_value_by_section_string(ppp->config_section ? ppp->config_section : ppp->dmmap_section, "proto", &proto); + if (DM_LSTRCMP(proto, "pppoe") != 0) + return FAULT_9001; + break; + case VALUESET: + dmuci_set_value_by_section(ppp->dmmap_section, "service", value); + if (ppp->config_section) + dmuci_set_value_by_section(ppp->config_section, "service", value); + break; + } + return 0; +} + +/************************************************************* + * OPERATE COMMANDS + *************************************************************/ +static int operate_PPPInterface_Reset(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct uci_section *ppp_s = ((struct dm_data *)data)->config_section; + + if (ppp_s) { + char interface_obj[64] = {0}; + + snprintf(interface_obj, sizeof(interface_obj), "network.interface.%s", section_name(ppp_s)); + dmubus_call_set(interface_obj, "down", UBUS_ARGS{0}, 0); + dmubus_call_set(interface_obj, "up", UBUS_ARGS{0}, 0); + } + + return 0; +} + +/********************************************************************************************************************************** +* OBJ & PARAM DEFINITION +***********************************************************************************************************************************/ +/* *** Device. *** */ +DMOBJ tDevicePPPObj[] = { +/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/ +{"PPP", &DMREAD, NULL, NULL, "file:/lib/netifd/proto/ppp.sh,/etc/config/network", NULL, NULL, NULL, tPPPObj, tPPPParams, NULL, BBFDM_BOTH, NULL}, +{0} +}; + +/* *** Device.PPP. *** */ +DMOBJ tPPPObj[] = { +/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/ +{"Interface", &DMWRITE, add_ppp_interface, delete_ppp_interface, NULL, browseInterfaceInst, NULL, NULL, tPPPInterfaceObj, tPPPInterfaceParams, NULL, BBFDM_BOTH, NULL}, +{0} +}; + +DMLEAF tPPPParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"InterfaceNumberOfEntries", &DMREAD, DMT_UNINT, get_PPP_InterfaceNumberOfEntries, NULL, BBFDM_BOTH}, +{"SupportedNCPs", &DMREAD, DMT_STRING, get_PPP_SupportedNCPs, NULL, BBFDM_BOTH}, +{0} +}; + +/* *** Device.PPP.Interface.{i}. *** */ +DMOBJ tPPPInterfaceObj[] = { +/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/ +{"PPPoE", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tPPPInterfacePPPoEParams, NULL, BBFDM_BOTH}, +{"IPCP", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tPPPInterfaceIPCPParams, NULL, BBFDM_BOTH}, +{"IPv6CP", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tPPPInterfaceIPv6CPParams, NULL, BBFDM_BOTH}, +{"Stats", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tPPPInterfaceStatsParams, NULL, BBFDM_BOTH}, +{0} +}; + +DMLEAF tPPPInterfaceParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"Alias", &DMWRITE, DMT_STRING, get_ppp_alias, set_ppp_alias, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"Enable", &DMWRITE, DMT_BOOL, get_ppp_enable, set_ppp_enable, BBFDM_BOTH}, +{"Status", &DMREAD, DMT_STRING, get_PPPInterface_Status, NULL, BBFDM_BOTH}, +{"LastChange", &DMREAD, DMT_UNINT, get_PPPInterface_LastChange, NULL, BBFDM_BOTH}, +{"Reset", &DMWRITE, DMT_BOOL, get_PPPInterface_Reset, set_PPPInterface_Reset, BBFDM_CWMP}, +{"Name", &DMREAD, DMT_STRING, get_ppp_name, NULL, BBFDM_BOTH, DM_FLAG_UNIQUE|DM_FLAG_LINKER}, +{"LowerLayers", &DMWRITE, DMT_STRING, get_ppp_lower_layer, set_ppp_lower_layer, BBFDM_BOTH, DM_FLAG_REFERENCE}, +{"ConnectionStatus", &DMREAD, DMT_STRING, get_ppp_status, NULL, BBFDM_BOTH}, +{"LastConnectionError", &DMREAD, DMT_STRING, get_PPPInterface_LastConnectionError, NULL, BBFDM_BOTH}, +{"Username", &DMWRITE, DMT_STRING, get_ppp_username, set_ppp_username, BBFDM_BOTH}, +{"Password", &DMWRITE, DMT_STRING, get_ppp_password, set_ppp_password, BBFDM_BOTH, DM_FLAG_SECURE}, +{"Reset()", &DMSYNC, DMT_COMMAND, NULL, operate_PPPInterface_Reset, BBFDM_USP}, +{"MaxMRUSize", &DMWRITE, DMT_UNINT, get_PPPInterface_MaxMRUSize, set_PPPInterface_MaxMRUSize, BBFDM_BOTH}, +{"CurrentMRUSize", &DMREAD, DMT_UNINT, get_PPPInterface_CurrentMRUSize, NULL, BBFDM_BOTH}, +{"LCPEcho", &DMREAD, DMT_UNINT, get_PPPInterface_LCPEcho, NULL, BBFDM_BOTH}, +{"LCPEchoRetry", &DMREAD, DMT_UNINT, get_PPPInterface_LCPEchoRetry, NULL, BBFDM_BOTH}, +{"IPCPEnable", &DMWRITE, DMT_BOOL, get_PPPInterface_IPCPEnable, set_PPPInterface_IPCPEnable, BBFDM_BOTH}, +{"IPv6CPEnable", &DMWRITE, DMT_BOOL, get_PPPInterface_IPv6CPEnable, set_PPPInterface_IPv6CPEnable, BBFDM_BOTH}, +{0} +}; + +/* *** Device.PPP.Interface.{i}.PPPoE. *** */ +DMLEAF tPPPInterfacePPPoEParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"SessionID", &DMREAD, DMT_UNINT, get_PPPInterfacePPPoE_SessionID, NULL, BBFDM_BOTH}, +{"ACName", &DMWRITE, DMT_STRING, get_PPPInterfacePPPoE_ACName, set_PPPInterfacePPPoE_ACName, BBFDM_BOTH}, +{"ServiceName", &DMWRITE, DMT_STRING, get_PPPInterfacePPPoE_ServiceName, set_PPPInterfacePPPoE_ServiceName, BBFDM_BOTH}, +{0} +}; + +/* *** Device.PPP.Interface.{i}.IPCP. *** */ +DMLEAF tPPPInterfaceIPCPParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"LocalIPAddress", &DMREAD, DMT_STRING, get_PPPInterfaceIPCP_LocalIPAddress, NULL, BBFDM_BOTH}, +{"RemoteIPAddress", &DMREAD, DMT_STRING, get_PPPInterfaceIPCP_RemoteIPAddress, NULL, BBFDM_BOTH}, +{"DNSServers", &DMREAD, DMT_STRING, get_PPPInterfaceIPCP_DNSServers, NULL, BBFDM_BOTH}, +//{"PassthroughEnable", &DMWRITE, DMT_BOOL, get_PPPInterfaceIPCP_PassthroughEnable, set_PPPInterfaceIPCP_PassthroughEnable, BBFDM_BOTH}, +//{"PassthroughDHCPPool", &DMWRITE, DMT_STRING, get_PPPInterfaceIPCP_PassthroughDHCPPool, set_PPPInterfaceIPCP_PassthroughDHCPPool, BBFDM_BOTH}, +{0} +}; + +/* *** Device.PPP.Interface.{i}.IPv6CP. *** */ +DMLEAF tPPPInterfaceIPv6CPParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version, version*/ +{"LocalInterfaceIdentifier", &DMREAD, DMT_STRING, get_PPPInterfaceIPv6CP_LocalInterfaceIdentifier, NULL, BBFDM_BOTH}, +{"RemoteInterfaceIdentifier", &DMREAD, DMT_STRING, get_PPPInterfaceIPv6CP_RemoteInterfaceIdentifier, NULL, BBFDM_BOTH}, +{0} +}; + +/* *** Device.PPP.Interface.{i}.Stats. *** */ +DMLEAF tPPPInterfaceStatsParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"BytesReceived", &DMREAD, DMT_UNLONG, get_ppp_eth_bytes_received, NULL, BBFDM_BOTH}, +{"BytesSent", &DMREAD, DMT_UNLONG, get_ppp_eth_bytes_sent, NULL, BBFDM_BOTH}, +{"PacketsReceived", &DMREAD, DMT_UNLONG, get_ppp_eth_pack_received, NULL, BBFDM_BOTH}, +{"PacketsSent", &DMREAD, DMT_UNLONG, get_ppp_eth_pack_sent, NULL, BBFDM_BOTH}, +{"ErrorsSent", &DMREAD, DMT_UNINT, get_PPPInterfaceStats_ErrorsSent, NULL, BBFDM_BOTH}, +{"ErrorsReceived", &DMREAD, DMT_UNINT, get_PPPInterfaceStats_ErrorsReceived, NULL, BBFDM_BOTH}, +{"UnicastPacketsSent", &DMREAD, DMT_UNLONG, get_PPPInterfaceStats_UnicastPacketsSent, NULL, BBFDM_BOTH}, +{"UnicastPacketsReceived", &DMREAD, DMT_UNLONG, get_PPPInterfaceStats_UnicastPacketsReceived, NULL, BBFDM_BOTH}, +{"DiscardPacketsSent", &DMREAD, DMT_UNINT, get_PPPInterfaceStats_DiscardPacketsSent, NULL, BBFDM_BOTH}, +{"DiscardPacketsReceived", &DMREAD, DMT_UNINT, get_PPPInterfaceStats_DiscardPacketsReceived, NULL, BBFDM_BOTH}, +{"MulticastPacketsSent", &DMREAD, DMT_UNLONG, get_PPPInterfaceStats_MulticastPacketsSent, NULL, BBFDM_BOTH}, +{"MulticastPacketsReceived", &DMREAD, DMT_UNLONG, get_PPPInterfaceStats_MulticastPacketsReceived, NULL, BBFDM_BOTH}, +{"BroadcastPacketsSent", &DMREAD, DMT_UNLONG, get_PPPInterfaceStats_BroadcastPacketsSent, NULL, BBFDM_BOTH}, +{"BroadcastPacketsReceived", &DMREAD, DMT_UNLONG, get_PPPInterfaceStats_BroadcastPacketsReceived, NULL, BBFDM_BOTH}, +{"UnknownProtoPacketsReceived", &DMREAD, DMT_UNINT, get_PPPInterfaceStats_UnknownProtoPacketsReceived, NULL, BBFDM_BOTH}, +{0} +}; diff --git a/src/ppp.h b/src/ppp.h new file mode 100644 index 0000000000000000000000000000000000000000..3e0e0f1e85565d1c429cea49ece13e32fc724842 --- /dev/null +++ b/src/ppp.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2019-2024 iopsys Software Solutions AB + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> + * + */ + +#ifndef __PPP_H +#define __PPP_H + +#include "libbbfdm-api/dmcommon.h" + +extern DMOBJ tDevicePPPObj[]; +extern DMOBJ tPPPObj[]; +extern DMLEAF tPPPParams[]; +extern DMOBJ tPPPInterfaceObj[]; +extern DMLEAF tPPPInterfaceParams[]; +extern DMLEAF tPPPInterfacePPPoEParams[]; +extern DMLEAF tPPPInterfaceIPCPParams[]; +extern DMLEAF tPPPInterfaceIPv6CPParams[]; +extern DMLEAF tPPPInterfaceStatsParams[]; + +#endif diff --git a/src/routeradvertisement.c b/src/routeradvertisement.c new file mode 100644 index 0000000000000000000000000000000000000000..dc17da1d33777c2038a6d81f030cf4fbd88f566f --- /dev/null +++ b/src/routeradvertisement.c @@ -0,0 +1,756 @@ +/* + * Copyright (C) 2021-2024 iopsys Software Solutions AB + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> + * + */ + +#include "routeradvertisement.h" + +/************************************************************* +* COMMON FUNCTIONS +**************************************************************/ +/* Returns dnsmasq section name belonging to LAN network */ +char *get_dhcp_dnsmasq_section_name(void) +{ + struct uci_section *s = NULL; + + uci_foreach_sections("dhcp", "dnsmasq", s) { + char *sec = section_name(s); + if (DM_STRCMP(sec, "dns_client") != 0) + return sec; + } + + return ""; +} + +static int radv_get_option_value(struct uci_section *s, char *option_list, const char *option_value, char **value) +{ + struct uci_list *uci_list = NULL; + + dmuci_get_value_by_section_list(s, option_list, &uci_list); + *value = (value_exists_in_uci_list(uci_list, option_value)) ? "1" : "0"; + return 0; +} + +static int radv_set_option_value(struct uci_section *s, char *option_list, const char *option_value, bool b) +{ + struct uci_list *uci_list = NULL; + + dmuci_get_value_by_section_list(s, option_list, &uci_list); + if (b) { + if (!value_exists_in_uci_list(uci_list, option_value)) + dmuci_add_list_value_by_section(s, option_list, (char *)option_value); + } else { + if (value_exists_in_uci_list(uci_list, option_value)) + dmuci_del_list_value_by_section(s, option_list, (char *)option_value); + } + return 0; +} + +/************************************************************* +* ENTRY METHOD +**************************************************************/ +/*#Device.RouterAdvertisement.InterfaceSetting.{i}.!UCI:dhcp/dhcp/dmmap_radv*/ +static int browseRouterAdvertisementInterfaceSettingInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +{ + char *inst = NULL, *ignore = NULL; + struct dm_data *curr_data = NULL; + LIST_HEAD(dup_list); + + synchronize_specific_config_sections_with_dmmap("dhcp", "dhcp", "dmmap_radv", &dup_list); + list_for_each_entry(curr_data, &dup_list, list) { + + // skip the section if option ignore = '1' + dmuci_get_value_by_section_string(curr_data->config_section, "ignore", &ignore); + if (ignore && DM_LSTRCMP(ignore, "1") == 0) + continue; + + inst = handle_instance(dmctx, parent_node, curr_data->dmmap_section, "radv_intf_instance", "radv_intf_alias"); + + if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)curr_data, inst) == DM_STOP) + break; + } + free_dmmap_config_dup_list(&dup_list); + return 0; +} + +static int browseRouterAdvertisementInterfaceSettingOptionInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +{ + struct uci_section *dhcp_s = ((struct dm_data *)prev_data)->config_section; + struct uci_section *dhcp_dmmap_s = NULL; + struct dm_data curr_data = {0}; + struct uci_list *dns_list = NULL; + char *inst = NULL, *option_value = NULL; + + dmuci_get_value_by_section_list(dhcp_s, "dns", &dns_list); + + if (dns_list != NULL) { + struct uci_element *e = NULL; + + uci_foreach_element(dns_list, e) { + if ((dhcp_dmmap_s = get_dup_section_in_dmmap_eq("dmmap_radv", "radv_option", section_name(dhcp_s), "option_value", e->name)) == NULL) { + dmuci_add_section_bbfdm("dmmap_radv", "radv_option", &dhcp_dmmap_s); + dmuci_set_value_by_section_bbfdm(dhcp_dmmap_s, "option_value", e->name); + dmuci_set_value_by_section_bbfdm(dhcp_dmmap_s, "section_name", section_name(dhcp_s)); + } + } + } + + uci_path_foreach_option_eq(bbfdm, "dmmap_radv", "radv_option", "section_name", section_name(dhcp_s), dhcp_dmmap_s) { + dmuci_get_value_by_section_string(dhcp_dmmap_s, "option_value", &option_value); + + curr_data.config_section = dhcp_s; + curr_data.dmmap_section = dhcp_dmmap_s; + curr_data.additional_data = (void *)option_value; + + inst = handle_instance(dmctx, parent_node, dhcp_dmmap_s, "radv_option_instance", "radv_option_alias"); + + if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)&curr_data, inst) == DM_STOP) + break; + } + return 0; +} + +/************************************************************* +* ADD & DEL OBJ +**************************************************************/ +static int addObjRouterAdvertisementInterfaceSetting(char *refparam, struct dmctx *ctx, void *data, char **instance) +{ + struct uci_section *dmmap = NULL, *s = NULL; + char ra_sname[32] = {0}; + + snprintf(ra_sname, sizeof(ra_sname), "ra_%s", *instance); + + dmuci_add_section("dhcp", "dhcp", &s); + dmuci_rename_section_by_section(s, ra_sname); + dmuci_set_value_by_section(s, "ignore", "0"); + dmuci_set_value_by_section(s, "ra", "disabled"); + dmuci_set_value_by_section(s, "ra_flags", "none"); + + dmuci_add_section_bbfdm("dmmap_radv", "dhcp", &dmmap); + dmuci_set_value_by_section(dmmap, "section_name", ra_sname); + dmuci_set_value_by_section(dmmap, "radv_intf_instance", *instance); + return 0; +} + +static int delObjRouterAdvertisementInterfaceSetting(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action) +{ + struct uci_section *s = NULL, *stmp = NULL; + + switch (del_action) { + case DEL_INST: + dmuci_delete_by_section(((struct dm_data *)data)->config_section, NULL, NULL); + dmuci_delete_by_section(((struct dm_data *)data)->dmmap_section, NULL, NULL); + break; + case DEL_ALL: + uci_foreach_sections_safe("dhcp", "dhcp", stmp, s) { + struct uci_section *dmmap_section = NULL; + + get_dmmap_section_of_config_section("dmmap_radv", "dhcp", section_name(s), &dmmap_section); + dmuci_delete_by_section(dmmap_section, NULL, NULL); + + dmuci_delete_by_section(s, NULL, NULL); + } + break; + } + return 0; +} + +static int addObjRouterAdvertisementInterfaceSettingOption(char *refparam, struct dmctx *ctx, void *data, char **instance) +{ + struct uci_section *dmmap_sect = NULL; + + dmuci_add_section_bbfdm("dmmap_radv", "radv_option", &dmmap_sect); + dmuci_set_value_by_section_bbfdm(dmmap_sect, "section_name", section_name(((struct dm_data *)data)->config_section)); + dmuci_set_value_by_section_bbfdm(dmmap_sect, "option_tag", "23"); + dmuci_set_value_by_section_bbfdm(dmmap_sect, "radv_option_instance", *instance); + return 0; +} + +static int delObjRouterAdvertisementInterfaceSettingOption(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action) +{ + struct uci_section *s = NULL, *stmp = NULL; + struct uci_list *dns_list = NULL; + + switch (del_action) { + case DEL_INST: + dmuci_get_value_by_section_list(((struct dm_data *)data)->config_section, "dns", &dns_list); + if (value_exists_in_uci_list(dns_list, ((struct dm_data *)data)->additional_data)) + dmuci_del_list_value_by_section(((struct dm_data *)data)->config_section, "dns", ((struct dm_data *)data)->additional_data); + + dmuci_delete_by_section(((struct dm_data *)data)->dmmap_section, NULL, NULL); + break; + case DEL_ALL: + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "dns", ""); + uci_path_foreach_sections_safe(bbfdm, "dmmap_radv", "radv_option", stmp, s) { + dmuci_delete_by_section(s, NULL, NULL); + } + break; + } + return 0; +} + +/************************************************************* +* GET & SET PARAM +**************************************************************/ +/*#Device.RouterAdvertisement.Enable!UCI:dhcp/dnsmasq,@dnsmasq[0]/raserver*/ +static int get_RouterAdvertisement_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *sec = get_dhcp_dnsmasq_section_name(); + + if (DM_STRLEN(sec) == 0) + return 0; + + *value = dmuci_get_option_value_fallback_def("dhcp", sec, "raserver", "1"); + return 0; +} + +static int set_RouterAdvertisement_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + bool b; + char *sec; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + sec = get_dhcp_dnsmasq_section_name(); + if (DM_STRLEN(sec) == 0) + return 0; + + string_to_bool(value, &b); + dmuci_set_value("dhcp", sec, "raserver", b ? "1" : "0"); + break; + } + return 0; +} + +static int get_RouterAdvertisement_InterfaceSettingNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + int cnt = get_number_of_entries(ctx, data, instance, browseRouterAdvertisementInterfaceSettingInst); + dmasprintf(value, "%d", cnt); + return 0; +} + +/*#Device.RouterAdvertisement.InterfaceSetting.{i}.Enable!UCI:dhcp/dhcp,@i-1/ra*/ +static int get_RouterAdvertisementInterfaceSetting_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "ra", value); + *value = (*value && DM_LSTRCMP(*value, "disabled") == 0) ? "0" : "1"; + return 0; +} + +static int set_RouterAdvertisementInterfaceSetting_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + bool b; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ra", b ? "server" : "disabled"); + break; + } + return 0; +} + +/*#Device.RouterAdvertisement.InterfaceSetting.{i}.Status!UCI:dhcp/dhcp,@i-1/ra*/ +static int get_RouterAdvertisementInterfaceSetting_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "ra", value); + *value = (*value && DM_LSTRCMP(*value, "disabled") == 0) ? "Disabled" : "Enabled"; + return 0; +} + +static int get_RouterAdvertisementInterfaceSetting_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return bbf_get_alias(ctx, ((struct dm_data *)data)->dmmap_section, "radv_intf_alias", instance, value); +} + +static int set_RouterAdvertisementInterfaceSetting_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + return bbf_set_alias(ctx, ((struct dm_data *)data)->dmmap_section, "radv_intf_alias", instance, value); +} + +/*#Device.RouterAdvertisement.InterfaceSetting.{i}.Interface!UCI:dhcp/dhcp,@i-1/interface*/ +static int get_RouterAdvertisementInterfaceSetting_Interface(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *linker = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "interface", &linker); + _bbfdm_get_references(ctx, "Device.IP.Interface.", "Name", linker, value); + return 0; +} + +static int set_RouterAdvertisementInterfaceSetting_Interface(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char *allowed_objects[] = {"Device.IP.Interface.", NULL}; + struct dm_reference reference = {0}; + + bbfdm_get_reference_linker(ctx, value, &reference); + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, reference.path, -1, -1, NULL, NULL)) + return FAULT_9007; + + if (dm_validate_allowed_objects(ctx, &reference, allowed_objects)) + return FAULT_9007; + + break; + case VALUESET: + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "interface", reference.value); + break; + } + return 0; +} + +static int get_RouterAdvertisementInterfaceSetting_Prefixes(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + json_object *res = NULL, *ipv6_prefix_obj = NULL, *arrobj = NULL; + char *interface = NULL, *ip_inst = NULL, list_val[512]; + struct uci_section *dmmap_s = NULL; + int i = 0, pos = 0; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "interface", &interface); + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "ip_int_instance", &ip_inst); + + list_val[0] = 0; + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", interface, String}}, 1, &res); + dmjson_foreach_obj_in_array(res, arrobj, ipv6_prefix_obj, i, 1, "ipv6-prefix-assignment") { + char ipv6_prefix[64], *ipv6_prefix_inst = NULL; + + char *address = dmjson_get_value(ipv6_prefix_obj, 1, "address"); + char *mask = dmjson_get_value(ipv6_prefix_obj, 1, "mask"); + snprintf(ipv6_prefix, sizeof(ipv6_prefix), "%s/%s", address, mask); + + uci_path_foreach_option_eq(bbfdm, "dmmap_network_ipv6_prefix", "intf_ipv6_prefix", "section_name", interface, dmmap_s) { + dmuci_get_value_by_section_string(dmmap_s, "address", &address); + if (address && DM_STRCMP(address, ipv6_prefix) == 0) { + dmuci_get_value_by_section_string(dmmap_s, "ipv6_prefix_instance", &ipv6_prefix_inst); + break; + } + } + + if (ip_inst && *ip_inst && ipv6_prefix_inst && *ipv6_prefix_inst) + pos += snprintf(&list_val[pos], sizeof(list_val) - pos, "Device.IP.Interface.%s.IPv6Prefix.%s,", ip_inst, ipv6_prefix_inst); + } + + /* cut tailing ',' */ + if (pos) + list_val[pos - 1] = 0; + + *value = dmstrdup(list_val); + return 0; +} + +/*#Device.RouterAdvertisement.InterfaceSetting.{i}.MaxRtrAdvInterval!UCI:dhcp/dhcp,@i-1/ra_maxinterval*/ +static int get_RouterAdvertisementInterfaceSetting_MaxRtrAdvInterval(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "ra_maxinterval", "600"); + return 0; +} + +static int set_RouterAdvertisementInterfaceSetting_MaxRtrAdvInterval(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"4","1800"}}, 1)) + return FAULT_9007; + break; + case VALUESET: + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ra_maxinterval", value); + break; + } + return 0; +} + +/*#Device.RouterAdvertisement.InterfaceSetting.{i}.MinRtrAdvInterval!UCI:dhcp/dhcp,@i-1/ra_mininterval*/ +static int get_RouterAdvertisementInterfaceSetting_MinRtrAdvInterval(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "ra_mininterval", "200"); + return 0; +} + +static int set_RouterAdvertisementInterfaceSetting_MinRtrAdvInterval(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"3","1350"}}, 1)) + return FAULT_9007; + break; + case VALUESET: + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ra_mininterval", value); + break; + } + return 0; +} + +/*#Device.RouterAdvertisement.InterfaceSetting.{i}.AdvDefaultLifetime!UCI:dhcp/dhcp,@i-1/ra_lifetime*/ +static int get_RouterAdvertisementInterfaceSetting_AdvDefaultLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "ra_lifetime", "1800"); + return 0; +} + +static int set_RouterAdvertisementInterfaceSetting_AdvDefaultLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{NULL,"65535"}}, 1)) + return FAULT_9007; + break; + case VALUESET: + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ra_lifetime", value); + break; + } + return 0; +} + +/*#Device.RouterAdvertisement.InterfaceSetting.{i}.AdvManagedFlag!UCI:dhcp/dhcp,@i-1/ra_flags*/ +static int get_RouterAdvertisementInterfaceSetting_AdvManagedFlag(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return radv_get_option_value(((struct dm_data *)data)->config_section, "ra_flags", "managed-config", value); +} + +static int set_RouterAdvertisementInterfaceSetting_AdvManagedFlag(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + bool b; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + return radv_set_option_value(((struct dm_data *)data)->config_section, "ra_flags", "managed-config", b); + } + return 0; +} + +/*#Device.RouterAdvertisement.InterfaceSetting.{i}.AdvOtherConfigFlag!UCI:dhcp/dhcp,@i-1/ra_flags*/ +static int get_RouterAdvertisementInterfaceSetting_AdvOtherConfigFlag(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return radv_get_option_value(((struct dm_data *)data)->config_section, "ra_flags", "other-config", value); +} + +static int set_RouterAdvertisementInterfaceSetting_AdvOtherConfigFlag(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + bool b; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + return radv_set_option_value(((struct dm_data *)data)->config_section, "ra_flags", "other-config", b); + } + return 0; +} + +/*#Device.RouterAdvertisement.InterfaceSetting.{i}.AdvMobileAgentFlag!UCI:dhcp/dhcp,@i-1/ra_flags*/ +static int get_RouterAdvertisementInterfaceSetting_AdvMobileAgentFlag(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return radv_get_option_value(((struct dm_data *)data)->config_section, "ra_flags", "home-agent", value); +} + +static int set_RouterAdvertisementInterfaceSetting_AdvMobileAgentFlag(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + bool b; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + return radv_set_option_value(((struct dm_data *)data)->config_section, "ra_flags", "home-agent", b); + } + return 0; +} + +/*#Device.RouterAdvertisement.InterfaceSetting.{i}.AdvPreferredRouterFlag!UCI:dhcp/dhcp,@i-1/ra_preference*/ +static int get_RouterAdvertisementInterfaceSetting_AdvPreferredRouterFlag(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *preferenece = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "ra_preference", &preferenece); + *value = (preferenece && *preferenece == 'h') ? "High" : (preferenece && *preferenece == 'l') ? "Low" : "Medium"; + return 0; +} + +static int set_RouterAdvertisementInterfaceSetting_AdvPreferredRouterFlag(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char *Adv_Preferred_RouterFlag[] = {"High", "Medium", "Low", NULL}; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, -1, Adv_Preferred_RouterFlag, NULL)) + return FAULT_9007; + break; + case VALUESET: + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ra_preference", (*value == 'H') ? "high" : (*value == 'L') ? "low" : "medium"); + break; + } + return 0; +} + +/*#Device.RouterAdvertisement.InterfaceSetting.{i}.AdvLinkMTU!UCI:dhcp/dhcp,@i-1/ra_mtu*/ +static int get_RouterAdvertisementInterfaceSetting_AdvLinkMTU(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "ra_mtu", "0"); + return 0; +} + +static int set_RouterAdvertisementInterfaceSetting_AdvLinkMTU(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{NULL,NULL}}, 1)) + return FAULT_9007; + break; + case VALUESET: + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ra_mtu", value); + break; + } + return 0; +} + +/*#Device.RouterAdvertisement.InterfaceSetting.{i}.AdvReachableTime!UCI:dhcp/dhcp,@i-1/ra_reachabletime*/ +static int get_RouterAdvertisementInterfaceSetting_AdvReachableTime(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "ra_reachabletime", "0"); + return 0; +} + +static int set_RouterAdvertisementInterfaceSetting_AdvReachableTime(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{NULL,"3600000"}}, 1)) + return FAULT_9007; + break; + case VALUESET: + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ra_reachabletime", value); + break; + } + return 0; +} + +/*#Device.RouterAdvertisement.InterfaceSetting.{i}.AdvRetransTimer!UCI:dhcp/dhcp,@i-1/ra_retranstime*/ +static int get_RouterAdvertisementInterfaceSetting_AdvRetransTimer(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "ra_retranstime", "0"); + return 0; +} + +static int set_RouterAdvertisementInterfaceSetting_AdvRetransTimer(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{NULL,NULL}}, 1)) + return FAULT_9007; + break; + case VALUESET: + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ra_retranstime", value); + break; + } + return 0; +} + +/*#Device.RouterAdvertisement.InterfaceSetting.{i}.AdvCurHopLimit!UCI:dhcp/dhcp,@i-1/ra_hoplimit*/ +static int get_RouterAdvertisementInterfaceSetting_AdvCurHopLimit(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "ra_hoplimit", "0"); + return 0; +} + +static int set_RouterAdvertisementInterfaceSetting_AdvCurHopLimit(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{NULL,"255"}}, 1)) + return FAULT_9007; + break; + case VALUESET: + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ra_hoplimit", value); + break; + } + return 0; +} + +static int get_RouterAdvertisementInterfaceSetting_OptionNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + int cnt = get_number_of_entries(ctx, data, instance, browseRouterAdvertisementInterfaceSettingOptionInst); + dmasprintf(value, "%d", cnt); + return 0; +} + +static int get_RouterAdvertisementInterfaceSettingOption_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct dm_data *radv_option_s = (struct dm_data *)data; + return radv_get_option_value(radv_option_s->config_section, "dns", radv_option_s->additional_data, value); +} + +static int set_RouterAdvertisementInterfaceSettingOption_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct dm_data *radv_option_s = (struct dm_data *)data; + bool b; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + return radv_set_option_value(radv_option_s->config_section, "dns", radv_option_s->additional_data, b); + } + return 0; +} + +static int get_RouterAdvertisementInterfaceSettingOption_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return bbf_get_alias(ctx, ((struct dm_data *)data)->dmmap_section, "radv_option_alias", instance, value); +} + +static int set_RouterAdvertisementInterfaceSettingOption_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + return bbf_set_alias(ctx, ((struct dm_data *)data)->dmmap_section, "radv_option_alias", instance, value); +} + +static int get_RouterAdvertisementInterfaceSettingOption_Tag(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "23"; + return 0; +} + +static int set_RouterAdvertisementInterfaceSettingOption_Tag(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"0","65535"}}, 1)) + return FAULT_9007; + break; + case VALUESET: + break; + } + return 0; +} + +static int get_RouterAdvertisementInterfaceSettingOption_Value(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + const char *option_value = ((struct dm_data *)data)->additional_data; + char hex[65535] = {0}; + + if (option_value && *option_value) + convert_string_to_hex(option_value, hex, sizeof(hex)); + + *value = (*hex) ? dmstrdup(hex) : ""; + return 0; +} + +static int set_RouterAdvertisementInterfaceSettingOption_Value(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct dm_data *radv_option_s = (struct dm_data *)data; + struct uci_list *dns_list = NULL; + char res[256] = {0}; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_hexBinary(ctx, value, RANGE_ARGS{{"0","65535"}}, 1)) + return FAULT_9007; + break; + case VALUESET: + convert_hex_to_string(value, res, sizeof(res)); + + dmuci_get_value_by_section_list(radv_option_s->config_section, "dns", &dns_list); + if (value_exists_in_uci_list(dns_list, radv_option_s->additional_data)) { + dmuci_del_list_value_by_section(radv_option_s->config_section, "dns", radv_option_s->additional_data); + dmuci_add_list_value_by_section(radv_option_s->config_section, "dns", res); + } + + dmuci_set_value_by_section_bbfdm(radv_option_s->dmmap_section, "option_value", res); + break; + } + return 0; +} + +/********************************************************************************************************************************** +* OBJ & PARAM DEFINITION +***********************************************************************************************************************************/ +/* *** Device. *** */ +DMOBJ tDeviceRouterAdvertisementObj[] = { +/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/ +{"RouterAdvertisement", &DMREAD, NULL, NULL, "file:/etc/config/dhcp", NULL, NULL, NULL, tRouterAdvertisementObj, tRouterAdvertisementParams, NULL, BBFDM_BOTH, NULL}, +{0} +}; + +/* *** Device.RouterAdvertisement. *** */ +DMOBJ tRouterAdvertisementObj[] = { +/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys*/ +{"InterfaceSetting", &DMWRITE, addObjRouterAdvertisementInterfaceSetting, delObjRouterAdvertisementInterfaceSetting, NULL, browseRouterAdvertisementInterfaceSettingInst, NULL, NULL, tRouterAdvertisementInterfaceSettingObj, tRouterAdvertisementInterfaceSettingParams, NULL, BBFDM_BOTH, NULL}, +{0} +}; + +DMLEAF tRouterAdvertisementParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"Enable", &DMWRITE, DMT_BOOL, get_RouterAdvertisement_Enable, set_RouterAdvertisement_Enable, BBFDM_BOTH}, +{"InterfaceSettingNumberOfEntries", &DMREAD, DMT_UNINT, get_RouterAdvertisement_InterfaceSettingNumberOfEntries, NULL, BBFDM_BOTH}, +{0} +}; + +/* *** Device.RouterAdvertisement.InterfaceSetting.{i}. *** */ +DMOBJ tRouterAdvertisementInterfaceSettingObj[] = { +/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys*/ +{"Option", &DMWRITE, addObjRouterAdvertisementInterfaceSettingOption, delObjRouterAdvertisementInterfaceSettingOption, NULL, browseRouterAdvertisementInterfaceSettingOptionInst, NULL, NULL, NULL, tRouterAdvertisementInterfaceSettingOptionParams, NULL, BBFDM_BOTH, NULL}, +{0} +}; + +DMLEAF tRouterAdvertisementInterfaceSettingParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"Enable", &DMWRITE, DMT_BOOL, get_RouterAdvertisementInterfaceSetting_Enable, set_RouterAdvertisementInterfaceSetting_Enable, BBFDM_BOTH}, +{"Status", &DMREAD, DMT_STRING, get_RouterAdvertisementInterfaceSetting_Status, NULL, BBFDM_BOTH}, +{"Alias", &DMWRITE, DMT_STRING, get_RouterAdvertisementInterfaceSetting_Alias, set_RouterAdvertisementInterfaceSetting_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"Interface", &DMWRITE, DMT_STRING, get_RouterAdvertisementInterfaceSetting_Interface, set_RouterAdvertisementInterfaceSetting_Interface, BBFDM_BOTH, DM_FLAG_UNIQUE|DM_FLAG_REFERENCE}, +//{"ManualPrefixes", &DMWRITE, DMT_STRING, get_RouterAdvertisementInterfaceSetting_ManualPrefixes, set_RouterAdvertisementInterfaceSetting_ManualPrefixes, BBFDM_BOTH}, +{"Prefixes", &DMREAD, DMT_STRING, get_RouterAdvertisementInterfaceSetting_Prefixes, NULL, BBFDM_BOTH}, +{"MaxRtrAdvInterval", &DMWRITE, DMT_UNINT, get_RouterAdvertisementInterfaceSetting_MaxRtrAdvInterval, set_RouterAdvertisementInterfaceSetting_MaxRtrAdvInterval, BBFDM_BOTH}, +{"MinRtrAdvInterval", &DMWRITE, DMT_UNINT, get_RouterAdvertisementInterfaceSetting_MinRtrAdvInterval, set_RouterAdvertisementInterfaceSetting_MinRtrAdvInterval, BBFDM_BOTH}, +{"AdvDefaultLifetime", &DMWRITE, DMT_UNINT, get_RouterAdvertisementInterfaceSetting_AdvDefaultLifetime, set_RouterAdvertisementInterfaceSetting_AdvDefaultLifetime, BBFDM_BOTH}, +{"AdvManagedFlag", &DMWRITE, DMT_BOOL, get_RouterAdvertisementInterfaceSetting_AdvManagedFlag, set_RouterAdvertisementInterfaceSetting_AdvManagedFlag, BBFDM_BOTH}, +{"AdvOtherConfigFlag", &DMWRITE, DMT_BOOL, get_RouterAdvertisementInterfaceSetting_AdvOtherConfigFlag, set_RouterAdvertisementInterfaceSetting_AdvOtherConfigFlag, BBFDM_BOTH}, +{"AdvMobileAgentFlag", &DMWRITE, DMT_BOOL, get_RouterAdvertisementInterfaceSetting_AdvMobileAgentFlag, set_RouterAdvertisementInterfaceSetting_AdvMobileAgentFlag, BBFDM_BOTH}, +{"AdvPreferredRouterFlag", &DMWRITE, DMT_STRING, get_RouterAdvertisementInterfaceSetting_AdvPreferredRouterFlag, set_RouterAdvertisementInterfaceSetting_AdvPreferredRouterFlag, BBFDM_BOTH}, +//{"AdvNDProxyFlag", &DMWRITE, DMT_BOOL, get_RouterAdvertisementInterfaceSetting_AdvNDProxyFlag, set_RouterAdvertisementInterfaceSetting_AdvNDProxyFlag, BBFDM_BOTH}, +{"AdvLinkMTU", &DMWRITE, DMT_UNINT, get_RouterAdvertisementInterfaceSetting_AdvLinkMTU, set_RouterAdvertisementInterfaceSetting_AdvLinkMTU, BBFDM_BOTH}, +{"AdvReachableTime", &DMWRITE, DMT_UNINT, get_RouterAdvertisementInterfaceSetting_AdvReachableTime, set_RouterAdvertisementInterfaceSetting_AdvReachableTime, BBFDM_BOTH}, +{"AdvRetransTimer", &DMWRITE, DMT_UNINT, get_RouterAdvertisementInterfaceSetting_AdvRetransTimer, set_RouterAdvertisementInterfaceSetting_AdvRetransTimer, BBFDM_BOTH}, +{"AdvCurHopLimit", &DMWRITE, DMT_UNINT, get_RouterAdvertisementInterfaceSetting_AdvCurHopLimit, set_RouterAdvertisementInterfaceSetting_AdvCurHopLimit, BBFDM_BOTH}, +{"OptionNumberOfEntries", &DMREAD, DMT_UNINT, get_RouterAdvertisementInterfaceSetting_OptionNumberOfEntries, NULL, BBFDM_BOTH}, +{0} +}; + +/* *** Device.RouterAdvertisement.InterfaceSetting.{i}.Option.{i}. *** */ +DMLEAF tRouterAdvertisementInterfaceSettingOptionParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"Enable", &DMWRITE, DMT_BOOL, get_RouterAdvertisementInterfaceSettingOption_Enable, set_RouterAdvertisementInterfaceSettingOption_Enable, BBFDM_BOTH}, +{"Alias", &DMWRITE, DMT_STRING, get_RouterAdvertisementInterfaceSettingOption_Alias, set_RouterAdvertisementInterfaceSettingOption_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"Tag", &DMWRITE, DMT_UNINT, get_RouterAdvertisementInterfaceSettingOption_Tag, set_RouterAdvertisementInterfaceSettingOption_Tag, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"Value", &DMWRITE, DMT_HEXBIN, get_RouterAdvertisementInterfaceSettingOption_Value, set_RouterAdvertisementInterfaceSettingOption_Value, BBFDM_BOTH}, +{0} +}; diff --git a/src/routeradvertisement.h b/src/routeradvertisement.h new file mode 100644 index 0000000000000000000000000000000000000000..ebf9c48068bf37cc755d8cc1c4b5efc3c668efb9 --- /dev/null +++ b/src/routeradvertisement.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2021-2024 iopsys Software Solutions AB + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> + * + */ + +#ifndef __ROUTERADVERTISEMENT_H +#define __ROUTERADVERTISEMENT_H + +#include "libbbfdm-api/dmcommon.h" + +extern DMOBJ tDeviceRouterAdvertisementObj[]; +extern DMOBJ tRouterAdvertisementObj[]; +extern DMLEAF tRouterAdvertisementParams[]; +extern DMOBJ tRouterAdvertisementInterfaceSettingObj[]; +extern DMLEAF tRouterAdvertisementInterfaceSettingParams[]; +extern DMLEAF tRouterAdvertisementInterfaceSettingOptionParams[]; + +#endif //__ROUTERADVERTISEMENT_H + diff --git a/src/routing.c b/src/routing.c new file mode 100644 index 0000000000000000000000000000000000000000..548664c953916e21b4007584b115e1f7369f733a --- /dev/null +++ b/src/routing.c @@ -0,0 +1,1372 @@ +/* + * Copyright (C) 2019-2024 iopsys Software Solutions AB + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> + * + */ + +#include "common.h" +#include "routing.h" + +#define MAX_ROUTE_LEN 512 + +struct route_args { + char *iface; + char *metric; + char destination[16]; + char gateway[16]; + char mask[16]; +}; + +struct route6_args { + char *iface; + char *metric; + char destination[INET6_ADDRSTRLEN + 8]; + char gateway[INET6_ADDRSTRLEN + 8]; +}; + +/************************************************************************************* +**** function related to get_object_router_ipv4forwarding **** +**************************************************************************************/ +static bool is_route_in_config(struct route_args *route) +{ + struct uci_section *s = NULL; + + uci_foreach_option_eq("network", "route", "target", route->destination, s) { + char *mask = NULL; + + dmuci_get_value_by_section_string(s, "netmask", &mask); + if (DM_STRLEN(mask) == 0) + return true; + + if (DM_STRCMP(route->mask, mask) == 0) + return true; + } + + uci_path_foreach_sections(bbfdm, "dmmap_routing", "route_dynamic", s) { + char *target = NULL, *gateway = NULL, *device = NULL; + + dmuci_get_value_by_section_string(s, "target", &target); + dmuci_get_value_by_section_string(s, "gateway", &gateway); + dmuci_get_value_by_section_string(s, "device", &device); + if (DM_STRCMP(target, route->destination) == 0 && DM_STRCMP(gateway, route->gateway) == 0 && DM_STRCMP(device, route->iface) == 0) + return true; + } + + return false; +} + +static bool is_route6_in_config(struct route6_args *route6) +{ + struct uci_section *s = NULL; + + uci_foreach_sections("network", "route6", s) { + char *ip_r = NULL, *gw_r = NULL, *intf_r = NULL; + + dmuci_get_value_by_section_string(s, "target", &ip_r); + dmuci_get_value_by_section_string(s, "gateway", &gw_r); + dmuci_get_value_by_section_string(s, "interface", &intf_r); + char *dev_r = get_l3_device(intf_r); + if (DM_STRCMP(route6->iface, dev_r) == 0 && DM_STRCMP(route6->gateway, gw_r) == 0 && DM_STRCMP(route6->destination, ip_r) == 0) + return true; + } + + uci_path_foreach_sections(bbfdm, "dmmap_routing", "route6_dynamic", s) { + char *ip_r6d = NULL, *gw_r6d = NULL, *dev_r6d = NULL; + + dmuci_get_value_by_section_string(s, "target", &ip_r6d); + dmuci_get_value_by_section_string(s, "gateway", &gw_r6d); + dmuci_get_value_by_section_string(s, "device", &dev_r6d); + if (DM_STRCMP(route6->iface, dev_r6d) == 0 && DM_STRCMP(route6->gateway, gw_r6d) == 0 && DM_STRCMP(route6->destination, ip_r6d) == 0) + return true; + } + + return false; +} + +static void parse_route_line(char *line, struct route_args *route) +{ + size_t length = 0; + + char **arr = strsplit(line, " ", &length); + if (arr == NULL || length == 0) + return; + + for (int i = 0; i < length; i++) { + if (strcmp(arr[i], "default") == 0) { + DM_STRNCPY(route->gateway, arr[i + 2], sizeof(route->gateway)); + DM_STRNCPY(route->destination, "0.0.0.0", sizeof(route->destination)); + DM_STRNCPY(route->mask, "0.0.0.0", sizeof(route->mask)); + i += 2; + } + + if (i == 0 && strcmp(arr[i], "default") != 0) { + char *p = strchr(arr[i], '/'); + if (p) *p = 0; + + DM_STRNCPY(route->destination, arr[i], sizeof(route->destination)); + DM_STRNCPY(route->mask, (p && DM_STRLEN(p + 1)) ? cidr2netmask(DM_STRTOL(p + 1)) : "0.0.0.0", sizeof(route->mask)); + DM_STRNCPY(route->gateway, "0.0.0.0", sizeof(route->gateway)); + } + + if (strcmp(arr[i], "dev") == 0) { + route->iface = arr[i + 1]; + i += 1; + } + + if (strcmp(arr[i], "metric") == 0) { + route->metric = arr[i + 1]; + i += 1; + } + } + + if (route->metric == NULL) + route->metric = "0"; + + if (route->iface == NULL) + route->iface = ""; +} + +static int parse_route6_line(const char *line, struct route6_args *route6) +{ + size_t length = 0; + + char **arr = strsplit(line, " ", &length); + if (arr == NULL || length == 0) + return -1; + + for (int i = 0; i < length; i++) { + + if (strcmp(arr[i], "dev") == 0 && strcmp(arr[i + 1], "lo") == 0) + return -1; + + if (strcmp(arr[i], "default") == 0) { + DM_STRNCPY(route6->gateway, arr[i + 2], sizeof(route6->gateway)); + DM_STRNCPY(route6->destination, "::", sizeof(route6->destination)); + i += 2; + } + + if (i == 0 && strcmp(arr[i], "default") != 0) { + DM_STRNCPY(route6->destination, arr[i], sizeof(route6->destination)); + DM_STRNCPY(route6->gateway, "::", sizeof(route6->gateway)); + } + + if (strcmp(arr[i], "dev") == 0) { + route6->iface = arr[i + 1]; + i += 1; + } + + if (strcmp(arr[i], "metric") == 0) { + route6->metric = arr[i + 1]; + i += 1; + } + } + + if (route6->metric == NULL) + route6->metric = "0"; + + if (route6->iface == NULL) + route6->iface = ""; + + return 0; +} + +static void dmmap_synchronizeRoutingRouterIPv4Forwarding(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +{ + struct uci_section *s = NULL, *stmp = NULL; + struct route_args route = {0}; + FILE *pp = NULL; + char *rt_table = NULL; + char line[MAX_ROUTE_LEN] = {0}; + char cmd[32] = {0}; + + dmuci_get_value_by_section_string(((struct dm_data *)prev_data)->dmmap_section, "rt_table", &rt_table); + snprintf(cmd, sizeof(cmd), "ip route show table %s", rt_table); + + uci_path_foreach_option_eq_safe(bbfdm, "dmmap_routing", "route_dynamic", "table", rt_table, stmp, s) { + char *target = NULL, *iface = NULL; + + dmuci_get_value_by_section_string(s, "target", &target); + dmuci_get_value_by_section_string(s, "device", &iface); + + pp = popen(cmd, "r"); + if (pp != NULL) { + bool found = false; + + while (fgets(line, MAX_ROUTE_LEN, pp) != NULL) { + remove_new_line(line); + parse_route_line(line, &route); + if ((DM_STRCMP(iface, route.iface) == 0) && DM_STRCMP(target, route.destination) == 0) { + found = true; + break; + } + } + + if (!found) + dmuci_delete_by_section(s, NULL, NULL); + + pclose(pp); + } + } + + pp = popen(cmd, "r"); + if (pp != NULL) { + while (fgets(line, MAX_ROUTE_LEN, pp) != NULL) { + remove_new_line(line); + + parse_route_line(line, &route); + if (is_route_in_config(&route)) + continue; + + char *iface = NULL; + uci_foreach_sections("network", "interface", s) { + char *str = get_l3_device(section_name(s)); + if (DM_STRCMP(str, route.iface) == 0) { + iface = section_name(s); + break; + } + } + + dmuci_add_section_bbfdm("dmmap_routing", "route_dynamic", &s); + dmuci_set_value_by_section_bbfdm(s, "target", route.destination); + dmuci_set_value_by_section_bbfdm(s, "netmask", route.mask); + dmuci_set_value_by_section_bbfdm(s, "metric", route.metric); + dmuci_set_value_by_section_bbfdm(s, "gateway", route.gateway); + dmuci_set_value_by_section_bbfdm(s, "device", route.iface); + dmuci_set_value_by_section_bbfdm(s, "interface", iface ? iface : ""); + dmuci_set_value_by_section_bbfdm(s, "table", rt_table); + } + pclose(pp); + } +} + +static void dmmap_synchronizeRoutingRouterIPv6Forwarding(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +{ + struct uci_section *s = NULL, *stmp = NULL; + struct route6_args route6 = {0}; + FILE *pp = NULL; + char *rt_table = NULL; + char line[MAX_ROUTE_LEN] = {0}; + char cmd[32] = {0}; + + dmuci_get_value_by_section_string(((struct dm_data *)prev_data)->dmmap_section, "rt_table", &rt_table); + snprintf(cmd, sizeof(cmd), "ip -6 route show table %s", rt_table); + + uci_path_foreach_option_eq_safe(bbfdm, "dmmap_routing", "route6_dynamic", "table", rt_table, stmp, s) { + char *iface = NULL, *target = NULL; + + dmuci_get_value_by_section_string(s, "target", &target); + dmuci_get_value_by_section_string(s, "device", &iface); + + pp = popen(cmd, "r"); + if (pp != NULL) { + bool found = false; + + while (fgets(line, MAX_ROUTE_LEN, pp) != NULL) { + remove_new_line(line); + + if (parse_route6_line(line, &route6)) + continue; + + if (DM_STRCMP(iface, route6.iface) == 0 && DM_STRCMP(route6.destination, target) == 0) { + found = 1; + break; + } + } + + if (!found) + dmuci_delete_by_section(s, NULL, NULL); + + pclose(pp); + } + } + + pp = popen(cmd, "r"); + if (pp != NULL) { + while (fgets(line, MAX_ROUTE_LEN, pp) != NULL) { + remove_new_line(line); + + if (parse_route6_line(line, &route6)) + continue; + + if (is_route6_in_config(&route6)) + continue; + + char *iface = NULL; + uci_foreach_sections("network", "interface", s) { + char *str = get_l3_device(section_name(s)); + if (DM_STRCMP(str, route6.iface) == 0) { + iface = section_name(s); + break; + } + } + + dmuci_add_section_bbfdm("dmmap_routing", "route6_dynamic", &s); + dmuci_set_value_by_section_bbfdm(s, "target", route6.destination); + dmuci_set_value_by_section_bbfdm(s, "gateway", route6.gateway); + dmuci_set_value_by_section_bbfdm(s, "interface", iface ? iface : ""); + dmuci_set_value_by_section_bbfdm(s, "device", route6.iface); + dmuci_set_value_by_section_bbfdm(s, "metric", route6.metric); + dmuci_set_value_by_section_bbfdm(s, "table", rt_table); + } + pclose(pp); + } +} + +static void create_routing_route_section(char *rt_table) +{ + if (!is_dmmap_section_exist_eq("dmmap_routing", "router", "rt_table", rt_table)) { + struct uci_section *s = NULL; + + dmuci_add_section_bbfdm("dmmap_routing", "router", &s); + dmuci_set_value_by_section(s, "rt_table", rt_table); + } +} + +static struct uci_section *route_sec(void *data) +{ + return ((struct dm_data *)data)->config_section ? ((struct dm_data *)data)->config_section : ((struct dm_data *)data)->dmmap_section; +} + +/************************************************************* +* ENTRY METHOD +**************************************************************/ +static int browseRouterInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +{ + struct uci_section *s = NULL; + char *inst = NULL, *idx = NULL, *device = NULL, *proto = NULL; + struct uci_section *dmmap_route = NULL; + struct dm_data curr_data = {0}; + + create_routing_route_section("254"); + uci_foreach_sections("network", "interface", s) { + + dmuci_get_value_by_section_string(s, "proto", &proto); + dmuci_get_value_by_section_string(s, "device", &device); + dmuci_get_value_by_section_string(s, "ip4table", &idx); + + if (strcmp(section_name(s), "loopback") == 0 || + DM_STRLEN(proto) == 0 || + ip___is_gre_protocols(proto) || + DM_STRCHR(device, '@') || + ip___is_ip_interface_instance_exists(section_name(s), device)) + continue; + + if (DM_STRLEN(idx)) + create_routing_route_section(idx); + } + + uci_path_foreach_sections(bbfdm, "dmmap_routing", "router", dmmap_route) { + + curr_data.dmmap_section = dmmap_route; + + inst = handle_instance(dmctx, parent_node, dmmap_route, "router_instance", "router_alias"); + + if (DM_LINK_INST_OBJ(dmctx, parent_node, &curr_data, inst) == DM_STOP) + break; + } + return 0; +} + +/*#Device.Routing.Router.{i}.IPv4Forwarding.{i}.!UCI:network/route/dmmap_routing*/ +static int browseIPv4ForwardingInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +{ + struct dm_data *curr_data = NULL; + struct uci_section *s = NULL; + char *rt_table = NULL, *inst = NULL; + LIST_HEAD(dup_list); + + dmuci_get_value_by_section_string(((struct dm_data *)prev_data)->dmmap_section, "rt_table", &rt_table); + + // Enable Routes + synchronize_specific_config_sections_with_dmmap("network", "route", "dmmap_routing", &dup_list); + list_for_each_entry(curr_data, &dup_list, list) { + char *table = NULL; + + dmuci_get_value_by_section_string(curr_data->config_section, "table", &table); + if (DM_STRCMP(rt_table, table) != 0 || (DM_STRLEN(table) == 0 && DM_STRCMP(rt_table, "254") != 0)) + continue; + + inst = handle_instance(dmctx, parent_node, curr_data->dmmap_section, "route_instance", "route_alias"); + + if (DM_LINK_INST_OBJ(dmctx, parent_node, curr_data, inst) == DM_STOP) + goto end; + } + free_dmmap_config_dup_list(&dup_list); + + // Dynamic Routes + dmmap_synchronizeRoutingRouterIPv4Forwarding(dmctx, parent_node, prev_data, prev_instance); + uci_path_foreach_option_eq(bbfdm, "dmmap_routing", "route_dynamic", "table", rt_table, s) { + + curr_data = dmcalloc(1, sizeof(struct dm_data)); + + curr_data->config_section = NULL; + curr_data->dmmap_section = s; + + inst = handle_instance(dmctx, parent_node, curr_data->dmmap_section, "route_instance", "route_alias"); + + if (DM_LINK_INST_OBJ(dmctx, parent_node, curr_data, inst) == DM_STOP) + goto end; + } + +end: + return 0; +} + +/*#Device.Routing.Router.{i}.IPv6Forwarding.{i}.!UCI:network/route6/dmmap_routing*/ +static int browseIPv6ForwardingInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +{ + struct dm_data *curr_data = NULL; + struct uci_section *s = NULL; + char *rt_table = NULL, *inst = NULL; + LIST_HEAD(dup_list); + + dmuci_get_value_by_section_string(((struct dm_data *)prev_data)->dmmap_section, "rt_table", &rt_table); + + // Enable Routes + synchronize_specific_config_sections_with_dmmap("network", "route6", "dmmap_routing", &dup_list); + list_for_each_entry(curr_data, &dup_list, list) { + char *table = NULL; + + dmuci_get_value_by_section_string(curr_data->config_section, "table", &table); + if (DM_STRCMP(rt_table, table) != 0 || (DM_STRLEN(table) == 0 && DM_STRCMP(rt_table, "254") != 0)) + continue; + + inst = handle_instance(dmctx, parent_node, curr_data->dmmap_section, "route6_instance", "route6_alias"); + + if (DM_LINK_INST_OBJ(dmctx, parent_node, curr_data, inst) == DM_STOP) + goto end; + } + free_dmmap_config_dup_list(&dup_list); + + // Dynamic Routes + dmmap_synchronizeRoutingRouterIPv6Forwarding(dmctx, parent_node, prev_data, prev_instance); + uci_path_foreach_option_eq(bbfdm, "dmmap_routing", "route6_dynamic", "table", rt_table, s) { + + curr_data = dmcalloc(1, sizeof(struct dm_data)); + + curr_data->config_section = NULL; + curr_data->dmmap_section = s; + + inst = handle_instance(dmctx, parent_node, s, "route6_instance", "route6_alias"); + + if (DM_LINK_INST_OBJ(dmctx, parent_node, curr_data, inst) == DM_STOP) + goto end; + } + +end: + return 0; +} + +static int browseRoutingRouteInformationInterfaceSettingInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +{ + struct dm_data curr_data = {0}; + struct uci_section *s = NULL; + char *inst = NULL; + int id = 0, i; + + uci_foreach_sections("network", "interface", s) { + char *proto = NULL, *ip6addr = NULL; + + dmuci_get_value_by_section_string(s, "proto", &proto); + dmuci_get_value_by_section_string(s, "ip6addr", &ip6addr); + if ((proto && DM_LSTRCMP(proto, "dhcpv6") == 0) || (ip6addr && ip6addr[0] != '\0')) { + json_object *res = NULL, *route_obj = NULL, *arrobj = NULL; + + char *if_name = section_name(s); + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", if_name, String}}, 1, &res); + dmjson_foreach_obj_in_array(res, arrobj, route_obj, i, 1, "route") { + + curr_data.json_object = route_obj; + + inst = handle_instance_without_section(dmctx, parent_node, ++id); + + if (DM_LINK_INST_OBJ(dmctx, parent_node, &curr_data, inst) == DM_STOP) + break; + } + } + } + return 0; +} + +/************************************************************* +* GET & SET PARAM +**************************************************************/ +static int get_router_nbr_entry(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "1"; + return 0; +} + +static int get_RoutingRouter_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "1"; + return 0; +} + +static int set_RoutingRouter_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + break; + } + return 0; +} + +static int get_RoutingRouter_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "Enabled"; + return 0; +} + +/*#Device.Routing.Router.{i}.IPv4ForwardingNumberOfEntries!UCI:network/route/*/ +static int get_RoutingRouter_IPv4ForwardingNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + int cnt = get_number_of_entries(ctx, data, instance, browseIPv4ForwardingInst); + dmasprintf(value, "%d", cnt); + return 0; +} + +/*#Device.Routing.Router.{i}.IPv6ForwardingNumberOfEntries!UCI:network/route6/*/ +static int get_RoutingRouter_IPv6ForwardingNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + int cnt = get_number_of_entries(ctx, data, instance, browseIPv6ForwardingInst); + dmasprintf(value, "%d", cnt); + return 0; +} + +static int get_router_ipv4forwarding_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + if (((struct dm_data *)data)->config_section == NULL) { // Dynamic route + *value = "1"; + } else { //Static route + char *disabled = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "disabled", &disabled); + *value = (disabled && *disabled == '1') ? "0" : "1"; + } + return 0; +} + +static int set_router_ipv4forwarding_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + bool b; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + return 0; + case VALUESET: + if (((struct dm_data *)data)->config_section == NULL) // Dynamic route + return 0; + + string_to_bool(value, &b); + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "disabled", b ? "0" : "1"); + return 0; + } + return 0; +} + +static int get_router_ipv4forwarding_status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + get_router_ipv4forwarding_enable(refparam, ctx, data, instance, value); + *value = ((*value)[0] == '1') ? "Enabled" : "Disabled"; + return 0; +} + +/*#Device.Routing.Router.{i}.IPv4Forwarding.{i}.DestIPAddress!UCI:network/route,@i-1/target*/ +static int get_router_ipv4forwarding_destip(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string(route_sec(data), "target", value); + return 0; +} + +static int set_router_ipv4forwarding_destip(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, 15, NULL, IPv4Address)) + return FAULT_9007; + return 0; + case VALUESET: + if (((struct dm_data *)data)->config_section == NULL) // Dynamic route + return 0; + + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "target", value); + return 0; + } + return 0; +} + +/*#Device.Routing.Router.{i}.IPv4Forwarding.{i}.DestSubnetMask!UCI:network/route,@i-1/netmask*/ +static int get_router_ipv4forwarding_destmask(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string(route_sec(data), "netmask", value); + return 0; +} + +static int set_router_ipv4forwarding_destmask(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, 15, NULL, IPv4Address)) + return FAULT_9007; + return 0; + case VALUESET: + if (((struct dm_data *)data)->config_section == NULL) // Dynamic route + return 0; + + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "netmask", value); + return 0; + } + return 0; +} + +static int get_router_ipv4forwarding_static_route(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = (((struct dm_data *)data)->config_section) ? "1" : "0"; + return 0; +} + +static int get_router_ipv4forwarding_forwarding_policy(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmuci_get_value_by_section_fallback_def(route_sec(data), "table", "-1"); + return 0; +} + +static int set_router_ipv4forwarding_forwarding_policy(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct uci_section *s = NULL; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_int(ctx, value, RANGE_ARGS{{"-1",NULL}}, 1)) + return FAULT_9007; + + uci_path_foreach_sections(bbfdm, "dmmap_routing", "router", s) { + char *rt_table = NULL; + + dmuci_get_value_by_section_string(s, "rt_table", &rt_table); + if (DM_STRCMP(value, rt_table) == 0) + return 0; + } + + bbfdm_set_fault_message(ctx, "Route table '%s' value doesn't exist on the device. It's only allowed to set an available route table."); + return FAULT_9007; + case VALUESET: + if (((struct dm_data *)data)->config_section == NULL) // Dynamic route + return 0; + + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "table", value); + dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "route_instance", ""); + break; + } + return 0; +} + +static int get_router_ipv4forwarding_origin(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + if (((struct dm_data *)data)->config_section) + *value = "Static"; + else { + json_object *res = NULL; + char *interface; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "interface", &interface); + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", interface, String}}, 1, &res); + DM_ASSERT(res, *value = "DHCPv4"); + char *proto = dmjson_get_value(res, 1, "proto"); + *value = (proto && DM_LSTRNCMP(proto, "ppp", 3) == 0) ? "IPCP" : "DHCPv4"; + } + return 0; +} + +/*#Device.Routing.Router.{i}.IPv4Forwarding.{i}.GatewayIPAddress!UCI:network/route,@i-1/gateway*/ +static int get_router_ipv4forwarding_gatewayip(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string(route_sec(data), "gateway", value); + return 0; +} + +static int set_router_ipv4forwarding_gatewayip(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, 15, NULL, IPv4Address)) + return FAULT_9007; + return 0; + case VALUESET: + if (((struct dm_data *)data)->config_section == NULL) // Dynamic route + return 0; + + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "gateway", value); + return 0; + } + return 0; +} + +static int get_RoutingRouterForwarding_Interface(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *linker = NULL; + + dmuci_get_value_by_section_string(route_sec(data), "interface", &linker); + _bbfdm_get_references(ctx, "Device.IP.Interface.", "Name", linker, value); + return 0; +} + +static int set_RoutingRouterForwarding_Interface(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char *allowed_objects[] = {"Device.IP.Interface.", NULL}; + struct dm_reference reference = {0}; + + bbfdm_get_reference_linker(ctx, value, &reference); + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, reference.path, -1, 256, NULL, NULL)) + return FAULT_9007; + + if (dm_validate_allowed_objects(ctx, &reference, allowed_objects)) + return FAULT_9007; + + return 0; + case VALUESET: + if (((struct dm_data *)data)->config_section == NULL) // Dynamic route + return 0; + + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "interface", reference.value); + return 0; + } + return 0; +} + +/*#Device.Routing.Router.{i}.IPv4Forwarding.{i}.ForwardingMetric!UCI:network/route,@i-1/metric*/ +static int get_router_ipv4forwarding_metric(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmuci_get_value_by_section_fallback_def(route_sec(data), "metric", "0"); + return 0; +} + +static int set_router_ipv4forwarding_metric(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_int(ctx, value, RANGE_ARGS{{"-1",NULL}}, 1)) + return FAULT_9007; + return 0; + case VALUESET: + if (((struct dm_data *)data)->config_section == NULL) // Dynamic route + return 0; + + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "metric", value); + return 0; + } + return 0; +} + +static int get_RoutingRouterIPv6Forwarding_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + if (((struct dm_data *)data)->config_section == NULL) { // Dynamic route + *value = "1"; + } else { + char *disabled = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "disabled", &disabled); + *value = (disabled && *disabled == '1') ? "0" : "1"; + } + return 0; +} + +static int set_RoutingRouterIPv6Forwarding_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + bool b; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + if (((struct dm_data *)data)->config_section == NULL) // Dynamic route + return 0; + + string_to_bool(value, &b); + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "disabled", b ? "0" : "1"); + break; + } + return 0; +} + +static int get_RoutingRouterIPv6Forwarding_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + get_RoutingRouterIPv6Forwarding_Enable(refparam, ctx, data, instance, value); + *value = ((*value)[0] == '1') ? "Enabled" : "Disabled"; + return 0; +} + +/*#Device.Routing.Router.{i}.IPv6Forwarding.{i}.DestIPPrefix!UCI:network/route,@i-1/target*/ +static int get_RoutingRouterIPv6Forwarding_DestIPPrefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string(route_sec(data), "target", value); + return 0; +} + +static int set_RoutingRouterIPv6Forwarding_DestIPPrefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, 49, NULL, IPv6Prefix)) + return FAULT_9007; + return 0; + case VALUESET: + if (((struct dm_data *)data)->config_section == NULL) // Dynamic route + return 0; + + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "target", value); + return 0; + } + return 0; +} + +static int get_RoutingRouterIPv6Forwarding_ForwardingPolicy(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmuci_get_value_by_section_fallback_def(route_sec(data), "table", "-1"); + return 0; +} + +static int set_RoutingRouterIPv6Forwarding_ForwardingPolicy(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct uci_section *s = NULL; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_int(ctx, value, RANGE_ARGS{{"-1",NULL}}, 1)) + return FAULT_9007; + + uci_path_foreach_sections(bbfdm, "dmmap_routing", "router", s) { + char *rt_table = NULL; + + dmuci_get_value_by_section_string(s, "rt_table", &rt_table); + if (DM_STRCMP(value, rt_table) == 0) + return 0; + } + + bbfdm_set_fault_message(ctx, "Route table '%s' value doesn't exist on the device. It's only allowed to set an available route table."); + return FAULT_9007; + case VALUESET: + if (((struct dm_data *)data)->config_section == NULL) // Dynamic route + return 0; + + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "table", value); + dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "route_instance", ""); + break; + } + return 0; +} + +/*#Device.Routing.Router.{i}.IPv6Forwarding.{i}.NextHop!UCI:network/route,@i-1/gateway*/ +static int get_RoutingRouterIPv6Forwarding_NextHop(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string(route_sec(data), "gateway", value); + return 0; +} + +static int set_RoutingRouterIPv6Forwarding_NextHop(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, 45, NULL, IPv6Address)) + return FAULT_9007; + return 0; + case VALUESET: + if (((struct dm_data *)data)->config_section == NULL) // Dynamic route + return 0; + + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "gateway", value); + return 0; + } + return 0; +} + +static int get_RoutingRouterIPv6Forwarding_Origin(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = (((struct dm_data *)data)->config_section) ? "Static" : "DHCPv6"; + return 0; +} + + +/*#Device.Routing.Router.{i}.IPv6Forwarding.{i}.ForwardingMetric!UCI:network/route,@i-1/metric*/ +static int get_RoutingRouterIPv6Forwarding_ForwardingMetric(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmuci_get_value_by_section_fallback_def(route_sec(data), "metric", "0"); + return 0; +} + +static int set_RoutingRouterIPv6Forwarding_ForwardingMetric(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_int(ctx, value, RANGE_ARGS{{"-1",NULL}}, 1)) + return FAULT_9007; + return 0; + case VALUESET: + if (((struct dm_data *)data)->config_section == NULL) // Dynamic route + return 0; + + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "metric", value); + return 0; + } + return 0; +} + +static int get_RoutingRouterIPv6Forwarding_ExpirationTime(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "9999-12-31T23:59:59Z"; + return 0; +} + +static int get_RoutingRouteInformation_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "1"; + return 0; +} + +static int set_RoutingRouteInformation_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + break; + } + return 0; +} + +static int get_RoutingRouteInformation_InterfaceSettingNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *s = NULL; + size_t nbre_routes = 0; + + uci_foreach_sections("network", "interface", s) { + char *proto = NULL, *ip6addr = NULL; + + dmuci_get_value_by_section_string(s, "proto", &proto); + dmuci_get_value_by_section_string(s, "ip6addr", &ip6addr); + if ((proto && DM_LSTRCMP(proto, "dhcpv6") == 0) || (ip6addr && ip6addr[0] != '\0')) { + json_object *res = NULL, *routes = NULL; + + char *if_name = section_name(s); + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", if_name, String}}, 1, &res); + DM_ASSERT(res, *value = "0"); + json_object_object_get_ex(res, "route", &routes); + nbre_routes = (routes) ? json_object_array_length(routes) : 0; + } + } + dmasprintf(value, "%d", nbre_routes); + return 0; +} + +static int get_RoutingRouteInformationInterfaceSetting_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *s = NULL; + char *target, *mask, *nexthop, *gateway, *ip_target, buf[64]; + + *value = "NoForwardingEntry"; + target = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "target"); + mask = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "mask"); + snprintf(buf, sizeof(buf), "%s/%s", target, mask); + nexthop = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "nexthop"); + uci_foreach_sections("network", "route6", s) { + dmuci_get_value_by_section_string(s, "target", &ip_target); + dmuci_get_value_by_section_string(s, "gateway", &gateway); + if(DM_STRCMP(ip_target, buf) == 0 && DM_STRCMP(nexthop, gateway) == 0) { + *value = "ForwardingEntryCreated"; + return 0; + } + } + return 0; +} + +static int get_RoutingRouteInformationInterfaceSetting_Interface(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct route6_args route6 = {0}; + struct uci_section *s = NULL; + char cmd[32] = {0}; + char *iface = NULL; + + char *source = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "source"); + char *nexthop = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "nexthop"); + + snprintf(cmd, sizeof(cmd), "ip -6 route show"); + + FILE *fp = fopen(PROC_ROUTE6, "r"); + if (fp != NULL) { + char line[MAX_ROUTE_LEN] = {0}; + + while (fgets(line, MAX_ROUTE_LEN, fp) != NULL) { + remove_new_line(line); + + if (parse_route6_line(line, &route6)) + continue; + + if((DM_STRCMP(source, route6.destination) == 0) && (DM_STRCMP(nexthop, route6.gateway) == 0)) + break; + } + + fclose(fp); + } + + if (DM_STRLEN(route6.iface)) { + uci_foreach_sections("network", "interface", s) { + char *str = get_l3_device(section_name(s)); + if (DM_STRCMP(str, route6.iface) == 0) { + iface = section_name(s); + break; + } + } + } + + _bbfdm_get_references(ctx, "Device.IP.Interface.", "Name", iface, value); + return 0; +} + +static int get_RoutingRouteInformationInterfaceSetting_SourceRouter(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "target"); + return 0; +} + +static int get_RoutingRouteInformationInterfaceSetting_RouteLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "0001-01-01T00:00:00Z"; + + char *valid = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "valid"); + if (valid && *valid != '\0' && DM_STRTOL(valid) > 0) { + char local_time[32] = {0}; + + if (get_shift_utc_time(DM_STRTOL(valid), local_time, sizeof(local_time)) == -1) + return 0; + + *value = dmstrdup(local_time); + } + return 0; +} + +/************************************************************* +* SET AND GET ALIAS FOR ROUTER OBJ +**************************************************************/ +static int get_RoutingRouter_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *rt_table = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "rt_table", &rt_table); + dmasprintf(value, "route_table-%s", rt_table ? rt_table : instance); + return 0; +} + +static int set_RoutingRouter_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, 64, NULL, NULL)) + return FAULT_9007; + break; + case VALUESET: + bbfdm_set_fault_message(ctx, "Internal designated unique identifier, not allowed to update"); + return FAULT_9007; + } + return 0; +} + +static int get_router_ipv4forwarding_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return bbf_get_alias(ctx, ((struct dm_data *)data)->dmmap_section, "route_alias", instance, value); +} + +static int set_router_ipv4forwarding_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + return bbf_set_alias(ctx, ((struct dm_data *)data)->dmmap_section, "route_alias", instance, value); +} + +static int get_RoutingRouterIPv6Forwarding_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return bbf_get_alias(ctx, ((struct dm_data *)data)->dmmap_section, "route6_alias", instance, value); +} + +static int set_RoutingRouterIPv6Forwarding_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + return bbf_set_alias(ctx, ((struct dm_data *)data)->dmmap_section, "route6_alias", instance, value); +} + +/************************************************************* +* ADD DEL OBJ +**************************************************************/ +static int add_router(char *refparam, struct dmctx *ctx, void *data, char **instance) +{ +#define LOCAL_TABLE_ID 255 + struct uci_section *dmmap_s = NULL; + char rt_table[32] = {0}; + + snprintf(rt_table, sizeof(rt_table), "%ld", LOCAL_TABLE_ID + DM_STRTOL(*instance) - 1); + + dmuci_add_section_bbfdm("dmmap_routing", "router", &dmmap_s); + dmuci_set_value_by_section(dmmap_s, "rt_table", rt_table); + dmuci_set_value_by_section(dmmap_s, "router_instance", *instance); + return 0; +} + +static int delete_router(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action) +{ + struct uci_section *s = NULL; + char *rt_table = NULL; + + switch (del_action) { + case DEL_INST: + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "rt_table", &rt_table); + if(DM_LSTRCMP(rt_table, "254") == 0) { + bbfdm_set_fault_message(ctx, "It's not allowed to delete the main '254' routing table."); + return FAULT_9003; + } + + uci_foreach_sections("network", "interface", s) { + char *curr_rt_table = NULL; + + dmuci_get_value_by_section_string(s, "ip4table", &curr_rt_table); + if (DM_STRCMP(curr_rt_table, rt_table) == 0) + dmuci_set_value_by_section(s, "ip4table", ""); + } + + dmuci_delete_by_section(((struct dm_data *)data)->dmmap_section, NULL, NULL); + break; + case DEL_ALL: + bbfdm_set_fault_message(ctx, "It's not allowed to delete all routing tables since there are some routing tables defined by the system '/etc/iproute2/rt_tables'."); + return FAULT_9005; + } + return 0; +} + +static int add_ipv4forwarding(char *refparam, struct dmctx *ctx, void *data, char **instance) +{ + struct uci_section *s = NULL, *dmmap_route = NULL; + char *rt_table = NULL; + char route_name[32]; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "rt_table", &rt_table); + snprintf(route_name, sizeof(route_name), "route_%s", *instance); + + dmuci_add_section("network", "route", &s); + dmuci_rename_section_by_section(s, route_name); + dmuci_set_value_by_section(s, "disabled", "1"); + dmuci_set_value_by_section(s, "table", rt_table); + + dmuci_add_section_bbfdm("dmmap_routing", "route", &dmmap_route); + dmuci_set_value_by_section(dmmap_route, "section_name", route_name); + dmuci_set_value_by_section(dmmap_route, "route_instance", *instance); + return 0; +} + +static int delete_ipv4forwarding(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action) +{ + struct uci_section *route_s = NULL, *stmp = NULL, *dmmap_section = NULL; + char *rt_table = NULL; + + switch (del_action) { + case DEL_INST: + // Return 9008 error if the removed route is dynamic + if (((struct dm_data *)data)->config_section == NULL) { // Dynamic route + bbfdm_set_fault_message(ctx, "This is a dynamic 'route' instance, therefore it's not permitted to delete it."); + return FAULT_9008; + } + + // Remove dmmap section + get_dmmap_section_of_config_section("dmmap_routing", "route", section_name(((struct dm_data *)data)->config_section), &dmmap_section); + dmuci_delete_by_section(dmmap_section, NULL, NULL); + + // Remove config section + dmuci_delete_by_section(((struct dm_data *)data)->config_section, NULL, NULL); + break; + case DEL_ALL: + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "rt_table", &rt_table); + + // Remove all static routes + uci_foreach_option_eq_safe("network", "route", "rt_table", rt_table, stmp, route_s) { + + // Remove dmmap section + get_dmmap_section_of_config_section("dmmap_routing", "route", section_name(route_s), &dmmap_section); + dmuci_delete_by_section(dmmap_section, NULL, NULL); + + // Remove config section + dmuci_delete_by_section(route_s, NULL, NULL); + } + break; + } + return 0; +} + +static int add_ipv6Forwarding(char *refparam, struct dmctx *ctx, void *data, char **instance) +{ + struct uci_section *s = NULL, *dmmap_route6 = NULL; + char *rt_table = NULL; + char route6_name[32]; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "rt_table", &rt_table); + snprintf(route6_name, sizeof(route6_name), "route6_%s", *instance); + + dmuci_add_section("network", "route6", &s); + dmuci_rename_section_by_section(s, route6_name); + dmuci_set_value_by_section(s, "disabled", "1"); + dmuci_set_value_by_section(s, "table", rt_table); + + dmuci_add_section_bbfdm("dmmap_routing", "route6", &dmmap_route6); + dmuci_set_value_by_section(dmmap_route6, "section_name", route6_name); + dmuci_set_value_by_section(dmmap_route6, "route6_instance", *instance); + return 0; +} + +static int delete_ipv6Forwarding(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action) +{ + struct uci_section *route6_s = NULL, *stmp = NULL, *dmmap_section = NULL; + char *rt_table = NULL; + + switch (del_action) { + case DEL_INST: + // Return 9008 error if the removed route6 is dynamic + if (((struct dm_data *)data)->config_section == NULL) { // Dynamic route + bbfdm_set_fault_message(ctx, "This is a dynamic 'route' instance, therefore it's not permitted to delete it."); + return FAULT_9008; + } + + // Remove dmmap section + get_dmmap_section_of_config_section("dmmap_routing", "route6", section_name(((struct dm_data *)data)->config_section), &dmmap_section); + dmuci_delete_by_section(dmmap_section, NULL, NULL); + + // Remove config section + dmuci_delete_by_section(((struct dm_data *)data)->config_section, NULL, NULL); + break; + case DEL_ALL: + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "rt_table", &rt_table); + + // Remove all static enable routes + uci_foreach_option_eq_safe("network", "route6", "rt_table", rt_table, stmp, route6_s) { + + // Remove dmmap section + get_dmmap_section_of_config_section("dmmap_routing", "route6", section_name(route6_s), &dmmap_section); + dmuci_delete_by_section(dmmap_section, NULL, NULL); + + // Remove config section + dmuci_delete_by_section(route6_s, NULL, NULL); + } + break; + } + return 0; +} + +/********************************************************************************************************************************** +* OBJ & PARAM DEFINITION +***********************************************************************************************************************************/ +/* *** Device. *** */ +DMOBJ tDeviceRoutingObj[] = { +/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/ +{"Routing", &DMREAD, NULL, NULL, "file:/etc/config/network", NULL, NULL, NULL, tRoutingObj, tRoutingParams, NULL, BBFDM_BOTH, NULL}, +{0} +}; + +/* *** Device.Routing. *** */ +DMOBJ tRoutingObj[] = { +/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/ +{"Router", &DMWRITE, add_router, delete_router, NULL, browseRouterInst, NULL, NULL, tRoutingRouterObj, tRoutingRouterParams, NULL, BBFDM_BOTH, NULL}, +{"RouteInformation", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tRoutingRouteInformationObj, tRoutingRouteInformationParams, NULL, BBFDM_BOTH, NULL}, +{0} +}; + +DMLEAF tRoutingParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"RouterNumberOfEntries", &DMREAD, DMT_UNINT, get_router_nbr_entry, NULL, BBFDM_BOTH}, +{0} +}; + +/* *** Device.Routing.Router.{i}. *** */ +DMOBJ tRoutingRouterObj[] = { +/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/ +{"IPv4Forwarding", &DMWRITE, add_ipv4forwarding, delete_ipv4forwarding, NULL, browseIPv4ForwardingInst, NULL, NULL, NULL, tRoutingRouterIPv4ForwardingParams, NULL, BBFDM_BOTH, NULL}, +{"IPv6Forwarding", &DMWRITE, add_ipv6Forwarding, delete_ipv6Forwarding, NULL, browseIPv6ForwardingInst, NULL, NULL, NULL, tRoutingRouterIPv6ForwardingParams, NULL, BBFDM_BOTH, NULL}, +{0} +}; + +DMLEAF tRoutingRouterParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"Enable", &DMWRITE, DMT_BOOL, get_RoutingRouter_Enable, set_RoutingRouter_Enable, BBFDM_BOTH}, +{"Status", &DMREAD, DMT_STRING, get_RoutingRouter_Status, NULL, BBFDM_BOTH}, +{"Alias", &DMWRITE, DMT_STRING, get_RoutingRouter_Alias, set_RoutingRouter_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE|DM_FLAG_LINKER}, +{"IPv4ForwardingNumberOfEntries", &DMREAD, DMT_UNINT, get_RoutingRouter_IPv4ForwardingNumberOfEntries, NULL, BBFDM_BOTH}, +{"IPv6ForwardingNumberOfEntries", &DMREAD, DMT_UNINT, get_RoutingRouter_IPv6ForwardingNumberOfEntries, NULL, BBFDM_BOTH}, +{0} +}; + +/* *** Device.Routing.Router.{i}.IPv4Forwarding.{i}. *** */ +DMLEAF tRoutingRouterIPv4ForwardingParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"Enable", &DMWRITE, DMT_BOOL, get_router_ipv4forwarding_enable, set_router_ipv4forwarding_enable, BBFDM_BOTH}, +{"Status", &DMREAD, DMT_STRING, get_router_ipv4forwarding_status, NULL, BBFDM_BOTH}, +{"Alias", &DMWRITE, DMT_STRING, get_router_ipv4forwarding_alias, set_router_ipv4forwarding_alias, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"StaticRoute", &DMREAD, DMT_BOOL, get_router_ipv4forwarding_static_route, NULL, BBFDM_BOTH}, +{"DestIPAddress", &DMWRITE, DMT_STRING, get_router_ipv4forwarding_destip, set_router_ipv4forwarding_destip, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"DestSubnetMask", &DMWRITE, DMT_STRING, get_router_ipv4forwarding_destmask, set_router_ipv4forwarding_destmask, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"ForwardingPolicy", &DMWRITE, DMT_INT, get_router_ipv4forwarding_forwarding_policy, set_router_ipv4forwarding_forwarding_policy, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"GatewayIPAddress", &DMWRITE, DMT_STRING, get_router_ipv4forwarding_gatewayip, set_router_ipv4forwarding_gatewayip, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"Interface", &DMWRITE, DMT_STRING, get_RoutingRouterForwarding_Interface, set_RoutingRouterForwarding_Interface, BBFDM_BOTH, DM_FLAG_UNIQUE|DM_FLAG_REFERENCE}, +{"Origin", &DMREAD, DMT_STRING, get_router_ipv4forwarding_origin, NULL, BBFDM_BOTH}, +{"ForwardingMetric", &DMWRITE, DMT_INT, get_router_ipv4forwarding_metric, set_router_ipv4forwarding_metric, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{0} +}; + +/* *** Device.Routing.Router.{i}.IPv6Forwarding.{i}. *** */ +DMLEAF tRoutingRouterIPv6ForwardingParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"Enable", &DMWRITE, DMT_BOOL, get_RoutingRouterIPv6Forwarding_Enable, set_RoutingRouterIPv6Forwarding_Enable, BBFDM_BOTH}, +{"Status", &DMREAD, DMT_STRING, get_RoutingRouterIPv6Forwarding_Status, NULL, BBFDM_BOTH}, +{"Alias", &DMWRITE, DMT_STRING, get_RoutingRouterIPv6Forwarding_Alias, set_RoutingRouterIPv6Forwarding_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"DestIPPrefix", &DMWRITE, DMT_STRING, get_RoutingRouterIPv6Forwarding_DestIPPrefix, set_RoutingRouterIPv6Forwarding_DestIPPrefix, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"ForwardingPolicy", &DMWRITE, DMT_INT, get_RoutingRouterIPv6Forwarding_ForwardingPolicy, set_RoutingRouterIPv6Forwarding_ForwardingPolicy, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"NextHop", &DMWRITE, DMT_STRING, get_RoutingRouterIPv6Forwarding_NextHop, set_RoutingRouterIPv6Forwarding_NextHop, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"Interface", &DMWRITE, DMT_STRING, get_RoutingRouterForwarding_Interface, set_RoutingRouterForwarding_Interface, BBFDM_BOTH, DM_FLAG_UNIQUE|DM_FLAG_REFERENCE}, +{"Origin", &DMREAD, DMT_STRING, get_RoutingRouterIPv6Forwarding_Origin, NULL, BBFDM_BOTH}, +{"ForwardingMetric", &DMWRITE, DMT_INT, get_RoutingRouterIPv6Forwarding_ForwardingMetric, set_RoutingRouterIPv6Forwarding_ForwardingMetric, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"ExpirationTime", &DMREAD, DMT_TIME, get_RoutingRouterIPv6Forwarding_ExpirationTime, NULL, BBFDM_BOTH}, +{0} +}; + +/* *** Device.Routing.RouteInformation. *** */ +DMOBJ tRoutingRouteInformationObj[] = { +/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/ +{"InterfaceSetting", &DMREAD, NULL, NULL, NULL, browseRoutingRouteInformationInterfaceSettingInst, NULL, NULL, NULL, tRoutingRouteInformationInterfaceSettingParams, NULL, BBFDM_BOTH, NULL}, +{0} +}; + +DMLEAF tRoutingRouteInformationParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"Enable", &DMWRITE, DMT_BOOL, get_RoutingRouteInformation_Enable, set_RoutingRouteInformation_Enable, BBFDM_BOTH}, +{"InterfaceSettingNumberOfEntries", &DMREAD, DMT_UNINT, get_RoutingRouteInformation_InterfaceSettingNumberOfEntries, NULL, BBFDM_BOTH}, +{0} +}; + +/* *** Device.Routing.RouteInformation.InterfaceSetting.{i}. *** */ +DMLEAF tRoutingRouteInformationInterfaceSettingParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ +{"Status", &DMREAD, DMT_STRING, get_RoutingRouteInformationInterfaceSetting_Status, NULL, BBFDM_BOTH}, +{"Interface", &DMREAD, DMT_STRING, get_RoutingRouteInformationInterfaceSetting_Interface, NULL, BBFDM_BOTH, DM_FLAG_UNIQUE|DM_FLAG_REFERENCE}, +{"SourceRouter", &DMREAD, DMT_STRING, get_RoutingRouteInformationInterfaceSetting_SourceRouter, NULL, BBFDM_BOTH}, +{"RouteLifetime", &DMREAD, DMT_TIME, get_RoutingRouteInformationInterfaceSetting_RouteLifetime, NULL, BBFDM_BOTH}, +{0} +}; diff --git a/src/routing.h b/src/routing.h new file mode 100644 index 0000000000000000000000000000000000000000..7cbaa0cf0a387e63f90919268b17906c9fc439ca --- /dev/null +++ b/src/routing.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2019-2024 iopsys Software Solutions AB + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> + * + */ + +#ifndef __ROUTING_H +#define __ROUTING_H + +#include "libbbfdm-api/dmcommon.h" + +extern DMOBJ tDeviceRoutingObj[]; +extern DMOBJ tRoutingObj[]; +extern DMLEAF tRoutingParams[]; +extern DMOBJ tRoutingRouterObj[]; +extern DMLEAF tRoutingRouterParams[]; +extern DMLEAF tRoutingRouterIPv4ForwardingParams[]; +extern DMLEAF tRoutingRouterIPv6ForwardingParams[]; +extern DMOBJ tRoutingRouteInformationObj[]; +extern DMLEAF tRoutingRouteInformationParams[]; +extern DMLEAF tRoutingRouteInformationInterfaceSettingParams[]; + +#endif