Merge uspd as bbfd with history

This commit is contained in:
Vivek Kumar Dutta 2023-03-20 12:07:27 +00:00
parent 32511db9d9
commit f24b03937d
109 changed files with 40278 additions and 0 deletions

19
bbfd/.gitignore vendored Normal file
View file

@ -0,0 +1,19 @@
.*.swp
.*.swo
.built*
.configured_*
.dep_files
.git_update
.pkgdir/
.prepared_*
ipkg-arm_xscale/
*.o
*.so
src/uspd
uspd
*.gcda
*.gcno
report/
*.log
*.xml
docs/index.md

71
bbfd/.gitlab-ci.yml Normal file
View file

@ -0,0 +1,71 @@
include:
- project: 'iopsys/gitlab-ci-pipeline'
file: '/static-code-analysis.yml'
variables:
COMMON_IMAGE: iopsys/code-analysis:0.26
DEBUG: 'TRUE'
SOURCE_FOLDER: "./src"
RUN_CPPCHECK: "cppcheck --enable=all --error-exitcode=1 --inline-suppr --suppress=missingInclude --include=/usr/include/libubox/list.h -DUSPD_MAX_MSG_LEN=1048576"
stages:
- static_code_analysis
- test
run_unit_test:
stage: test
image: iopsys/code-analysis:latest
allow_failure: false
script:
- "./gitlab-ci/install-dependencies.sh"
- "./gitlab-ci/setup.sh"
- "./gitlab-ci/unit-test.sh"
artifacts:
untracked: true
when: always
paths:
- timestamp.log
- unit-test-coverage.xml
run_functional_test:
stage: test
image: iopsys/code-analysis:latest
allow_failure: false
script:
- "./gitlab-ci/install-dependencies.sh"
- "./gitlab-ci/setup.sh"
- "./gitlab-ci/functional-test.sh"
artifacts:
untracked: true
when: always
reports:
junit: ./report/*.xml
paths:
- funl-result.log
- funl-test-coverage.xml
- memory-report.xml
- timestamp.log
- report/
run_api_test:
stage: test
image: iopsys/code-analysis:latest
allow_failure: false
script:
- "./gitlab-ci/install-dependencies.sh"
- "./gitlab-ci/setup.sh"
- "./gitlab-ci/functional-api-test.sh"
artifacts:
untracked: true
when: always
reports:
junit: ./report/*.xml
paths:
- timestamp.log
- api-test-coverage.xml
- memory-report.xml
- api-result.log
- report/

308
bbfd/LICENSE Normal file
View file

@ -0,0 +1,308 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
uspd - USP Daemon exposing USP API over uBus
Copyright (C) 2019 iopsys Software Solutions AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

25
bbfd/Makefile Normal file
View file

@ -0,0 +1,25 @@
all:
make -C src all
uspd:
make -C src uspd
test:
make -C src test
unit-test:
make -C test/cmocka unit-test USPD_LIB_DIR=$(PWD)
func-test:
make -C src func-test
clean:
make -C src clean
make -C test/cmocka clean
rm -f uspd
find -name '*.gcda' -exec rm {} -fv \;
find -name '*.gcno' -exec rm {} -fv \;
find -name '*.gcov' -exec rm {} -fv \;
find -name '*.so' -exec rm {} -fv \;
rm -f *.log *.xml
rm -rf report

100
bbfd/README.md Normal file
View file

@ -0,0 +1,100 @@
# USP Daemon (uspd)
`uspd` is data-model daemon which exposes data-model objects over ubus as required
by [TR-069/cwmp](https://cwmp-data-models.broadband-forum.org/) or [TR-369/USP](https://usp.technology/),
`uspd` also understand [USP syntax](https://usp.technology/specification/architecture/) as defined in R-ARC.7 - R-ARC.12
and provide details for data-model queries.
> Note 1: The command outputs shown in this readme are examples only, actual output may differ based on device and configuration.
> Note 2: Long command outputs are compressed for better readability
## 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.
## UCI Config
`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.
```bash
config uspd 'usp'
option granularitylevel '0'
option debug 'true'
option loglevel '2'
option sock '/tmp/usp.sock'
option transaction_timeout 60
option subprocess_level '1'
option refresh_time '5'
```
In the above uci, loglevel can have below value:
|loglevel | Meaning |
|---------| -----------------------------------------|
| 0 | Disabled logging |
| 1 | Only errors will be logged |
| 2 | Only errors and warnings will be logged |
| 3 | Log everything except debug |
| 4 | Everything will be logged |
For more info on the `uspd` UCI configuration visit [uci documentation](./docs/api/uci/uspd.md) OR [raw uci schema](https://dev.iopsys.eu/iopsys/uspd/-/tree/module_docs/schemas/uci/uspd.json)
## Concepts and Workflow
`uspd` internally uses `libbbfdm` to get the data-model 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 qualified 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 data-model available with `libbbfdm`.
## Important topics
* [UBUS methods](./docs/guide/ubus_methods.md)
* [UBUS Errors](./docs/guide/ubus_errors.md)
* [UBUS examples](./docs/guide/ubus_example.md)
* [Parallel UBUS call](./docs/guide/ubus_parallel_call.md)
* [Third party datamodel integration](./docs/guide/data_model_integration.md)
## 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/available before `uspd`.
| Dependency | Link | License |
| ---------- | ---------------------------------------- | -------- |
| ubusd | https://git.openwrt.org/project/ubus.git | LGPL 2.1 |
| libbbfdm | https://dev.iopsys.eu/iopsys/bbf.git | LGPL 2.1 |
System daemon `ubusd` is used to expose the USP functionality over `ubus`.

7
bbfd/docs/.pages Normal file
View file

@ -0,0 +1,7 @@
title: "USP Daemon Documentation"
nav:
- "api"
- "guide"
- "spec"
- "..."

6
bbfd/docs/api/.pages Normal file
View file

@ -0,0 +1,6 @@
title: "USP Daemon API"
nav:
- "ubus"
- "uci"
- "..."

View file

@ -0,0 +1,4 @@
title: "USP Daemon UBUS"
nav:
- "..."

3162
bbfd/docs/api/ubus/usp.md Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

4
bbfd/docs/api/uci/.pages Normal file
View file

@ -0,0 +1,4 @@
title: "USP Daemon UCI"
nav:
- "..."

216
bbfd/docs/api/uci/uspd.md Normal file
View file

@ -0,0 +1,216 @@
# UCI Config
<tbody>
<tr>
<td colspan="2">
<div style="font-weight: bold">uspd</div>
<table style="width:100%">
<tbody>
<tr>
<td>
<div style="font-weight: bold; font-size: 14px">section</div>
</td>
<td>
<div style="font-weight: bold; font-size: 14px">description</div>
</td>
<td>
<div style="font-weight: bold; font-size: 14px">multi</div>
</td>
<td>
<div style="font-weight: bold; font-size: 14px">options</div>
</td>
</tr>
<tr>
<td class="td_row_even">
<div class="td_row_even">uspd</div>
</td>
<td class="td_row_even">
<div class="td_row_even">USP daemon Settings</div>
</td>
<td class="td_row_even">
<div class="td_row_even">false</div>
</td>
<td class="td_row_even">
<table style="width:100%">
<tbody>
<tr>
<td>
<div style="font-weight: bold; font-size: 14px">name</div>
</td>
<td>
<div style="font-weight: bold; font-size: 14px">type</div>
</td>
<td>
<div style="font-weight: bold; font-size: 14px">required</div>
</td>
<td>
<div style="font-weight: bold; font-size: 14px">default</div>
</td>
<td>
<div style="font-weight: bold; font-size: 14px">description</div>
</td>
</tr>
<tr>
<td class="td_row_even">
<div class="td_row_even">granularitylevel</div>
</td>
<td class="td_row_even">
<div class="td_row_even">integer</div>
</td>
<td class="td_row_even">
<div class="td_row_even">no</div>
</td>
<td class="td_row_even">
<div class="td_row_even">0</div>
</td>
<td class="td_row_even">
<div class="td_row_even">Creates ubus objects along with object names, depth of object name depends
on granularitylevel</div>
</td>
</tr>
<tr>
<td class="td_row_odd">
<div class="td_row_odd">debug</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">boolean</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">no</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd"></div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">Enabled debug logging</div>
</td>
</tr>
<tr>
<td class="td_row_even">
<div class="td_row_even">sock</div>
</td>
<td class="td_row_even">
<div class="td_row_even">string</div>
</td>
<td class="td_row_even">
<div class="td_row_even">no</div>
</td>
<td class="td_row_even">
<div class="td_row_even"></div>
</td>
<td class="td_row_even">
<div class="td_row_even">Path for ubus socket to register uspd services</div>
</td>
</tr>
<tr>
<td class="td_row_odd">
<div class="td_row_odd">transaction_timeout</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">integer</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">no</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">10</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">Transaction timeout value in seconds</div>
</td>
</tr>
<tr>
<td class="td_row_even">
<div class="td_row_even">loglevel</div>
</td>
<td class="td_row_even">
<div class="td_row_even">integer</div>
</td>
<td class="td_row_even">
<div class="td_row_even">no</div>
</td>
<td class="td_row_even">
<div class="td_row_even">1</div>
</td>
<td class="td_row_even">
<div class="td_row_even">Internal loglevel for debugging {0: No Logs; 1: Errors only; 2: Errors
and warnings; 3: Error, warning and info; 4: Everything}</div>
</td>
</tr>
<tr>
<td class="td_row_even">
<div class="td_row_even">subprocess_level</div>
</td>
<td class="td_row_even">
<div class="td_row_even">integer</div>
</td>
<td class="td_row_even">
<div class="td_row_even">no</div>
</td>
<td class="td_row_even">
<div class="td_row_even">2</div>
</td>
<td class="td_row_even">
<div class="td_row_even">This parameter configures when subprocess can be used for get operation. Level here denotes the Datamodel object depth up-to which subprocess will be used to collect the get data. For example, if this is configured to 1, then only get for 'Device.' shall be called within the subprocess. If configured as level 2, then all the get with up-to depth 2 like 'Device.WiFi.', 'Device.IP.' shall be called in subprocess.</div>
</td>
</tr>
<tr>
<td class="td_row_even">
<div class="td_row_even">bbf_caching_time</div>
</td>
<td class="td_row_even">
<div class="td_row_even">integer</div>
</td>
<td class="td_row_even">
<div class="td_row_even">no</div>
</td>
<td class="td_row_even">
<div class="td_row_even">0</div>
</td>
<td class="td_row_even">
<div class="td_row_even">Max caching time in seconds for ubus output used in datamodel parameters. If not configured, output shall be cleared end the end of call.</div>
</td>
</tr>
<tr>
<td class="td_row_even">
<div class="td_row_even">dm_version</div>
</td>
<td class="td_row_even">
<div class="td_row_even">string</div>
</td>
<td class="td_row_even">
<div class="td_row_even">no</div>
</td>
<td class="td_row_even">
<div class="td_row_even"></div>
</td>
<td class="td_row_even">
<div class="td_row_even">Configures the datamodel version to use for datamodel parameters, if not configured show all defined datamodel</div>
</td>
</tr>
<tr>
<td class="td_row_even">
<div class="td_row_even">refresh_time</div>
</td>
<td class="td_row_even">
<div class="td_row_even">integer</div>
</td>
<td class="td_row_even">
<div class="td_row_even">no</div>
</td>
<td class="td_row_even">
<div class="td_row_even">5</div>
</td>
<td class="td_row_even">
<div class="td_row_even">The time period in seconds after which uspd will refresh the datamodel instances in a periodic manner. If configured to '0' then instance updater will be disabled. If not configured at all then after every 5 seconds datamodel instances will be refreshed.</div>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>

Binary file not shown.

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 330 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 329 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

124
bbfd/docs/css/colors.css Executable file
View file

@ -0,0 +1,124 @@
////
/// Copyright (c) 2016-2021 Martin Donath <martin.donath@squidfunk.com>
///
/// Permission is hereby granted, free of charge, to any person obtaining a
/// copy of this software and associated documentation files (the "Software"),
/// to deal in the Software without restriction, including without limitation
/// the rights to use, copy, modify, merge, publish, distribute, sublicense,
/// and/or sell copies of the Software, and to permit persons to whom the
/// Software is furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in
/// all copies or substantial portions of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
/// DEALINGS
////
// ----------------------------------------------------------------------------
// Rules
// ----------------------------------------------------------------------------
// Color variables
:root {
// Default color shades
--md-default-fg-color: hsla(0, 0%, 0%, 0.87);
--md-default-fg-color--light: hsla(0, 0%, 0%, 0.54);
--md-default-fg-color--lighter: hsla(0, 0%, 0%, 0.32);
--md-default-fg-color--lightest: hsla(0, 0%, 0%, 0.07);
--md-default-bg-color: hsla(0, 0%, 100%, 1);
--md-default-bg-color--light: hsla(0, 0%, 100%, 0.7);
--md-default-bg-color--lighter: hsla(0, 0%, 100%, 0.3);
--md-default-bg-color--lightest: hsla(0, 0%, 100%, 0.12);
// Primary color shades
--md-primary-fg-color: hsla(#{hex2hsl($clr-indigo-500)}, 1);
--md-primary-fg-color--light: hsla(#{hex2hsl($clr-indigo-400)}, 1);
--md-primary-fg-color--dark: hsla(#{hex2hsl($clr-indigo-700)}, 1);
--md-primary-bg-color: hsla(0, 0%, 100%, 1);
--md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);
// Accent color shades
--md-accent-fg-color: hsla(#{hex2hsl($clr-indigo-a200)}, 1);
--md-accent-fg-color--transparent: hsla(#{hex2hsl($clr-indigo-a200)}, 0.1);
--md-accent-bg-color: hsla(0, 0%, 100%, 1);
--md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);
// Light theme (default)
> * {
// Code color shades
--md-code-fg-color: hsla(200, 18%, 26%, 1);
--md-code-bg-color: hsla(0, 0%, 96%, 1);
// Code highlighting color shades
--md-code-hl-color: hsla(#{hex2hsl($clr-yellow-a200)}, 0.5);
--md-code-hl-number-color: hsla(0, 67%, 50%, 1);
--md-code-hl-special-color: hsla(340, 83%, 47%, 1);
--md-code-hl-function-color: hsla(291, 45%, 50%, 1);
--md-code-hl-constant-color: hsla(250, 63%, 60%, 1);
--md-code-hl-keyword-color: hsla(219, 54%, 51%, 1);
--md-code-hl-string-color: hsla(150, 63%, 30%, 1);
--md-code-hl-name-color: var(--md-code-fg-color);
--md-code-hl-operator-color: var(--md-default-fg-color--light);
--md-code-hl-punctuation-color: var(--md-default-fg-color--light);
--md-code-hl-comment-color: var(--md-default-fg-color--light);
--md-code-hl-generic-color: var(--md-default-fg-color--light);
--md-code-hl-variable-color: var(--md-default-fg-color--light);
// Typeset color shades
--md-typeset-color: var(--md-default-fg-color);
// Typeset `a` color shades
--md-typeset-a-color: var(--md-primary-fg-color);
// Typeset `mark` color shades
--md-typeset-mark-color: hsla(#{hex2hsl($clr-yellow-a200)}, 0.5);
// Typeset `del` and `ins` color shades
--md-typeset-del-color: hsla(6, 90%, 60%, 0.15);
--md-typeset-ins-color: hsla(150, 90%, 44%, 0.15);
// Typeset `kbd` color shades
--md-typeset-kbd-color: hsla(0, 0%, 98%, 1);
--md-typeset-kbd-accent-color: hsla(0, 100%, 100%, 1);
--md-typeset-kbd-border-color: hsla(0, 0%, 72%, 1);
// Typeset `table` color shades
--md-typeset-table-color: hsla(0, 0%, 0%, 0.12);
// Admonition color shades
--md-admonition-fg-color: var(--md-default-fg-color);
--md-admonition-bg-color: var(--md-default-bg-color);
// Footer color shades
--md-footer-fg-color: hsla(0, 0%, 100%, 1);
--md-footer-fg-color--light: hsla(0, 0%, 100%, 0.7);
--md-footer-fg-color--lighter: hsla(0, 0%, 100%, 0.3);
--md-footer-bg-color: hsla(0, 0%, 0%, 0.87);
--md-footer-bg-color--dark: hsla(0, 0%, 0%, 0.32);
}
// Shadow depth 1
--md-shadow-z1:
0 #{px2rem(4px)} #{px2rem(10px)} hsla(0, 0%, 0%, 0.05),
0 0 #{px2rem(1px)} hsla(0, 0%, 0%, 0.1);
// Shadow depth 2
--md-shadow-z2:
0 #{px2rem(4px)} #{px2rem(10px)} hsla(0, 0%, 0%, 0.1),
0 0 #{px2rem(1px)} hsla(0, 0%, 0%, 0.25);
// Shadow depth 3
--md-shadow-z3:
0 #{px2rem(4px)} #{px2rem(10px)} hsla(0, 0%, 0%, 0.2),
0 0 #{px2rem(1px)} hsla(0, 0%, 0%, 0.35);
}

2601
bbfd/docs/css/extra.css Executable file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Lager_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 460 84" style="enable-background:new 0 0 460 84;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<g>
<g>
<rect x="2.8" y="4.3" class="st0" width="16.7" height="76.1"/>
<path class="st0" d="M88.8,3C65.3,3,48.3,20.8,48.3,42.4v0.2c0,21.6,16.9,39.1,40.3,39.1c23.5,0,40.6-17.7,40.6-39.4v-0.2
C129.1,20.5,112.3,3,88.8,3z M111.6,42.6c0,13-9.4,23.7-22.8,23.7c-13.5,0-23-10.9-23-23.9v-0.2c0-13,9.4-23.7,22.8-23.7
c13.5,0,23.1,10.9,23.1,23.9v0.2H111.6z"/>
<path class="st0" d="M271.4,34.9c-13.2-3.4-16.4-5-16.4-10v-0.2c0-3.7,3.4-6.6,9.8-6.6s13,2.8,19.8,7.5l8.7-12.6
c-7.7-6.2-17.2-9.7-28.3-9.7c-15.5,0-26.6,9.1-26.6,22.9v0.2c0,15.1,9.9,19.4,25.2,23.3c12.7,3.3,15.3,5.4,15.3,9.7v0.2
c0,4.5-4.1,7.2-11,7.2c-8.7,0-15.9-3.6-22.7-9.2l-9.9,11.9c9.1,8.2,20.8,12.2,32.3,12.2c16.4,0,27.9-8.5,27.9-23.6v-0.2
C295.5,44.5,286.8,38.9,271.4,34.9z"/>
<polygon class="st0" points="347.3,34.9 329.1,4.3 309.5,4.3 338.8,50.4 338.8,80.4 355.5,80.4 355.5,50.1 384.8,4.3 365.7,4.3
"/>
<path class="st0" d="M432.2,34.9c-13.2-3.4-16.4-5-16.4-10v-0.2c0-3.7,3.4-6.6,9.8-6.6s13,2.8,19.8,7.5l8.7-12.6
c-7.7-6.2-17.2-9.7-28.3-9.7c-15.6,0-26.6,9.1-26.6,22.9v0.2c0,15.1,9.9,19.4,25.2,23.3c12.7,3.3,15.3,5.4,15.3,9.7v0.2
c0,4.5-4.1,7.2-11,7.2c-8.7,0-15.9-3.6-22.7-9.2l-9.9,11.9c9.1,8.2,20.8,12.2,32.3,12.2c16.4,0,27.9-8.5,27.9-23.6v-0.2
C456.3,44.5,447.6,38.9,432.2,34.9z"/>
<path class="st0" d="M186,4.3h-31.5v15.3h30c8.5,0,13.8,4.1,13.8,11.7v0.2c0,6.6-5,11.7-13.4,11.7h-30.4v37.2h16.9V58.3h12.9
c17.3,0,31.1-9.2,31.1-27.1V31C215.5,15.2,204.3,4.3,186,4.3z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

17
bbfd/docs/css/pdf.css Normal file
View file

@ -0,0 +1,17 @@
@page {
size: a4 portrait;
margin: 25mm 10mm 25mm 10mm;
counter-increment: page;
font-family: 'Madera', 'Lucida Sans Unicode', 'Lucida Grande', sans-serif;
white-space: pre;
color: grey;
@top-left {
content: '© 2022 IOPSYS';
}
@top-center {
content: string(chapter);
}
@top-right {
content: 'Page ' counter(page);
}
}

4
bbfd/docs/guide/.pages Normal file
View file

@ -0,0 +1,4 @@
title: "USP Daemon Developer Guide"
nav:
- "..."

View file

@ -0,0 +1,326 @@
# Third party data model integration
It is also possible to itegrate thrid party data model to the uspd to expose it to the ubus. To do so certain APIs in data model library needs to be implemented to make the data model compatible with uspd. APIs are described below.
## List of libbbf methods used in uspd to integrate third party data model
### Refernces
Deatils of bbf data model librabry can be found at [link](https://dev.iopsys.eu/iopsys/bbf/-/tree/devel/docs)
following are the libbbf methods used in uspd to access the data model defined in libbbf
``` dm_get_supported_dm
dm_entry_param_method
dm_entry_apply
dm_ctx_init
dm_ctx_init_sub
dm_ctx_clean
dm_ctx_clean_sub
set_bbfdatamodel_type
dm_entry_restart_services
dm_entry_revert_changes
dm_debug_browse_path
get_dm_type
dm_entry_manage_services
dm_config_ubus
```
## Methods
Description of the methods are given below
### dm_get_supported_dm
used to get the complete data model schema in one browse
```
int dm_get_supported_dm(struct dmctx *ctx, char *path, bool first_level, schema_type_t schema_type)
inputs
struct dmctx *ctx
pointer to struct dmctx strunture. The list of parameters will be updated in ctx.list_parameter. each node in the list is of type
struct dm_parameter which contains char *name (name of the parameter), char *data, char *type and char *additional_data;
the content of fields are as follows-
| Type | Data | Addtional Data |
|------------- |------------ |--------------------- |
|DMT_COMMAND |in parameters |command type(sync/async) |
| |out parameter | |
|DMT_EVENT |in parameters |NA |
|$ref(type) |writable(0/1) |unique keys |
| | | |
char * path
Complete object element path for which the data model schema is to be read. default path is "Device."
bool first_level
if true, read only paramters at next level to path
schem_type_t schema_type
enumeration to type of the schema to be get. Possible values are
ALL_SCHEMA - Complete schema
PARAM_ONLY - Parameters only
EVENT_ONLY - Events only
COMMAND_ONLY - Commands only
return
int fault
contains the fault code if API is not able to read the data model.
```
### dm_entry_param_method
used to read the data model based on the input given
```
int dm_entry_param_method(struct dmctx *ctx, int cmd, char *inparam, char *arg1, char *arg2)
inputs
struct dmctx *ctx
pointer to struct dmctx strunture. The list of parameter will be updated in ctx.list_parameter. each node in the list is of type
struct dm_parameter which contains char *name, char *data, char *type and char *additional_data;
the content of fields are updated based on the cmd and are as follows-
cmd | Name | Type | Data | Addtional Data |
|------------- |------------- |------------- |------------ |--------------------- |
|CMD_GET_VALUE |Parameter |$ref(type) |Value | NA |
|CMD_GET_NAME |Parameter |$ref(type) |writable(0/1) | NA |
|CMD_SET_VALUE |path | NA | NA | NA |
|CMD_ADD_OBJECT |path | NA | NA | NA |
|CMD_DEL_OBJECT |path | NA | NA | NA |
|CMD_USP_OPERATE |path | NA | NA | NA |
|CMD_USP_LIST_OPERATE |parameter |DMT_COMMAND |in/out parameters |cmd type (sync/async) |
|CMD_USP_LIST_EVENT |paramter |DMT_EVENT |in parameters |NA |
|CMD_GET_SCHEMA |paramter ||$ref(type) |writable(0/1) |unique keys |
|CMD_GET_INSTANCES |parameter | NA |NA |NA |
int cmd
command to API to tell how the data model is to be read, possible values are
CMD_GET_VALUE - Read the values of the parameters from data model
CMD_GET_NAME - Read the names of the parameters from data model
CMD_SET_VALUE - Set value of specified parameters in the data model
CMD_ADD_OBJECT - Add object in a multi instance parameter in the data model
CMD_DEL_OBJECT - Delete object from a multi instance parameter in the data model
CMD_USP_OPERATE - execute the specified command
CMD_USP_LIST_OPERATE - Read all the command type parameter from data model.
CMD_USP_LIST_EVENT - Read all the event type parameter from data model.
CMD_GET_SCHEMA - Read all the parameter type parameter from data model.
CMD_GET_INSTANCES - Read all the instance of multi instance parameter from data model.
char * inparam
Complete object element path for which the data model schema is to be read. default path is "Device."
char *arg1 and char *arg2
arguments specific to commands.
return
int fault
contains the fault code if API is not able to read the data model. returns 0 on success.
```
### dm_entry_apply
This method is called to apply the changes done to data model. used with set_value
```
int dm_entry_apply(struct dmctx *ctx, int cmd)
inputs
struct dmctx *ctx
pointer to struct dmctx strunture. The list of parameter will be updated in ctx.list_parameter
int cmd
command to API to tell how the data model is to be read, possible values are
CMD_SET_VALUE - Set value of specified parameters in the data model
char *arg1
return
int fault
contains the fault code if API is not able to read the data model.
```
### dm_ctx_init
This method is used to initialize the dmctx structure object to read the data model.
```
int dm_ctx_init(struct dmctx *ctx, unsigned int instance_mode)
inputs
struct dmctx *ctx
pointer to struct dmctx strunture to be initialized.
unsigned int instance_mode
instance mode of the dmctx to be set.
return
int fault
returns 0 on success.
```
### dm_ctx_init_sub
This method is an extension of dm_ctx_init method. only difference it only intializes dmctx structure object and does not intializes other resources used in reading data model
```
int dm_ctx_init_sub(struct dmctx *ctx, unsigned int instance_mode)
inputs
struct dmctx *ctx
pointer to struct dmctx strunture to be initialized.
unsigned int instance_mode
instance mode of the dmctx to be set.
return
int fault
returns 0 on success.
```
### dm_ctx_clean
This method is used to free the dmctx structure object and other resources post reading the data model.
```
int dm_ctx_clean(struct dmctx *ctx)
input
struct dmctx *ctx
pointer to struct dmctx strunture to be freed.
return
int fault
returns 0 on success.
```
### dm_ctx_clean_sub
This method is an extension of dm_ctx_clean method. only difference is it frees the dmctx structure and does not free other resources used in reading data model
```
int dm_ctx_clean_sub(struct dmctx *ctx)
input
struct dmctx *ctx
pointer to struct dmctx strunture to be freed.
return
int fault
returns 0 on success.
```
### set_bbfdatamodel_type
This method is used to set the type of protocol for which the data model is to be read
```
int set_bbfdatamodel_type(int bbf_type)
input
int cmd
the protocol through which the data model is to be read, possible values are
BBFDM_USP - Protocol USP
BBFDM_CWMP - Protocol CWMP
BBFDM_BOTH - Both USP and CWMP
return
int
returns 0 on success.
```
### dm_entry_restart_services
This method is used to restart the state of data model whenever its state is changed
```
int dm_entry_restart_services(void)
input
None
return
int
returns 0 on success.
```
### dm_entry_revert_changes
This method is used to restart the state of data model whenever its state is changed
```
int dm_entry_revert_changes(void)
input
None
return
int
returns 0 on success.
```
### dm_debug_browse_path
This method returns the last accessed path in the data model
```
int dm_debug_browse_path(char *buff, size_t len)
input
char *buff
pointer to the buffer in which the path will be returned
size_t len
length of the buffer
return
int
returns 0 on success.
```
### get_dm_type
This method is used to get the type assigned to the data model parameter.
```
int get_dm_type(char *dm_str)
input
char *dm_str
data model parameter type, eg. xsd:string, xsd:unit etc.
return
int
type of data model assigned to the object eg. DMT_STRING, DMT_UNINT etc.
```
### dm_entry_manage_services
This method is used to commit the changes made to the data model using either ubus call or uci commit.
```
int dm_entry_manage_services(struct blob_buf *bb, bool restart)
input
struct blob_buf *bb
pointer to the struct blob_buf object. contains all the packages updated.
bool restart
if true packages will be updated through ubus call.
if false packages will be updated through uci.
return
int - returns 0 on success.
```
### dm_entry_restart_services
this method is used to commit all the changes made to the data model.
```
int dm_entry_restart_services(void)
return
int - returns 0 on success.
```
### dm_config_ubus
This method is used to configure ubus.
```
void dm_config_ubus(struct ubus_context *ctx)
input
struct ubus_context *ctx
pointer to struct ubus_context object to be intialized.

View file

@ -0,0 +1,115 @@
# UBUS Errors
## Path syntax and possible error cases
Please note some error scenerios with the uspd.
1. The path parameter value must start with 'Device.'. The command below doesn't have Device before path "Users.User."
```console
root@iopsys:~# ubus call usp.raw get '{"path":"Users.User."}'
{
"fault": 7026
}
```
2. The path parameter must end with a '.' if the path element is not a leaf element e.g.,
Note that first two commands doesn't end with a '.' while the command with Alias is correct, due to Alias
being the leaf element. To find correct schema path user can check with dump_schema option.
```console
root@iopsys:~#
root@iopsys:~# ubus call usp get '{"path":"Device.Users.User.4"}'
{
"fault": 7026
}
root@iopsys:~#
root@iopsys:~# ubus call usp get '{"path":"Device.Users.User"}'
{
"fault": 9005
}
root@iopsys:~#
root@iopsys:~# ubus call usp get '{"path":"Device.Users.User.*"}'
{
"fault": 7026
}
root@iopsys:~#
root@iopsys:~# ubus call usp get '{"path":"Device.Users.User.4.Alias"}'
{
"Alias": "cpe-4"
}
```
3. In path parameter value below, note that, the first search expression 'Type==Normal' is string which should be used as : Type==\"Normal\"
```console
root@iopsys:~# ubus call usp get '{"path":"Device.IP.Interface.[Type==Normal].IPv4Address.[AddressingType==\"Static\"].IPAddress"}'
{
"fault": 7008
}
root@iopsys:~#
root@iopsys:~# ubus call usp get '{"path":"Device.IP.Interface.[Type==\"Normal\"].IPv4Address.[AddressingType==\"Static\"].IPAddress"}'
{
"Interface": [
{
"IPv4Address": [
{
"IPAddress": "2.0.0.3"
}
]
}
]
}
```
4. The path parameter value must not have an empty search expression
```console
root@iopsys:~# ubus call usp get '{"path":"Device.Users.User.[]."}'
{
"fault": 9005
}
```
5. The path parameter value must use proper '.' separated path search expression. Note that a '.' is missing between User and *
```console
root@iopsys:~# ubus call usp get '{"path":"Device.Users.User*."}'
{
"fault": 7026
}
```
6. The path parameter value must be a valid path schema, in example below SSID is used which is invalid schema element for Device.Users.User.{i}.
```console
root@iopsys:~# ubus call usp get '{"path":"Device.Users.User.1.SSID"}'
{
"fault": 7026
}
```
7. Please note that in search expression, string comparison only work with "==" or "!=". Whereas in command below its =
```console
root@iopsys:~# ubus call usp get '{"path":"Device.Users.User.[Username=\"user\"].Alias"}'
{
"fault": 7008
}
```
#### Errors Codes
| Error Code | Meaning |
|------------|--------------------------------------------------------------|
| 7003 | Message failed due to an internal error. |
| 7004 | Message failed due to invalid values in the request elements and/or failure to update one or more parameters during Add or Set requests. |
| 7005 | Message failed due to memory or processing limitations. |
| 7008 | Requested path was invalid or a reference was invalid. |
| 7010 | Requested Path Name associated with this ParamError did not match any instantiated parameters. |
| 7011 | Unable to convert string value to correct data type. |
| 7012 | Out of range or invalid enumeration. |
| 7022 | Command failed to operate. |
| 7026 | Path is not present in the data model schema. |

View file

@ -0,0 +1,205 @@
# UBUS examples
```console
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 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 get '{"path":"Device.Users.User.*.Username"}'
{
"User": [
{
"Username": "user"
},
{
"Username": "support"
},
{
"Username": "admin"
}
]
}
root@iopsys:~# ubus call usp.raw set '{"path":"Device.IP.Diagnostics.IPPing.DiagnosticsState", "value":"Requested", "proto":"cwmp"}'
{
"parameters": [
{
"path": "Device.IP.Diagnostics.IPPing.DiagnosticsState",
"status": true,
}
]
}
root@iopsys:~# ubus call usp.raw set '{"path":"Device.Users.User.2.Username", "value":"abc", "proto":"cwmp"}'
{
"parameters": [
{
"path": "Device.Users.User.2.Username",
"status": true,
}
]
}
root@iopsys:~# ubus call usp.raw set '{"path":"Device.Users.User.2.Username", "value":"abc", "proto":"usp"}'
{
"parameters": [
{
"path": "Device.Users.User.2.Username",
"status": true
}
]
}
root@iopsys:~# ubus call usp.raw set '{"path":"Device.Users.User.2.Username", "value":"abc"}'
{
"parameters": [
{
"path": "Device.Users.User.2.Username",
"status": true
}
]
}
root@iopsys:~#
root@iopsys:~# ubus call usp set '{"path":"Device.Users.User.[Username==\"xyz1\"].", "values":{"Username":"xyz1", "Enable":"dummy", "Password":"yzssssx"}, "proto":"usp"}'
{
"parameters": [
{
"path": "Device.Users.User.2.Username",
"status": true
},
{
"path": "Device.Users.User.2.Enable",
"status": false,
"fault": 7012
},
{
"path": "Device.Users.User.2.Password",
"status": true
}
]
}
root@iopsys:~#
root@iopsys:~# ubus call usp.raw setm_values '{"pv_tuple":[{"path":"Device.Users.User.2.Username", "value":"xzzz"}, {"path":"Device.Users.User.2.RemoteAccessCapable", "value":"1"}, {"path":"Device.Users.User.2.Password", "value":"zzzzzzz"}], "proto":"usp"}'
{
"parameters": [
{
"path": "Device.Users.User.2.Username",
"status": true
},
{
"path": "Device.Users.User.2.RemoteAccessCapable",
"status": false,
"fault": 7012
},
{
"path": "Device.Users.User.2.Password",
"status": true
}
]
}
```
- For more info on the usp ubus API see [link](../api/ubus/usp.md)
- For more info on the usp.raw ubus API see [link](../api/ubus/usp.raw.md)

View file

@ -0,0 +1,874 @@
# UBUS Methods
`uspd` needs to be started on startup after `ubusd`, as it exposes the data-model
objects over `ubus`. By default(when granularity is not set in `uci`), `uspd` registers
below two namespaces with `ubus`.
```console
root@iopsys:~# ubus list |grep usp
usp
usp.raw
```
`usp` namespace is to provide the output as required by `End User` or in pretty format,
whereas `usp.raw` namespace is to provide output in raw JSON format for easy API integration,
which can be used by other USP front-end applications(like: `obuspa`, `icwmp`).
`usp` namespace has fewer methods defined to provide a simple interface to `end users`,
whereas `usp.raw` has more features/methods to provide more customization options.
Default namespace with functionalities:
```console
root@iopsys:~# ubus -v list usp
'usp' @78f3eaca
"list_operate":{}
"get":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"object_names":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"instances":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"validate":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"set":{"path":"String","value":"String","values":"Table","proto":"String","instance_mode":"Integer"}
"operate":{"path":"String","action":"String","input":"Table","proto":"String","instance_mode":"Integer"}
"add_object":{"path":"String","proto":"String","instance_mode":"Integer"}
"del_object":{"path":"String","proto":"String","instance_mode":"Integer"}
root@iopsys:~#
root@iopsys:~# ubus -v list usp.raw
'usp.raw' @08a13407
"dump_schema":{}
"list_operate":{}
"list_events":{}
"get":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"getm_values":{"paths":"Array","proto":"String","next-level":"Boolean","instance_mode":"Integer"}
"getm_names":{"paths":"Array","proto":"String","next-level":"Boolean","instance_mode":"Integer"}
"object_names":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"instances":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"validate":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"transaction_start":{"app":"String","max_timeout":"Integer"}
"set":{"path":"String","value":"String","values":"Table","proto":"String","instance_mode":"Integer","transaction_id":"Integer"}
"operate":{"path":"String","action":"String","input":"Table","proto":"String","instance_mode":"Integer"}
"add_object":{"path":"String","proto":"String","instance_mode":"Integer","transaction_id":"Integer"}
"del_object":{"path":"String","proto":"String","instance_mode":"Integer","transaction_id":"Integer"}
"setm_values":{"pv_tuple":"Array","proto":"String","instance_mode":"Integer","transaction_id":"Integer"}
"transaction_commit":{"transaction_id":"Integer"}
"transaction_abort":{"transaction_id":"Integer"}
"transaction_status":{"transaction_id":"Integer"}
"notify_event":{"name":"String","input":"Table"}
root@iopsys:~#
```
> Note1: `proto` in each method specify the data-model prototype('cwmp', 'usp') to use, if not provided default data-model will be used.
> Note2: `instance_mode` could be 0 or 1, for instance number, instance alias respectively.
> Note3: `next-level` true means only get next level objects and false means get all objects recursively
> Note4: `maxdepth` is measured on max number of .(Dot) present in object name
> Note5: `key` is used specifically for cwmp param_key
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.
## Granularity
Granularity feature is basically exposes the same USP functionality by registering
additional ubus namespaces to reduce the `path` length in ubus parameter.
It is the number of levels(Dots) up to which we want to shorten the length.
Ex:
- When Granularity is set to 1, exposed ubus namespaces are
```console
root@iopsys:~# ubus list|grep usp
usp
usp.Device.
usp.raw
```
- When Granularity is set to 2, exposed ubus namespaces are
```console
root@iopsys:~# ubus list|grep usp
usp
usp.Device.
usp.Device.Bridging.
usp.Device.DHCPv4.
usp.Device.DHCPv6.
usp.Device.DNS.
usp.Device.DeviceInfo.
usp.Device.DynamicDNS.
usp.Device.Ethernet.
usp.Device.Firewall.
usp.Device.Hosts.
usp.Device.IP.
usp.raw
root@iopsys:~#
```
These granular ubus objects provides the same functionality as of `usp` ubus namespace
```console
root@iopsys:~# ubus -v list usp.Device.WiFi.
'usp.Device.WiFi.' @6fd43aca
"list_operate":{}
"get":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"object_names":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"instances":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"validate":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"set":{"path":"String","value":"String","values":"Table","proto":"String","instance_mode":"Integer"}
"operate":{"path":"String","action":"String","input":"Table","proto":"String","instance_mode":"Integer"}
"add_object":{"path":"String","proto":"String","instance_mode":"Integer"}
"del_object":{"path":"String","proto":"String","instance_mode":"Integer"}
root@iopsys:~#
```
Registered method can be called with appropriate parameters, like:
```console
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
}
}
root@iopsys:~#
```
## Overview
`uspd` provides below commands in pretty(usp) or raw(usp.raw) formats, some methods only available for API integration in usp.raw namespace:
- Get
- Get multiple values
- Get multiple names
- Set
- Operate
- Add object
- Delete object
- Object names
- Instances
- Validate
- List operate
- Dump schema
- Set multiple values
- Transaction start
- Transaction status
- Transaction commit
- Transaction abort
- List supported usp events
- Send notification for an event
It also provide a granularity layer which can be configured using uci parameter and provide additional ubus objects.
### Get
API to query the value of a specific object.
```console
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
}
}
root@iopsys:~#
root@iopsys:~# ubus call usp get '{"path":"Device.IP.Diagnostics.", "proto":"cwmp"}'
{
"Diagnostics": {
"DownloadDiagnostics": {
"BOMTime": "0",
"DSCP": 0,
"DiagnosticsState": "None",
"DownloadDiagnosticMaxConnections": 1,
"TotalBytesSent": 0,
"TotalBytesSentUnderFullLoading": 0
},
"IPPing": {
"AverageResponseTime": 0,
"AverageResponseTimeDetailed": 0,
"DSCP": 0,
"DataBlockSize": 64,
"ProtocolVersion": "Any",
"SuccessCount": 0,
"Timeout": 1000
},
"IPv4DownloadDiagnosticsSupported": true,
"IPv4PingSupported": true,
"IPv4ServerSelectionDiagnosticsSupported": true,
"IPv6UDPEchoDiagnosticsSupported": true,
"IPv6UploadDiagnosticsSupported": true,
}
}
}
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
}
}
root@iopsys:~#
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"
}
]
}
```
- For more info on the `usp` ubus API see [link](../api/ubus/usp.md#get)
- For more info on the `usp.raw` ubus API see [link](../api/ubus/usp.raw.md#get)
### Get multiple values
API to get values of multiple objects at once, object name must be provided in `paths` parameter array as below.
> Note: This method is only available in `usp.raw` namespace.
```console
root@iopsys:~# ubus call usp.raw getm_values '{"paths":["Device.Users.User.1.Username","Device.DeviceInfo.SerialNumber"]}'
{
"parameters": [
{
"parameter": "Device.Users.User.1.Username",
"value": "user",
"type": "xsd:string"
},
{
"parameter": "Device.DeviceInfo.SerialNumber",
"value": "E40A24H185027824",
"type": "xsd:string"
}
]
}
```
### Get multiple objects
API to get multiple objects from multiple paths at once.
> Note: This method only available in `usp.raw` namespace
```console
root@iopsys:~# ubus call usp.raw getm_names '{"paths":["Device.Users.User.1.","Device.DeviceInfo.SerialNumber"]}'
{
"parameters": [
{
"parameter": "Device.Users.User.1.",
"value": "1",
"type": "xsd:object"
},
{
"parameter": "Device.Users.User.1.Alias",
"value": "1",
"type": "xsd:string"
},
{
"parameter": "Device.Users.User.1.Enable",
"value": "1",
"type": "xsd:boolean"
},
{
"parameter": "Device.Users.User.1.Language",
"value": "1",
"type": "xsd:string"
},
{
"parameter": "Device.Users.User.1.Password",
"value": "1",
"type": "xsd:string"
},
{
"parameter": "Device.Users.User.1.RemoteAccessCapable",
"value": "1",
"type": "xsd:boolean"
},
{
"parameter": "Device.Users.User.1.Username",
"value": "1",
"type": "xsd:string"
},
{
"parameter": "Device.DeviceInfo.SerialNumber",
"value": "0",
"type": "xsd:string"
}
]
}
root@iopsys:~#
```
### Set
API to set value to specific object, object name must be provided in `path` parameter and value to be set in `value` option.
> Note 1: In usp namespace, set method creates a internal transaction before actually setting the value. After set operation it automatically commits the transaction.
> Note 2: In usp.raw namespace, set method requires a transaction to be created before calling the set method. Please refer to transaction APIs for more details.
```console
root@iopsys:/tmp# ubus call usp set '{"path":"Device.WiFi.SSID.[BSSID==\"00:22:07:ae:ee:03\"].SSID", "value":"test-2g"}'
{
"status": true
}
root@iopsys:/tmp# ubus call usp.raw set '{"path":"Device.WiFi.SSID.[BSSID==\"00:22:07:ae:ee:03\"].SSID", "value":"test-2g", "transaction_id":12345}'
{
"status": true
}
root@iopsys:~# ubus call usp get '{"path":"Device.WiFi.SSID.[BSSID==\"00:22:07:ae:ee:03\"].SSID"}'
{
"SSID": [
{
"SSID": "test-2g"
}
]
}
```
- For more info on the `usp` ubus API see [link](../api/ubus/usp.md#set)
- For more info on the `usp.raw` ubus API see [link](../api/ubus/usp.raw.md#set)
### Operate
API to run operate/diagnostics commands as defined in TR-369
```console
root@iopsys:~# ubus call usp operate '{"path":"Device.IP.Diagnostics.", "action":"IPPing()","input":{"Host":"iopsys.eu"}}'
{
"Results": [
{
"path": "Device.IP.Diagnostics.IPPing",
"result": [
{
"AverageResponseTime": 0,
"AverageResponseTimeDetailed": 0,
"FailureCount": 3,
"MaximumResponseTime": 0,
"MaximumResponseTimeDetailed": 0,
"MinimumResponseTime": 9999,
"MinimumResponseTimeDetailed": 999999999,
"SuccessCount": 0
}
]
}
]
}
root@iopsys:~# ubus call usp.raw operate '{"path":"Device.IP.Diagnostics.", "action":"IPPing()","input":{"Host":"iopsys.eu"}}'
{
"Results": [
{
"path": "Device.IP.Diagnostics.IPPing",
"parameters": [
{
"parameter": "AverageResponseTime",
"value": "0",
"type": "xsd:unsignedInt"
},
{
"parameter": "AverageResponseTimeDetailed",
"value": "0",
"type": "xsd:unsignedInt"
},
{
"parameter": "FailureCount",
"value": "3",
"type": "xsd:unsignedInt"
},
{
}
]
}
root@iopsys:~# ubus call usp operate '{"path":"Device.IP.Interface.[Name==\"wan\"].", "action":"Reset()"}'
{
"Results": [
{
"path": "Device.IP.Interface.2.Reset",
"result": [
{
}
]
}
]
}
root@iopsys:~# ubus call usp.raw operate '{"path":"Device.IP.Interface.[Name==\"wan\"].", "action":"Reset()"}'
{
"Results": [
{
"path": "Device.IP.Interface.2.Reset",
"parameters": [
]
}
]
}
```
- For more info on the `usp` ubus API see [link](../api/ubus/usp.md#operate)
- For more info on the `usp.raw` ubus API see [link](../api/ubus/usp.raw.md#operate)
### Add object
API to add new objects in multi-instance object
> Note 1: In usp namespace, `add_object` method creates a internal transaction before actually setting the value. After set operation it automatically commits the transaction.
> Note 2: In usp.raw namespace, `add_object` method requires a transaction to be created before calling the set method. Please refer to transaction APIs for more details.
```console
root@iopsys:~# ubus call usp add_object '{"path":"Device.Users.User."}'
{
"parameters": [
{
"parameter": "Device.Users.User.",
"status": true,
"instance": "4"
}
]
}
root@iopsys:~# ubus call usp.raw add_object '{"path":"Device.Users.User.", "transaction_id":12345}'
{
"parameters": [
{
"parameter": "Device.Users.User.",
"status": true,
"instance": "5"
}
]
}
```
- For more info on the `usp` ubus API see [link](../api/ubus/usp.md#add_object)
- For more info on the `usp.raw` ubus API see [link](../api/ubus/usp.raw.md#add_object)
### Delete object
API to delete an existing object from multi-instance object
> Note 1: In usp namespace, `del_object` method creates a internal transaction before actually setting the value. After set operation it automatically commits the transaction.
> Note 2: In usp.raw namespace, `del_object` method requires a transaction to be created before calling the set method. Please refer to transaction APIs for more details.
```console
root@iopsys:/tmp# ubus call usp del_object '{"path":"Device.Users.User.4"}'
{
"parameters": [
{
"parameter": "Device.Users.User.4.",
"status": true
}
]
}
root@iopsys:/tmp# ubus call usp.raw del_object '{"path":"Device.Users.User.3", "transaction_id": 12345}'
{
"parameters": [
{
"parameter": "Device.Users.User.3.",
"status": true
}
]
}
```
- For more info on the `usp` ubus API see [link](../api/ubus/usp.md#del_object)
- For more info on the `usp.raw` ubus API see [link](../api/ubus/usp.raw.md#del_object)
### Object names
API to get the available list of object names.
```console
root@iopsys:~# ubus call usp object_names '{"path":"Device.DeviceInfo.SerialNumber"}'
{
"parameters": [
{
"parameter": "Device.DeviceInfo.SerialNumber",
"writable": "0",
"type": "xsd:string"
}
]
}
root@iopsys:~#
root@iopsys:~# ubus call usp.raw object_names '{"path":"Device.Users.User.1."}'
{
"parameters": [
{
"parameter": "Device.Users.User.1.",
"writable": "1",
"type": "xsd:object"
},
{
"parameter": "Device.Users.User.1.Alias",
"writable": "1",
"type": "xsd:string"
},
{
"parameter": "Device.Users.User.1.Enable",
"writable": "1",
"type": "xsd:boolean"
},
{
"parameter": "Device.Users.User.1.Language",
"writable": "1",
"type": "xsd:string"
},
{
"parameter": "Device.Users.User.1.Password",
"writable": "1",
"type": "xsd:string"
},
{
"parameter": "Device.Users.User.1.RemoteAccessCapable",
"writable": "1",
"type": "xsd:boolean"
},
{
"parameter": "Device.Users.User.1.Username",
"writable": "1",
"type": "xsd:string"
}
]
}
root@iopsys:~#
```
- For more info on the `usp` ubus API see [link](../api/ubus/usp.md)
- For more info on the `usp.raw` ubus API see [link](../api/ubus/usp.raw.md)
### Instances
API to get the available instances of an multi-instance object. USP Instances method returns the registered instances.
```console
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."
}
]
}
```
- For more info on the `usp` ubus API see [link](../api/ubus/usp.md#instances)
- For more info on the `usp.raw` ubus API see [link](../api/ubus/usp.raw.md#instances)
### Validate
API to validate a object in data-model. This api shall simply return the object name
if present in data-model objects or generates a fault if object not available in
data-model.
```console
root@iopsys:~# ubus call usp validate '{"path":"Device.DeviceInfo."}'
{
"parameter": "Device.DeviceInfo"
}
root@iopsys:~# ubus call usp.raw validate '{"path":"invalid.object"}'
{
"fault": 9005
}
```
### List Operate
API to list all available operate commands with supported input and output parameters
```console
root@iopsys:~# ubus call usp list_operate
{
"parameters": [
{
"parameter": "Device.DHCPv4.Client.{i}.Renew()",
"type": "sync"
},
{
"parameter": "Device.DNS.Diagnostics.NSLookupDiagnostics()",
"type": "async",
"in": [
"HostName",
"Interface",
"DNSServer",
"Timeout",
"NumberOfRepetitions"
],
"out": [
"Status",
"AnswerType",
"HostNameReturned",
"IPAddresses",
"DNSServerIP",
"ResponseTime"
]
},
{
"parameter": "Device.DeviceInfo.FirmwareImage.{i}.Activate()",
"type": "async"
},
{
"parameter": "Device.IP.Diagnostics.IPPing()",
"type": "async",
"in": [
"Interface",
"ProtocolVersion",
"Host",
"NumberOfRepetitions",
"Timeout",
"DataBlockSize",
"DSCP"
],
"out": [
"Status",
"IPAddressUsed",
"SuccessCount",
"FailureCount",
"AverageResponseTime",
"MinimumResponseTime",
"MaximumResponseTime",
"AverageResponseTimeDetailed",
"MinimumResponseTimeDetailed",
"MaximumResponseTimeDetailed"
]
},
{
```
### Dump schema
API to dump all registered schema paths,
```console
root@iopsys:~# ubus call usp dump_schema
{
"parameters": [
{
"parameter": "Device.ATM.Link.{i}.",
"writable": "1",
"type": "xsd:object"
},
{
"parameter": "Device.ATM.Link.{i}.Alias",
"writable": "1",
"type": "xsd:string"
},
{
"parameter": "Device.ATM.Link.{i}.DestinationAddress",
"writable": "1",
"type": "xsd:string"
},
{
"parameter": "Device.ATM.Link.{i}.Enable",
"writable": "1",
"type": "xsd:boolean"
},
{
```
### Set multiple values
API to set value of multiple parameters at once.
> Note: This method only available in usp.raw namespace
```console
root@iopsys:~# ubus call usp.raw setm_values '{"pv_tuple":[{"path":"Device.Users.User.2.Username", "value":"xzzz"}, {"path":"Device.Users.User.2.RemoteAccessCapable", "value":"true"}, {"path":"Device.Users.User.2.Password", "value":"zzzzzzz"}], "proto":"usp", "transaction_id":1249743667}'
{
"status": true
}
root@iopsys:~#
root@iopsys:~#
root@iopsys:~# ubus call usp.raw setm_values '{"pv_tuple":[{"path":"Device.Users.User.2.Username", "value":"xzzz"}, {"path":"Device.Users.User.2.RemoteAccessCapable", "value":"dummy"}, {"path":"Device.Users.User.2.Password", "value":"zzzzzzz"}], "proto":"usp", "transaction_id":738335779}'
{
"parameters": [
{
"path": "Device.Users.User.2.RemoteAccessCapable",
"status": false,
"fault": 7012
}
]
}
```
### Transaction start
To support the `allow_partial` and `required` parameters in Add/Del/Set operation as defined in TR-369, transaction_* APIs introduced.
It basically works around data-model objects which has dependent uci config files for each CUD operation.
API to start a transaction in usp.raw namespace for add/del/set operations in usp.raw namespace
> Note: This API only available in usp.raw namespace
```console
root@iopsys:~# ubus call usp.raw transaction_start '{"app":"test"}'
{
"status": true,
"transaction_id": 955001092
}
```
It's sometime required to have a per transaction timeout, which can be defined along with transaction_start
```bash
root@4949e4da3d27:~# ubus call usp.raw transaction_start '{"app":"test", "max_timeout":5000}'
{
"status": true,
"transaction_id": 491944812
}
```
> Note: max_timeout is time in milliseconds, its an optional input argument if not provided, uci default (uspd.usp.transaction_timeout) is used which is defined in seconds
> If uci option uspd.usp.transaction_timeout not set than a default 10 second timeout is used for the transactions.
### Get status of a transaction
API to get details and check status of a transaction id in usp.raw namespace
```console
root@iopsys:~# ubus call usp.raw transaction_status '{"transaction_id":955001092}'
{
"app": "test",
"status": "on-going",
"remaining_time": 634
}
root@iopsys:~#
root@iopsys:~# ubus call usp.raw transaction_status '{"transaction_id":869066287}'
{
"status": "not-exists"
}
root@iopsys:~#
```
### Transaction commit
API to commit an on-going transaction, on calling this api, uci changes shall
be committed and required services shall be restarted.
```console
root@iopsys:~# ubus call usp.raw transaction_commit '{"transaction_id":955001092}'
{
"status": true
}
root@iopsys:~#
```
### Transaction abort
API to abort an on-going transaction, on calling this api, staged changes in
uci shall be reverted to earlier values.
```console
root@iopsys:~# ubus call usp.raw transaction_abort '{"transaction_id":955001092}'
{
"status": true
}
root@iopsys:~#
```
### List supported usp events
API to list down the data-model events for usp notification supported by uspd.
```console
root@iopsys:~# ubus call usp.raw list_events
{
"parameters": [
{
"parameter": "Device.LocalAgent.TransferComplete!",
"in": [
"Command",
"CommandKey",
"Requestor",
"TransferType",
"Affected",
"TransferURL",
"StartTime",
"CompleteTime",
"FaultCode",
"FaultString"
]
}
]
}
```

View file

@ -0,0 +1,20 @@
# Parallel UBUS calls
All `operate` operation and `get` operation with a depth up to 'USP_SUBPROCESS_DEPTH(2)'
runs in a parallel subprocess to avoid blocking the next call.
```console
root@iopsys:~# time ubus call usp.raw get '{"path":"Device."}' >/dev/null &
root@iopsys:~# time ubus call usp.raw get '{"path":"Device.Users."}' >/dev/null
real 0m 0.07s
user 0m 0.00s
sys 0m 0.00s
root@iopsys:~#
real 0m 1.86s
user 0m 0.05s
sys 0m 0.00s
[1]+ Done time ubus call usp.raw get "{\"path\":\"Device.\"}" >/dev/null
root@iopsys:~#
```

90
bbfd/docs/mkdocs.yml Executable file
View file

@ -0,0 +1,90 @@
site_name: Documentation Instructions
site_url: https://docs.iopsys.se/portal2/uspd/
edit_uri: "https://dev.iopsys.eu/docs/portal2/uspd"
site_description: IOWRT Technical Documentation
site_author: IOPSYS
docs_dir: '.'
site_dir: 'site'
theme:
name: material
include_sidebar: true
highlightjs: true
hljs_languages:
- yaml
- python
language: en
font:
text: Roboto
code: Roboto Mono
logo: iopsys-white.svg
icon:
logo: icon.png
repo: fontawesome/brands/gitlab
extra:
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/squidfunk
features:
- toc.autohide
- navigation.tabs
- navigation.tabs.sticky
- navigation.top
- navigation.tracking
- navigation.expand
palette:
# Primary color used for header, sidebar and links, default: indigo
primary: black
# Accent color for highlighting user interaction, default: indigo
accent: deep orange
extra_css:
- css/extra.css
- https://unpkg.com/mermaid@8.5.1/dist/mermaid.css
- https://cdn.jsdelivr.net/gh/fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css
extra_javascript:
- https://unpkg.com/mermaid/dist/mermaid.min.js
- https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.min.js
- https://cdn.jsdelivr.net/gh/fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js
markdown_extensions:
- meta
- admonition
- pymdownx.arithmatex
- pymdownx.betterem:
smart_enable: all
- pymdownx.caret
- pymdownx.critic
- pymdownx.details
- pymdownx.emoji:
emoji_index: !!python/name:materialx.emoji.twemoji
emoji_generator: !!python/name:materialx.emoji.to_svg
- pymdownx.inlinehilite
- pymdownx.magiclink
- pymdownx.mark
- pymdownx.smartsymbols
- pymdownx.tasklist:
custom_checkbox: true
- pymdownx.tilde
- pymdownx.superfences:
# make exceptions to highlighting of code:
custom_fences:
- name: mermaid
class: mermaid
format: !!python/name:mermaid2.fence_mermaid
- fontawesome_markdown
plugins:
- search:
lang:
- en
separator: '[\s\-\.]+'
- awesome-pages:
collapse_single_pages: true
- mermaid2
- section-index

10
bbfd/docs/preview.sh Executable file
View file

@ -0,0 +1,10 @@
#!/usr/bin/env bash
# Copy README.md as index.md and change links
pip install -r requirements.txt
# Copy README.md as index.md and change links
sed -r -e 's![\.\/]*docs[\/]*!./!g' ../README.md > index.md
# Start mkdocs local server
mkdocs serve -f mkdocs.yml

7
bbfd/docs/requirements.txt Executable file
View file

@ -0,0 +1,7 @@
mkdocs
mkdocs-material
mkdocs-awesome-pages-plugin
mkdocs-section-index
fontawesome_markdown
mkdocs-print-site-plugin
mkdocs-mermaid2-plugin

4
bbfd/docs/spec/.pages Normal file
View file

@ -0,0 +1,4 @@
title: "USP Daemon Specification"
nav:
- "..."

View file

@ -0,0 +1,336 @@
# Function Specification
The scope of uspd is to expose the datamodel provided by libbbfdm APIs over ubus, along with provididng the features deinfed by requirements R-ARC.7 to R-ARC.12 of USP protocol.
```
root@iopsys:~# ubus -v list usp
'usp' @232da280
"list_operate":{}
"get_supported_dm":{"path":"String","next-level":"Boolean","schema_type":"Integer"}
"get":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"object_names":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"instances":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"validate":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"set":{"path":"String","value":"String","values":"Table","proto":"String","instance_mode":"Integer"}
"operate":{"path":"String","action":"String","input":"Table","proto":"String","instance_mode":"Integer"}
"add_object":{"path":"String","proto":"String","instance_mode":"Integer"}
"del_object":{"path":"String","proto":"String","instance_mode":"Integer"}
root@iopsys:~#
root@iopsys:~# ubus -v list usp.raw
'usp.raw' @4c9c3c6e
"dump_schema":{}
"list_operate":{}
"list_events":{}
"get_supported_dm":{"path":"String","next-level":"Boolean","schema_type":"Integer"}
"get":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"getm_values":{"paths":"Array","proto":"String","next-level":"Boolean","instance_mode":"Integer"}
"getm_names":{"paths":"Array","proto":"String","next-level":"Boolean","instance_mode":"Integer"}
"object_names":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"instances":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"validate":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"transaction_start":{"app":"String"}
"set":{"path":"String","value":"String","values":"Table","proto":"String","instance_mode":"Integer","transaction_id":"Integer"}
"operate":{"path":"String","action":"String","input":"Table","proto":"String","instance_mode":"Integer"}
"add_object":{"path":"String","proto":"String","instance_mode":"Integer","transaction_id":"Integer"}
"del_object":{"path":"String","proto":"String","instance_mode":"Integer","transaction_id":"Integer"}
"setm_values":{"pv_tuple":"Array","proto":"String","instance_mode":"Integer","transaction_id":"Integer"}
"transaction_commit":{"transaction_id":"Integer","restart_services":"Boolean"}
"transaction_abort":{"transaction_id":"Integer"}
"transaction_status":{"transaction_id":"Integer"}
"notify_event":{"name":"String","input":"Table"}
```
# Contents
* [usp](#usp)
* [usp.raw](#uspraw)
## APIs
uspd publishes two different types UBUS objects, `usp`, `usp.raw`. USP object is meant for end users/CLI users
usp.raw is meant for API integration
usp.raw has more ganureality in the function to match the third party apllication requiremtns whereas usp obect take cares of cutomization internally to provide simple interface for the end users.
### usp
An object that publishes device information.
````bash
"list_operate":{}
"get_supported_dm":{"path":"String","next-level":"Boolean","schema_type":"Integer"}
"get":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"object_names":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"instances":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"validate":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"set":{"path":"String","value":"String","values":"Table","proto":"String","instance_mode":"Integer"}
"operate":{"path":"String","action":"String","input":"Table","proto":"String","instance_mode":"Integer"}
"add_object":{"path":"String","proto":"String","instance_mode":"Integer"}
"del_object":{"path":"String","proto":"String","instance_mode":"Integer"}
````
| Method |Function ID |
| :--- | :--- |
| [list_operate](#list_operate) | 1 |
| [get_supported_dm](#get_supported_dm) | 2 |
| [get](#get) | 3 |
| [object_names](#object_names) | 4 |
| [instances](#instances) | 5 |
| [validate](#validate) | 6 |
| [set](#set) | 7 |
| [operate](#operate) | 8 |
| [add_object](#add_object) | 9 |
| [del_object](#del_object) | 10 |
#### Methods
Below methods are supported in usp methods. Method description of the `usp` object in succeding paragraphs .
##### list_operate
Exposes various sync and async operations supported by datamodel. e.g., IPPing(), NeighbourDiagnostics() etc.
* [list_operate documentation](../api/ubus/usp.md#list_operate)
##### get_supported_dm
This method exposes the all type of objects supported in the data model in one browse. it will expose name, type, cmd_type and writable properties of the object depending on the type of the parameters present in the data model.
* [get_supported_dm documentation](../api/ubus/usp.md#get_supported_dm)
##### get
This method exposes information regarding various schema parameters registered in the data model.
* [get documentation](../api/ubus/usp.md#get)
##### object_names
This method exposes names of the object registered in the data model.
* [object_names documentation](../api/ubus/usp.md#object_names)
##### instances
This method exposes information of all instances of various objects registered in the data model for specified schema path.
* [disconnect documentation](../api/ubus/usp.md#instances)
##### validate
This method validates whether the path provided is valid as per registerd schema paths.
* [validate documentation](../api/ubus/usp.md#validate)
##### set
This method is used to set information of various registered schema parameters.
* [set documentation](../api/ubus/usp.md#set)
##### operate
This method is used to execute various sync/async operations e.g., IPPing(), NeighbourDiagnostics() etc.
* [operate documentation](../api/ubus/usp.md#operate)
##### add_object
This method is used to add an object to specified multi instance object in registered schema.
* [add_object neighbor documentation](../api/ubus/usp.md#add_object)
##### del_object
This method is used to delete an object from specified multi instance object in registered schema.
* [del_object documentation](../api/ubus/usp.md#del_object)
### usp.raw
Object for device functionality. One object per device will be published to
ubus.
````bash
"dump_schema":{}
"list_operate":{}
"list_events":{}
"get_supported_dm":{"path":"String","next-level":"Boolean","schema_type":"Integer"}
"get":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"getm_values":{"paths":"Array","proto":"String","next-level":"Boolean","instance_mode":"Integer"}
"getm_names":{"paths":"Array","proto":"String","next-level":"Boolean","instance_mode":"Integer"}
"object_names":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"instances":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"validate":{"path":"String","proto":"String","maxdepth":"Integer","next-level":"Boolean","instance_mode":"Integer"}
"transaction_start":{"app":"String"}
"set":{"path":"String","value":"String","values":"Table","proto":"String","instance_mode":"Integer","transaction_id":"Integer"}
"operate":{"path":"String","action":"String","input":"Table","proto":"String","instance_mode":"Integer"}
"add_object":{"path":"String","proto":"String","instance_mode":"Integer","transaction_id":"Integer"}
"del_object":{"path":"String","proto":"String","instance_mode":"Integer","transaction_id":"Integer"}
"setm_values":{"pv_tuple":"Array","proto":"String","instance_mode":"Integer","transaction_id":"Integer"}
"transaction_commit":{"transaction_id":"Integer","restart_services":"Boolean"}
"transaction_abort":{"transaction_id":"Integer"}
"transaction_status":{"transaction_id":"Integer"}
"notify_event":{"name":"String","input":"Table"}
````
| Method |Function ID |
| :--- | :--- |
| [dump_schema](#dump_schema_raw) | 1 |
| [list_operate](#list_operate_raw) | 2 |
| [list_events](#list_events_raw) | 3 |
| [get_supported_dm](#get_supported_dm_raw) | 4 |
| [get](#get_raw) | 5 |
| [getm_values](#getm_values_raw) | 6 |
| [getm_names](#getm_names_raw) | 7 |
| [object_names](#object_names_raw) | 8 |
| [instances](#instances_raw) | 9 |
| [validate](#validate_raw) | 10 |
| [transaction_start](#transaction_start_raw) | 11 |
| [set](#set_raw) | 12 |
| [operate](#operate_raw) | 13 |
| [add_object](#add_object_raw) | 14 |
| [del_object](#del_object_raw) | 15 |
| [setm_values](#setm_values_raw) | 16 |
| [transaction_commit](#transaction_commit_raw) | 17 |
| [transaction_abort](#transaction_abort_raw) | 18 |
| [transaction_status](#transaction_status_raw) | 19 |
| [notify_event](#notify_event_raw) | 20 |
#### Methods
Below methods are supported in usp methods. Method description of the `usp` object in succeding paragraphs .
##### dump_schema_raw
This method exposes schema registered in the data model .
* [dump_schema documentation](../api/ubus/usp.raw.md#dump_schema)
##### list_operate_raw
Exposes various sync and async operations supported by datamodel. e.g., IPPing(), NeighbourDiagnostics() etc.
* [list_operate documentation](../api/ubus/usp.raw.md#list_operate)
##### list_events_raw
Exposes various events registered in the datamodel.
* [list_events documentation](../api/ubus/usp.raw.md#list_events)
##### get_supported_dm_raw
This method exposes the all type of objects supported in the data model in one browse. it will expose name, type, cmd_type and writable properties of the object depending on the type of the parameters present in the data model.
* [get_supported_dm documentation](../api/ubus/usp.md#get_supported_dm)
##### get_raw
This method exposes information of various schema parameters registered in the data model.
* [get documentation](../api/ubus/usp.raw.md#get)
##### getm_values_raw
This method is an extension to get method, this method can be use to get parameter values for multiple query paths at once.
* [getm_values documentation](../api/ubus/usp.raw.md#getm_values)
##### getm_names_raw
This method is an extension to get method, this method can be use to get parameter names for multiple query paths at once.
* [getm_names documentation](../api/ubus/usp.raw.md#getm_names)
##### object_names_raw
This method exposes names of the objects in the spectified query path registered in the data model.
* [object_names documentation](../api/ubus/usp.raw.md#object_names)
##### instances_raw
Get all the instances for specified schema path.
* [disconnect documentation](../api/ubus/usp.raw.md#instances)
##### validate_raw
This method validates whether the path provided is valid as per registerd schema paths.
* [validate documentation](../api/ubus/usp.raw.md#validate)
##### transaction_start
This method starts a transaction with the name provided.
* [transaction_start documentation](../api/ubus/usp.raw.md#transaction_start)
##### set_raw
This method is used to set information of various registered schema parameters.
* [set documentation](../api/ubus/usp.raw.md#set)
##### operate_raw
This method is used to execute various sync/async operations e.g., IPPing(), NeighbourDiagnostics() etc.
* [operate documentation](../api/ubus/usp.raw.md#operate)
##### add_object_raw
This method is used to add an object to specified multi instance object in registered schema.
* [add_object neighbor documentation](../api/ubus/usp.raw.md#add_object)
##### del_object_raw
This method is used to delete an object from specified multi instance object in registered schema.
* [del_object documentation](../api/ubus/usp.raw.md#del_object)
##### setm_values_raw
This method is an extension to set method, this method can be use to set parameter values for multiple query paths at once.
* [setm_values documentation](../api/ubus/usp.raw.md#setm_values)
##### transaction_commit
This method commits the changes made by an ongoing transaction.
* [transaction_commit documentation](../api/ubus/usp.raw.md#transaction_commit)
##### transaction_abort
This method aborts an ongoing transaction.
* [transaction_abort documentation](../api/ubus/usp.raw.md#transaction_abort)
##### transaction_status
This method provides with the status of an ongoing transaction.
* [transaction_status documentation](../api/ubus/usp.raw.md#transaction_status)
##### notify_event
This method is used to get notified whenever the specified event occurs
* [notify_event documentation](../api/ubus/usp.raw.md#notify_event)

464
bbfd/docs/spec/testspec.md Normal file
View file

@ -0,0 +1,464 @@
# Test Specification
Most of the functionalities in uspd can be tested via its ubus API. Each
API can be broken down into an individual test case to show full coverage is
achieved.
# Sections
* [Preqreuisites](#prerequisites)
* [Test Suites](#test-suites)
* [Functional API Tests](#functional-api-tests)
* [Unit Tests](#unit-tests)
* [Functional Tests](#functional-tests)
## Prerequisites
The prerequisite for the uspd test suites is that libbbfdm and ubusd has to be
built for the TEST platform, a version prepared to publish dummy data for get
API, and record set API to a test logfile at `/tmp/test.log`.
| Dependency | Link | License |
| :--- | :--- | :--- |
| ---------- | ---------------------------------------- | -------- |
| ubusd | https://git.openwrt.org/project/ubus.git | LGPL 2.1 |
| libbbfdm | https://dev.iopsys.eu/iopsys/bbf.git | LGPL 2.1 |
## Test Suites
The uspd build pipe has three test suites, a functional-api suite, unit test suite
and functional test suite.
### Functional API Tests
The functional API tests consists of two individual test suites, one per object
Ubus under test. The functional API tests use the Ubus-API-validation
command-line interface tool to invoke a method, programmatically through
libubus, and validates it against the objects json-schema.
#### usp
| Execution ID | Method | Description | Function ID Coverage |
| :--- | :--- | :--- | :--- |
| 1 | list_operate | No argument | [1](./functionspec.md#list_operate) |
| 2 | get_supported_dm \ with path argument | [2](./functionspec.md#get_supported_dm) |
| 3 | get | With path argument | [3](./functionspec.md#get) |
| 4 | object_names | With path argument | [4](./functionspec.md#object_names) |
| 5 | instances | With path argument | [5](./functionspec.md#instances) |
| 6 | validate | With path argument | [6](./functionspec.md#validate) |
| 7 | set | With path and value arguments | [7](./functionspec.md#set) |
| 8 | operate | With path, action and input arguments | [8](./functionspec.md#operate) |
| 9 | add_object | With path argument | [9](./functionspec.md#add_object) |
| 10 | del_object | With path argument | [10](./functionspec.md#del_object) |
#### usp.raw
| Execution ID | Method | Description | Function ID Coverage |
| :--- | :--- | :--- | :--- |
| 1 | dump_schema | No argument | [15](./functionspec.md#dump_schema_raw) |
| 2 | list_operate | No argument | [16](./functionspec.md#list_operate_raw) |
| 3 | list_events | No argument | [16](./functionspec.md#list_events) |
| 4 | get_supported_dm | with path argument | [2](./functionspec.md#get_supported_dm) |
| 5 | get | With path argument | [17](./functionspec.md#get_raw) |
| 6 | getm_values | With paths array argument | [25](./functionspec.md#getm_values_raw) |
| 7 | getm_name | With paths array argument | [26](./functionspec.md#getm_names_raw) |
| 8 | object_names | With path argument | [18](./functionspec.md#object_names_raw) |
| 9 | instances | With path argument | [19](./functionspec.md#instances_raw) |
| 10 | validate | With path argument | [20](./functionspec.md#validate_raw) |
| 11 | transaction_start | With app argument | [17](./functionspec.md#transaction_start) |
| 12 | set | With path and value arguments | [21](./functionspec.md#set_raw) |
| 13 | operate | With path, action and input arguments | [22](./functionspec.md#operate_raw) |
| 14 | add_object | With path argument | [23](./functionspec.md#add_object_raw) |
| 15 | del_object | With path argument | [24](./functionspec.md#del_object_raw) |
| 16 | setm_values | With pv_tuple and transaction_id argument | [17](./functionspec.md#setm_val) |
| 17 | transaction_commit | With transaction_id argument | [17](./functionspec.md#transaction_commit) |
| 18 | transaction_abort | With transaction_id argument | [17](./functionspec.md#transaction_abort) |
| 19 | transaction_status | With transaction_id argument | [17](./functionspec.md#transaction_status) |
| 20 | notify_event | With ***** argument | [17](./functionspec.md#notify_event) |
### Unit Tests
The uspd unit tests are written in cmocka, invoking the ubus callbacks
directly from the source code, which is compiled into a shared library.
This means mocking the arguments of a cli or libubus invoke in a
`struct blob_attr *`. The results of the call will be logged to the logfile at
`/tmp/test.log`.
| Execution ID | Method | Test Case Name | Function ID Coverage |
| :--- | :--- | :--- | :--- |
| 1 | dump_schema | [test_api_usp_raw_dump_schema](#test_api_usp_raw_dump_schema) | [1](./functionspec.md#dump_schema_raw)
| 2 | list_operate | [test_api_usp_list_operate](#test_api_usp_list_operate) | [2](./functionspec.md#list_operate) |
| 3 | get | [test_api_usp_get](#test_api_usp_get) | [3](./functionspec.md#get) |
| 4 | object_names | [test_api_usp_object_name](#test_api_usp_object_name) | [4](./functionspec.md#object_names) |
| 5 | instances | [test_api_usp_instances](#test_api_usp_instances) | [5](./functionspec.md#instances) |
| 6 | validate | [test_api_usp_resolve](#test_api_usp_resolve) | [6](./functionspec.md#validate) |
| 7 | set | [test_api_usp_set](#test_api_usp_set) | [7](./functionspec.md#set) |
| 8 | add_object | [test_api_usp_add_object](#test_api_usp_add_object) | [9](./functionspec.md#add_object) |
| 9 | del_object | [test_api_usp_del](#test_api_usp_del_object) | [10](./functionspec.md#del_object) |
| 10 | getm_values | [test_api_usp_get_safe_values](#test_api_usp_get_safe_values) | [11](./functionspec.md#getm_values) |
| 11 | getm_name | [test_api_usp_get_safe_names](#test_api_usp_get_safe_names) | [12](./functionspec.md#getm_names) |
#### test_api_usp_dump_schema
##### Description
Tests the uspd ubus API callback `dump_schema`, publishing the method
[dump_schema](./functionspec.md#dump_schema).
##### Test Steps
Issuing a dump_schema to a client from the uspd test platform.
Read the logfile and verify that the `schema` argument was
accurately logged.
##### Test Expected Results
The expected result is for the log file to have recorded a call to the
dump_schema function.
````bash
{
"parameters": [
{
"parameter": "Device.ATM.Link.{i}.",
"writable": "1",
"type": "xsd:object"
},
{
"parameter": "Device.ATM.Link.{i}.Alias",
"writable": "1",
"type": "xsd:string"
},
{
"parameter": "Device.ATM.Link.{i}.DestinationAddress",
"writable": "1",
"type": "xsd:string"
},
{
"parameter": "Device.ATM.Link.{i}.Enable",
"writable": "1",
"type": "xsd:boolean"
},
{
...
}
```
#### test_api_usp_list_operate
##### Description
Tests the uspd ubus API `list_operate`, publishing the method
[list_operate](./functionspec.md#list_operate).
##### Test Steps
Issuing a list_operate to a client from the uspd test platform.
Read the logfile and verify that the `list_operate` argument was
accurately logged.
##### Test Expected Results
````bash
{
"parameters": [
{
"parameter": "Device.DHCPv4.Client.{i}.Renew()",
"type": "sync"
},
{
"parameter": "Device.DNS.Diagnostics.NSLookupDiagnostics()",
"type": "async"
},
{
{
"parameter": "Device.IP.Diagnostics.IPPing()",
"type": "async"
},
{
"parameter": "Device.IP.Diagnostics.TraceRoute()",
"type": "async"
},
{
"parameter": "Device.IP.Diagnostics.UDPEchoDiagnostics()",
"type": "async"
},
{
"parameter": "Device.IP.Interface.{i}.Reset()",
"type": "sync"
},
{
"parameter": "Device.Reboot()",
"type": "sync"
},
{
```
#### test_api_usp_get
##### Description
Tests the uspd ubus API get, publishing the method
[get](./functionspec.md#get).
##### Test Steps
Prepare the arguments as:
````bash
{"path":"Device.IP.Diagnostics.", "proto":"usp"}
```
Requesting the libbfdm with the path `Device.IP.Diagnostics.`.
Read the logfile and verify that the interface and arguments were accurately
logged.
##### Test Expected Results
The expected result is for the log file to have recorded a call to the
`libbbfdm`, through ubus and with the argument `path` as `Device.IP.Diagnostics.`
`proto` as `usp`.
````bash
{
"Diagnostics": {
"IPv4DownloadDiagnosticsSupported": true,
"IPv4PingSupported": true,
"IPv4ServerSelectionDiagnosticsSupported": true,
"IPv4TraceRouteSupported": true,
"IPv6UploadDiagnosticsSupported": true,
"UDPEchoConfig": {
"BytesReceived": 0,
"BytesResponded": 0,
"TimeFirstPacketReceived": "0",
"TimeLastPacketReceived": "0",
"UDPPort": 0
}
}
}
```
#### test_api_usp_instances
##### Description
Tests the uspd ubus API instances, publishing the method
[instances](./functionspec.md#instances).
##### Test Steps
Prepare the arguments as:
````bash
{"path":"Device.IP.Interface.", "proto":"usp"}
```
Requesting the libbfdm with the path `Device.IP.Interface.`.
Read the logfile and verify that the interface and arguments were accurately
logged.
##### Test Expected Results
The expected result is for the log file to have recorded a call to the
`libbbfdm`, through ubus and with the argument `path` as `Device.IP.Interface.`
`proto` as `usp`.
````bash
{
"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."
}
]
}
```
#### test_api_usp_instances
##### Description
Tests the uspd ubus API instances, publishing the method
[instances](./functionspec.md#instances).
##### Test Steps
Prepare the arguments as:
````bash
{"path":"Device.IP.Interface.", "proto":"usp"}
````
Requesting the libbfdm with the path `Device.IP.Interface.`.
Read the logfile and verify that the interface and arguments were accurately
logged.
##### Test Expected Results
The expected result is for the log file to have recorded a call to the
`libbbfdm`, through ubus and with the argument `path` as `Device.IP.Interface.`
`proto` as `usp`.
```bash
{
"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."
}
]
}
```
### Functional Tests
#### test_func_ref_follow
##### Description
Tests the reference follow for search path. Reference follow is basically
quering a search path, which is referenced by the path queried for.
##### Test Steps
Prepare the arguments as:
````bash
{"path":"Device.WiFi.SSID.1.LowerLayers+.Alias", "proto":"usp"}
```
##### Test Expected Results
The expected result is for the log file to have recorded a call to the
`libbbfdm`, through ubus and with the argument `path` as `Device.WiFi.SSID.1.LowerLayers+.Alias` and `proto` as `usp`.
````bash
{
"Device": {
"WiFi": {
"Radio": [
{
"Alias": "cpe-1"
}
]
}
}
}
```
#### test_func_list_of_ref
##### Description
Tests the list of reference following for search path. Reference follow is basically
quering a search path, which is referenced by the path queried for.
##### Test Steps
Prepare the arguments as:
````bash
{"path":"Device.WiFi.SSID.1.LowerLayers#1+.Name"}
```
##### Test Expected Results
The expected result is for the log file to have recorded a call to the
`libbbfdm`, through ubus and with the argument `path` as `Device.WiFi.SSID.1.LowerLayers#1+.Name` and `proto` as `usp`.
````bash
{
"Device": {
"WiFi": {
"Radio": [
{
"Name": "wl0"
}
]
}
}
}
```
#### test_func_search_expr
##### Description
Testing search path, this is a path Name that contains search criteria for addressing a
set of Multi-Instance Objects and/or their parameters. A Search path may contain a
Search Expression or Wildcard.
##### Test Steps
Prepare the arguments as:
````bash
{"path":"Device.WiFi.SSID.[Status==\"Up\"].Alias"}
```
##### Test Expected Results
In the above bash parameter path we can identify the square brackets as search path. So basically through this search path we are querying 'Alias' for any WiFi.SSID instance having
`Up` Status.
The expected result is for the log file to have recorded a call to the
`libbbfdm`, through ubus and with the argument `path` as `Device.WiFi.SSID.1.LowerLayers#1+.Name` and `proto` as `usp`.
````bash
{
"SSID": [
{
"Alias": "cpe-1"
},
{
"Alias": "cpe-2"
}
]
}
```

View file

@ -0,0 +1,63 @@
#!/bin/bash
echo "$0 preparation script"
pwd
source ./gitlab-ci/shared.sh
trap cleanup EXIT
trap cleanup SIGINT
# clean and make
make clean
CFLAGS="-g -Os -fprofile-arcs -ftest-coverage -DUSPD_MAX_MSG_LEN=1048576" LDFLAGS="--coverage" make func-test -C ./
check_ret $?
supervisorctl update
supervisorctl restart all
supervisorctl status all
exec_cmd ubus wait_for usp.raw usp
supervisorctl status all
# debug logging
echo "Checking ubus status [$(date '+%d/%m/%Y %H:%M:%S')]"
ubus list
ubus -v list usp.raw
ubus -v list usp
echo "Checking system resources"
free -h
df -h
sleep 5
# run functional on usp object validation
if [ -f "/usr/share/rpcd/schemas/usp*.json" ]; then
rm /usr/share/rpcd/schemas/usp*.json
fi
cp -r ./schemas/ubus/usp.json /usr/share/rpcd/schemas
ubus-api-validator -t 5 -f ./test/api/json/usp.validation.json > ./api-result.log
generate_report usp_api api-result.log
# run functional on usp object validation
if [ -f "/usr/share/rpcd/schemas/usp*.json" ]; then
rm /usr/share/rpcd/schemas/usp*.json
fi
cp -r ./schemas/ubus/usp.raw.json /usr/share/rpcd/schemas
ubus-api-validator -t 5 -f ./test/api/json/usp.raw.validation.json >> ./api-result.log
generate_report usp_raw_api api-result.log
supervisorctl status all
supervisorctl stop all
supervisorctl status
#report part
date +%s > timestamp.log
gcovr -r . --xml -o ./api-test-coverage.xml
gcovr -r .
echo "Checking memory leaks..."
grep -q "Leak" memory-report.xml
error_on_zero $?
echo "Functional ubus API test :: PASS"

111
bbfd/gitlab-ci/functional-test.sh Executable file
View file

@ -0,0 +1,111 @@
#!/bin/bash
echo "$0 preparation script"
pwd
source ./gitlab-ci/shared.sh
trap cleanup EXIT
trap cleanup SIGINT
make clean
CFLAGS="-g -Os -fprofile-arcs -ftest-coverage -DUSPD_MAX_MSG_LEN=1048576" LDFLAGS="--coverage" make func-test -C ./
check_ret $?
ls
supervisorctl update
supervisorctl restart all
supervisorctl status all
exec_cmd ubus wait_for usp.raw usp
supervisorctl status all
# debug logging
echo "Checking ubus status [$(date '+%d/%m/%Y %H:%M:%S')]"
ubus list
ubus -v list usp.raw
ubus -v list usp
echo "Checking system resources"
free -h
df -h
echo "## Preparing shared library for uspd msglen test ##"
exec_cmd make -C ./test
echo "## Running python based verification of functionalities ##"
echo > ./funl-result.log
num=0
for test in `ls -1 ./test/python/*.py`
do
num=$(( num + 1 ))
sleep 1
$test
if [ $? -eq 0 ]; then
echo "ok ${num} - $test" >> ./funl-result.log
else
echo "not ok ${num} - $test" >> ./funl-result.log
fi
done
echo "1..${num}" >> ./funl-result.log
generate_report python_test ./funl-result.log
# run functional on usp object validation
if [ -f "/usr/share/rpcd/schemas/usp*.json" ]; then
rm /usr/share/rpcd/schemas/usp*.json
fi
fault=0
# run functional on usp object validation
cp -r ./test/funl/schema/usp_test_positive.json /usr/share/rpcd/schemas/usp.json
ubus-api-validator -t 5 -f ./test/funl/validation/usp.validation.positive.json > ./funl-result.log
fault=$?
generate_report usp_positive ./funl-result.log
cp -r ./test/funl/schema/usp_test_negative.json /usr/share/rpcd/schemas/usp.json
ubus-api-validator -t 5 -f ./test/funl/validation/usp.validation.negative.json > ./funl-result.log
fault=$(( $fault + $? ))
generate_report usp_negative ./funl-result.log
# run functional on usp.raw object validation
rm /usr/share/rpcd/schemas/usp*.json
cp -r ./test/funl/schema/usp.raw_test_positive.json /usr/share/rpcd/schemas/usp.raw.json
ubus-api-validator -t 5 -f ./test/funl/validation/usp.raw.validation.positive.json > ./funl-result.log
fault=$(( $fault + $? ))
generate_report usp_raw_positive ./funl-result.log
#test usp.raw for negative test cases
cp -r ./test/funl/schema/usp.raw_test_negative.json /usr/share/rpcd/schemas/usp.raw.json
ubus-api-validator -t 5 -f ./test/funl/validation/usp.raw.validation.negative.json > ./funl-result.log
fault=$(( $fault + $? ))
generate_report usp_raw_negative ./funl-result.log
# TODO: add for granularity ubus objects
#uci set uspd.usp.granularitylevel='1'
#uci commit
#ubus-api-validator -f ./test/funl/json/gran/gran.validation.json >> ./funl-result.log
#fault=$?
#uci set uspd.usp.granularitylevel='0'
#uci commit
supervisorctl stop all
supervisorctl status
#report part
gcovr -r . --xml -o ./funl-test-coverage.xml
gcovr -r .
date +%s > timestamp.log
echo "Checking memory leaks..."
grep -q "Leak" memory-report.xml
error_on_zero $?
if [ "${fault}" -ne 0 ]; then
echo "Failed running ubus-api-validator fault[$fault]"
exit $fault
fi
echo "Functional Test :: PASS"

View file

@ -0,0 +1,56 @@
#!/bin/bash
echo "install dependencies of uspd"
pwd
source ./gitlab-ci/shared.sh
# install required packages
exec_cmd apt update
exec_cmd apt install -y python3-pip
exec_cmd pip3 install pexpect ubus
git config --global --add safe.directory ${PWD}
branch="$(git branch --show-current)"
# install libbbf
cd /opt/dev
rm -rf bbf
if [ -z "${BBF_TAR_URL}" ]; then
if ! git clone -b ${branch} https://dev.iopsys.eu/iopsys/bbf.git; then
exec_cmd git clone https://dev.iopsys.eu/iopsys/bbf.git
fi
cd bbf
echo "BBF Upstream Hash ${UPSTREAM_BBF_SHA}, uspd branch ${branch}"
if [ -n "${UPSTREAM_BBF_SHA}" ]; then
exec_cmd git checkout ${UPSTREAM_BBF_SHA}
fi
git log -1
source ./gitlab-ci/shared.sh
install_libbbf
./gitlab-ci/setup.sh
else
echo "## Installing upstream libbbf release from [${BBF_TAR_URL}] ##"
mkdir -p bbf
cd bbf
exec_cmd wget -q ${BBF_TAR_URL} -O bbf.sh
chmod +x bbf.sh
./bbf.sh --prefix=/ --exclude-subdir --skip-license
ldconfig
cd ..
fi
cd -
# install usermngr plugin
rm -rf /opt/dev/usermngr
exec_cmd git clone https://dev.iopsys.eu/iopsys/usermngr.git /opt/dev/usermngr
echo "Compiling libusermngr"
make clean -C /opt/dev/usermngr/src
make -C /opt/dev/usermngr/src
echo "Installing libusermngr"
cp -f /opt/dev/usermngr/src/libusermngr.so /usr/lib/bbfdm

View file

@ -0,0 +1,15 @@
[program:ubusd]
autorestart=false
priority=1
command=/bin/bash -c "/usr/sbin/ubusd"
[program:rpcd]
autorestart=false
priority=2
command=/bin/bash -c "/usr/sbin/rpcd"
[program:uspd]
autorestart=false
priority=3
command=/bin/bash -c "/usr/bin/valgrind --xml=yes --xml-file=/builds/iopsys/uspd/memory-report.xml --leak-check=full --show-reachable=yes --show-leak-kinds=all --errors-for-leak-kinds=all --error-exitcode=1 --track-origins=yes --leak-resolution=high --show-error-list=yes --child-silent-after-fork=yes /builds/iopsys/uspd/uspd"

14
bbfd/gitlab-ci/setup.sh Executable file
View file

@ -0,0 +1,14 @@
#!/bin/bash
echo "preparation script"
pwd
cp -r ./test/files/* /
cp ./gitlab-ci/iopsys-supervisord.conf /etc/supervisor/conf.d/
ls /etc/config/
ls /usr/share/rpcd/schemas/
ls /etc/supervisor/conf.d/
supervisorctl shutdown
supervisord -c /etc/supervisor/supervisord.conf

44
bbfd/gitlab-ci/shared.sh Normal file
View file

@ -0,0 +1,44 @@
#!/bin/bash
function cleanup()
{
echo ""
}
function check_ret()
{
ret=$1
if [ "$ret" -ne 0 ]; then
echo "Validation of last command failed, ret(${ret})"
exit $ret
fi
}
function error_on_zero()
{
ret=$1
if [ "$ret" -eq 0 ]; then
echo "Validation of last command failed, ret(${ret})"
exit $ret
fi
}
function exec_cmd()
{
echo "executing $@"
$@ >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Failed to execute $@"
exit 1
fi
}
function generate_report()
{
exec_cmd tap-junit --name "${1}" --input "${2}" --output report
sync
}

22
bbfd/gitlab-ci/unit-test.sh Executable file
View file

@ -0,0 +1,22 @@
#!/bin/bash
echo "preparation script"
pwd
source ./gitlab-ci/shared.sh
trap cleanup EXIT
trap cleanup SIGINT
echo "Running the unit test cases"
make clean
make unit-test -C ./src/
check_ret $?
#report part
#GitLab-CI output
gcovr -r .
# Artefact
gcovr -r . --xml -o ./unit-test-coverage.xml
date +%s > timestamp.log
echo "Unit test PASS"

View file

@ -0,0 +1,43 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=uspd
PKG_VERSION:=1.0.5
PKG_RELEASE:=$(PKG_SOURCE_VERSION)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://dev.iopsys.eu/iopsys/uspd.git
PKG_SOURCE_VERSION=x
PKG_SOURCE:=$(PKG_NAME)-$(PKG_SOURCE_VERSION).tar.gz
PKG_MAINTAINER:=IOPSYS Dev <dev@iopsys.eu>
CONFIG_SRC_TREE_OVERRIDE:=y
include $(INCLUDE_DIR)/package.mk
define Package/uspd
SECTION:=iopsys
CATEGORY:=IOPSYS
TITLE:=USP ubus backend
DEPENDS:=+libubox +ubus +libbbfdm
endef
define Package/uspd/description
Ubus based backend for TR-369/USP which can be used by other USP agents
running on top of it.
endef
TARGET_CFLAGS += \
-I$(STAGING_DIR)/usr/include \
-D_GNU_SOURCE
define Package/uspd/install
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_BIN) ./files/uspd.init $(1)/etc/init.d/uspd
$(INSTALL_CONF) ./files/uspd.config $(1)/etc/config/uspd
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/uspd $(1)/usr/sbin/
endef
$(eval $(call BuildPackage,uspd))

View file

@ -0,0 +1,2 @@
config uspd 'usp'
option granularitylevel '0'

View file

@ -0,0 +1,25 @@
#!/bin/sh /etc/rc.common
START=94
STOP=10
USE_PROCD=1
PROG=/usr/sbin/uspd
start_service() {
procd_open_instance
procd_set_param command ${PROG}
procd_set_param respawn
procd_close_instance
}
reload_service() {
stop
start
}
service_triggers()
{
procd_add_reload_trigger "cwmp"
procd_add_config_trigger "config.change" "uspd" /etc/init.d/uspd restart
}

1
bbfd/openwrt/uspd/git-src Symbolic link
View file

@ -0,0 +1 @@
../../.git/

791
bbfd/schemas/ubus/usp.json Normal file
View file

@ -0,0 +1,791 @@
{
"definitions": {
"path_t": {
"description": "Complete object element path as per TR181",
"type": "string",
"minLength": 6,
"maxLength": 1024,
"examples": [
"Device.",
"Device.DeviceInfo.Manufacturer",
"Device.WiFi.SSID.1.",
"Device.WiFi."
]
},
"schema_path_t": {
"description": "Datamodel object schema path",
"type": "string",
"minLength": 6,
"maxLength": 1024,
"examples": [
"Device.Bridging.Bridge.{i}.",
"Device.DeviceInfo.Manufacturer",
"Device.WiFi.SSID.{i}.SSID"
]
},
"boolean_t": {
"type": "string",
"enum": [
"0",
"1"
]
},
"operate_path_t": {
"description": "Datamodel object schema path",
"type": "string",
"minLength": 6,
"maxLength": 1024,
"examples": [
"Device.DHCPv4.Client.{i}.Renew()",
"Device.FactoryReset()"
]
},
"operate_type_t": {
"type": "string",
"enum": [
"async",
"sync"
]
},
"query_path_t": {
"description": "DM object path with search queries",
"type": "string",
"minLength": 6,
"maxLength": 1024,
"examples": [
"Device.",
"Device.DeviceInfo.Manufacturer",
"Device.WiFi.SSID.[SSID==\"test_ssid\"].BSSID",
"Device.WiFi.SSID.*.BSSID",
"Device.WiFi.SSID.[SSID!=\"test_ssid\"&&Enable==1].BSSID",
"Device.WiFi."
]
},
"instance_t": {
"description": "Multi object instances",
"type": "string",
"minLength": 6,
"maxLength": 256
},
"proto_t": {
"type": "string",
"default": "both",
"enum": [
"usp",
"cwmp",
"both"
]
},
"type_t": {
"type": "string",
"enum": [
"xsd:string",
"xsd:unsignedInt",
"xsd:int",
"xsd:unsignedLong",
"xsd:long",
"xsd:boolean",
"xsd:dateTime",
"xsd:hexBinary",
"xsd:object"
]
},
"fault_t": {
"type": "integer",
"minimum": 7000,
"maximum": 9050
}
},
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://dev.iopsys.eu/iopsys/uspd/-/blob/devel/docs/api/usp.md",
"type": "object",
"title": "usp",
"object": "usp",
"additionalProperties": false,
"properties": {
"get_supported_dm": {
"title": "Get list of supported datamodel parameters",
"description": "Schema will have all the nodes/objects supported by libbbf",
"type": "object",
"required": [
"output"
],
"properties": {
"input": {
"type": "object",
"properties": {
"path": {
"$ref": "#/definitions/query_path_t"
},
"next-level": {
"type": "boolean",
"description": "gets only next level objects if true"
},
"schema_type": {
"type": "integer",
"minimum": 0,
"maximum": 3,
"description": "0-All, 1-Parameter only 2- Event only 3- operate only"
}
}
},
"output": {
"oneof": [
{
"fault": {
"$ref": "#/definitions/fault_t",
"Description": "Any discrepancy in input will result in fault. The type of fault can be identified by fault code"
}
},
{
"type": "object",
"properties": {
"parameters": {
"type": "array",
"items": [
{
"type": "object",
"required": [
"parameter",
"type",
"writable"
],
"properties": {
"parameter": {
"$ref": "#/definitions/schema_path_t"
},
"writable": {
"$ref": "#/definitions/boolean_t"
},
"type": {
"$ref": "#/definitions/type_t"
},
"cmd_type": {
"$ref": "#/definitions/operate_type_t"
},
"in": {
"type": "array",
"uniqueItems": true,
"items": [
{
"type": "string"
}
]
},
"out": {
"type": "array",
"uniqueItems": true,
"items": [
{
"type": "string"
}
]
}
}
}
]
}
}
}
]
}
}
},
"list_operate": {
"title": "List down supported usp operate commands",
"description": "Commands will be shown in schema format",
"type": "object",
"required": [
"output"
],
"properties": {
"input": {
"type": "object",
"properties": {}
},
"output": {
"type": "object",
"required": [
"parameters"
],
"properties": {
"parameters": {
"type": "array",
"items": {
"type": "object",
"required": [
"parameter",
"type"
],
"properties": {
"parameter": {
"$ref": "#/definitions/operate_path_t"
},
"type": {
"$ref": "#/definitions/operate_type_t"
},
"in": {
"type": "array",
"items": {
"type": "string"
}
},
"out": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
}
}
}
},
"get": {
"title": "Get handler",
"description": "Query the datamodel object",
"type": "object",
"required": [
"input",
"output"
],
"properties": {
"input": {
"type": "object",
"required": [
"path"
],
"properties": {
"path": {
"$ref": "#/definitions/query_path_t"
},
"proto": {
"$ref": "#/definitions/proto_t"
},
"maxdepth": {
"type": "integer",
"description": "Integer to decide the depth of data model to be parsed"
},
"next-level": {
"type": "boolean",
"description": "gets only next level objects if true"
},
"instance-mode": {
"type": "integer",
"description": ""
}
}
},
"output": {
"oneof": [
{
"fault": {
"$ref": "#/definitions/fault_t",
"Description": "Any discrepancy in input will result in fault. The type of fault can be identified by fault code in fault_t"
}
},
{
"type": "object",
"properties": {},
"examples": [
"root@iopsys:/tmp# ubus call usp get '{\"path\":\"Device.Users.User.2.\"}'\n{\n\t\"User\": [\n\t\t{\n\t\t\t\"Alias\": \"\",\n\t\t\t\"Enable\": true,\n\t\t\t\"Language\": \"\",\n\t\t\t\"Password\": \"\",\n\t\t\t\"RemoteAccessCapable\": false,\n\t\t\t\"Username\": \"user_2\"\n\t\t}\n\t]\n}",
"root@iopsys:/tmp# ubus call usp get '{\"path\":\"Device.Users.\"}'\n{\n\t\"Users\": {\n\t\t\"User\": [\n\t\t\t{\n\t\t\t\t\"Alias\": \"\",\n\t\t\t\t\"Enable\": true,\n\t\t\t\t\"Language\": \"\",\n\t\t\t\t\"Password\": \"\",\n\t\t\t\t\"RemoteAccessCapable\": true,\n\t\t\t\t\"Username\": \"user\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"Alias\": \"\",\n\t\t\t\t\"Enable\": true,\n\t\t\t\t\"Language\": \"\",\n\t\t\t\t\"Password\": \"\",\n\t\t\t\t\"RemoteAccessCapable\": false,\n\t\t\t\t\"Username\": \"user_2\"\n\t\t\t}\n\t\t],\n\t\t\"UserNumberOfEntries\": 2\n\t}\n}"
]
}
]
}
}
},
"set": {
"title": "Set handler",
"description": "Set values of datamodel object element",
"type": "object",
"required": [
"input",
"output"
],
"properties": {
"input": {
"type": "object",
"required": [
"path",
"value"
],
"properties": {
"path": {
"$ref": "#/definitions/query_path_t"
},
"proto": {
"$ref": "#/definitions/proto_t"
},
"value": {
"description": "value of the object element provided in path, path should contains valid writable object element",
"type": "string",
"examples": [
"{\"path\":\"Device.WiFi.SSID.1.SSID\", \"value\":\"test_ssid\"}",
"{\"path\":\"Device.WiFi.SSID.2.Enable\", \"value\":\"true\"}",
"{\"path\":\"Device.WiFi.SSID.1.Enable\", \"value\":\"0\"}"
]
},
"values": {
"description": "To set multiple values at once, path should be relative to object elements",
"examples": [
"{\"path\":\"Device.WiFi.SSID.1\", \"values\":{\".SSID\":\"test_ssid\",\".Name\":\"test_name\"}}",
"{\"path\":\"Device.WiFi.SSID.2\", \"values\":{\".SSID\":\"test_ssid\"}}"
],
"type": "object",
"properties": {}
},
"instance_mode": {
"type": "integer",
"minimum": 0,
"maximum": 1
}
}
},
"output": {
"oneof": [
{
"type": "object",
"properties": {
"status": {
"const": "1"
}
}
},
{
"type": "object",
"required": [
"parameters"
],
"properties": {
"parameters": {
"type": "array",
"items": {
"type": "object",
"properties": {
"path": {
"$ref": "#/definitions/path_t"
},
"status": {
"const": "0"
},
"fault": {
"$ref": "#/definitions/fault_t"
}
}
}
}
}
}
]
}
}
},
"add_object": {
"title": "Add a new object instance",
"description": "Add a new object in multi instance object",
"type": "object",
"required": [
"input",
"output"
],
"properties": {
"input": {
"type": "object",
"required": [
"path"
],
"properties": {
"path": {
"$ref": "#/definitions/path_t"
},
"proto": {
"$ref": "#/definitions/proto_t"
},
"instance_mode": {
"type": "integer",
"minimum": 0,
"maximum": 1
}
}
},
"output": {
"type": "object",
"required": [
"parameters"
],
"properties": {
"parameters": {
"type": "array",
"items": {
"type": "object",
"required": [
"parameter",
"status"
],
"properties": {
"parameter": {
"$ref": "#/definitions/path_t"
},
"status": {
"type": "boolean"
},
"instance": {
"type": "string"
},
"fault": {
"$ref": "#/definitions/fault_t"
}
}
}
}
}
}
}
},
"del_object": {
"title": "Delete object instance",
"description": "Delete a object instance from multi instance object",
"type": "object",
"required": [
"input",
"output"
],
"properties": {
"input": {
"type": "object",
"required": [
"path"
],
"properties": {
"path": {
"$ref": "#/definitions/query_path_t"
},
"proto": {
"$ref": "#/definitions/proto_t"
},
"instance_mode": {
"type": "integer",
"minimum": 0,
"maximum": 1
}
}
},
"output": {
"type": "object",
"required": [
"parameters"
],
"properties": {
"parameters": {
"type": "array",
"items": {
"type": "object",
"required": [
"parameter",
"status"
],
"properties": {
"parameter": {
"$ref": "#/definitions/path_t"
},
"status": {
"type": "boolean"
},
"fault": {
"$ref": "#/definitions/fault_t"
}
}
}
}
}
}
}
},
"validate": {
"title": "Validate a datamodel object",
"description": "API to check if a datamodel object is available",
"type": "object",
"required": [
"input",
"output"
],
"properties": {
"input": {
"type": "object",
"required": [
"path"
],
"properties": {
"path": {
"$ref": "#/definitions/query_path_t"
},
"proto": {
"$ref": "#/definitions/proto_t"
},
"maxdepth": {
"type": "integer",
"description": "Integer to decide the depth of data model to be parsed"
},
"next-level": {
"type": "boolean",
"description": "gets only next level objects if true"
},
"instance-mode": {
"type": "integer",
"description": ""
}
}
},
"output": {
"type": "object",
"properties": {
"parameter": {
"type": "string"
},
"fault": {
"$ref": "#/definitions/fault_t"
}
}
}
}
},
"instances": {
"title": "Instance query handler",
"description": "Get the instances of multi object",
"type": "object",
"required": [
"input",
"output"
],
"properties": {
"input": {
"type": "object",
"required": [
"path"
],
"properties": {
"path": {
"$ref": "#/definitions/query_path_t"
},
"proto": {
"$ref": "#/definitions/proto_t"
},
"maxdepth": {
"type": "integer",
"description": "Integer to decide the depth of data model to be parsed"
},
"next-level": {
"type": "boolean",
"description": "gets only next level objects if true"
},
"instance-mode": {
"type": "integer",
"description": ""
}
}
},
"output": {
"oneof": [
{
"fault": {
"$ref": "#/definitions/fault_t",
"Description": "Any discrepancy in input will result in fault. The type of fault can be identified by fault code in fault_t"
}
},
{
"type": "object",
"required": [
"parameters"
],
"properties": {
"parameters": {
"type": "array",
"items": {
"type": "object",
"properties": {
"parameter": {
"$ref": "#/definitions/instance_t"
}
}
}
}
}
}
]
}
}
},
"object_names": {
"title": "Get objects names",
"description": "Get names of all the objects below input object path",
"type": "object",
"required": [
"input",
"output"
],
"properties": {
"input": {
"type": "object",
"required": [
"path"
],
"properties": {
"path": {
"$ref": "#/definitions/query_path_t"
},
"proto": {
"$ref": "#/definitions/proto_t"
},
"maxdepth": {
"type": "integer",
"description": "Integer to decide the depth of data model to be parsed"
},
"next-level": {
"type": "boolean",
"description": "gets only next level objects if true"
},
"instance-mode": {
"type": "integer",
"description": ""
}
}
},
"output": {
"oneof": [
{
"fault": {
"$ref": "#/definitions/fault_t",
"Description": "Any discrepancy in input will result in fault. The type of fault can be identified by fault code in fault_t"
}
},
{
"type": "object",
"required": [
"parameters"
],
"properties": {
"parameters": {
"type": "array",
"items": {
"type": {
"$ref": "#/definitions/type_t"
},
"required": [
"parameter",
"type",
"writable"
],
"writable": {
"$ref": "#/definitions/boolean_t"
},
"properties": {
"parameter": {
"$ref": "#/definitions/path_t"
}
}
}
}
}
}
]
}
}
},
"operate": {
"title": "Operate handler",
"description": "Operate on object element provided in path",
"type": "object",
"required": [
"input",
"output"
],
"properties": {
"input": {
"type": "object",
"required": [
"path",
"action"
],
"properties": {
"path": {
"$ref": "#/definitions/query_path_t"
},
"proto": {
"$ref": "#/definitions/proto_t"
},
"instance-mode": {
"type": "integer",
"description": ""
},
"action": {
"description": "Opreate command as defined in TR-369, TR-181-2.13",
"type": "string",
"examples": [
"{\"path\":\"Device.WiFi.\", \"action\":\"Reset\\(\\)\"}"
],
"pattern": "[a-zA-Z]+\\(\\)"
},
"input": {
"description": "Input arguments for the operate command as defined in TR-181-2.13",
"examples": [
"{\"path\":\"Device.IP.Diagnostics\", \"action\":\"IPPing\\(\\)\", \"input\":{\"Host\":\"iopsys.eu\"}}"
],
"type": "object",
"properties": {}
}
}
},
"output": {
"oneof": [
{
"fault": {
"$ref": "#/definitions/fault_t",
"Description": "Any discrepancy in input will result in fault. The type of fault can be identified by fault code in fault_t"
}
},
{
"description": "Output will have status for sync commands and for async commands parameters as defined in TR-181-2.13",
"type": "object",
"required": [
"Results"
],
"properties": {
"Results": {
"type": "array",
"items": {
"type": "object",
"properties": {
"path": {
"$ref": "#/definitions/path_t"
},
"result": {
"type": "array",
"items": {
"type": "object",
"properties": {
"Result": {
"type": "string",
"Description": "Success or Failure"
}
}
}
}
}
}
}
},
"examples": [
"{\n\t\"status\": true}",
"{\n\t\"AverageResponseTime\": \"0\",\n\t\"AverageResponseTimeDetailed\": \"130\",\n\t\"FailureCount\": \"0\",\n\t\"MaximumResponseTime\": \"0\",\n\t\"MaximumResponseTimeDetailed\": \"140\",\n\t\"MinimumResponseTime\": \"0\",\n\t\"MinimumResponseTimeDetailed\": \"120\",\n\t\"SuccessCount\": \"3\"}"
]
}
]
}
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,74 @@
{
"uspd": [
{
"section": "uspd",
"description": "USP daemon Settings",
"multi": false,
"options": [
{
"name": "granularitylevel",
"type": "integer",
"required": "no",
"default": "0",
"description": "Creates ubus objects along with object names, depth of object name depends on granularitylevel"
},
{
"name": "debug",
"type": "boolean",
"required": "no",
"default": "",
"description": "Enabled debug logging"
},
{
"name": "sock",
"type": "string",
"required": "no",
"default": "",
"description": "Path for ubus socket to register uspd services"
},
{
"name": "transaction_timeout",
"type": "integer",
"required": "no",
"default": "10",
"description": "Transaction timeout value in seconds"
},
{
"name": "loglevel",
"type": "integer",
"required": "no",
"default": "1",
"description": "Internal loglevel for debugging {0: No Logs; 1: Errors only; 2: Errors and warnings; 3: Error, warning and info; 4: Everything}"
},
{
"name": "subprocess_level",
"type": "integer",
"required": "no",
"default": "2",
"description": "This parameter configures when subprocess can be used for get operation. Level here denotes the Datamodel object depth up-to which subprocess will be used to collect the get data. For example, if this is configured to 1, then only get for 'Device.' shall be called within the subprocess. If configured as level 2, then all the get with up-to depth 2 like 'Device.WiFi.', 'Device.IP.' shall be called in subprocess."
},
{
"name": "bbf_caching_time",
"type": "integer",
"required": "no",
"default": "0",
"description": "Max caching time in seconds for ubus output used in datamodel parameters. If not configured, output shall be cleared end the end of call."
},
{
"name": "dm_version",
"type": "string",
"required": "no",
"default": "",
"description": "Configures the datamodel version to use for datamodel parameters, if not configured show all defined datamodel"
},
{
"name": "refresh_time",
"type": "integer",
"required": "no",
"default": "5",
"description": "The time period in seconds after which uspd will refresh the datamodel instances in a periodic manner. If configured to '0' then instance updater will be disabled. If not configured at all then after every 5 seconds datamodel instances will be refreshed."
}
]
}
]
}

58
bbfd/src/Makefile Normal file
View file

@ -0,0 +1,58 @@
PROG = uspd
OBJS =common.o get.o get_helper.o set.o operate.o add_delete.o pretty_print.o usp.o events.o
CP=cp -f
PROG_CFLAGS = $(CFLAGS) \
-fstrict-aliasing \
-Wall -Wextra -Werror \
-Wformat \
-Wformat-signedness -fPIC
PROG_LDFLAGS = $(LDFLAGS)
PROG_LDFLAGS += -luci -lubus -lubox -ljson-c -lblobmsg_json -lbbfdm
ifeq ($(USE_MBEDTLS),yes)
PROG_LDFLAGS += -lmbedcrypto -lmbedtls
endif
ifeq ($(USE_OPENSSL),yes)
PROG_LDFLAGS += -lssl -lcrypto
endif
ifeq ($(USE_WOLFSSL),yes)
PROG_LDFLAGS += -lwolfssl
endif
%.o: %.c
$(CC) $(PROG_CFLAGS) -c -o $@ $<
all: ${PROG}
${PROG}: $(OBJS)
$(CC) $(PROG_CFLAGS) -o $@ $^ $(PROG_LDFLAGS)
$(CP) ${PROG} ../${PROG}
test: PROG_CFLAGS += -fPIC
test: ${OBJS}
${CC} $(PROG_CFLAGS) -shared -o libuspd.so ${OBJS} $(PROG_LDFLAGS)
$(CP) libuspd.so ../libuspd.so
unit-test: CFLAGS += -g -O0 -fprofile-arcs -ftest-coverage
unit-test: LDFLAGS += --coverage
unit-test: clean_objs
unit-test: test
make -C ../test/cmocka unit-test USPD_LIB_DIR=$(PWD)
func-test: CFLAGS += -g -O0 -fprofile-arcs -ftest-coverage
func-test: LDFLAGS += --coverage
func-test: clean_objs
func-test: ${PROG}
clean_objs:
rm -f *.o
clean:
rm -f *.o libuspd.so $(PROG)
rm -f *.xml *.html
find -name '*.gcda' -exec rm {} -fv \;
find -name '*.gcno' -exec rm {} -fv \;
find -name '*.gcov' -exec rm {} -fv \;

77
bbfd/src/add_delete.c Normal file
View file

@ -0,0 +1,77 @@
/*
* add_delete.c: Add/Delete handler for uspd
*
* Copyright (C) 2019 iopsys Software Solutions AB. All rights reserved.
*
* Author: Vivek Dutta <vivek.dutta@iopsys.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include "common.h"
#include "add_delete.h"
#include "get_helper.h"
#include <libbbfdm/dmbbfcommon.h>
typedef int (*ADD_DEL_CB_T)(struct dmctx *bbf_ctx, struct blob_buf *bb, char *path, const char *pkey);
static int handle_add_del_req(usp_data_t *data, struct blob_buf *bb, ADD_DEL_CB_T req_cb)
{
int fault = 0;
struct dmctx bbf_ctx;
LIST_HEAD(resolved_paths);
memset(&bbf_ctx, 0, sizeof(struct dmctx));
set_bbfdatamodel_type(data->proto);
bbf_init(&bbf_ctx, data->instance);
fault = get_resolved_paths(&bbf_ctx, data->qpath, &resolved_paths);
if (fault) {
fill_resolve_err(bb, data->qpath, fault);
} else {
struct pathNode *p;
void *array;
array = blobmsg_open_array(bb, "parameters");
list_for_each_entry(p, &resolved_paths, list) {
void *table = blobmsg_open_table(bb, NULL);
int op_fault;
op_fault = req_cb(&bbf_ctx, bb, p->path, data->set_key);
blobmsg_close_table(bb, table);
// Preserve the first error
if (fault == USP_ERR_OK && op_fault != USP_ERR_OK)
fault = op_fault;
}
blobmsg_close_array(bb, array);
}
// Free
bbf_cleanup(&bbf_ctx);
free_path_list(&resolved_paths);
return fault;
}
int create_add_response(usp_data_t *data, struct blob_buf *bb)
{
return handle_add_del_req(data, bb, &usp_add_object);
}
int create_del_response(usp_data_t *data, struct blob_buf *bb)
{
return handle_add_del_req(data, bb, &usp_del_object);
}

23
bbfd/src/add_delete.h Normal file
View file

@ -0,0 +1,23 @@
#ifndef ADD_DEL_H
#define ADD_DEL_H
#include "usp.h"
enum {
DM_ADD_PATH,
DM_ADD_PROTO,
DM_ADD_INSTANCE,
__DM_ADD_MAX
};
enum {
DM_RAW_ADD_PATH,
DM_RAW_ADD_PROTO,
DM_RAW_ADD_INSTANCE,
DM_RAW_ADD_TRANS_ID,
__DM_RAW_ADD_MAX
};
int create_add_response(usp_data_t *data, struct blob_buf *bb);
int create_del_response(usp_data_t *data, struct blob_buf *bb);
#endif /* ADD_DEL_H */

