README
uspd
is a TR-369/USP backend ubus daemon process to understand USP syntax defined in R-ARC.7 - R-ARC.12 and provide details.
Project Components
Project consists of following components:
- Application itself written in C programming language
- Documentation in a Markdown format
Build Instructions
uspd
is written using C programming language and depends on a number of components found in OpenWrt for building and running.
Usage
uspd
needs to be started on startup after ubusd
, as it exposes the USP functionality over ubus. By default(when granularity is not set in uci), uspd registers below two namespaces with ubus.
root@iopsys:~# ubus list |grep usp
usp
usp.raw
Each namespace provide the similar result but in different formats. usp
namespace is to provide the output as required by USP
or End User
or in pretty format, whereas usp.raw
namespace is to provide output in raw format, which can be used by other USP frontend applications(like: obuspa). Each namespace has below functionalities.
root@iopsys:~# ubus -v list usp
'usp' @fd7d6f13
"get":{"path":"String","proto":"String"}
"set":{"path":"String","value":"String","values":"Table","proto":"String"}
"operate":{"path":"String","action":"String","input":"Table","proto":"String"}
"add_object":{"path":"String","proto":"String"}
"del_object":{"path":"String","proto":"String"}
"object_names":{"path":"String","proto":"String"}
"instances":{"path":"String","proto":"String"}
root@iopsys:~#
root@iopsys:~# ubus -v list usp.raw
'usp.raw' @97a67525
"get":{"path":"String","proto":"String"}
"set":{"path":"String","value":"String","values":"Table","proto":"String"}
"operate":{"path":"String","action":"String","input":"Table","proto":"String"}
"add_object":{"path":"String","proto":"String"}
"del_object":{"path":"String","proto":"String"}
"object_names":{"path":"String","proto":"String"}
"instances":{"path":"String","proto":"String"}
root@iopsys:~#
Note:
proto
in each method specify the datamodel prototype('cwmp', 'usp') to use, if not provided default datamodel will be used.
The objects registered with the above namespaces can be called with appropriate parameters to perform a USP Get/Set/Operate/Add Object/Delete Object
operation as below.
To get the output in pretty format use usp
ubus namespace:
root@iopsys:~# ubus call usp get '{"path":"Device.IP.Diagnostics.", "proto":"usp"}'
{
"Diagnostics": {
"IPv4DownloadDiagnosticsSupported": true,
"IPv4PingSupported": true,
"IPv4ServerSelectionDiagnosticsSupported": true,
"IPv4TraceRouteSupported": true,
"IPv4UDPEchoDiagnosticsSupported": true,
"IPv4UploadDiagnosticsSupported": true,
"IPv6DownloadDiagnosticsSupported": true,
"IPv6PingSupported": true,
"IPv6ServerSelectionDiagnosticsSupported": true,
"IPv6TraceRouteSupported": true,
"IPv6UDPEchoDiagnosticsSupported": true,
"IPv6UploadDiagnosticsSupported": true,
"UDPEchoConfig": {
"BytesReceived": 0,
"BytesResponded": 0,
"EchoPlusEnabled": false,
"EchoPlusSupported": false,
"Enable": false,
"Interface": "",
"PacketsReceived": 0,
"PacketsResponded": 0,
"SourceIPAddress": "",
"TimeFirstPacketReceived": "0",
"TimeLastPacketReceived": "0",
"UDPPort": 0
}
}
}
root@iopsys:~#
root@iopsys:~# ubus call usp get '{"path":"Device.IP.Diagnostics.", "proto":"cwmp"}'
{
"Diagnostics": {
"DownloadDiagnostics": {
"BOMTime": "0",
"DSCP": 0,
"DiagnosticsState": "None",
"DownloadDiagnosticMaxConnections": 1,
"DownloadTransports": "HTTP,FTP",
"DownloadURL": "",
"EOMTime": "0",
"EnablePerConnectionResults": false,
"EthernetPriority": 0,
"Interface": "",
"NumberOfConnections": 1,
"PerConnectionResultNumberOfEntries": 0,
"PeriodOfFullLoading": 0,
"ProtocolVersion": "Any",
"ROMTime": "0",
"TCPOpenRequestTime": "0",
"TCPOpenResponseTime": "0",
"TestBytesReceived": 0,
"TestBytesReceivedUnderFullLoading": 0,
"TotalBytesReceived": 0,
"TotalBytesReceivedUnderFullLoading": 0,
"TotalBytesSent": 0,
"TotalBytesSentUnderFullLoading": 0
},
"IPPing": {
"AverageResponseTime": 0,
"AverageResponseTimeDetailed": 0,
"DSCP": 0,
"DataBlockSize": 64,
"DiagnosticsState": "None",
"FailureCount": 0,
"Host": "",
"Interface": "",
"MaximumResponseTime": 0,
"MaximumResponseTimeDetailed": 0,
"MinimumResponseTime": 0,
"MinimumResponseTimeDetailed": 0,
"NumberOfRepetitions": 3,
"ProtocolVersion": "Any",
"SuccessCount": 0,
"Timeout": 1000
},
"IPv4DownloadDiagnosticsSupported": true,
"IPv4PingSupported": true,
"IPv4ServerSelectionDiagnosticsSupported": true,
"IPv4TraceRouteSupported": true,
"IPv4UDPEchoDiagnosticsSupported": true,
"IPv4UploadDiagnosticsSupported": true,
"IPv6DownloadDiagnosticsSupported": true,
"IPv6PingSupported": true,
"IPv6ServerSelectionDiagnosticsSupported": true,
"IPv6TraceRouteSupported": true,
"IPv6UDPEchoDiagnosticsSupported": true,
"IPv6UploadDiagnosticsSupported": true,
"ServerSelectionDiagnostics": {
"AverageResponseTime": 0,
"DiagnosticsState": "None",
"FastestHost": "",
"HostList": "",
"Interface": "",
"MaximumResponseTime": 0,
"MinimumResponseTime": 0,
"NumberOfRepetitions": 3,
"Port": 0,
"Protocol": "ICMP",
"ProtocolVersion": "Any",
"Timeout": 1000
},
"TraceRoute": {
"DSCP": 0,
"DataBlockSize": 38,
"DiagnosticsState": "None",
"Host": "",
"Interface": "",
"MaxHopCount": 30,
"NumberOfTries": 3,
"ProtocolVersion": "Any",
"ResponseTime": 0,
"RouteHopsNumberOfEntries": 0,
"Timeout": 5000
},
"UDPEchoConfig": {
"BytesReceived": 0,
"BytesResponded": 0,
"EchoPlusEnabled": false,
"EchoPlusSupported": false,
"Enable": false,
"Interface": "",
"PacketsReceived": 0,
"PacketsResponded": 0,
"SourceIPAddress": "",
"TimeFirstPacketReceived": "0",
"TimeLastPacketReceived": "0",
"UDPPort": 0
},
"UDPEchoDiagnostics": {
"AverageResponseTime": 0,
"DSCP": 0,
"DataBlockSize": 24,
"DiagnosticsState": "None",
"FailureCount": 0,
"Host": "",
"InterTransmissionTime": 1000,
"Interface": "",
"MaximumResponseTime": 0,
"MinimumResponseTime": 0,
"NumberOfRepetitions": 1,
"Port": 0,
"ProtocolVersion": "Any",
"SuccessCount": 0,
"Timeout": 5000
},
"UploadDiagnostics": {
"BOMTime": "0",
"DSCP": 0,
"DiagnosticsState": "None",
"EOMTime": "0",
"EnablePerConnectionResults": false,
"EthernetPriority": 0,
"Interface": "",
"NumberOfConnections": 1,
"PerConnectionResultNumberOfEntries": 0,
"PeriodOfFullLoading": 0,
"ProtocolVersion": "Any",
"ROMTime": "0",
"TCPOpenRequestTime": "0",
"TCPOpenResponseTime": "0",
"TestBytesSent": 0,
"TestBytesSentUnderFullLoading": 0,
"TestFileLength": 0,
"TotalBytesReceived": 0,
"TotalBytesReceivedUnderFullLoading": 0,
"TotalBytesSent": 0,
"TotalBytesSentUnderFullLoading": 0,
"UploadTransports": "HTTP,FTP",
"UploadURL": ""
}
}
}
root@iopsys:~#
root@iopsys:~# ubus call usp get '{"path":"Device.Users."}'
{
"Users": {
"User": [
{
"Alias": "cpe-1",
"Enable": true,
"Language": "",
"Password": "",
"RemoteAccessCapable": true,
"Username": "user"
},
{
"Alias": "cpe-2",
"Enable": true,
"Language": "",
"Password": "",
"RemoteAccessCapable": true,
"Username": "support"
},
{
"Alias": "cpe-3",
"Enable": true,
"Language": "",
"Password": "",
"RemoteAccessCapable": true,
"Username": "admin"
}
],
"UserNumberOfEntries": 3
}
}
To get the output in raw format use usp.raw
ubus namespace:
root@iopsys:~# ubus call usp.raw get '{"path":"Device.Users."}'
{
"parameters": [
{
"parameter": "Device.Users.User.1.Alias",
"value": "cpe-1",
"type": "xsd:string"
},
{
"parameter": "Device.Users.User.1.Enable",
"value": "1",
"type": "xsd:boolean"
},
{
"parameter": "Device.Users.User.1.Language",
"value": "",
"type": "xsd:string"
},
{
"parameter": "Device.Users.User.1.Password",
"value": "",
"type": "xsd:string"
},
{
"parameter": "Device.Users.User.1.RemoteAccessCapable",
"value": "1",
"type": "xsd:boolean"
},
{
"parameter": "Device.Users.User.1.Username",
"value": "user",
"type": "xsd:string"
},
{
"parameter": "Device.Users.User.2.Alias",
"value": "cpe-2",
"type": "xsd:string"
},
{
"parameter": "Device.Users.User.2.Enable",
"value": "1",
"type": "xsd:boolean"
},
{
"parameter": "Device.Users.User.2.Language",
"value": "",
"type": "xsd:string"
},
{
"parameter": "Device.Users.User.2.Password",
"value": "",
"type": "xsd:string"
},
{
"parameter": "Device.Users.User.2.RemoteAccessCapable",
"value": "1",
"type": "xsd:boolean"
},
{
"parameter": "Device.Users.User.2.Username",
"value": "support",
"type": "xsd:string"
},
{
"parameter": "Device.Users.User.3.Alias",
"value": "cpe-3",
"type": "xsd:string"
},
{
"parameter": "Device.Users.User.3.Enable",
"value": "1",
"type": "xsd:boolean"
},
{
"parameter": "Device.Users.User.3.Language",
"value": "",
"type": "xsd:string"
},
{
"parameter": "Device.Users.User.3.Password",
"value": "",
"type": "xsd:string"
},
{
"parameter": "Device.Users.User.3.RemoteAccessCapable",
"value": "1",
"type": "xsd:boolean"
},
{
"parameter": "Device.Users.User.3.Username",
"value": "admin",
"type": "xsd:string"
},
{
"parameter": "Device.Users.UserNumberOfEntries",
"value": "3",
"type": "xsd:unsignedInt"
}
]
}
Granularity feature is basically exposes the same USP functionality by registering additinal ubus namespaces to reduce the path
length in ubus parameter. It is the number of levels upto which we want to shorten the length.
Ex:
- When Granularity is set to 1, exposed ubus namespaces are
root@iopsys:~# ubus list|grep usp
usp
usp.Device
usp.raw
- When Granularity is set to 2, exposed ubus namespaces are
root@iopsys:~# ubus list|grep usp
usp
usp.Device
usp.Device.ATM
usp.Device.Bridging
usp.Device.BulkData
usp.Device.DHCPv4
usp.Device.DHCPv6
usp.Device.DNS
usp.Device.DSL
usp.Device.DeviceInfo
usp.Device.Ethernet
usp.Device.Firewall
usp.Device.Hosts
usp.Device.IP
usp.Device.InterfaceStack
usp.Device.ManagementServer
usp.Device.NAT
usp.Device.PPP
usp.Device.PTM
usp.Device.Routing
usp.Device.Services
usp.Device.SoftwareModules
usp.Device.Time
usp.Device.UPnP
usp.Device.USB
usp.Device.UserInterface
usp.Device.Users
usp.Device.WiFi
usp.Device.XMPP
usp.Device.X_IOPSYS_EU_Buttons
usp.Device.X_IOPSYS_EU_Dropbear
usp.Device.X_IOPSYS_EU_ICE
usp.Device.X_IOPSYS_EU_IGMP
usp.Device.X_IOPSYS_EU_IpAccCfg
usp.Device.X_IOPSYS_EU_LoginCfg
usp.Device.X_IOPSYS_EU_Owsd
usp.Device.X_IOPSYS_EU_PowerManagement
usp.Device.X_IOPSYS_EU_SyslogCfg
usp.Device.X_IOPSYS_EU_WiFiLife
usp.raw
These granular ubus objects provides the same functionality as of usp
ubus namespace
root@iopsys:~# ubus -v list usp.Device.WiFi
'usp.Device.WiFi' @69650977
"get":{"path":"String","proto":"String"}
"set":{"path":"String","value":"String","values":"Table","proto":"String"}
"operate":{"path":"String","action":"String","input":"Table","proto":"String"}
"add_object":{"path":"String","proto":"String"}
"del_object":{"path":"String","proto":"String"}
"object_names":{"path":"String","proto":"String"}
"instances":{"path":"String","proto":"String"}
Registered method can be called with appropriate parameters, like:
root@iopsys:~# ubus call usp.Device get '{"path":"Users."}'
{
"Users": {
"User": [
{
"Alias": "cpe-1",
"Enable": true,
"Language": "",
"Password": "",
"RemoteAccessCapable": true,
"Username": "user"
},
{
"Alias": "cpe-2",
"Enable": true,
"Language": "",
"Password": "",
"RemoteAccessCapable": true,
"Username": "support"
},
{
"Alias": "cpe-3",
"Enable": true,
"Language": "",
"Password": "",
"RemoteAccessCapable": true,
"Username": "admin"
}
],
"UserNumberOfEntries": 3
}
}
More example
root@iopsys:~# ubus call usp get '{"path":"Device.WiFi.SSID.*.SSID"}'
{
"SSID": [
{
"SSID": "NORRLAND-34E380760120"
},
{
"SSID": "NORRLAND-34E380760120"
}
]
}
root@iopsys:~# ubus call usp get '{"path":"Device.WiFi.SSID.*.BSSID"}'
{
"SSID": [
{
"BSSID": "34:E3:80:76:01:22"
},
{
"BSSID": "34:E3:80:76:01:23"
}
]
}
root@iopsys:~# ubus call usp get '{"path":"Device.WiFi.SSID.[BSSID==\"34:E3:80:76:01:22\"].SSID"}'
{
"SSID": [
{
"SSID": "NORRLAND-34E380760120"
}
]
}
root@iopsys:~# ubus call usp set '{"path":"Device.WiFi.SSID.[BSSID==\"34:E3:80:76:01:22\"].SSID", "value":"test-2g"}'
{
{
"status": true,
"path": "Device.WiFi.SSID.1.SSID"
}
}
root@iopsys:~# ubus call usp get '{"path":"Device.WiFi.SSID.[BSSID==\"34:E3:80:76:01:22\"].SSID"}'?
{
"SSID": [
{
"SSID": "test-2g"
}
]
}
root@iopsys:~# ubus call usp get '{"path":"Device.IP.Interface.[Status==\"Up\"].IPv4Address.[AddressingType==\"DHCP\"].IPAddress"}'
{
"Interface": [
{
"IPv4Address": [
{
"IPAddress": "192.168.0.96"
}
]
}
]
}
root@iopsys:~# ubus call usp get '{"path":"Device.IP.Interface.[Status==\"Up\"].IPv4Address.[AddressingType==\"DHCP\"&&Status==\"Up\"]."}'
{
"Interface": [
{
"IPv4Address": [
{
"AddressingType": "DHCP",
"Alias": "cpe-2",
"Enable": true,
"IPAddress": "192.168.0.96",
"Status": "Up",
"SubnetMask": "255.255.255.0",
"X_IOPSYS_EU_FirewallEnabled": true
}
]
}
]
}
root@iopsys:~# ubus call usp get '{"path":"Device.IP.Interface.[Type==\"Normal\"&&Stats.PacketsSent<=500].IPv4Address.[AddressingType==\"Static\"].IPAddress"}'
{
"Interface": [
{
"IPv4Address": [
{
"IPAddress": "192.168.1.1"
}
]
}
]
}
root@iopsys:~# ubus call usp get '{"path":"Device.WiFi.AccessPoint.[SSIDReference+.SSID==\"NORRLAND-34E380760120\"].AssociatedDevice.[Noise>15].SignalStrength"}
'
{
"AccessPoint": [
{
"AssociatedDevice": [
{
"SignalStrength": -31
}
]
}
]
}
root@iopsys:~# ubus call usp get '{"path":"Device.WiFi.SSID.*.LowerLayers#1+.Name"}'
{
{
"Name": "wlan0",
"Name": "wlan2"
}
}
root@iopsys:~# ubus call usp add_object '{"path":"Device.Users.User"}'
{
"status": true,
"instance": "4"
}
root@iopsys:~# ubus call usp del_object '{"path":"Device.Users.User.[Username==\"user_4\"]."}'
{
"status": true
}
root@iopsys:~# ubus call usp get '{"path":"Device.Users.User.*.Username"}'
{
"User": [
{
"Username": "user"
},
{
"Username": "support"
},
{
"Username": "admin"
}
]
}
root@iopsys:~# ubus call usp operate '{"path":"Device.IP.Diagnostics.", "action":"IPPing","input":{"Host":"iopsys.eu"}}'
{
"AverageResponseTime": "0",
"AverageResponseTimeDetailed": "0",
"FailureCount": "3",
"MaximumResponseTime": "0",
"MaximumResponseTimeDetailed": "0",
"MinimumResponseTime": "9999",
"MinimumResponseTimeDetailed": "999999999",
"SuccessCount": "0"
}
root@iopsys:~# ubus call usp operate '{"path":"Device.IP.Interface.[Name==\"wan\"]", "action":"Reset"}'
{
"status": true
}
USP Instances method returns the registered instances.
root@iopsys:~# ubus call usp instances '{"path":"Device.IP.Interface.", "proto":"usp"}'
{
"parameters": [
{
"parameter": "Device.IP.Interface.1."
},
{
"parameter": "Device.IP.Interface.1.IPv4Address.1."
},
{
"parameter": "Device.IP.Interface.2."
},
{
"parameter": "Device.IP.Interface.3."
},
{
"parameter": "Device.IP.Interface.3.IPv4Address.1."
},
{
"parameter": "Device.IP.Interface.3.IPv6Address.1."
},
{
"parameter": "Device.IP.Interface.3.IPv6Prefix.1."
}
]
}
Configuration File
uspd requires a configuration file to provide more granular objects over ubus. Granularity is an optional feature of uspd, it can be skipped or set to level 0. The configuration file is an uci file /etc/config/uspd
. Sample configuration file is provided below.
config uspd 'usp'
option granularitylevel '0'
Concepts and Workflow
uspd internally uses libbbfdm to get the datamodel objects. On startup it parses the uci file to check if the granularity is set and then as per the granularity value it registers the required ubus namespaces.
When a ubus method is called it first checks the path
parameter to identify if it has special USP syntax, if present it parses and determine the correct objects from libbbfdm, then proceeds with the Get/Set/Operate/Add/Del
operation on the quilified objects.
So, uspd
search for [[+*]+
in path expression, if it matches then segments the path and get the schema from libbbfdm
and store it in a link-list, then it proceeds with the next segment to filter out the unneeded schema paths. It keeps on doing so till all the expressions are solved and it finally left with qualified objects.
Once all the expressions are solved, it starts getting the values for qualified objects and store it in a stack
to print the output in pretty format.
For operate command, it solve the path expression and then call bbf_operate
from libbbfdm
to execute the operate command.
uspd
uses dm_entry_param_method
API from libbbfdm
to get the device tree schema and it's values.
In short, it covers/supports the new syntax introduced in TR-369
by using the existing datamodel available with libbbfdm.
Dependencies
Build-Time Dependencies
To successfully build uspd, following libraries are needed:
Dependency | Link | License |
---|---|---|
libuci | https://git.openwrt.org/project/uci.git | LGPL 2.1 |
libubox | https://git.openwrt.org/project/libubox.git | BSD |
libubus | https://git.openwrt.org/project/ubus.git | LGPL 2.1 |
libjson-c | https://s3.amazonaws.com/json-c_releases | MIT |
libbbfdm | https://dev.iopsys.eu/iopsys/bbf.git | LGPL 2.1 |
Run-Time Dependencies
In order to run the uspd, following dependencies are needed to be running before uspd.
Dependency | Link | License |
---|---|---|
ubusd | https://git.openwrt.org/project/ubus.git | LGPL 2.1 |
System daemon ubusd is used to expose the USP functionality over ubus.