210
bbfd/src/common.c Normal file
View file

@ -0,0 +1,210 @@
/*
* common.c: Common utils of Get/Set/Operate handlers
*
* Copyright (C) 2019 iopsys Software Solutions AB. All rights reserved.
*
* Author: Vivek Dutta <vivek.dutta@iopsys.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include "common.h"
#include <libbbfdm/dmbbfcommon.h>
#include "ipc.h"
#include "get_helper.h"
#define DEFAULT_LOG_LEVEL (2)
static unsigned char gLogLevel = DEFAULT_LOG_LEVEL;
// Logging utilities
void set_debug_level(unsigned char level)
{
gLogLevel = level;
}
void print_error(const char *format, ...)
{
va_list arglist;
if (gLogLevel < 1)
return;
va_start(arglist, format);
vsyslog(LOG_ERR, format, arglist);
va_end(arglist);
}
void print_warning(const char *format, ...)
{
va_list arglist;
if (gLogLevel < 2)
return;
va_start(arglist, format);
vsyslog(LOG_WARNING, format, arglist);
va_end(arglist);
}
void print_info(const char *format, ...)
{
va_list arglist;
if (gLogLevel < 3)
return;
va_start(arglist, format);
vsyslog(LOG_INFO, format, arglist);
va_end(arglist);
}
void print_debug(const char *format, ...)
{
va_list arglist;
if (gLogLevel < 4)
return;
va_start(arglist, format);
vsyslog(LOG_DEBUG, format, arglist);
va_end(arglist);
}
bool is_str_eq(const char *s1, const char *s2)
{
if (strcmp(s1, s2) == 0)
return true;
return false;
}
bool get_boolean_string(char *value)
{
if (!value)
return false;
if (strncasecmp(value, "true", 4) == 0 ||
value[0] == '1' ||
strncasecmp(value, "on", 2) == 0 ||
strncasecmp(value, "yes", 3) == 0 ||
strncasecmp(value, "enabled", 7) == 0)
return true;
return false;
}
bool is_node_instance(char *path)
{
bool ret = false;
char *rb = NULL;
DEBUG("entry |%s|", path);
if (!path)
return false;
if (path[0] == '[') {
char temp_char[MAX_DM_KEY_LEN] = {'\0'};
size_t shift;
rb = strchr(path, ']');
shift = (size_t) labs(rb - path);
strncpyt(temp_char, path, shift + 1);
if (!match(temp_char, GLOB_EXPR))
ret = true;
} else {
if (strtol(path, NULL, 10))
ret = true;
}
return ret;
}
bool get_uci_option_string(char *package, char *section,
char *option, char **value)
{
struct uci_context *uci_ctx;
struct uci_ptr ptr = {0};
bool ret = true;
*value = NULL;
uci_ctx = uci_alloc_context();
if (!uci_ctx)
return false;
if (bbfdmuci_lookup_ptr(uci_ctx, &ptr, package, section, option, NULL)) {
*value = NULL;
ret = false;
} else if (ptr.o && ptr.o->v.string) {
*value = strdup(ptr.o->v.string);
} else {
*value = NULL;
ret = false;
}
uci_free_context(uci_ctx);
return ret;
}
// RE utilities
bool match(const char *string, const char *pattern)
{
int status;
regex_t re;
if (regcomp(&re, pattern, REG_EXTENDED) != 0)
return 0;
status = regexec(&re, string, 0, NULL, 0);
regfree(&re);
if (status != 0)
return false;
return true;
}
int count_delim(const char *path)
{
int count = 0;
char *token, *save;
char *pp = strdup(path);
token = strtok_r(pp, ".", &save);
while (token) {
token = strtok_r(NULL, ".", &save);
count++;
}
free(pp);
// count is the count of tokens
return (count - 1);
}
bool validate_msglen(struct blob_buf *bb)
{
size_t data_len = blob_pad_len(bb->head);
if (data_len >= DEF_IPC_DATA_LEN) {
ERR("Blob exceed max len(%zd), data len(%zd)", DEF_IPC_DATA_LEN, data_len);
blob_buf_free(bb);
blob_buf_init(bb, 0);
fill_err_code(bb, FAULT_9002);
return false;
}
return true;
}

73
bbfd/src/common.h Normal file
View file

@ -0,0 +1,73 @@
#ifndef COMMON_H
#define COMMON_H
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <syslog.h>
#include <regex.h>
#include <sys/param.h>
#include <string.h>
#include <libubox/blobmsg.h>
#include <libubox/blobmsg_json.h>
#include <libubox/utils.h>
#include <libubox/list.h>
#define ROOT_NODE "Device."
#define USP "usp"
#define USPRAW "usp.raw"
#define USPEXT "usp.Device."
#define USP_ADD_EVENT "usp.AddObj"
#define USP_DEL_EVENT "usp.DelObj"
#define MAX_DM_KEY_LEN 256
#define MAX_DM_PATH 1024
#define MAX_DM_VALUE 4096
#define DM_VALUE_SEP ","
#define DELIM '.'
#define GLOB_CHAR "[[+*]+"
#define GLOB_EXPR "[=><]+"
#define GLOB_USP_PATH "[+#=><]+"
#define USP_ERR_OK 0
bool match(const char *string, const char *pattern);
bool is_str_eq(const char *s1, const char *s2);
bool is_node_instance(char *path);
int count_delim(const char *path);
bool get_uci_option_string(char *package, char *section,
char *option, char **value);
void set_debug_level(unsigned char level);
void print_error(const char *format, ...);
void print_warning(const char *format, ...);
void print_info(const char *format, ...);
void print_debug(const char *format, ...);
bool get_boolean_string(char *value);
bool validate_msglen(struct blob_buf *bb);
#define DEBUG(fmt, args...) \
print_debug("[%s:%d]"fmt, __func__, __LINE__, ##args)
#define INFO(fmt, args...) \
print_info(fmt, ##args)
#define ERR(fmt, args...) \
print_error("[%s:%d] " fmt, __func__, __LINE__, ##args)
#define WARNING(fmt, args...) \
print_warning("[%s:%d] " fmt, __func__, __LINE__, ##args)
// glibc doesn't guarantee a 0 termianted string on strncpy
// strncpy with always 0 terminated string
static inline void strncpyt(char *dst, const char *src, size_t n)
{
if (n > 1) {
strncpy(dst, src, n - 1);
dst[n - 1] = 0;
}
}
#endif /* COMMON_H */

267
bbfd/src/events.c Normal file
View file

@ -0,0 +1,267 @@
/*
* events.c: Handler to generate usp events on ubus
*
* Copyright (C) 2021 iopsys Software Solutions AB. All rights reserved.
*
* Author: Vivek Dutta <vivek.dutta@iopsys.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include "common.h"
#include "events.h"
#include "get_helper.h"
#include <libbbfdm/dmentry.h>
#include <libubus.h>
static struct event_map_list ev_map_list[] = {
/* { event name, DM Path, .arguments[] = { event_args, dm_args } } */
{ "wifi.dataelements.Associated", "Device.WiFi.DataElements.AssociationEvent.Associated!",
.args = {
{ "eventTime", "TimeStamp" },
{ "wfa-dataelements:AssociationEvent.AssocData.BSSID", "BSSID" },
{ "wfa-dataelements:AssociationEvent.AssocData.MACAddress", "MACAddress" },
{ "wfa-dataelements:AssociationEvent.AssocData.StatusCode", "StatusCode" },
{ "wfa-dataelements:AssociationEvent.AssocData.HTCapabilities", "HTCapabilities" },
{ "wfa-dataelements:AssociationEvent.AssocData.VHTCapabilities", "VHTCapabilities" },
{ "wfa-dataelements:AssociationEvent.AssocData.HECapabilities", "HECapabilities" },
{0}
}
},
{ "wifi.dataelements.Disassociated", "Device.WiFi.DataElements.DisassociationEvent.Disassociated!",
.args = {
{ "eventTime", "TimeStamp" },
{ "wfa-dataelements:DisassociationEvent.DisassocData.BSSID", "BSSID" },
{ "wfa-dataelements:DisassociationEvent.DisassocData.MACAddress", "MACAddress" },
{ "wfa-dataelements:DisassociationEvent.DisassocData.ReasonCode", "ReasonCode" },
{ "wfa-dataelements:DisassociationEvent.DisassocData.BytesSent", "BytesSent" },
{ "wfa-dataelements:DisassociationEvent.DisassocData.BytesReceived", "BytesReceived" },
{ "wfa-dataelements:DisassociationEvent.DisassocData.PacketsSent", "PacketsSent" },
{ "wfa-dataelements:DisassociationEvent.DisassocData.PacketsReceived", "PacketsReceived" },
{ "wfa-dataelements:DisassociationEvent.DisassocData.ErrorsSent", "ErrorsSent" },
{ "wfa-dataelements:DisassociationEvent.DisassocData.ErrorsReceived", "ErrorsReceived" },
{ "wfa-dataelements:DisassociationEvent.DisassocData.RetransCount", "RetransCount" },
{0}
}
}
};
static char* get_events_dm_path(const char *event)
{
unsigned int i;
if (!event) {
return NULL;
}
for (i = 0; i < sizeof(ev_map_list)/sizeof(ev_map_list[0]); i++) {
if (strcmp(event, ev_map_list[i].event) == 0)
return ev_map_list[i].dm_path;
}
return NULL;
}
static struct event_args_list* get_events_args(const char *event)
{
unsigned int i;
if (!event) {
return NULL;
}
for (i = 0; i < sizeof(ev_map_list)/sizeof(ev_map_list[0]); i++) {
if (strcmp(event, ev_map_list[i].event) == 0)
return ev_map_list[i].args;
}
return NULL;
}
static void serialize_blob_msg(struct blob_attr *msg, char *node, struct list_head *pv_list)
{
struct blob_attr *attr;
size_t rem;
blobmsg_for_each_attr(attr, msg, rem) {
char path[MAX_DM_PATH], value[MAX_DM_VALUE];
snprintf(path, sizeof(path), "%s%s%s",
DM_STRLEN(node) ? node : "",
blobmsg_name(attr),
(blobmsg_type(attr) == BLOBMSG_TYPE_TABLE && DM_STRLEN(blobmsg_name(attr))) ? "." : "");
switch (blobmsg_type(attr)) {
case BLOBMSG_TYPE_STRING:
snprintf(value, MAX_DM_VALUE, "%s", blobmsg_get_string(attr));
add_pv_node(path, value, NULL, pv_list);
break;
case BLOBMSG_TYPE_INT8:
snprintf(value, MAX_DM_VALUE, "%d", blobmsg_get_u8(attr));
add_pv_node(path, value, NULL, pv_list);
break;
case BLOBMSG_TYPE_INT16:
snprintf(value, MAX_DM_VALUE, "%d", blobmsg_get_u16(attr));
add_pv_node(path, value, NULL, pv_list);
break;
case BLOBMSG_TYPE_INT32:
snprintf(value, MAX_DM_VALUE, "%u", blobmsg_get_u32(attr));
add_pv_node(path, value, NULL, pv_list);
break;
case BLOBMSG_TYPE_INT64:
snprintf(value, MAX_DM_VALUE, "%"PRIu64"", blobmsg_get_u64(attr));
add_pv_node(path, value, NULL, pv_list);
break;
case BLOBMSG_TYPE_TABLE:
serialize_blob_msg(attr, path, pv_list);
}
}
}
static char *get_dm_arg_value(const char *event_arg, struct list_head *pv_list)
{
struct pvNode *pv = NULL;
list_for_each_entry(pv, pv_list, list) {
if (strcmp(pv->param, event_arg) == 0)
return pv->val;
}
return NULL;
}
static void generate_blob_input(struct blob_buf *b, const char *type, struct list_head *pv_list)
{
struct event_args_list *args = get_events_args(type);
if (args == NULL)
return;
for (int i = 0; args[i].event_arg; i++) {
char *dm_arg = get_dm_arg_value(args[i].event_arg, pv_list);
blobmsg_add_string(b, args[i].dm_arg, dm_arg ? dm_arg : "");
}
}
static void uspd_event_handler(struct ubus_context *ctx, struct ubus_event_handler *ev,
const char *type, struct blob_attr *msg)
{
(void)ev;
if (!msg || !type)
return;
char *dm_path = get_events_dm_path(type);
if (dm_path == NULL)
return;
LIST_HEAD(pv_list);
serialize_blob_msg(msg, "", &pv_list);
struct blob_buf b, bb;
memset(&b, 0, sizeof(struct blob_buf));
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&b, 0);
blob_buf_init(&bb, 0);
blobmsg_add_string(&b, "name", dm_path);
generate_blob_input(&bb, type, &pv_list);
blobmsg_add_field(&b, BLOBMSG_TYPE_TABLE, "input", blob_data(bb.head), blob_len(bb.head));
ubus_send_event(ctx, "usp.event", b.head);
blob_buf_free(&bb);
blob_buf_free(&b);
free_pv_list(&pv_list);
}
static void add_ubus_event_handler(struct ubus_event_handler *ev, struct list_head *ev_list)
{
if (ev == NULL || ev_list == NULL)
return;
struct ev_handler_node *node = NULL;
node = (struct ev_handler_node *) malloc(sizeof(struct ev_handler_node));
if (!node) {
ERR("Out of memory!");
return;
}
node->ev_handler = ev;
INIT_LIST_HEAD(&node->list);
list_add_tail(&node->list, ev_list);
}
void list_event_schema(struct blob_buf *bb)
{
bbf_dm_get_supported_dm(bb, ROOT_NODE, false, EVENT_ONLY);
}
bool is_registered_event(char *name)
{
return bbf_dm_event_registered(name);
}
void free_ubus_event_handler(struct ubus_context *ctx, struct list_head *ev_list)
{
struct ev_handler_node *iter = NULL, *node = NULL;
if (ctx == NULL || ev_list == NULL)
return;
list_for_each_entry_safe(iter, node, ev_list, list) {
if (iter->ev_handler != NULL) {
ubus_unregister_event_handler(ctx, iter->ev_handler);
free(iter->ev_handler);
}
list_del(&iter->list);
free(iter);
}
}
int register_events_to_ubus(struct ubus_context *ctx, struct list_head *ev_list)
{
unsigned int i;
if (ctx == NULL || ev_list == NULL)
return -1;
for (i = 0; i < sizeof(ev_map_list)/sizeof(ev_map_list[0]); i++) {
if (ev_map_list[i].event == NULL) {
continue;
}
struct ubus_event_handler *ev = (struct ubus_event_handler *)malloc(sizeof(struct ubus_event_handler));
if (!ev) {
ERR("Out of memory!");
return -1;
}
memset(ev, 0, sizeof(struct ubus_event_handler));
ev->cb = uspd_event_handler;
if (0 != ubus_register_event_handler(ctx, ev, ev_map_list[i].event)) {
ERR("Failed to register: %s", ev_map_list[i].event);
return -1;
}
add_ubus_event_handler(ev, ev_list);
}
return 0;
}

23
bbfd/src/events.h Normal file
View file

@ -0,0 +1,23 @@
#ifndef EVENT_H
#define EVENT_H
#include "usp.h"
#include "common.h"
struct event_args_list {
char *event_arg;
char *dm_arg;
};
struct event_map_list {
char *event;
char *dm_path;
struct event_args_list args[16];
};
void list_event_schema(struct blob_buf *bb);
bool is_registered_event(char *name);
void free_ubus_event_handler(struct ubus_context *ctx, struct list_head *ev_list);
int register_events_to_ubus(struct ubus_context *ctx, struct list_head *ev_list);
#endif /* EVENT_H */

306
bbfd/src/get.c Normal file
View file

@ -0,0 +1,306 @@
/*
* get.c: Get handler for uspd
*
* Copyright (C) 2019 iopsys Software Solutions AB. All rights reserved.
*
* Author: Vivek Dutta <vivek.dutta@iopsys.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include "get.h"
#include "get_helper.h"
#include "pretty_print.h"
#include "ipc.h"
#include <libubus.h>
#include <libbbfdm/dmbbfcommon.h>
void init_dmmap(void)
{
struct dmctx bbf_ctx;
LIST_HEAD(resolved_list);
memset(&bbf_ctx, 0, sizeof(struct dmctx));
bbf_init(&bbf_ctx, INSTANCE_MODE_NUMBER);
get_resolved_paths(&bbf_ctx, ROOT_NODE, &resolved_list);
// Commit dmmap
bbf_uci_commit_bbfdm();
free_path_list(&resolved_list);
bbf_cleanup(&bbf_ctx);
}
void usp_get_value_async(usp_data_t *data, void *output)
{
struct blob_buf bb;
int fault = USP_ERR_OK;
struct dmctx bbf_ctx;
LIST_HEAD(resolved_list);
memset(&bbf_ctx, 0, sizeof(struct dmctx));
set_bbfdatamodel_type(data->proto);
bbf_init(&bbf_ctx, data->instance);
// Fill the blob_buf for sharing the result
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
INFO("Preparing result for(%s)", data->qpath);
fault = get_resolved_paths(&bbf_ctx, data->qpath, &resolved_list);
if (fault) {
fill_err_code(&bb, fault);
} else {
if (data->is_raw)
prepare_result_raw(&bb, &bbf_ctx, &resolved_list);
else
prepare_pretty_result(data->depth, data->qpath, &bb, &bbf_ctx, &resolved_list);
}
if (!validate_msglen(&bb)) {
ERR("IPC failed for path(%s)", data->qpath);
}
memcpy(output, bb.head, blob_pad_len(bb.head));
// free
blob_buf_free(&bb);
free_path_list(&resolved_list);
bbf_cleanup(&bbf_ctx);
}
void usp_get_value(usp_data_t *data)
{
struct ubus_context *ctx;
struct ubus_request_data *req;
struct blob_buf bb;
int fault = USP_ERR_OK;
char *qpath;
bool raw;
uint8_t depth;
struct dmctx bbf_ctx;
ctx = data->ctx;
req = data->req;
qpath = data->qpath;
raw = data->is_raw;
depth = data->depth;
LIST_HEAD(resolved_list);
// Fill the blob_buf for sharing the result
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
memset(&bbf_ctx, 0, sizeof(struct dmctx));
set_bbfdatamodel_type(data->proto);
bbf_init(&bbf_ctx, data->instance);
fault = get_resolved_paths(&bbf_ctx, qpath, &resolved_list);
INFO("Preparing result for(%s), fault(%d)", qpath, fault);
if (fault) {
fill_err_code(&bb, fault);
} else {
if (raw)
prepare_result_raw(&bb, &bbf_ctx, &resolved_list);
else
prepare_pretty_result(depth, qpath, &bb, &bbf_ctx, &resolved_list);
}
if (!validate_msglen(&bb)) {
ERR("IPC failed for path(%s)", data->qpath);
}
ubus_send_reply(ctx, req, bb.head);
// Apply all bbfdm changes
if (is_transaction_running() == false)
bbf_uci_commit_bbfdm();
// free
blob_buf_free(&bb);
free_path_list(&resolved_list);
bbf_cleanup(&bbf_ctx);
}
void usp_validate_path(usp_data_t *data)
{
struct ubus_context *ctx;
struct ubus_request_data *req;
struct blob_buf bb;
int fault = USP_ERR_OK;
char *qpath;
struct dmctx bbf_ctx;
memset(&bbf_ctx, 0, sizeof(struct dmctx));
set_bbfdatamodel_type(data->proto);
bbf_init(&bbf_ctx, data->instance);
ctx = data->ctx;
req = data->req;
qpath = data->qpath;
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
fault = bbf_dm_get_names(&bbf_ctx, qpath, data->next_level);
if (!list_empty(&bbf_ctx.list_parameter)) {
size_t len = DM_STRLEN(qpath);
if (len > 0) {
if (qpath[len - 1] == '.')
qpath[len - 1] = '\0';
blobmsg_add_string(&bb, "parameter", qpath);
}
}
if (fault)
fill_err_code(&bb, fault);
ubus_send_reply(ctx, req, bb.head);
// Apply all bbfdm changes
if (is_transaction_running() == false)
bbf_uci_commit_bbfdm();
// free
blob_buf_free(&bb);
bbf_cleanup(&bbf_ctx);
}
void usp_get_instance(usp_data_t *data)
{
struct ubus_context *ctx;
struct ubus_request_data *req;
struct blob_buf bb;
int fault = USP_ERR_OK;
char *qpath;
struct dmctx bbf_ctx;
memset(&bbf_ctx, 0, sizeof(struct dmctx));
set_bbfdatamodel_type(data->proto);
bbf_init(&bbf_ctx, data->instance);
ctx = data->ctx;
req = data->req;
qpath = data->qpath;
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
fault = bbf_dm_get_instances(&bbf_ctx, qpath, data->next_level);
if (fault) {
fill_err_code(&bb, fault);
} else {
struct dm_parameter *n;
void *array;
array = blobmsg_open_array(&bb, "parameters");
list_for_each_entry(n, &bbf_ctx.list_parameter, list) {
void *table = blobmsg_open_table(&bb, NULL);
blobmsg_add_string(&bb, "parameter", n->name);
blobmsg_close_table(&bb, table);
}
blobmsg_close_array(&bb, array);
}
ubus_send_reply(ctx, req, bb.head);
// Apply all bbfdm changes
if (is_transaction_running() == false)
bbf_uci_commit_bbfdm();
// free
blob_buf_free(&bb);
bbf_cleanup(&bbf_ctx);
}
void usp_get_name(usp_data_t *data)
{
struct ubus_context *ctx;
struct ubus_request_data *req;
struct blob_buf bb;
int fault;
char *qpath;
struct dmctx bbf_ctx;
memset(&bbf_ctx, 0, sizeof(struct dmctx));
set_bbfdatamodel_type(data->proto);
bbf_init(&bbf_ctx, data->instance);
ctx = data->ctx;
req = data->req;
qpath = data->qpath;
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
fault = bbf_dm_get_names(&bbf_ctx, qpath, data->next_level);
if (fault) {
fill_err_code(&bb, fault);
} else {
void *array;
struct dm_parameter *n;
array = blobmsg_open_array(&bb, "parameters");
list_for_each_entry(n, &bbf_ctx.list_parameter, list) {
void *table = blobmsg_open_table(&bb, NULL);
blobmsg_add_string(&bb, "parameter", n->name);
blobmsg_add_string(&bb, "writable", n->data);
blobmsg_add_string(&bb, "type", n->type);
blobmsg_close_table(&bb, table);
}
blobmsg_close_array(&bb, array);
}
ubus_send_reply(ctx, req, bb.head);
// Commit all bbfdm changes if transaction is not in progress
if (is_transaction_running() == false)
bbf_uci_commit_bbfdm();
// free
blob_buf_free(&bb);
bbf_cleanup(&bbf_ctx);
}
void get_mpath(usp_data_t *data)
{
struct blob_buf bb;
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
if (data->is_raw) {
void *array = blobmsg_open_array(&bb, "parameters");
bbf_get_raw(data, &bb);
blobmsg_close_array(&bb, array);
} else {
bbf_get_blob(data, &bb);
}
ubus_send_reply(data->ctx, data->req, bb.head);
blob_buf_free(&bb);
}

31
bbfd/src/get.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef GET_H
#define GET_H
#include "usp.h"
#include "common.h"
enum {
DM_GET_PATH,
DM_GET_PROTO,
DM_GET_MAXDEPTH,
DM_GET_NXT_LVL,
DM_GET_INSTANCE,
__DM_GET_MAX
};
enum {
DM_GET_SAFE_PATHS,
DM_GET_SAFE_PROTO,
DM_GET_SAFE_NXT_LVL,
DM_GET_SAFE_INSTANCE,
__DM_GET_SAFE_MAX
};
void init_dmmap(void);
void usp_validate_path(usp_data_t *data);
void usp_get_value(usp_data_t *data);
void usp_get_instance(usp_data_t *data);
void usp_get_name(usp_data_t *data);
void get_mpath(usp_data_t *data);
void usp_get_value_async(usp_data_t *data, void *output);
#endif /* GET_H */

2039
bbfd/src/get_helper.c Normal file

File diff suppressed because it is too large Load diff

89
bbfd/src/get_helper.h Normal file
View file

@ -0,0 +1,89 @@
#ifndef GET_HELPER_H
#define GET_HELPER_H
#include "usp.h"
#include "common.h"
#include <libbbf_api/dmbbf.h>
#include <libubus.h>
enum operation {
OPER_EQUAL_EQUAL,
OPER_NOT_EQUAL,
OPER_LESS_THAN_EQUAL,
OPER_GREATER_THAN_EQUAL,
OPER_LESS_THAN,
OPER_GREATER_THAN,
};
struct pvNode {
char *param;
char *val;
char *type;
struct list_head list;
};
struct pathNode {
struct list_head list;
char path[MAX_DM_PATH];
};
int resolve_path(struct dmctx *bbf_ctx, char *qPath, size_t pos,
struct list_head *resolved_plist);
void add_path_node(char *para, struct list_head *plist);
void fill_err_code(struct blob_buf *bb, int fault);
void fill_resolve_err(struct blob_buf *bb, char *spath, int fault);
void add_pv_node(char *para, char *val, char *type,
struct list_head *pv_list);
bool path_present_in_pvlist(struct list_head *pvlist, char *entry);
void free_pv_list(struct list_head *head);
void free_pv_node(struct pvNode *pv);
void free_path_list(struct list_head *head);
bool get_granural_object_paths(struct list_head *path_list,
uint8_t maxdepth);
int bbf_dm_get_supported_dm(struct blob_buf *bb, char *path, bool first_level, int schema_type);
int bbf_dm_get_values(struct dmctx *bbf_ctx, char *path);
int bbf_dm_get_schema(struct blob_buf *bb);
int bbf_dm_get_names(struct dmctx *bbf_ctx, char *path, char *next);
int bbf_dm_list_operate(struct dmctx *bbf_ctx);
int usp_dm_set(struct dmctx *dm_ctx, char *path, char *value);
int get_resolved_paths(struct dmctx *bbf_ctx, char *qpath,
struct list_head *resolved_paths);
int usp_dm_operate(struct blob_buf *bb, char *path, char *input_params, bool raw, int instance);
int usp_del_object(struct dmctx *bbf_ctx, struct blob_buf *bb, char *path, const char *pkey);
int usp_add_object(struct dmctx *bbf_ctx, struct blob_buf *bb, char *path, const char *pkey);
int bbf_get_blob(usp_data_t *data, struct blob_buf *bb);
int bbf_get_raw(usp_data_t *data, struct blob_buf *bb);
bool get_next_param(char *qPath, size_t *pos, char *param);
int bbf_dm_get_instances(struct dmctx *bbf_ctx, char *path, char *next);
void bbf_init(struct dmctx *dm_ctx, int instance);
void bbf_configure_ubus(struct ubus_context *ctx);
void bbf_cleanup(struct dmctx *dm_ctx);
void bb_add_string(struct blob_buf *bb, const char *name, const char *value);
bool bbf_dm_event_registered(char *ename);
void set_datamodel_version(char * version);
bool present_in_path_list(struct list_head *plist, char *entry);
// Transaction related
bool is_transaction_running(void);
bool is_transaction_valid(int trans_id);
int transaction_start(const char *app, uint32_t max_timeout);
int fill_transaction_status(struct blob_buf *bb, int trans_id);
int transaction_commit(int trans_id, struct blob_buf *bp_service_list, bool is_service_restart);
int transaction_abort(int trans_id);
int configure_transaction_timeout(int timeout);
void handle_pending_signal(int);
void print_last_dm_object(void);
int usp_dm_exec_apply(struct dmctx *bbf_ctx, int cmd);
#endif /* GET_HELPER_H */

34
bbfd/src/ipc.h Normal file
View file

@ -0,0 +1,34 @@
/*
* ipc.h: File to handle ipc related functionality
*
* Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
*
* Author: Vivek Dutta <vivek.dutta@iopsys.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#ifndef IPC_H
#define IPC_H
#include <sys/mman.h>
#ifdef USPD_MAX_MSG_LEN
#define DEF_IPC_DATA_LEN (USPD_MAX_MSG_LEN - 128) // Configured Len - 128 bytes
#else
#define DEF_IPC_DATA_LEN (10 * 1024 * 1024 - 128) // 10M - 128 bytes
#endif
#endif // end IPC_H

156
bbfd/src/operate.c Normal file
View file

@ -0,0 +1,156 @@
/*
* operate.c: Operate handler for uspd
*
* Copyright (C) 2019 iopsys Software Solutions AB. All rights reserved.
*
* Author: Vivek Dutta <vivek.dutta@iopsys.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include "common.h"
#include "operate.h"
#include "get_helper.h"
#include "pretty_print.h"
#include "ipc.h"
#include <libbbfdm/dmbbfcommon.h>
#include <libubus.h>
static void usp_operate_cmd(usp_data_t *data, struct blob_buf *bb)
{
struct dmctx bbf_ctx;
int fault;
memset(&bbf_ctx, 0, sizeof(struct dmctx));
set_bbfdatamodel_type(data->proto);
bbf_init(&bbf_ctx, data->instance);
LIST_HEAD(resolved_paths);
fault = get_resolved_paths(&bbf_ctx, data->qpath, &resolved_paths);
bbf_cleanup(&bbf_ctx);
if (fault) {
fill_err_code(bb, fault);
} else {
void *array;
struct pathNode *rv;
array = blobmsg_open_array(bb, "Results");
list_for_each_entry(rv, &resolved_paths, list) {
char path[MAX_DM_PATH] = {0};
snprintf(path, MAX_DM_PATH, "%s%s", rv->path, data->op_action);
void *table = blobmsg_open_table(bb, NULL);
blobmsg_add_string(bb, "path", path);
usp_dm_operate(bb, path, data->op_input, data->is_raw, data->instance);
blobmsg_close_table(bb, table);
}
blobmsg_close_array(bb, array);
}
free_path_list(&resolved_paths);
}
void list_operate_schema(struct blob_buf *bb)
{
struct dm_parameter *n;
void *array;
struct dmctx bbf_ctx;
memset(&bbf_ctx, 0, sizeof(struct dmctx));
set_bbfdatamodel_type(BBFDM_USP);
bbf_init(&bbf_ctx, INSTANCE_MODE_NUMBER);
bbf_dm_list_operate(&bbf_ctx);
array = blobmsg_open_array(bb, "parameters");
list_for_each_entry(n, &bbf_ctx.list_parameter, list) {
void *table = blobmsg_open_table(bb, NULL);
bb_add_string(bb, "parameter", n->name);
bb_add_string(bb, "type", n->additional_data);
DEBUG("Operate node|%s|, type(%s)", n->name, n->type);
// filling in and out parameter
if (n->data) {
int i;
void *array_arg;
operation_args *args = (operation_args *) n->data;
const char **ap = args->in;
if (ap) {
array_arg = blobmsg_open_array(bb, "in");
for (i = 0; ap[i] != NULL; i++)
blobmsg_add_string(bb, NULL, ap[i]);
blobmsg_close_array(bb, array_arg);
}
ap = args->out;
if (ap) {
array_arg = blobmsg_open_array(bb, "out");
for (i = 0; ap[i] != NULL; i++)
blobmsg_add_string(bb, NULL, ap[i]);
blobmsg_close_array(bb, array_arg);
}
}
blobmsg_close_table(bb, table);
}
blobmsg_close_array(bb, array);
bbf_cleanup(&bbf_ctx);
}
void usp_operate_cmd_async(usp_data_t *data, void *output)
{
struct blob_buf bb;
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
usp_operate_cmd(data, &bb);
if (!validate_msglen(&bb)) {
ERR("IPC failed for path(%s)", data->qpath);
}
memcpy(output, bb.head, blob_pad_len(bb.head));
// free
blob_buf_free(&bb);
}
void usp_operate_cmd_sync(usp_data_t *data)
{
struct blob_buf bb;
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
usp_operate_cmd(data, &bb);
if (!validate_msglen(&bb)) {
ERR("IPC failed for path(%s)", data->qpath);
}
ubus_send_reply(data->ctx, data->req, bb.head);
// free
blob_buf_free(&bb);
}

19
bbfd/src/operate.h Normal file
View file

@ -0,0 +1,19 @@
#ifndef OPERATE_H
#define OPERATE_H
#include "usp.h"
#include "common.h"
enum {
DM_OPERATE_PATH,
DM_OPERATE_ACTION,
DM_OPERATE_INPUT,
DM_OPERATE_PROTO,
DM_OPERATE_INSTANCE,
__DM_OPERATE_MAX,
};
void list_operate_schema(struct blob_buf *bb);
void usp_operate_cmd_async(usp_data_t *data, void *output);
void usp_operate_cmd_sync(usp_data_t *data);
#endif /* OPERATE_H */

490
bbfd/src/pretty_print.c Normal file
View file

@ -0,0 +1,490 @@
/*
* pretty_print.c: utils for pretty printing of results
*
* Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
*
* Author: Vivek Dutta <vivek.dutta@iopsys.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include "common.h"
#include "get_helper.h"
#include "pretty_print.h"
#include <libbbfdm/dmbbfcommon.h>
// private function and structures
struct resultstack {
void *cookie;
char *key;
struct list_head list;
};
static bool is_search_by_reference(char *path)
{
DEBUG("Entry |%s|", path);
if (match(path, "[+]+")) {
size_t pindex = 0, bindex = 0;
char *last_plus, *last_bracket;
last_bracket = strrchr(path, ']');
if (!last_bracket)
return true;
last_plus = strrchr(path, '+');
pindex = (size_t)labs(last_plus - path);
bindex = (size_t)labs(last_bracket - path);
if (pindex > bindex)
return true;
}
return false;
}
//if matched start will have first match index, end will have end index
static bool is_res_required(char *str, size_t *start, size_t *len)
{
DEBUG("Entry |%s|", str);
if (match(str, GLOB_CHAR)) {
size_t s_len, b_len, p_len;
char *star, *b_start, *b_end, *plus;
char temp_char[MAX_DM_KEY_LEN] = {'\0'};
s_len = DM_STRLEN(str);
b_len = s_len;
p_len = s_len;
star = strchr(str, '*');
b_start = strchr(str, '[');
b_end = strchr(str, ']');
plus = strchr(str, '+');
if (star)
s_len = (size_t)labs(star - str);
if (b_start)
b_len = (size_t)labs(b_start - str);
if (plus)
p_len = (size_t)labs(plus - str);
*start = MIN(MIN(s_len, p_len), b_len);
if (*start == s_len) {
*len = 1;
} else if (*start == p_len) {
size_t i = 0, index = 0;
while ((str+i) != plus) {
if (str[i] == DELIM)
index = i;
++i;
}
*start = index+1;
*len = p_len - index;
} else {
*len = (size_t)labs(b_end - b_start);
}
// Check if naming with aliases used
snprintf(temp_char, *len+1, "%s", str + *start);
if (match(temp_char, GLOB_EXPR))
return true;
if (match(temp_char, "[*+]+"))
return true;
}
*start = DM_STRLEN(str);
return false;
}
static size_t get_glob_len(char *path)
{
size_t m_index = 0, m_len = 0, ret = 0;
size_t plen = DM_STRLEN(path);
char temp_name[MAX_DM_KEY_LEN] = {'\0'};
char *end = NULL;
DEBUG("Entry");
if (is_res_required(path, &m_index, &m_len)) {
if (m_index <= MAX_DM_KEY_LEN)
snprintf(temp_name, m_index, "%s", path);
end = strrchr(temp_name, DELIM);
if (end != NULL)
ret = m_index - DM_STRLEN(end);
} else {
char name[MAX_DM_KEY_LEN] = {'\0'};
if (plen == 0)
return ret;
if (path[plen - 1] == DELIM) {
if (plen <= MAX_DM_KEY_LEN)
snprintf(name, plen, "%s", path);
} else {
ret = 1;
if (plen < MAX_DM_KEY_LEN)
snprintf(name, plen + 1, "%s", path);
}
end = strrchr(name, DELIM);
if (end == NULL)
return ret;
ret = ret + DM_STRLEN(path) - DM_STRLEN(end);
if (is_node_instance(end+1)) {
int copy_len = plen - DM_STRLEN(end);
if (copy_len <= MAX_DM_KEY_LEN)
snprintf(temp_name, copy_len, "%s", path);
end = strrchr(temp_name, DELIM);
if (end != NULL)
ret = ret - DM_STRLEN(end);
}
}
return(ret);
}
static void resulting(uint8_t maxdepth, char *path, char *qPath, struct dmctx *bbf_ctx, struct list_head *pv_local)
{
struct dm_parameter *n;
uint8_t count;
size_t plen = get_glob_len(qPath);
//size_t plen = 0;
size_t path_len = DM_STRLEN(path);
list_for_each_entry(n, &bbf_ctx->list_parameter, list) {
if (path_len == 0)
continue;
if (path[path_len - 1] == DELIM) {
if (!strncmp(n->name, path, path_len)) {
if (is_search_by_reference(qPath))
plen = 0;
if (maxdepth > 4 || maxdepth == 0) {
add_pv_node(n->name + plen, n->data, n->type, pv_local);
} else {
count = count_delim(n->name + path_len);
if (count < maxdepth)
add_pv_node(n->name + plen, n->data, n->type, pv_local);
}
}
} else {
if (!strcmp(n->name, path)) {
if (is_search_by_reference(qPath))
plen = 0;
if (maxdepth > 4 || maxdepth == 0) {
add_pv_node(n->name + plen, n->data, n->type, pv_local);
} else {
count = count_delim(n->name + path_len);
if (count < maxdepth)
add_pv_node(n->name + plen, n->data, n->type, pv_local);
}
}
}
}
}
static void add_data_blob(struct blob_buf *bb, char *param, char *value, char *type)
{
if (param == NULL || value == NULL || type == NULL)
return;
DEBUG("# Adding BLOB (%s)::(%s)", param, value);
switch (get_dm_type(type)) {
case DMT_UNINT:
blobmsg_add_u64(bb, param, (uint32_t)strtoul(value, NULL, 10));
break;
case DMT_INT:
blobmsg_add_u32(bb, param, (int)strtol(value, NULL, 10));
break;
case DMT_LONG:
blobmsg_add_u64(bb, param, strtoll(value, NULL, 10));
break;
case DMT_UNLONG:
blobmsg_add_u64(bb, param, (uint64_t)strtoull(value, NULL, 10));
break;
case DMT_BOOL:
if (get_boolean_string(value))
blobmsg_add_u8(bb, param, true);
else
blobmsg_add_u8(bb, param, false);
break;
default: //"xsd:hexbin" "xsd:dateTime" "xsd:string"
bb_add_string(bb, param, value);
break;
}
}
static void free_result_list(struct list_head *head)
{
struct resultstack *iter = NULL, *node = NULL;
list_for_each_entry_safe(iter, node, head, list) {
free(iter->key);
list_del(&iter->list);
free(iter);
}
}
static void free_result_node(struct resultstack *rnode)
{
if (rnode) {
DEBUG("## ResStack DEL(%s)", rnode->key);
free(rnode->key);
list_del(&rnode->list);
free(rnode);
}
}
static void add_result_node(struct list_head *rlist, char *key, char *cookie)
{
struct resultstack *rnode = NULL;
rnode = (struct resultstack *) malloc(sizeof(*rnode));
if (!rnode) {
ERR("Out of memory!");
return;
}
rnode->key = (key) ? strdup(key) : strdup("");
rnode->cookie = cookie;
DEBUG("## ResSTACK ADD (%s) ##", rnode->key);
INIT_LIST_HEAD(&rnode->list);
list_add(&rnode->list, rlist);
}
static bool is_leaf_element(char *path)
{
char *ptr = NULL;
if (!path)
return true;
ptr = strchr(path, DELIM);
return (ptr == NULL);
}
static bool get_next_element(char *path, char *param)
{
char *ptr;
size_t len;
if (!path)
return false;
len = DM_STRLEN(path);
ptr = strchr(path, DELIM);
if (ptr)
strncpyt(param, path, (size_t)labs(ptr - path) + 1);
else
strncpyt(param, path, len + 1);
return true;
}
static bool is_same_group(char *path, char *group)
{
return (strncmp(path, group, DM_STRLEN(group)) == 0);
}
static bool add_paths_to_stack(struct blob_buf *bb, char *path, size_t begin,
struct pvNode *pv, struct list_head *result_stack)
{
char key[MAX_DM_KEY_LEN], param[MAX_DM_PATH], *ptr;
size_t parsed_len = 0;
void *c;
char *k;
ptr = path + begin;
if (is_leaf_element(ptr)) {
add_data_blob(bb, ptr, pv->val, pv->type);
return true;
}
while (get_next_element(ptr, key)) {
parsed_len += DM_STRLEN(key) + 1;
ptr += DM_STRLEN(key) + 1;
if (is_leaf_element(ptr)) {
strncpyt(param, path, begin + parsed_len + 1);
if (is_node_instance(key))
c = blobmsg_open_table(bb, NULL);
else
c = blobmsg_open_table(bb, key);
k = param;
add_result_node(result_stack, k, c);
add_data_blob(bb, ptr, pv->val, pv->type);
break;
}
strncpyt(param, pv->param, begin + parsed_len + 1);
if (is_node_instance(ptr))
c = blobmsg_open_array(bb, key);
else
c = blobmsg_open_table(bb, key);
k = param;
add_result_node(result_stack, k, c);
}
return true;
}
// public functions
void prepare_result_blob(struct blob_buf *bb, struct list_head *pv_list)
{
char *ptr;
size_t len;
struct pvNode *pv;
struct resultstack *rnode;
LIST_HEAD(result_stack);
if (!bb || !pv_list)
return;
if (list_empty(pv_list))
return;
list_for_each_entry(pv, pv_list, list) {
ptr = pv->param;
if (list_empty(&result_stack)) {
DEBUG("stack empty Processing (%s)", ptr);
add_paths_to_stack(bb, pv->param, 0, pv, &result_stack);
} else {
bool is_done = false;
while (is_done == false) {
rnode = list_entry(result_stack.next, struct resultstack, list);
if (is_same_group(ptr, rnode->key)) {
len = DM_STRLEN(rnode->key);
ptr = ptr + len;
DEBUG("GROUP (%s), ptr(%s), len(%d)", pv->param, ptr, len);
add_paths_to_stack(bb, pv->param, len, pv, &result_stack);
is_done = true;
} else {
// Get the latest entry before deleting it
DEBUG("DIFF GROUP pv(%s), param(%s)", pv->param, ptr);
blobmsg_close_table(bb, rnode->cookie);
free_result_node(rnode);
if (list_empty(&result_stack)) {
add_paths_to_stack(bb, pv->param, 0, pv, &result_stack);
is_done = true;
}
}
}
}
}
// Close the stack entry if left
list_for_each_entry(rnode, &result_stack, list) {
blobmsg_close_table(bb, rnode->cookie);
}
free_result_list(&result_stack);
}
void prepare_pretty_result(uint8_t maxdepth, char *qPath, struct blob_buf *bb,
struct dmctx *bbf_ctx, struct list_head *rslvd)
{
struct pathNode *iter = NULL;
LIST_HEAD(pv_local);
list_for_each_entry(iter, rslvd, list) {
resulting(maxdepth, iter->path, qPath, bbf_ctx, &pv_local);
}
struct pvNode *pv;
DEBUG("################### DATA to PROCESS ##################");
list_for_each_entry(pv, &pv_local, list) {
DEBUG("## %s ##", pv->param);
}
DEBUG("######################################################");
prepare_result_blob(bb, &pv_local);
free_pv_list(&pv_local);
}
/* This function is not used anywhere but kept for debugging purpose hence suppressed */
// cppcheck-suppress unusedFunction
void dump_pv_list(struct list_head *pv_list)
{
struct pvNode *pv = NULL;
INFO("############### PV list Dump #########");
list_for_each_entry(pv, pv_list, list) {
INFO("## (%s)::(%s)::(%s) ##", pv->param, pv->val, pv->type);
}
INFO("############# dump done ###############");
}
/* This function is not used anywhere but kept for debugging purpose hence suppressed */
// cppcheck-suppress unusedFunction
void dump_resolved_list(struct list_head *resolved_list)
{
struct pathNode *iter;
INFO("********************Resolved List Dump***********************");
list_for_each_entry(iter, resolved_list, list) {
INFO("## %s ##", iter->path);
}
INFO("**************************DONE*******************************");
}
void prepare_result_raw(struct blob_buf *bb, struct dmctx *bbf_ctx, struct list_head *rslvd)
{
struct pathNode *iter = NULL;
struct dm_parameter *n;
void *array, *table;
array = blobmsg_open_array(bb, "parameters");
list_for_each_entry(iter, rslvd, list) {
size_t ilen = DM_STRLEN(iter->path);
if (ilen == 0)
continue;
list_for_each_entry(n, &bbf_ctx->list_parameter, list) {
if (iter->path[ilen - 1] == DELIM) {
if (!strncmp(n->name, iter->path, ilen)) {
table = blobmsg_open_table(bb, NULL);
bb_add_string(bb, "parameter", n->name);
bb_add_string(bb, "value", n->data);
bb_add_string(bb, "type", n->type);
blobmsg_close_table(bb, table);
}
} else {
if (!strcmp(n->name, iter->path)) {
table = blobmsg_open_table(bb, NULL);
bb_add_string(bb, "parameter", n->name);
bb_add_string(bb, "value", n->data);
bb_add_string(bb, "type", n->type);
blobmsg_close_table(bb, table);
}
}
}
}
blobmsg_close_array(bb, array);
}

33
bbfd/src/pretty_print.h Normal file
View file

@ -0,0 +1,33 @@
/*
* pretty_print.h: utils for pretty printing of results
*
* Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
*
* Author: Vivek Dutta <vivek.dutta@iopsys.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#ifndef PRETTY_PRINT_H
#define PRETTY_PRINT_H
void prepare_result_blob(struct blob_buf *bb, struct list_head *pv_list);
void prepare_pretty_result(uint8_t maxdepth, char *qPath, struct blob_buf *bb,
struct dmctx *bbf_ctx, struct list_head *rslvd);
void prepare_result_raw(struct blob_buf *bb, struct dmctx *bbf_ctx, struct list_head *rslvd);
void dump_pv_list(struct list_head *pv_list);
void dump_resolved_list(struct list_head *resolved_list);
#endif

225
bbfd/src/set.c Normal file
View file

@ -0,0 +1,225 @@
/*
* set.c: Set handler for uspd
*
* Copyright (C) 2019 iopsys Software Solutions AB. All rights reserved.
*
* Author: Vivek Dutta <vivek.dutta@iopsys.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include "set.h"
#include "get_helper.h"
#include <libubus.h>
#include <libbbfdm/dmbbfcommon.h>
static const struct blobmsg_policy dm_setm_value_policy[] = {
[DM_SET_V_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
[DM_SET_V_VALUE] = { .name = "value", .type = BLOBMSG_TYPE_STRING },
};
int usp_set_value(usp_data_t *data)
{
struct blob_buf bb;
struct ubus_context *ctx;
struct ubus_request_data *req;
void *array = NULL;
struct pvNode *pv = NULL;
struct dmctx bbf_ctx;
int fault = USP_ERR_OK;
struct param_fault *p = NULL;
void *table;
bool fault_occured = false;
memset(&bbf_ctx, 0, sizeof(struct dmctx));
set_bbfdatamodel_type(data->proto);
bbf_init(&bbf_ctx, data->instance);
ctx = data->ctx;
req = data->req;
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
list_for_each_entry(pv, data->pv_list, list) {
fault = usp_dm_set(&bbf_ctx, pv->param, pv->val);
if (fault == 0)
fault = usp_dm_exec_apply(&bbf_ctx, CMD_SET_VALUE);
if (fault) {
if (fault_occured == false) {
fault_occured = true;
if (!array)
array = blobmsg_open_array(&bb, "parameters");
}
while (bbf_ctx.list_fault_param.next != &bbf_ctx.list_fault_param) {
p = list_entry(bbf_ctx.list_fault_param.next, struct param_fault, list);
table = blobmsg_open_table(&bb, NULL);
bb_add_string(&bb, "path", p->name);
blobmsg_add_u8(&bb, "status", false);
blobmsg_add_u32(&bb, "fault", (uint32_t)p->fault);
blobmsg_close_table(&bb, table);
del_list_fault_param(p);
}
}
}
if (fault_occured == false)
blobmsg_add_u8(&bb, "status", true);
if (array)
blobmsg_close_array(&bb, array);
ubus_send_reply(ctx, req, bb.head);
// free
blob_buf_free(&bb);
bbf_cleanup(&bbf_ctx);
return fault;
}
int fill_pvlist_from_table(char *bpath, struct blob_attr *blob_value, struct list_head *pv_list, int instance)
{
struct blob_attr *attr;
char path[MAX_DM_PATH], value[MAX_DM_VALUE];
struct dmctx bbf_ctx;
int fault = USP_ERR_OK;
struct pathNode *p;
size_t tlen;
LIST_HEAD(resolved_paths);
if (!blob_value)
return 0;
tlen = (size_t)blobmsg_data_len(blob_value);
memset(&bbf_ctx, 0, sizeof(struct dmctx));
bbf_init(&bbf_ctx, instance);
fault = get_resolved_paths(&bbf_ctx, bpath, &resolved_paths);
if (fault) {
bbf_cleanup(&bbf_ctx);
free_path_list(&resolved_paths);
return fault;
}
__blob_for_each_attr(attr, blobmsg_data(blob_value), tlen) {
struct blobmsg_hdr *hdr = blob_data(attr);
switch (blob_id(attr)) {
case BLOBMSG_TYPE_STRING:
snprintf(value, MAX_DM_VALUE, "%s", blobmsg_get_string(attr));
break;
case BLOBMSG_TYPE_INT8:
snprintf(value, MAX_DM_VALUE, "%d", blobmsg_get_u8(attr));
break;
case BLOBMSG_TYPE_INT16:
snprintf(value, MAX_DM_VALUE, "%d", blobmsg_get_u16(attr));
break;
case BLOBMSG_TYPE_INT32:
snprintf(value, MAX_DM_VALUE, "%u", blobmsg_get_u32(attr));
break;
case BLOBMSG_TYPE_INT64:
snprintf(value, MAX_DM_VALUE, "%"PRIu64"", blobmsg_get_u64(attr));
break;
default:
INFO("Unhandled set request type|%x|", blob_id(attr));
bbf_cleanup(&bbf_ctx);
free_path_list(&resolved_paths);
return USP_FAULT_INVALID_ARGUMENT;
}
list_for_each_entry(p, &resolved_paths, list) {
snprintf(path, MAX_DM_PATH, "%s%s", p->path, (char *)hdr->name);
add_pv_node(path, value, NULL, pv_list);
}
}
bbf_cleanup(&bbf_ctx);
free_path_list(&resolved_paths);
return fault;
}
int fill_pvlist_from_tuple(struct blob_attr *blob, struct list_head *pv_list)
{
size_t rem;
struct blob_attr *cur;
blobmsg_for_each_attr(cur, blob, rem) {
struct blob_attr *tb[__DM_SET_V_MAX];
char *path, *value, *key;
key = NULL;
blobmsg_parse(dm_setm_value_policy, __DM_SET_V_MAX, tb,
blobmsg_data(cur), blobmsg_len(cur));
// ignore the tuples which does not have path and values
if (!tb[DM_SET_V_PATH] || !tb[DM_SET_V_VALUE])
continue;
path = blobmsg_get_string(tb[DM_SET_V_PATH]);
value = blobmsg_get_string(tb[DM_SET_V_VALUE]);
add_pv_node(path, value, key, pv_list);
}
return 0;
}
int fill_pvlist_from_path(char *path, struct blob_attr *val_blob, struct list_head *pv_list, int instance)
{
int fault = USP_ERR_OK;
size_t plen;
char *val = NULL;
struct dmctx bbf_ctx;
LIST_HEAD(resolved_paths);
if (!val_blob)
return 0;
memset(&bbf_ctx, 0, sizeof(struct dmctx));
bbf_init(&bbf_ctx, instance);
plen = DM_STRLEN(path);
if (plen == 0)
fault = USP_FAULT_INVALID_PATH;
if (fault == USP_ERR_OK) {
if (path[plen - 1] == '.')
fault = USP_FAULT_INVALID_PATH;
}
if (fault == USP_ERR_OK)
fault = get_resolved_paths(&bbf_ctx, path, &resolved_paths);
if (fault == USP_ERR_OK) {
struct pathNode *p;
list_for_each_entry(p, &resolved_paths, list) {
val = blobmsg_get_string(val_blob);
add_pv_node(p->path, val, NULL, pv_list);
}
}
free_path_list(&resolved_paths);
bbf_cleanup(&bbf_ctx);
return fault;
}

60
bbfd/src/set.h Normal file
View file

@ -0,0 +1,60 @@
#ifndef SET_H
#define SET_H
#include "usp.h"
#include "common.h"
enum {
DM_SETS_PATHS,
DM_SETS_PROTO,
DM_SETS_INSTANCE,
DM_SETS_TRANS_ID,
__DM_SETS_MAX
};
enum {
DM_SETS_A_NOTIF_PATH,
DM_SETS_A_NOTIF_VALUE,
DM_SETS_A_NOTIF_CHANGE,
__DM_SETS_A_NOTIF_MAX
};
enum {
DM_SET_PATH,
DM_SET_VALUE,
DM_SET_VALUE_TABLE,
DM_SET_PROTO,
DM_SET_INSTANCE,
__DM_SET_MAX,
};
enum {
DM_RAW_SET_PATH,
DM_RAW_SET_VALUE,
DM_RAW_SET_VALUE_TABLE,
DM_RAW_SET_PROTO,
DM_RAW_SET_INSTANCE,
DM_RAW_SET_TRANS_ID,
__DM_RAW_SET_MAX,
};
enum {
DM_SET_V_PATH,
DM_SET_V_VALUE,
__DM_SET_V_MAX
};
enum {
DM_SET_MULTI_TUPLE,
DM_SET_MULTI_PROTO,
DM_SET_MULTI_INSTANCE,
DM_SET_MULTI_TRANS_ID,
__DM_SET_MULTI_MAX
};
int fill_pvlist_from_table(char *bpath, struct blob_attr *blob_value, struct list_head *pv_list, int instance);
int fill_pvlist_from_tuple(struct blob_attr *blob, struct list_head *pv_list);
int fill_pvlist_from_path(char *path, struct blob_attr *val_blob, struct list_head *pv_list, int instance);
int usp_set_value(usp_data_t *data);
#endif /* SET_H */

1686
bbfd/src/usp.c Normal file

File diff suppressed because it is too large Load diff

137
bbfd/src/usp.h Normal file
View file

@ -0,0 +1,137 @@
#ifndef USP_H
#define USP_H
#include <libubus.h>
#include <libubox/blobmsg.h>
#include <libubox/list.h>
#define USP_ATTR_UNUSED __attribute__((unused))
#define USP_EXT_LEN (4) // length of usp.
#define MAX_GRANURALITY_DEPTH (3)
#define USP_SUBPROCESS_DEPTH (2)
#define SCHEMA_UPDATE_TIMEOUT (30 * 1000)
struct uspd_async_req {
struct ubus_context *ctx;
struct ubus_request_data req;
struct uloop_process process;
void *result;
};
struct usp_context {
struct ubus_context ubus_ctx;
size_t dm_schema_len;
struct uloop_timeout schema_timer;
struct uloop_timeout instance_timer;
struct ubus_object *notify_object;
struct list_head obj_list;
struct list_head event_handlers;
struct list_head instances;
struct list_head old_instances;
};
struct ev_handler_node {
struct ubus_event_handler *ev_handler;
struct list_head list;
};
typedef struct usp_data {
struct ubus_context *ctx;
struct ubus_request_data *req;
bool is_raw;
int proto;
char *qpath;
uint8_t depth;
char *next_level;
int dm_cmd;
struct list_head *plist;
struct list_head *pv_list;
char *set_key;
char *op_action;
char *op_input;
int instance;
int trans_id;
} usp_data_t;
enum {
DM_LIST_NOTIFY_INSTANCE,
__DM_LIST_NOTIFY_MAX,
};
enum {
DM_SUPPORTED_PATH,
DM_SUPPORTED_NXT_LEVEL,
DM_SUPPORTED_SCHEMA_TYPE,
__DM_SUPPORTED_MAX
};
enum {
DM_NOTIFY_NAME,
DM_NOTIFY_PRAMS,
__DM_NOTIFY_MAX,
};
struct obNode {
struct ubus_object *obj;
struct list_head list;
};
int get_multi(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, struct blob_attr *msg,
int bbf_cmd);
int usp_getm_values(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req,
USP_ATTR_UNUSED const char *method,
struct blob_attr *msg);
int usp_getm_names(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req,
USP_ATTR_UNUSED const char *method,
struct blob_attr *msg);
int usp_add_del_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg);
int usp_raw_add_del_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg);
int usp_get_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method USP_ATTR_UNUSED,
struct blob_attr *msg);
int usp_set(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg);
int usp_raw_set(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg);
int usp_operate(struct ubus_context *ctx, struct ubus_object *obj USP_ATTR_UNUSED,
struct ubus_request_data *req, const char *method USP_ATTR_UNUSED,
struct blob_attr *msg);
int usp_list_schema(struct ubus_context *actx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg USP_ATTR_UNUSED);
int usp_list_operate(struct ubus_context *actx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg USP_ATTR_UNUSED);
int handle_set_multi_value(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method USP_ATTR_UNUSED,
struct blob_attr *msg);
int usp_transaction_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg);
bool usp_pre_init(struct usp_context *u);
bool usp_post_init(struct usp_context *u);
bool usp_cleanup(struct usp_context *u);
#endif /* COMMON_H */

16
bbfd/test/Makefile Normal file
View file

@ -0,0 +1,16 @@
LIB = libuspd_test.so
LIB_OBJS = libuspd_test.o
LIB_CFLAGS = $(CFLAGS) -Wall -Werror -fPIC
LIB_LDFLAGS = $(LDFLAGS)
%.o: %.c
$(CC) $(LIB_CFLAGS) -I/usr/local/include/libbbf_api/ -c -o $@ $<
all: $(LIB)
$(LIB): $(LIB_OBJS)
$(CC) $(LIB_CFLAGS) $(LIB_LDFLAGS) -shared -o $@ $^
clean:
rm -fv *.o $(LIB)

39
bbfd/test/Readme.md Normal file
View file

@ -0,0 +1,39 @@
# USPD Tests
USPD module test is based on `iopsys/code-analysis-dev` docker image. It consists
of below test phases, in each phase different kind of test perform:
1. Static code analysis
2. Unit Test
3. API Test
4. Functional Test
## 1. Static code Analysis
In this stage code is being tested for flaws by running static code analysers,
it also runs CPD tests which determine the optimal reusable codes.
Tests running in this phase are:
- Flaw finder
- CPP Check
- CPD Test
## 2. Unit Test
In this stage various wrapper functions being tested for memory leaks using
`valgrind`.
Tests running in this phase are:
- Cmocka Test cases
- Coverage report
- memory check using valgrind
## 3. API Test
In this stage ubus exposed APIs getting tested using `ubus-api-validator`
## 4. Functional Test
In this stage functionality provided by uspd is getting tested.
Below tests and verifications done in this stage:
- Compilation check
- Python based bug verification
- Functionality testing based on schema validation

View file

@ -0,0 +1,157 @@
{
"object": "usp.raw",
"methods": [
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "usp"
},
"rc": 0
},
{
"method": "hello",
"rc": 3
},
{
"method": "instances",
"args": {
"path": "Device.Users.User.",
"proto": "usp"
},
"rc": 0
},
{
"method": "transaction_start",
"args": {
"app": "test"
},
"rc": 0
},
{
"method": "set",
"args": {
"path": "Device.WiFi.SSID.1.SSID",
"value": "test-2g",
"transaction_id": 123
},
"rc": 0
},
{
"method": "transaction_abort",
"args": {
"transaction_id": 123
},
"rc": 0
},
{
"method": "object_names",
"args": {
"path": "Device.WiFi.SSID.1.",
"proto": "usp"
},
"rc": 0
},
{
"method": "operate",
"args": {
"path":"Device.IP.Diagnostics.",
"action":"IPPing()",
"input":{
"Host":"127.0.0.1",
"Timeout":".5"
}
},
"rc": 0
},
{
"method": "get_supported_dm",
"args": {
"path":"Device.USB.",
"next-level":false,
"schema_type":1
},
"rc": 0
},
{
"method": "get_supported_dm",
"args": {
"path":"Device.WiFi."
},
"rc": 0
},
{
"method": "get_supported_dm",
"args": {
"path":"Device.WiFi.",
"next-level":false,
"schema_type":2
},
"rc": 0
},
{
"method": "get_supported_dm",
"args": {
"path":"Device.USB.",
"next-level":false,
"schema_type":3
},
"rc": 0
},
{
"method": "get_supported_dm",
"args": {
"path":"Device.WiFi.",
"schema_type":1
},
"rc": 0
},
{
"method": "get_supported_dm",
"args": {},
"rc": 0
},
{
"method": "dump_schema",
"args": {},
"rc": 0
},
{
"method": "list_operate",
"args": {},
"rc": 0
},
{
"method": "transaction_start",
"args": {
"app": "test"
},
"rc": 0
},
{
"method": "setm_values",
"args": {
"pv_tuple": [{"path":"Device.Users.User.1.Alias", "value":"cpe-1"}, {"path":"Device.Users.User.2.Alias", "value":"cpe-2"}],
"proto": "usp",
"transaction_id": 123
},
"rc": 0
},
{
"method": "transaction_commit",
"args": {
"transaction_id": 123
},
"rc": 0
},
{
"method": "getm_names",
"args": {
"paths": ["Device.WiFi.SSID.1.SSID","Device.WiFi.SSID.2.SSID"],
"proto": "usp"
},
"rc": 0
}
]
}

View file

@ -0,0 +1,117 @@
{
"object": "usp",
"methods": [
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "usp"
},
"rc": 0
},
{
"method": "object_names",
"args": {
"path": "Device.WiFi.SSID.1.",
"proto": "usp"
},
"rc": 0
},
{
"method": "instances",
"args": {
"path": "Device.Users.User.",
"proto": "usp"
},
"rc": 0
},
{
"method": "validate",
"args": {
"path": "Device.Users.User.1.Alias",
"proto": "usp"
},
"rc": 0
},
{
"method": "set",
"args": {
"path": "Device.WiFi.SSID.1.SSID",
"value": "test-2g"
},
"rc": 0
},
{
"method": "operate",
"args": {
"path":"Device.IP.Diagnostics.",
"action":"IPPing()",
"input":{
"Host":"127.0.0.1"
}
},
"rc": 0
},
{
"method": "add_object",
"args": {
"path": "Device.Users.User.",
"proto": "usp"
},
"rc": 0
},
{
"method": "list_operate",
"args": {},
"rc": 0
},
{
"method": "get_supported_dm",
"args": {
"path":"Device.USB.",
"next-level":false,
"schema_type":1
},
"rc": 0
},
{
"method": "get_supported_dm",
"args": {
"path":"Device.WiFi."
},
"rc": 0
},
{
"method": "get_supported_dm",
"args": {
"path":"Device.WiFi.",
"next-level":false,
"schema_type":2
},
"rc": 0
},
{
"method": "get_supported_dm",
"args": {
"path":"Device.USB.",
"next-level":false,
"schema_type":3
},
"rc": 0
},
{
"method": "get_supported_dm",
"args": {
"Path":"Device.WiFi.",
"schema_type":1
},
"rc": 0
},
{
"method": "get_supported_dm",
"args": {},
"rc": 0
}
]
}

23
bbfd/test/cmocka/Makefile Normal file
View file

@ -0,0 +1,23 @@
CC = gcc
USPD_LIB_DIR ?= $(shell dirname $(PWD))
USPD_LIB = -luspd -L$(USPD_LIB_DIR)
CMOCKA_LIB = -l cmocka
LIBS = $(USPD_LIB) $(CMOCKA_LIB) -luci -pthread -lubus -lubox -ljson-c -lblobmsg_json -lbbfdm -lpthread
CFLAGS = -g -Wall -I../../src
LDFLAGS = $(LIBS) -Wl,-rpath=$(USPD_LIB_DIR) -I$(USPD_LIB_DIR)
UNIT_TESTS = unit_test_uspd
VALGRIND = valgrind --leak-check=full --show-reachable=no \
--show-leak-kinds=all --errors-for-leak-kinds=all \
--error-exitcode=1 --track-origins=yes
unit_test_uspd: unit_test_uspd.o
$(CC) -o $@ $^ $(LDFLAGS)
unit-test: $(UNIT_TESTS)
$(foreach testprog, $(UNIT_TESTS), sudo $(VALGRIND) ./$(testprog);)
.PHONY: clean
clean:
rm $(UNIT_TESTS) *.o -fv

View file

@ -0,0 +1,9 @@
#ifndef TEST_UTILS_H
#define TEST_UTILS_H
#define GET_PATH "Device.DeviceInfo.Manufacturer"
#define GET_PROTO "usp"
#define GET_RAW_PROTO "usp.raw"
#define GET_CWMP_PROTO "cwmp"
#endif

View file

@ -0,0 +1,980 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include <libubus.h>
#include <libubox/blobmsg_json.h>
#include <libubox/blobmsg.h>
#include <libubox/list.h>
#include <syslog.h>
#include <json-c/json.h>
#include "usp.h"
#include "get_helper.h"
#include "test_utils.h"
struct test_ctx {
struct usp_context uspctx;
struct blob_buf bb;
struct ubus_object usp;
struct ubus_object usp_raw;
FILE *fp;
struct ubus_request_data *req;
unsigned long instance;
};
// Stub functions to override existing functionalities
void ubus_complete_deferred_request(struct ubus_context *ctx,
struct ubus_request_data *req, int ret)
{
}
static int group_setup(void **state)
{
struct test_ctx *ctx = calloc(1, sizeof(struct test_ctx));
if (!ctx)
return -1;
openlog("unit_test", LOG_CONS| LOG_NDELAY, LOG_LOCAL1);
memset(&ctx->uspctx, 0, sizeof(struct usp_context));
ubus_connect_ctx(&ctx->uspctx.ubus_ctx, NULL);
INIT_LIST_HEAD(&ctx->uspctx.obj_list);
INIT_LIST_HEAD(&ctx->uspctx.instances);
INIT_LIST_HEAD(&ctx->uspctx.old_instances);
usp_pre_init(&ctx->uspctx);
remove("/tmp/test.log");
ctx->usp.name = "usp";
ctx->usp_raw.name = "usp.raw";
memset(&ctx->bb, 0, sizeof(struct blob_buf));
ctx->req = (struct ubus_request_data *) calloc(1, sizeof(struct ubus_request_data));
*state = ctx;
return 0;
}
static int setup(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
remove("/tmp/test.log");
blob_buf_init(&ctx->bb, 0);
return 0;
}
static int group_teardown(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
usp_cleanup(&ctx->uspctx);
blob_buf_free(&ctx->bb);
ubus_shutdown(&ctx->uspctx.ubus_ctx);
free(ctx->req);
free(ctx);
remove("/tmp/test.log");
return 0;
}
static void test_api_usp_get_DeviceInfo_Manufacturer(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp;
struct ubus_request_data *req = ctx->req;
struct json_object *jobj, *tmp;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
blobmsg_add_string(bb, "path", "DeviceInfo.Manufacturer");
blobmsg_add_string(bb, "proto", GET_PROTO);
usp_get_handler(uctx, obj, req, "get", bb->head);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
//printf("json(%s)\n", json_object_to_json_string(jobj));
json_object_object_get_ex(jobj, "fault", &tmp);
assert_string_equal(json_object_to_json_string(tmp), "7026");
json_object_put(jobj);
return;
}
static void test_api_usp_raw_getm_values_Device_WiFi_SSID_Alias(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp_raw;
struct ubus_request_data *req = ctx->req;
struct json_object *jobj, *tmp;
struct json_object *local;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
void *paths;
paths = blobmsg_open_array(bb, "paths");
blobmsg_add_string(bb, NULL, "Device.WiFi.SSID.1.Alias");
blobmsg_close_array(bb, paths);
blobmsg_add_string(bb, "proto", GET_RAW_PROTO);
usp_getm_values(uctx, obj, req, "getm_values", bb->head);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
printf("json(%s)\n", json_object_to_json_string(jobj));
json_object_object_get_ex(jobj, "parameters", &tmp);
if (json_object_get_type(tmp) == json_type_array) {
for (int i = 0; i<json_object_array_length(tmp);++i) {
struct json_object *val = json_object_array_get_idx(tmp, i);
json_object_object_get_ex(val, "value", &local);
assert_string_equal(json_object_get_string(local), "cpe-1");
}
}
json_object_put(jobj);
return;
}
static void test_api_usp_raw_resolve_Device_Users_User(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp_raw;
struct ubus_request_data *req = ctx->req;
struct json_object *jobj, *tmp;
struct json_object *local;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
blobmsg_add_string(bb, "path", "Device.Users.User.1.Username");
blobmsg_add_string(bb, "proto", GET_RAW_PROTO);
usp_get_handler(uctx, obj, req, "validate", bb->head);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
printf("json(%s)\n", json_object_to_json_string(jobj));
json_object_object_get_ex(jobj, "parameters", &tmp);
if (json_object_get_type(tmp) == json_type_array) {
for (int i = 0; i<json_object_array_length(tmp); ++i) {
struct json_object *val = json_object_array_get_idx(tmp, i);
json_object_object_get_ex(val, "parameter", &local);
assert_string_equal(json_object_get_string(local), "Device.Users.User.1.Usernam");
}
}
json_object_put(jobj);
return;
}
static void test_api_usp_resolve_Device_Users_User(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp;
struct ubus_request_data *req = ctx->req;
struct json_object *jobj, *tmp;
struct json_object *local;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
blobmsg_add_string(bb, "path", "Device.Users.User.1.Username");
blobmsg_add_string(bb, "proto", GET_PROTO);
usp_get_handler(uctx, obj, req, "validate", bb->head);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
printf("json(%s)\n", json_object_to_json_string(jobj));
json_object_object_get_ex(jobj, "parameters", &tmp);
if (json_object_get_type(tmp) == json_type_array) {
for (int i = 0; i<json_object_array_length(tmp); ++i) {
struct json_object *val = json_object_array_get_idx(tmp, i);
json_object_object_get_ex(val, "parameter", &local);
assert_string_equal(json_object_get_string(local), "Device.Users.User.1.Usernam");
}
}
json_object_put(jobj);
return;
}
static void test_api_usp_raw_getm_names_Device_WiFi_SSID_Alias(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp_raw;
struct ubus_request_data *req = ctx->req;
struct json_object *jobj, *tmp;
struct json_object *local;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
void *paths;
paths = blobmsg_open_array(bb, "paths");
blobmsg_add_string(bb, NULL, "Device.WiFi.SSID.1.Alias");
blobmsg_close_array(bb, paths);
blobmsg_add_string(bb, "proto", GET_RAW_PROTO);
usp_getm_names(uctx, obj, req, "getm_names", bb->head);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
printf("json(%s)\n", json_object_to_json_string(jobj));
json_object_object_get_ex(jobj, "parameters", &tmp);
if (json_object_get_type(tmp) == json_type_array) {
for (int i = 0; i<json_object_array_length(tmp); ++i) {
struct json_object *val = json_object_array_get_idx(tmp, i);
json_object_object_get_ex(val, "parameter", &local);
assert_string_equal(json_object_get_string(local), "Device.WiFi.SSID.1.Alias");
json_object_object_get_ex(val, "value", &local);
assert_string_equal(json_object_get_string(local), "1");
}
}
json_object_put(jobj);
return;
}
static void test_api_usp_raw_dump_schema(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct ubus_context *ubus_ctx = &ctx->uspctx.ubus_ctx;
struct ubus_object *obj = &ctx->usp_raw;
struct ubus_request_data *req = ctx->req;
struct json_object *jobj;
usp_list_schema(ubus_ctx, obj, req, "dump_schema", NULL);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
//printf("json(%s)\n", json_object_to_json_string(jobj));
json_object_put(jobj);
return;
}
static void test_api_usp_list_operate(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct ubus_context *ubus_ctx = &ctx->uspctx.ubus_ctx;
struct ubus_object *obj = &ctx->usp;
struct ubus_request_data *req = ctx->req;
struct json_object *jobj;
usp_list_operate(ubus_ctx, obj, req, "list_operate", NULL);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
//printf("json(%s)\n", json_object_to_json_string(jobj));
json_object_put(jobj);
return;
}
static void test_api_usp_get_wrong_name_Device_IP_Interface(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp;
struct ubus_request_data *req = ctx->req;
struct json_object *jobj, *tmp;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
blobmsg_add_string(bb, "path","Device.IP._Interface.1.Status");
blobmsg_add_string(bb, "proto", GET_PROTO);
usp_get_handler(uctx, obj, req, "get", bb->head);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
printf("json(%s)\n", json_object_to_json_string(jobj));
json_object_object_get_ex(jobj, "fault", &tmp);
assert_string_equal(json_object_to_json_string(tmp), "7026");
json_object_put(jobj);
return;
}
static void test_api_usp_get_wrong_braces_Device_IP_Interface(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp;
struct ubus_request_data *req = ctx->req;
struct json_object *jobj, *tmp;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
blobmsg_add_string(bb, "path","Device.IP.Interface.{Type==\"Normal\"}.Status");
blobmsg_add_string(bb, "proto", GET_PROTO);
usp_get_handler(uctx, obj, req, "get", bb->head);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
printf("json(%s)\n", json_object_to_json_string(jobj));
json_object_object_get_ex(jobj, "fault", &tmp);
assert_string_equal(json_object_to_json_string(tmp), "7026");
json_object_put(jobj);
return;
}
static void test_api_usp_get_wrong_exp_Device_IP_Interface(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp;
struct ubus_request_data *req = ctx->req;
struct json_object *jobj, *tmp;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
blobmsg_add_string(bb, "path","Device.IP.Interface.[Type==\"Normal\"&&IPv4Address.*.AddressingType==\"Static\"].Status");
blobmsg_add_string(bb, "proto", GET_PROTO);
usp_get_handler(uctx, obj, req, "get", bb->head);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
printf("json(%s)\n", json_object_to_json_string(jobj));
json_object_object_get_ex(jobj, "fault", &tmp);
assert_string_equal(json_object_to_json_string(tmp), "7011");
json_object_put(jobj);
return;
}
static void test_api_usp_get_Device_IP_Interface(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp;
struct ubus_request_data *req = ctx->req;
struct json_object *jobj, *tmp;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
blobmsg_add_string(bb, "path", "Device.IP.Interface.[].");
blobmsg_add_string(bb, "proto", GET_PROTO);
usp_get_handler(uctx, obj, req, "get", bb->head);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
printf("json(%s)\n", json_object_to_json_string(jobj));
json_object_object_get_ex(jobj, "fault", &tmp);
assert_string_equal(json_object_to_json_string(tmp), "7026");
json_object_put(jobj);
return;
}
static void test_api_usp_get_search_exp_Device_WiFi_SSID(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp;
struct ubus_request_data *req = ctx->req;
struct json_object *jobj, *tmp, *array_obj;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
blobmsg_add_string(bb, "path", "Device.WiFi.SSID.[Status==\"Up\"].Alias");
blobmsg_add_string(bb, "proto", GET_PROTO);
usp_get_handler(uctx, obj, req, "get", bb->head);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
printf("json(%s)\n", json_object_to_json_string(jobj));
array_obj = json_object_object_get(jobj, "SSID");
if (json_object_get_type(array_obj) == json_type_array) {
for (int i = 0; i<json_object_array_length(array_obj);++i) {
char temp[512];
struct json_object *array_index_obj = json_object_array_get_idx(array_obj, i);
json_object_object_get_ex(array_index_obj, "Alias", &tmp);
snprintf(temp, 512, "cpe-%d", i+1);
assert_string_equal(json_object_get_string(tmp), temp);
}
}
json_object_put(jobj);
return;
}
static void test_api_usp_get_Device_WiFi_SSID(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp;
struct ubus_request_data *req = ctx->req;
struct json_object *jobj, *tmp, *array_obj;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
blobmsg_add_string(bb, "path", "Device.WiFi.SSID.*.Alias");
blobmsg_add_string(bb, "proto", GET_PROTO);
usp_get_handler(uctx, obj, req, "get", bb->head);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
printf("json(%s)\n", json_object_to_json_string(jobj));
array_obj = json_object_object_get(jobj, "SSID");
if (json_object_get_type(array_obj) == json_type_array) {
for (int i = 0; i < json_object_array_length(array_obj); ++i) {
char temp[512];
struct json_object *array_index_obj = json_object_array_get_idx(array_obj, i);
json_object_object_get_ex(array_index_obj, "Alias", &tmp);
snprintf(temp, 512, "cpe-%d", i+1);
assert_string_equal(json_object_get_string(tmp), temp);
}
}
json_object_put(jobj);
return;
}
static void test_api_usp_get_wrong_oper_Device_WiFi_SSID(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp;
struct ubus_request_data *req = ctx->req;
struct json_object *jobj, *tmp;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
blobmsg_add_string(bb, "path", "Device.WiFi.SSID.[Status>Up].Alias");
blobmsg_add_string(bb, "proto", GET_PROTO);
usp_get_handler(uctx, obj, req, "get", bb->head);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
printf("json(%s)\n", json_object_to_json_string(jobj));
json_object_object_get_ex(jobj, "fault", &tmp);
assert_string_equal(json_object_to_json_string(tmp), "7008");
json_object_put(jobj);
return;
}
static void test_api_usp_get_Device_DeviceInfo_Manufacturer(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp;
struct json_object *jobj, *tmp;
struct ubus_request_data *req = ctx->req;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
blobmsg_add_string(bb, "path", GET_PATH);
blobmsg_add_string(bb, "proto", GET_PROTO);
usp_get_handler(uctx, obj, req, "get", bb->head);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
printf("json(%s)\n", json_object_to_json_string(jobj));
json_object_object_get_ex(jobj, "Manufacturer", &tmp);
assert_string_equal(json_object_get_string(tmp), "iopsys");
json_object_put(jobj);
return;
}
static void test_api_usp_add_object_Device_Users_User(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp;
struct json_object *jobj, *tmp, *array_index_obj, *array_obj;
struct ubus_request_data *req = ctx->req;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
blobmsg_add_string(bb, "path", "Device.Users.User.");
blobmsg_add_string(bb, "proto", GET_PROTO);
usp_add_del_handler(uctx, obj, req, "add_object", bb->head);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
printf("json(%s)\n", json_object_to_json_string(jobj));
array_obj = json_object_object_get(jobj, "parameters");
array_index_obj = json_object_array_get_idx(array_obj, 0);
tmp = json_object_object_get(array_index_obj, "parameter");
assert_string_equal(json_object_get_string(tmp), "Device.Users.User.");
json_object_object_get_ex(array_index_obj, "status", &tmp);
assert_string_equal(json_object_get_string(tmp), "true");
tmp = NULL;
json_object_object_get_ex(array_index_obj, "instance", &tmp);
assert_non_null(tmp);
ctx->instance = strtoul(json_object_get_string(tmp), NULL, 10);
assert_int_not_equal((int)ctx->instance, 0);
json_object_put(jobj);
return;
}
static void test_api_usp_del_Device_Users_User(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp;
struct json_object *jobj, *tmp, *array_obj, *array_index_obj;
struct ubus_request_data *req = ctx->req;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
assert_int_not_equal((int)ctx->instance, 0);
char path[1024] = {0};
snprintf(path, sizeof(path), "Device.Users.User.%lu.", ctx->instance);
blobmsg_add_string(bb, "path", path);
blobmsg_add_string(bb, "proto", GET_PROTO);
usp_add_del_handler(uctx, obj, req, "del_object", bb->head);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
printf("json(%s)\n", json_object_to_json_string(jobj));
array_obj = json_object_object_get(jobj, "parameters");
array_index_obj = json_object_array_get_idx(array_obj, 0);
tmp = json_object_object_get(array_index_obj, "parameter");
assert_string_equal(json_object_get_string(tmp), path);
tmp = json_object_object_get(array_index_obj, "status");
assert_string_equal(json_object_get_string(tmp), "true");
ctx->instance = 0;
json_object_put(jobj);
return;
}
static void test_api_usp_instances_Device_Users_User(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp;
struct json_object *jobj, *tmp, *array_obj, *array_index_obj;
struct ubus_request_data *req = ctx->req;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
blobmsg_add_string(bb, "path", "Device.Users.User.");
blobmsg_add_string(bb, "proto", GET_PROTO);
usp_get_handler(uctx, obj, req, "instances", bb->head);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
array_obj = json_object_object_get(jobj, "parameters");
array_index_obj = json_object_array_get_idx(array_obj, 0);
tmp = json_object_object_get(array_index_obj, "parameter");
assert_string_equal(json_object_get_string(tmp), "Device.Users.User.1");
json_object_put(jobj);
return;
}
static void test_api_usp_instances_Device(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp;
struct json_object *jobj, *array_obj, *array_index_obj;
struct ubus_request_data *req = ctx->req;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
blobmsg_add_string(bb, "path", "Device.");
blobmsg_add_string(bb, "proto", GET_PROTO);
usp_get_handler(uctx, obj, req, "instances", bb->head);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
array_obj = json_object_object_get(jobj, "parameters");
array_index_obj = json_object_array_get_idx(array_obj, 0);
assert_non_null(array_index_obj);
json_object_put(jobj);
return;
}
static void test_api_usp_set_Device_Users_User(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp;
struct json_object *jobj, *tmp;
struct ubus_request_data *req = ctx->req;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
assert_int_not_equal((int)ctx->instance, 0);
char path[1024] = {0};
snprintf(path, sizeof(path), "Device.Users.User.%lu.Username", ctx->instance);
blobmsg_add_string(bb, "path", path);
blobmsg_add_string(bb, "value", "user2");
usp_set(uctx, obj, req, "set", bb->head);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
printf("json(%s)\n", json_object_to_json_string(jobj));
tmp = json_object_object_get(jobj, "status");
assert_string_equal(json_object_get_string(tmp), "true");
json_object_put(jobj);
return;
}
static void test_api_usp_object_name_Device_Users_User(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp;
struct json_object *jobj, *tmp, *array_obj, *array_index_obj;
struct ubus_request_data *req = ctx->req;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
blobmsg_add_string(bb, "path", "Device.Users.User.");
blobmsg_add_string(bb, "proto", GET_PROTO);
blobmsg_add_u8(bb, "next-level", true);
usp_get_handler(uctx, obj, req, "object_names", bb->head);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
printf("json(%s)\n", json_object_to_json_string(jobj));
array_obj = json_object_object_get(jobj, "parameters");
array_index_obj = json_object_array_get_idx(array_obj, 0);
tmp = json_object_object_get(array_index_obj, "parameter");
assert_string_equal(json_object_get_string(tmp), "Device.Users.User.1.");
json_object_put(jobj);
return;
}
static void test_api_usp_raw_get_Device_DeviceInfo_Manufacturer(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp_raw;
struct json_object *jobj, *tmp, *array_obj, *array_index_obj;
struct ubus_request_data *req = ctx->req;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
blobmsg_add_string(bb, "path", GET_PATH);
blobmsg_add_string(bb, "proto", GET_PROTO);
usp_get_handler(uctx, obj, req, "get", bb->head);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
printf("json(%s)\n", json_object_to_json_string(jobj));
array_obj = json_object_object_get(jobj, "parameters");
array_index_obj = json_object_array_get_idx(array_obj, 0);
tmp = json_object_object_get(array_index_obj, "parameter");
assert_string_equal(json_object_get_string(tmp), "Device.DeviceInfo.Manufacturer");
tmp = json_object_object_get(array_index_obj, "value");
assert_string_equal(json_object_get_string(tmp), "iopsys");
json_object_put(jobj);
return;
}
static void test_api_usp_raw_add_object_Device_Users_User(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp_raw;
struct json_object *jobj, *tmp, *array_obj, *array_index_obj;
struct ubus_request_data *req = ctx->req;
int trans_id;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
trans_id = transaction_start("ut", 0);
blobmsg_add_string(bb, "path", "Device.Users.User.");
blobmsg_add_string(bb, "proto", GET_PROTO);
blobmsg_add_u32(bb, "transaction_id", trans_id);
usp_raw_add_del_handler(uctx, obj, req, "add_object", bb->head);
transaction_commit(trans_id, NULL, true);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
printf("json(%s)\n", json_object_to_json_string(jobj));
array_obj = json_object_object_get(jobj, "parameters");
array_index_obj = json_object_array_get_idx(array_obj, 0);
json_object_object_get_ex(array_index_obj, "status", &tmp);
assert_string_equal(json_object_get_string(tmp), "true");
tmp = NULL;
json_object_object_get_ex(array_index_obj, "instance", &tmp);
assert_non_null(tmp);
ctx->instance = strtoul(json_object_get_string(tmp), NULL, 10);
assert_int_not_equal((int)ctx->instance, 0);
json_object_put(jobj);
return;
}
static void test_api_usp_raw_del_Device_Users_User(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp_raw;
struct json_object *jobj, *tmp, *array_obj, *array_index_obj;
struct ubus_request_data *req = ctx->req;
int trans_id;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
assert_int_not_equal((int)ctx->instance, 0);
char path[1024] = {0};
snprintf(path, sizeof(path), "Device.Users.User.%lu.", ctx->instance);
trans_id = transaction_start("ut", 0);
blobmsg_add_string(bb, "path", path);
blobmsg_add_string(bb, "proto", GET_PROTO);
blobmsg_add_u32(bb, "transaction_id", trans_id);
usp_raw_add_del_handler(uctx, obj, req, "del_object", bb->head);
transaction_commit(trans_id, NULL, true);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
printf("json(%s)\n", json_object_to_json_string(jobj));
array_obj = json_object_object_get(jobj, "parameters");
array_index_obj = json_object_array_get_idx(array_obj, 0);
tmp = json_object_object_get(array_index_obj, "parameter");
assert_string_equal(json_object_get_string(tmp), path);
tmp = json_object_object_get(array_index_obj, "status");
assert_string_equal(json_object_get_string(tmp), "true");
ctx->instance = 0;
json_object_put(jobj);
return;
}
static void test_api_usp_raw_instances_Device_Users_User(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp_raw;
struct json_object *jobj, *tmp, *array_obj, *array_index_obj;
struct ubus_request_data *req = ctx->req;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
blobmsg_add_string(bb, "path", "Device.Users.User.");
blobmsg_add_string(bb, "proto", GET_PROTO);
usp_get_handler(uctx, obj, req, "instances", bb->head);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
printf("json(%s)\n", json_object_to_json_string(jobj));
array_obj = json_object_object_get(jobj, "parameters");
array_index_obj = json_object_array_get_idx(array_obj, 0);
tmp = json_object_object_get(array_index_obj, "parameter");
assert_string_equal(json_object_get_string(tmp), "Device.Users.User.1");
json_object_put(jobj);
return;
}
static void test_api_usp_raw_set_Device_Users_User(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp_raw;
struct json_object *jobj, *tmp;
struct ubus_request_data *req = ctx->req;
int trans_id;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
assert_int_not_equal((int)ctx->instance, 0);
char path[1024] = {0};
snprintf(path, sizeof(path), "Device.Users.User.%lu.Username", ctx->instance);
trans_id = transaction_start("ut", 0);
blobmsg_add_string(bb, "path", path);
blobmsg_add_string(bb, "value", "user3");
blobmsg_add_u32(bb, "transaction_id", trans_id);
usp_raw_set(uctx, obj, req, "set", bb->head);
transaction_commit(trans_id, NULL, true);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
printf("json(%s)\n", json_object_to_json_string(jobj));
tmp = json_object_object_get(jobj, "status");
if (tmp == NULL) {
json_object_put(jobj);
}
assert_non_null(tmp);
assert_string_equal(json_object_get_string(tmp), "true");
json_object_put(jobj);
return;
}
static void test_api_usp_raw_object_name_Device_Users_User(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp_raw;
struct json_object *jobj, *tmp, *array_obj, *array_index_obj;
struct ubus_request_data *req = ctx->req;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
blobmsg_add_string(bb, "path", "Device.Users.User.");
blobmsg_add_string(bb, "proto", GET_PROTO);
blobmsg_add_u8(bb, "next-level", true);
usp_get_handler(uctx, obj, req, "object_names", bb->head);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
printf("json(%s)\n", json_object_to_json_string(jobj));
array_obj = json_object_object_get(jobj, "parameters");
array_index_obj = json_object_array_get_idx(array_obj, 0);
tmp = json_object_object_get(array_index_obj, "parameter");
assert_string_equal(json_object_get_string(tmp), "Device.Users.User.1.");
json_object_put(jobj);
return;
}
static void test_api_usp_get_cwmp_Device_DeviceInfo_Manufacturer(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
struct blob_buf *bb = &ctx->bb;
struct ubus_object *obj = &ctx->usp;
struct json_object *jobj, *tmp;
struct ubus_request_data *req = ctx->req;
struct ubus_context *uctx = &ctx->uspctx.ubus_ctx;
blobmsg_add_string(bb, "path", GET_PATH);
blobmsg_add_string(bb, "proto", GET_CWMP_PROTO);
usp_get_handler(uctx, obj, req, "get", bb->head);
jobj = json_object_from_file("/tmp/test.log");
assert_non_null(jobj);
printf("json(%s)\n", json_object_to_json_string(jobj));
json_object_object_get_ex(jobj, "Manufacturer", &tmp);
assert_string_equal(json_object_get_string(tmp), "iopsys");
json_object_put(jobj);
return;
}
// overriding this function
int ubus_send_event(struct ubus_context *ctx, const char *id,
struct blob_attr *data)
{
char *str;
str = blobmsg_format_json(data, true);
printf("{\"%s\": %s }", id, str);
free(str);
return 0;
}
int ubus_send_reply(struct ubus_context *ctx, struct ubus_request_data *req,
struct blob_attr *msg)
{
char *str;
FILE *fp;
fp = fopen("/tmp/test.log", "w");
if (!fp) {
printf("failed to open file\n");
return -1;
}
if (!msg) {
fclose(fp);
return -1;
}
str = blobmsg_format_json_indent(msg, true, -1);
fprintf(fp, "%s", str);
fclose(fp);
free(str);
return 0;
}
int main(void)
{
const struct CMUnitTest tests[] = {
// usp object test cases
cmocka_unit_test_setup(test_api_usp_list_operate, setup),
cmocka_unit_test_setup(test_api_usp_get_Device_DeviceInfo_Manufacturer, setup),
cmocka_unit_test_setup(test_api_usp_get_Device_WiFi_SSID, setup),
cmocka_unit_test_setup(test_api_usp_get_search_exp_Device_WiFi_SSID, setup),
cmocka_unit_test_setup(test_api_usp_instances_Device_Users_User, setup),
cmocka_unit_test_setup(test_api_usp_instances_Device, setup),
cmocka_unit_test_setup(test_api_usp_resolve_Device_Users_User, setup),
cmocka_unit_test_setup(test_api_usp_add_object_Device_Users_User, setup),
cmocka_unit_test_setup(test_api_usp_set_Device_Users_User, setup),
cmocka_unit_test_setup(test_api_usp_del_Device_Users_User, setup),
cmocka_unit_test_setup(test_api_usp_object_name_Device_Users_User, setup),
// usp.raw object test cases
cmocka_unit_test_setup(test_api_usp_raw_dump_schema, setup),
cmocka_unit_test_setup(test_api_usp_raw_get_Device_DeviceInfo_Manufacturer, setup),
cmocka_unit_test_setup(test_api_usp_raw_getm_values_Device_WiFi_SSID_Alias, setup),
cmocka_unit_test_setup(test_api_usp_raw_getm_names_Device_WiFi_SSID_Alias, setup),
cmocka_unit_test_setup(test_api_usp_raw_instances_Device_Users_User, setup),
cmocka_unit_test_setup(test_api_usp_raw_resolve_Device_Users_User, setup),
cmocka_unit_test_setup(test_api_usp_raw_add_object_Device_Users_User, setup),
cmocka_unit_test_setup(test_api_usp_raw_set_Device_Users_User, setup),
cmocka_unit_test_setup(test_api_usp_raw_del_Device_Users_User, setup),
cmocka_unit_test_setup(test_api_usp_raw_object_name_Device_Users_User, setup),
cmocka_unit_test_setup(test_api_usp_get_cwmp_Device_DeviceInfo_Manufacturer, setup),
// -ve scenerios
cmocka_unit_test_setup(test_api_usp_get_DeviceInfo_Manufacturer, setup),
cmocka_unit_test_setup(test_api_usp_get_wrong_oper_Device_WiFi_SSID, setup),
cmocka_unit_test_setup(test_api_usp_get_Device_IP_Interface, setup),
cmocka_unit_test_setup(test_api_usp_get_wrong_exp_Device_IP_Interface, setup),
cmocka_unit_test_setup(test_api_usp_get_wrong_braces_Device_IP_Interface, setup),
cmocka_unit_test_setup(test_api_usp_get_wrong_name_Device_IP_Interface, setup)
};
return cmocka_run_group_tests(tests, group_setup, group_teardown);
}

View file

@ -0,0 +1,132 @@
{
"Device.LocalAgent.": {
"type": "object",
"version": "2.12",
"protocols": [
"usp"
],
"access": false,
"array": false,
"TransferComplete!": {
"type": "event",
"version": "2.12",
"protocols": [
"usp"
],
"Command": {
"type": "string",
"read": true,
"write": true,
"version": "2.12",
"protocols": [
"usp"
],
"datatype": "string"
},
"CommandKey": {
"type": "string",
"read": true,
"write": true,
"version": "2.12",
"protocols": [
"usp"
],
"datatype": "string"
},
"Requestor": {
"type": "string",
"read": true,
"write": true,
"version": "2.12",
"protocols": [
"usp"
],
"datatype": "string"
},
"TransferType": {
"type": "string",
"read": true,
"write": true,
"version": "2.12",
"protocols": [
"usp"
],
"datatype": "string",
"enumerations": [
"Download",
"Upload"
]
},
"Affected": {
"type": "string",
"read": true,
"write": true,
"version": "2.12",
"protocols": [
"usp"
],
"datatype": "string"
},
"TransferURL": {
"type": "string",
"read": true,
"write": true,
"version": "2.12",
"protocols": [
"usp"
],
"datatype": "URL",
"range": [
{
"max": 2048
}
]
},
"StartTime": {
"type": "dateTime",
"read": true,
"write": true,
"version": "2.12",
"protocols": [
"usp"
],
"datatype": "dateTime"
},
"CompleteTime": {
"type": "dateTime",
"read": true,
"write": true,
"version": "2.12",
"protocols": [
"usp"
],
"datatype": "dateTime"
},
"FaultCode": {
"type": "unsignedInt",
"read": true,
"write": true,
"version": "2.12",
"protocols": [
"usp"
],
"datatype": "unsignedInt"
},
"FaultString": {
"type": "string",
"read": true,
"write": true,
"version": "2.12",
"protocols": [
"usp"
],
"datatype": "string",
"range": [
{
"max": 256
}
]
}
}
}
}

View file

@ -0,0 +1,11 @@
config deviceinfo 'deviceinfo'
option Manufacturer 'iopsys'
option ProductClass 'FirstClass'
option SerialNumber '000000001'
option SoftwareVersion 'IOPSYS-CODE-ANALYSIS'
option HardwareVersion '1.0'
option DeviceCategory 'Gateway'
option ModelName 'ModelName'
option Description 'Iopsys code analysis test simulator'
option ManufacturerOUI 'XXX'
option BaseMACAddress 'feeddeadbeef'

View file

@ -0,0 +1,185 @@
config globals 'globals'
option enabled '1'
config defaults
option syn_flood '1'
option input 'ACCEPT'
option output 'ACCEPT'
option forward 'REJECT'
config zone
option name 'lan'
list network 'lan'
option input 'ACCEPT'
option output 'ACCEPT'
option forward 'ACCEPT'
config zone
option name 'wan'
list network 'wan'
list network 'wan6'
option input 'REJECT'
option output 'ACCEPT'
option forward 'REJECT'
option masq '1'
option mtu_fix '1'
config forwarding
option src 'lan'
option dest 'wan'
config rule
option name 'Allow-DHCP-Renew'
option src 'wan'
option proto 'udp'
option dest_port '68'
option target 'ACCEPT'
option family 'ipv4'
config rule
option name 'Allow-Ping'
option src 'wan'
option proto 'icmp'
option icmp_type 'echo-request'
option family 'ipv4'
option target 'ACCEPT'
config rule
option name 'Allow-IGMP'
option src 'wan'
option proto 'igmp'
option family 'ipv4'
option target 'ACCEPT'
config rule
option name 'Allow-DHCPv6'
option src 'wan'
option proto 'udp'
option src_ip 'fc00::/6'
option dest_ip 'fc00::/6'
option dest_port '546'
option family 'ipv6'
option target 'ACCEPT'
config rule
option name 'Allow-MLD'
option src 'wan'
option proto 'icmp'
option src_ip 'fe80::/10'
list icmp_type '130/0'
list icmp_type '131/0'
list icmp_type '132/0'
list icmp_type '143/0'
option family 'ipv6'
option target 'ACCEPT'
config rule
option name 'Allow-ICMPv6-Input'
option src 'wan'
option proto 'icmp'
list icmp_type 'echo-request'
list icmp_type 'echo-reply'
list icmp_type 'destination-unreachable'
list icmp_type 'packet-too-big'
list icmp_type 'time-exceeded'
list icmp_type 'bad-header'
list icmp_type 'unknown-header-type'
list icmp_type 'router-solicitation'
list icmp_type 'neighbour-solicitation'
list icmp_type 'router-advertisement'
list icmp_type 'neighbour-advertisement'
option limit '1000/sec'
option family 'ipv6'
option target 'ACCEPT'
config rule
option name 'Allow-ICMPv6-Forward'
option src 'wan'
option dest '*'
option proto 'icmp'
list icmp_type 'echo-request'
list icmp_type 'echo-reply'
list icmp_type 'destination-unreachable'
list icmp_type 'packet-too-big'
list icmp_type 'time-exceeded'
list icmp_type 'bad-header'
list icmp_type 'unknown-header-type'
option limit '1000/sec'
option family 'ipv6'
option target 'ACCEPT'
config rule
option name 'Allow-IPSec-ESP'
option src 'wan'
option dest 'lan'
option proto 'esp'
option target 'ACCEPT'
config rule
option name 'Allow-ISAKMP'
option src 'wan'
option dest 'lan'
option dest_port '500'
option proto 'udp'
option target 'ACCEPT'
config rule
option name 'Support-UDP-Traceroute'
option src 'wan'
option dest_port '33434:33689'
option proto 'udp'
option family 'ipv4'
option target 'REJECT'
option enabled 'false'
config dmz 'dmz'
option enabled '0'
option exclude_ports '5060 7547'
config include
option path '/etc/firewall.user'
option reload '1'
config include 'ddos'
option path '/etc/firewall.ddos'
option reload '1'
config include 'parental'
option path '/etc/firewall.parental'
option reload '1'
config include 'qos'
option path '/etc/firewall.qos'
option reload '1'
config include 'cwmp'
option path '/etc/firewall.cwmp'
option reload '1'
config include 'miniupnpd'
option type 'script'
option path '/usr/share/miniupnpd/firewall.include'
option family 'any'
option reload '1'
config include 'sip'
option path '/etc/firewall.sip'
option reload '1'
config include 'dmzhost'
option path '/etc/firewall.dmz'
option reload '1'
config redirect 'port_mapping_1'
option enabled '1'
option src 'wan'
option dest 'lan'
option target 'DNAT'
option reflection '1'
option name 'test'
option proto 'tcp'
option dest_ip 'wan'
option src_dport '192.168.3.45'
option src_dport '50:60'
option dest_port '44'

View file

@ -0,0 +1,123 @@
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 'fddb:7949:7caa::/48'
config device
option name 'br-lan'
option type 'bridge'
list ports 'eth1'
list ports 'eth2'
list ports 'eth3'
list ports 'eth4'
option macaddr '44:D4:37:71:B8:11'
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:B8:11'
config interface 'wan'
option proto 'dhcp'
option hostname 'iopsysWrt-44D43771B810'
option vendorid 'eg400'
option device 'eth0.1'
option reqopts '12 43'
option sendopts '60:iopsystest 61:iopsys'
option macaddr '44:D4:37:71:B8:12'
config interface 'wan6'
option proto 'dhcpv6'
option device '@wan'
config device 'ethwan'
option type 'untagged'
option ifname 'eth0'
option name 'eth0.1'
option macaddr '44:D4:37:71:B8:12'
config device 'br_test_1'
option name 'br-test'
option type 'bridge'
list ports 'eth1.100'
list ports 'eth2.100'
list ports 'eth3.100'
list ports 'eth4.100'
option macaddr '44:D4:37:71:B8:13'
config interface 'lan100'
option device 'br-test'
option proto 'static'
option ipaddr '172.32.1.1'
option macaddr '44:D4:37:71:B8:13'
config device 'eth1_100'
option type 'untagged'
option ifname 'eth1'
option name 'eth1.100'
option vid '100'
config device 'eth2_100'
option type 'untagged'
option ifname 'eth2'
option name 'eth2.100'
option vid '100'
config device 'eth3_100'
option type '8021q'
option ifname 'eth3'
option name 'eth3.100'
option vid '100'
config device 'eth4_100'
option type '8021q'
option ifname 'eth4'
option name 'eth4.100'
option vid '100'
config interface 'ppp_wan'
option type 'anywan'
option proto 'pppoe'
option username 'iopsyshome@iopsys.eu'
option password 'iopsys'
option device 'eth0.1'
option ipv6 '1'
option macaddr '44:D4:37:71:B8:14'
config route 'route4'
option interface 'wan'
option target '0.0.0.0/0'
option gateway '10.72.197.110'
config route6 'route6'
option interface 'wan6'
option target '::/0'
config interface 'stabridge'
option proto 'relay'
option network 'lan wan'
config interface 'mygre'
option ipaddr '10.1.1.1'
option peeraddr '10.2.2.1'
option proto 'gre'
config interface 'mygre_static'
option proto 'static'
option device '@mygre'
option ipaddr '172.16.12.1'
option netmask '255.255.255.252'
config route 'tunnel'
option interface 'mygre_static'
option target '172.16.2.0'
option netmask '255.255.255.0'
option gateway '172.16.12.2'

View file

@ -0,0 +1,7 @@
config user 'user'
option enabled '1'
option remote_access '1'
list _access_w 'admin'
list _access_w 'support'
list _access_w 'user'

View file

@ -0,0 +1,6 @@
config uspd 'usp'
option granularitylevel '0'
option debug '1'
option loglevel '2'
option subprocess_level '1'
option refresh_time '0'

View file

@ -0,0 +1,56 @@
config wifi-device 'test1'
option type 'mac80211'
option channel '36'
option hwmode '11a'
option country 'DE'
option htmode 'HE80'
option apsta '0'
option phy 'phy0'
config wifi-iface 'no_mp_test1'
option device 'test1'
option network 'lan'
option mode 'ap'
option ifname 'test1'
option encryption 'psk2'
option wps_pushbutton '1'
option ieee80211k '1'
option ieee80211v '1'
option bss_transition '1'
option ssid 'NON-MULTI-AP-TEST'
config wifi-iface 'default_test1'
option device 'test1'
option network 'lan'
option mode 'ap'
option ifname 'test1'
option ssid 'MAP-44D43771B810-BH-5GHz'
option encryption 'psk2'
option wps_pushbutton '1'
option ieee80211k '1'
option ieee80211v '1'
option bss_transition '1'
option multi_ap '3'
config wifi-device 'test2'
option type 'mac80211'
option channel '11'
option hwmode '11g'
option country 'DE'
option htmode 'HE20'
option apsta '0'
option phy 'phy1'
config wifi-iface 'default_test2'
option device 'test2'
option network 'lan'
option mode 'ap'
option ifname 'test2'
option ssid 'iopsysWrt-44D43771B810'
option encryption 'psk2'
option key 'MPUEO3L7WHJ45P'
option wps_pushbutton '1'
option ieee80211k '1'
option ieee80211v '1'
option bss_transition '1'
option multi_ap '2'

25
bbfd/test/files/etc/init.d/uspd Executable file
View file

@ -0,0 +1,25 @@
#!/bin/sh /etc/rc.common
START=94
STOP=10
USE_PROCD=1
PROG=/usr/sbin/uspd
start_service() {
procd_open_instance
procd_set_param command ${PROG}
procd_set_param respawn
procd_close_instance
}
reload_service() {
stop
start
}
service_triggers()
{
procd_add_reload_trigger "cwmp"
procd_add_config_trigger "config.change" "uspd" /etc/init.d/uspd restart
}

View file

@ -0,0 +1,13 @@
{
"object": "usp.Device.",
"methods": [
{
"method": "get",
"args": {
"path": "Users."
},
"rc": 0
}
]
}

View file

@ -0,0 +1,350 @@
{
"object": "usp.raw",
"methods": [
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "usp"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "usp"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "cwmp"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Users.User.*.Alias",
"proto": "cwmp"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "both"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "usp",
"maxdepth": "1"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "usp",
"maxdepth": "1",
"next-level": true
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.1.LowerLayers+.Name"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.1.LowerLayers#1+.Name"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Users.User.*.Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.1.LowerLayers#*+.Name"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[Status==\"Up\"].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[SSID==\"test-2g\"&&Status==\"Up\"].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[SSID==\"test-2g\"&&Stats.PacketsSent>0].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[BytesSent>0].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[Enable==true].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[Enable!=true].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.USB.USBHosts.Host.[Enable==0].Device."
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.USB.USBHosts.Host.*.Device."
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort==68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort!=68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort>68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort<68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort>=68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort<=68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order==1].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order!=1].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order>8].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order>=8].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order<2].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order<=2].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.AccessPoint.[SSIDReference+.Alias==\"cpe-1\"].AssociatedDeviceNumberOfEntries"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.AccessPoint.[SSIDReference#1+.Alias==\"cpe-1\"].WPS.ConfigMethodsSupported"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.USB.USBHosts.Host.[Enable==0].Device."
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.USB.USBHosts.Host.*.Device."
},
"rc": 0
},
{
"method": "hello",
"rc": 3
},
{
"method": "instances",
"args": {
"path": "Device.Users.User.",
"proto": "usp"
},
"rc": 0
},
{
"method": "set",
"args": {
"path": "Device.WiFi.SSID.1.SSID",
"value": "test-2g",
"transaction_id": 123
},
"rc": 0
},
{
"method": "object_names",
"args": {
"path": "Device.WiFi.SSID.1.",
"proto": "usp"
},
"rc": 0
},
{
"method": "operate",
"args": {
"path":"Device.IP.Diagnostics.",
"action":"IPPing()",
"input":{
"Host":"iopsys.eu"
}
},
"rc": 0
},
{
"method": "dump_schema",
"args": {},
"rc": 0
},
{
"method": "list_operate",
"args": {},
"rc": 0
},
{
"method": "transaction_commit",
"args": {
"transaction_id": 123
},
"rc": 0
},
{
"method": "transaction_abort",
"args": {
"transaction_id": 123
},
"rc": 0
},
{
"method": "getm_names",
"args": {
"paths": ["Device.WiFi.SSID.1.SSID","Device.WiFi.SSID.2.SSID"],
"proto": "usp"
},
"rc": 0
},
{
"method": "setm_values",
"args": {
"pv_tuple": [{"path":"Device.Users.User.1.Alias", "value":"cpe-1"}, {"path":"Device.Users.User.2.Alias", "value":"cpe-2"}],
"proto": "usp",
"transaction_id": 123
},
"rc": 0
},
]
}

View file

@ -0,0 +1,463 @@
{
"object": "usp",
"methods": [
{
"method": "list_operate",
"args": {},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.",
"proto": "usp"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "usp"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "cwmp"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Users.User.*.Alias",
"proto": "cwmp"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "both"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "usp",
"maxdepth": "1"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "usp",
"maxdepth": "1",
"next-level": true
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.1.LowerLayers+.Name"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.1.LowerLayers#1+.Name"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Users.User.*.Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.1.LowerLayers#*+.Name"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.IP.Interface.*.IPv4Address.*.AddressingType"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[Status==\"Up\"].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[SSID==\"test-2g\"&&Status==\"Up\"].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[SSID==\"test-2g\"&&Stats.PacketsSent>0].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[BytesSent>0].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[Enable==true].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[Enable!=true].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.USB.USBHosts.Host.[Enable==0].Device."
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.USB.USBHosts.Host.*.Device."
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort==68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort!=68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort>68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort<68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort>=68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort<=68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order==1].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order!=1].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order>8].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order>=8].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order<2].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order<=2].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[Status>\"Up\"].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.{Status==\"Up\"}.Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.AccessPoint.[SSIDReference+.Alias==\"cpe-1\"].AssociatedDeviceNumberOfEntries"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.AccessPoint.[SSIDReference#1+.Alias==\"cpe-1\"].WPS.ConfigMethodsSupported"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.AccessPoint.[SSIDReference#*+.Alias==\"cpe-1\"].WPS.ConfigMethodsSupported"
},
"rc": 0
},
{
"method": "object_names",
"args": {
"path": "Device.WiFi.SSID.1.",
"proto": "usp"
},
"rc": 0
},
{
"method": "object_names",
"args": {
"path": "Device.WiFi.SSID.1.Stats.",
"proto": "usp"
},
"rc": 0
},
{
"method": "instances",
"args": {
"path": "Device.Users.User.",
"proto": "usp"
},
"rc": 0
},
{
"method": "instances",
"args": {
"path": "Device.",
"proto": "usp"
},
"rc": 0
},
{
"method": "instances",
"args": {
"path": "Device.Users.User.",
"proto": "usp"
},
"rc": 0
},
{
"method": "validate",
"args": {
"path": "Device.Users.User.1.Alias",
"proto": "usp"
},
"rc": 0
},
{
"method": "validate",
"args": {
"path": "Device.Users.User.1.",
"proto": "usp"
},
"rc": 0
},
{
"method": "validate",
"args": {
"path": "Device.Users.User.*.",
"proto": "usp"
},
"rc": 0
},
{
"method": "set",
"args": {
"path": "Device.WiFi.SSID.1.SSID",
"value": "test-1g"
},
"rc": 0
},
{
"method": "set",
"args": {
"path": "Device.Users.User.1.",
"values": {"username":"funl-test", "password":"ft1234"}
},
"rc": 0
},
{
"method": "set",
"args": {
"path": "Device.Firewall.Chain.1.Rule.1.",
"values": {"DestPortRangeMax":"5"}
},
"rc": 0
},
{
"method": "set",
"args": {
"path": "Device.Firewall.Chain.1.Rule.1.",
"values": {"Order":"7"}
},
"rc": 0
},
{
"method": "set",
"args": {
"path": "Device.Firewall.Chain.1.Rule.1.",
"values": {"DestPortRangeMax":5}
},
"rc": 0
},
{
"method": "operate",
"args": {
"path":"Device.IP.Diagnostics.",
"action":"IPPing()",
"input":{
"Host":"iopsys.eu"
}
},
"rc": 0
},
{
"method": "operate",
"args": {
"path":"Device.IP.Diagnostics.",
"action":"IPPing()",
"input":{
"Host":"iopsys.eu",
"Host":"localhost"
}
},
"rc": 0
},
{
"method": "operate",
"args": {
"path":"Device.WiFi.SSID.1.",
"action":"NeighboringWiFiDiagnostic()"
},
"rc": 0
},
{
"method": "operate",
"args": {
"path":"Device.WiFi",
"action":""
},
"rc": 0
},
{
"method": "add_object",
"args": {
"path": "Device.Users.User.",
"proto": "usp"
},
"rc": 0
},
{
"method": "del_object",
"args": {
"path": "Device.Users.User.[Username>admin].",
"proto": "usp"
},
"rc": 0
},
{
"method": "del_object",
"args": {
"path": "Device.Users.User.2.",
"proto": "usp"
},
"rc": 0
}
]
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,338 @@
{
"definitions": {
"path_t": {
"description": "Complete object element path as per TR181",
"type": "string",
"minLength": 6,
"maxLength": 1024,
"examples": [
"Device.",
"Device.DeviceInfo.Manufacturer",
"Device.WiFi.SSID.1.",
"Device.WiFi."
]
},
"schema_path_t": {
"description": "Datamodel object schema path",
"type": "string",
"minLength": 6,
"maxLength": 1024,
"examples": [
"Device.Bridging.Bridge.{i}.",
"Device.DeviceInfo.Manufacturer",
"Device.WiFi.SSID.{i}.SSID"
]
},
"boolean_t": {
"type": "string",
"enum": [
"0",
"1"
]
},
"operate_path_t": {
"description": "Datamodel object schema path",
"type": "string",
"minLength": 6,
"maxLength": 1024,
"examples": [
"Device.DHCPv4.Client.{i}.Renew()",
"Device.FactoryReset()"
]
},
"operate_type_t": {
"type": "string",
"enum": [
"async",
"sync"
]
},
"query_path_t": {
"description": "DM object path with search queries",
"type": "string",
"minLength": 6,
"maxLength": 1024,
"examples": [
"Device.",
"Device.DeviceInfo.Manufacturer",
"Device.WiFi.SSID.[SSID==\"test_ssid\"].BSSID",
"Device.WiFi.SSID.*.BSSID",
"Device.WiFi.SSID.[SSID!=\"test_ssid\"&&Enable==1].BSSID",
"Device.WiFi."
]
},
"instance_t": {
"description": "Multi object instances",
"type": "string",
"minLength": 6,
"maxLength": 256
},
"proto_t": {
"type": "string",
"default": "both",
"enum": [
"usp",
"cwmp",
"both"
]
},
"type_t": {
"type": "string",
"enum": [
"xsd:string",
"xsd:unsignedInt",
"xsd:int",
"xsd:unsignedLong",
"xsd:long",
"xsd:boolean",
"xsd:dateTime",
"xsd:hexBinary",
"xsd:object"
]
},
"fault_t": {
"type": "integer",
"minimum": 7000,
"maximum": 9050
}
},
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://dev.iopsys.eu/iopsys/uspd/-/blob/devel/docs/api/usp.md",
"type": "object",
"title": "usp",
"object": "usp",
"additionalProperties": false,
"properties": {
"get": {
"title": "Get handler",
"description": "Query the datamodel object",
"type": "object",
"required": [
"input",
"output"
],
"properties": {
"input": {
"type": "object",
"required": [
"path"
],
"properties": {
"path": {
"$ref": "#/definitions/query_path_t"
},
"proto": {
"$ref": "#/definitions/proto_t"
},
"maxdepth": {
"type": "integer",
"description": "Integer to decide the depth of data model to be parsed"
},
"next-level": {
"type": "boolean",
"description": "gets only next level objects if true"
},
"instance-mode": {
"type": "integer",
"description": ""
}
}
},
"output": {
"required": [
"fault"
],
"fault": {
"$ref": "#/definitions/fault_t"
}
}
}
},
"set": {
"title": "Set handler",
"description": "Set values of datamodel object element",
"type": "object",
"required": [
"input",
"output"
],
"properties": {
"input": {
"type": "object",
"required": [
"path"
],
"properties": {
"path": {
"$ref": "#/definitions/query_path_t"
},
"proto": {
"$ref": "#/definitions/proto_t"
},
"value": {
"type": "string"
},
"values": {
"type": "object",
"properties": {}
},
"instance_mode": {
"type": "integer",
"minimum": 0,
"maximum": 1
}
}
},
"output": {
"type": "object",
"required": [
"parameters"
],
"properties": {
"parameters": {
"type": "array",
"items": {
"type": "object",
"required": [
"parameter",
"fault"
],
"properties": {
"parameter": {
"$ref": "#/definitions/path_t"
},
"status": {
"type": "boolean",
"const": false
},
"fault": {
"$ref": "#/definitions/fault_t"
}
}
}
}
}
}
}
},
"add_object": {
"title": "Add a new object instance",
"description": "Add a new object in multi instance object",
"type": "object",
"required": [
"input",
"output"
],
"properties": {
"input": {
"type": "object",
"required": [
"path"
],
"properties": {
"path": {
"$ref": "#/definitions/path_t"
},
"proto": {
"$ref": "#/definitions/proto_t"
},
"instance_mode": {
"type": "integer",
"minimum": 0,
"maximum": 1
}
}
},
"output": {
"type": "object",
"required": [
"parameters"
],
"properties": {
"parameters": {
"type": "array",
"items": {
"type": "object",
"required": [
"parameter",
"status",
"fault"
],
"properties": {
"parameter": {
"$ref": "#/definitions/path_t"
},
"status": {
"type": "boolean"
},
"fault": {
"$ref": "#/definitions/fault_t"
}
}
}
}
}
}
}
},
"del_object": {
"title": "Delete object instance",
"description": "Delete a object instance from multi instance object",
"type": "object",
"required": [
"input",
"output"
],
"properties": {
"input": {
"type": "object",
"required": [
"path"
],
"properties": {
"path": {
"$ref": "#/definitions/query_path_t"
},
"proto": {
"$ref": "#/definitions/proto_t"
},
"instance_mode": {
"type": "integer",
"minimum": 0,
"maximum": 1
}
}
},
"output": {
"type": "object",
"required": [
"parameters"
],
"properties": {
"parameters": {
"type": "array",
"items": {
"type": "object",
"required": [
"parameter",
"fault"
],
"properties": {
"parameter": {
"$ref": "#/definitions/path_t"
},
"status": {
"type": "boolean"
},
"fault": {
"$ref": "#/definitions/fault_t"
}
}
}
}
}
}
}
}
}
}

View file

@ -0,0 +1,315 @@
{
"definitions": {
"path_t": {
"description": "Complete object element path as per TR181",
"type": "string",
"minLength": 6,
"maxLength": 1024,
"examples": [
"Device.",
"Device.DeviceInfo.Manufacturer",
"Device.WiFi.SSID.1.",
"Device.WiFi."
]
},
"schema_path_t": {
"description": "Datamodel object schema path",
"type": "string",
"minLength": 6,
"maxLength": 1024,
"examples": [
"Device.Bridging.Bridge.{i}.",
"Device.DeviceInfo.Manufacturer",
"Device.WiFi.SSID.{i}.SSID"
]
},
"boolean_t": {
"type": "string",
"enum": [
"0",
"1"
]
},
"operate_path_t": {
"description": "Datamodel object schema path",
"type": "string",
"minLength": 6,
"maxLength": 1024,
"examples": [
"Device.DHCPv4.Client.{i}.Renew()",
"Device.FactoryReset()"
]
},
"operate_type_t": {
"type": "string",
"enum": [
"async",
"sync"
]
},
"query_path_t": {
"description": "DM object path with search queries",
"type": "string",
"minLength": 6,
"maxLength": 1024,
"examples": [
"Device.",
"Device.DeviceInfo.Manufacturer",
"Device.WiFi.SSID.[SSID==\"test_ssid\"].BSSID",
"Device.WiFi.SSID.*.BSSID",
"Device.WiFi.SSID.[SSID!=\"test_ssid\"&&Enable==1].BSSID",
"Device.WiFi."
]
},
"instance_t": {
"description": "Multi object instances",
"type": "string",
"minLength": 6,
"maxLength": 256
},
"proto_t": {
"type": "string",
"default": "both",
"enum": [
"usp",
"cwmp",
"both"
]
},
"type_t": {
"type": "string",
"enum": [
"xsd:string",
"xsd:unsignedInt",
"xsd:int",
"xsd:unsignedLong",
"xsd:long",
"xsd:boolean",
"xsd:dateTime",
"xsd:hexBinary",
"xsd:object"
]
},
"fault_t": {
"type": "integer",
"minimum": 7000,
"maximum": 9050
}
},
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://dev.iopsys.eu/iopsys/uspd/-/blob/devel/docs/api/usp.md",
"type": "object",
"title": "usp",
"object": "usp",
"additionalProperties": false,
"properties": {
"get": {
"title": "Get handler",
"description": "Query the datamodel object",
"type": "object",
"required": [
"input",
"output"
],
"properties": {
"input": {
"type": "object",
"required": [
"path"
],
"properties": {
"path": {
"$ref": "#/definitions/query_path_t"
},
"proto": {
"$ref": "#/definitions/proto_t"
},
"maxdepth": {
"type": "integer",
"description": "Integer to decide the depth of data model to be parsed"
},
"next-level": {
"type": "boolean",
"description": "gets only next level objects if true"
},
"instance-mode": {
"type": "integer",
"description": ""
}
}
},
"output": {
"type": "object",
"properties": {}
}
}
},
"set": {
"title": "Set handler",
"description": "Set values of datamodel object element",
"type": "object",
"required": [
"input",
"output"
],
"properties": {
"input": {
"type": "object",
"required": [
"path",
"value"
],
"properties": {
"path": {
"$ref": "#/definitions/query_path_t"
},
"proto": {
"$ref": "#/definitions/proto_t"
},
"value": {
"type": "string"
},
"values": {
"description": "To set multiple values at once, path should be relative to object elements",
"type": "object",
"properties": {}
},
"instance_mode": {
"type": "integer",
"minimum": 0,
"maximum": 1
}
}
},
"output": {
"type": "object",
"required": [
"status"
],
"properties": {
"status": {
"const": true
}
}
}
}
},
"add_object": {
"title": "Add a new object instance",
"description": "Add a new object in multi instance object",
"type": "object",
"required": [
"input",
"output"
],
"properties": {
"input": {
"type": "object",
"required": [
"path"
],
"properties": {
"path": {
"$ref": "#/definitions/path_t"
},
"proto": {
"$ref": "#/definitions/proto_t"
},
"instance_mode": {
"type": "integer",
"minimum": 0,
"maximum": 1
}
}
},
"output": {
"type": "object",
"required": [
"parameters"
],
"properties": {
"parameters": {
"type": "array",
"items": {
"type": "object",
"required": [
"parameter",
"status",
"instance"
],
"properties": {
"parameter": {
"$ref": "#/definitions/path_t"
},
"status": {
"type": "boolean"
},
"instance": {
"type": "string"
}
}
}
}
}
}
}
},
"del_object": {
"title": "Delete object instance",
"description": "Delete a object instance from multi instance object",
"type": "object",
"required": [
"input",
"output"
],
"properties": {
"input": {
"type": "object",
"required": [
"path"
],
"properties": {
"path": {
"$ref": "#/definitions/query_path_t"
},
"proto": {
"$ref": "#/definitions/proto_t"
},
"instance_mode": {
"type": "integer",
"minimum": 0,
"maximum": 1
}
}
},
"output": {
"type": "object",
"required": [
"parameters"
],
"properties": {
"parameters": {
"type": "array",
"items": {
"type": "object",
"required": [
"parameter",
"status"
],
"properties": {
"parameter": {
"$ref": "#/definitions/path_t"
},
"status": {
"type": "boolean",
"const": true
}
}
}
}
}
}
}
}
}
}

View file

@ -0,0 +1,64 @@
{
"object": "usp.raw",
"methods": [
{
"method": "get",
"args": {
"path": "Device.DeviceInfo",
"proto": "usp"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.InvalidPath",
"proto": "usp"
},
"rc": 0
},
{
"method": "get_supported_dm",
"args": {
"path": "Device.DeviceInfo.InvalidPath",
},
"rc": 0
},
{
"method": "instances",
"args": {
"path": "Device.Users.InvalidUser.",
"proto": "usp"
},
"rc": 0
},
{
"method": "operate",
"args": {
"path":"Device.IP.Diagnostics.InvalidPath",
"action":"IPPing()",
"input":{
"Host":"iopsys.eu"
}
},
"rc": 0
},
{
"method": "getm_names",
"args": {
"paths": ["Device.WiFi.SSID.1.Invalid","Device.WiFi.SSID.2.Invalid"],
"proto": "usp"
},
"rc": 0
},
{
"method": "object_names",
"args": {
"path": "Device.WiFi.SSID.1.Invalid",
"proto": "usp"
},
"rc": 0
}
]
}

View file

@ -0,0 +1,368 @@
{
"object": "usp.raw",
"methods": [
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "usp"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "usp"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "cwmp"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Users.User.*.Alias",
"proto": "cwmp"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "both"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "usp",
"maxdepth": "1"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "usp",
"maxdepth": "1",
"next-level": true
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.1.LowerLayers+.Name"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.1.LowerLayers#1+.Name"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Users.User.*.Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.1.LowerLayers#*+.Name"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[Status==\"Up\"].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[SSID==\"test-2g\"&&Status==\"Up\"].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[SSID==\"test-2g\"&&Stats.PacketsSent>0].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[BytesSent>0].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[Enable==true].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[Enable!=true].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.USB.USBHosts.Host.[Enable==0].Device."
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.USB.USBHosts.Host.*.Device."
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort==68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort!=68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort>68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort<68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort>=68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort<=68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order==1].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order!=1].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order>8].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order>=8].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order<2].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order<=2].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.AccessPoint.[SSIDReference+.Alias==\"cpe-1\"].AssociatedDeviceNumberOfEntries"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.AccessPoint.[SSIDReference#1+.Alias==\"cpe-1\"].WPS.ConfigMethodsSupported"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.USB.USBHosts.Host.[Enable==0].Device."
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.USB.USBHosts.Host.*.Device."
},
"rc": 0
},
{
"method": "hello",
"rc": 3
},
{
"method": "instances",
"args": {
"path": "Device.Users.User.",
"proto": "usp"
},
"rc": 0
},
{
"method": "set",
"args": {
"path": "Device.WiFi.SSID.1.SSID",
"value": "test-2g",
"transaction_id": 123
},
"rc": 0
},
{
"method": "object_names",
"args": {
"path": "Device.WiFi.SSID.1.",
"proto": "usp"
},
"rc": 0
},
{
"method": "operate",
"args": {
"path":"Device.IP.Diagnostics.",
"action":"IPPing()",
"input":{
"Host":"iopsys.eu"
}
},
"rc": 0
},
{
"method": "dump_schema",
"args": {},
"rc": 0
},
{
"method": "list_operate",
"args": {},
"rc": 0
},
{
"method": "get_supported_dm",
"args": {
"path": "Device.DeviceInfo.",
},
"rc": 0
},
{
"method": "operate",
"args": {
"path":"Device.IP.Diagnostics.",
"action":"IPPing()",
"input":{
"Host":"iopsys.eu"
}
},
"rc": 0
},
{
"method": "transaction_commit",
"args": {
"transaction_id": 123
},
"rc": 0
},
{
"method": "transaction_abort",
"args": {
"transaction_id": 123
},
"rc": 0
},
{
"method": "getm_names",
"args": {
"paths": ["Device.WiFi.SSID.1.SSID","Device.WiFi.SSID.2.SSID"],
"proto": "usp"
},
"rc": 0
},
{
"method": "setm_values",
"args": {
"pv_tuple": [{"path":"Device.Users.User.1.Alias", "value":"cpe-1"}, {"path":"Device.Users.User.2.Alias", "value":"cpe-2"}],
"proto": "usp",
"transaction_id": 123
},
"rc": 0
},
]
}

View file

@ -0,0 +1,62 @@
{
"object": "usp",
"methods": [
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Invalid",
"proto": "usp"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.Invalid",
"proto": "usp"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Invalid",
"proto": "cwmp"
},
"rc": 0
},
{
"method": "set",
"args": {
"path": "Device.WiFi.SSID.1.Invalid",
"value": "test-1g"
},
"rc": 0
},
{
"method": "add_object",
"args": {
"path": "Device.Users.User.Invalid",
"proto": "usp"
},
"rc": 0
},
{
"method": "del_object",
"args": {
"path": "Device.Users.User.Invalid.",
"proto": "usp"
},
"rc": 0
},
{
"method": "del_object",
"args": {
"path": "Device.Users.User.[Username>admin].",
"proto": "usp"
},
"rc": 0
}
]
}

View file

@ -0,0 +1,323 @@
{
"object": "usp",
"methods": [
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.",
"proto": "usp"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "usp"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "cwmp"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Users.User.*.Alias",
"proto": "cwmp"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "both"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "usp",
"maxdepth": "1"
},
"rc": 0
},
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"proto": "usp",
"maxdepth": "1",
"next-level": true
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.1.LowerLayers+.Name"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.1.LowerLayers#1+.Name"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Users.User.*.Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.1.LowerLayers#*+.Name"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.IP.Interface.*.IPv4Address.*.AddressingType"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[Status==\"Up\"].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[SSID==\"test-2g\"&&Status==\"Up\"].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[SSID==\"test-2g\"&&Stats.PacketsSent>0].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[BytesSent>0].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[Enable==true].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[Enable!=true].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.USB.USBHosts.Host.[Enable==0].Device."
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.USB.USBHosts.Host.*.Device."
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort==68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort!=68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort>68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort<68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort>=68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[DestPort<=68].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order==1].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order!=1].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order>8].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order>=8].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order<2].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.Firewall.Chain.1.Rule.[Order<=2].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[Status>\"Up\"].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.{Status==\"Up\"}.Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.SSID.[].Alias"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.AccessPoint.[SSIDReference+.Alias==\"cpe-1\"].AssociatedDeviceNumberOfEntries"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.AccessPoint.[SSIDReference#1+.Alias==\"cpe-1\"].WPS.ConfigMethodsSupported"
},
"rc": 0
},
{
"method": "get",
"args": {
"path":"Device.WiFi.AccessPoint.[SSIDReference#*+.Alias==\"cpe-1\"].WPS.ConfigMethodsSupported"
},
"rc": 0
},
{
"method": "set",
"args": {
"path": "Device.WiFi.SSID.1.SSID",
"value": "test-1g"
},
"rc": 0
},
{
"method": "set",
"args": {
"path": "Device.Firewall.Chain.1.Rule.1.",
"values": {"Order":"7"}
},
"rc": 0
},
{
"method": "add_object",
"args": {
"path": "Device.Users.User.",
"proto": "usp"
},
"rc": 0
},
{
"method": "del_object",
"args": {
"path": "Device.Users.User.2.",
"proto": "usp"
},
"rc": 0
}
]
}

52
bbfd/test/libuspd_test.c Normal file
View file

@ -0,0 +1,52 @@
/*
* Copyright (C) 2021 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: Suvendhu Hansa <suvendhu.hansa@iopsys.eu>
*/
/* This file is used for validating USPD max msg len using libbbf APIs */
#include <stdlib.h>
#include <libbbf_api/dmbbf.h>
#include <libbbf_api/dmcommon.h>
#ifndef DEF_IPC_DATA_LEN
#define DEF_IPC_DATA_LEN (1024 * 1024 - 128)
#endif
/*************************************************************
* GET PARAM
**************************************************************/
static int get_X_IOPSYS_EU_testUSPDParam_TestText(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
char *ptr = (char *)calloc(1, DEF_IPC_DATA_LEN);
if (ptr == NULL) {
*value = "";
return 0;
}
memset(ptr, 'a', DEF_IPC_DATA_LEN - 1);
dmasprintf(value, ptr);
free(ptr);
return 0;
}
/**********************************************************************************************************************************
* OBJ & PARAM DEFINITION
***********************************************************************************************************************************/
/*** Device. ***/
DMLEAF tX_IOPSYS_EU_testUSPDParam[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/
{"X_IOPSYS_EU_TestText", &DMREAD, DMT_STRING, get_X_IOPSYS_EU_testUSPDParam_TestText, NULL, BBFDM_BOTH},
{0}
};
/* ********** DynamicObj ********** */
DM_MAP_OBJ tDynamicObj[] = {
/* parentobj, nextobject, parameter */
{"Device.", NULL, tX_IOPSYS_EU_testUSPDParam},
{0}
};

View file

@ -0,0 +1,27 @@
#!/usr/bin/python3
import subprocess
import json
TEST_NAME = "BUG_3272"
print("Running: " + TEST_NAME)
def usp_get(path, proto = ""):
path_arg = "{\"path\":\"" + path + "\",\"proto\":\"" + proto + "\"}"
cmd = ['ubus', 'call', 'usp.raw', 'get', path_arg]
out = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
stdout,stderr = out.communicate()
return stdout
# check fault code of invalid path
output = json.loads(usp_get("Device.USB.USBHosts.Host.[Enable==0].Device."))
for param in enumerate(output["parameters"]):
assert param[1]["parameter"].endswith("DeviceNumberOfEntries") == False, "FAIL" + TEST_NAME
print("PASS: " + TEST_NAME)

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