BBF: Library to expose dynamic DM over ubus

This commit is contained in:
Suvendhu Hansa 2021-11-25 13:20:53 +00:00 committed by Amin Ben Ramdhane
parent 947ecd0bea
commit 8a1c125ddb
18 changed files with 4055 additions and 12 deletions

View file

@ -6,6 +6,7 @@ stages:
- static_code_analysis
- unit_test
- functional_test
- libbbf_ubus_test
- memory_test
- uspd
@ -55,6 +56,23 @@ run_functional_api_test:
- timestamp.log
- functional-api-test-coverage.xml
run_libbbf_ubus_test:
stage: libbbf_ubus_test
image: iopsys/code-analysis:latest
allow_failure: false
script:
- "./gitlab-ci/setup.sh"
- "./gitlab-ci/libbbf_ubus_api_test.sh"
artifacts:
when: always
reports:
junit: ./report/tap.xml
paths:
- timestamp.log
- memory-report.xml
- api-result.log
run_tools_test:
stage: unit_test
image: iopsys/code-analysis:latest

View file

@ -2,9 +2,11 @@ MAINTAINERCLEANFILES = Makefile.in
libbbfdm_includedir = $(includedir)/libbbfdm
libbbf_api_includedir = $(includedir)/libbbf_api
libbbf_ubus_includedir = $(includedir)/libbbf_ubus
libbbfdm_tr181_includedir = $(libbbfdm_includedir)
libbbfdm_include_HEADERS = *.h
libbbf_api_include_HEADERS = libbbf_api/*.h
libbbf_ubus_include_HEADERS = include/*.h
SUBDIRS = bin
SUBDIRS = bin libbbf_ubus

View file

@ -1,6 +1,15 @@
# BroadBand Forum Data Models (BBFDM)
`bbfdm` is a data model library implementation which includes a list of objects, parameters and operates used for CPE management through remote control protocols such as [TR-069/CWMP](https://cwmp-data-models.broadband-forum.org/) or [TR-369/USP](https://usp.technology/).
This package comprises of the below libraries:
| Library | Description |
| ------- | ------------------------------------------------- |
| libbbfdm | This provides the mechanism to add new parameters or extend the existing DM tree using json plugin or shared library plugin. |
| libbbf_api | This provides the APIs for UCI, Ubus, JSON, CLI and memory management. |
| libbbf_ubus | This library helps to expose the datamodel directly over ubus. Application can expose any datamodel(need not be part of "Device."/TR-181) using this library. |
Note: Applications that use libbbf_ubus to expose datamodel, not required to use libbbfdm.
## Design of bbfdm
@ -19,6 +28,7 @@
│   ├── openwrt
│   └── vendor.h
├── libbbf_api
├── libbbf_ubus
├── scripts
└── tools
```
@ -37,6 +47,8 @@
- `libbbf_api` folder which contains the source code of all API functions (UCI, Ubus, JSON, CLI and memory management)
- `libbbf_ubus` folder which contains the source code of all API functions helps in exposing datamodel directly over ubus
- `scripts` folder which contains the Diagnostics scripts
- `tools` folder which contains some tools to generate Data Model in C, JSON, XML and Excel format
@ -1034,9 +1046,21 @@ The input json file should be defined as follow:
- For more examples of tools input json file, you can see this link: [tools_input.json](./devel/tools/tools_input.json)
## Dependencies
# How to expose datamodel over ubus directly with the help of libbbf APIs
To successfully build libbbfdm, the following libraries are needed:
`Libbbf_ubus` is the library that helps in exposing the datamodel over ubus directly using libbbf_api.
Application using `libbbf_ubus`, shall not use the `libbbfdm` library because all needed operations from `libbbfdm` library has been internally handled in `libbbf_ubus`.
To identify the mechanism of exposing datamodel directly over ubus please refer to the sample code [dmtest.c](./test/dynamicdm_ubus_test/bbf_ubus.c)
For more info you can see the schemas at:
- Raw schema [link](./schemas/dmtest.json)
- Markdown schema [link](./docs/api/dmtest.md)
## Dependencies of of libbbfdm and libbbf_ubus
To successfully build libbbfdm or libbbf_ubus, the following libraries are needed:
| Dependency | Link | License |
| ----------- | ------------------------------------------- | -------------- |
@ -1047,3 +1071,4 @@ To successfully build libbbfdm, the following libraries are needed:
| libcurl | https://dl.uxnr.de/mirror/curl | MIT |
| libtrace | https://github.com/apietila/libtrace.git | GPLv2 |
| libbbf_api | https://dev.iopsys.eu/iopsys/bbf.git | LGPL 2.1 |

View file

@ -1,6 +1,10 @@
AC_INIT([libbbfdm], [0.1], [mohamed.kallel@pivasoftware.com])
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([foreign subdir-objects])
AC_CONFIG_SUBDIRS([libbbf_ubus])
AC_ARG_ENABLE(tr181, [AS_HELP_STRING([--enable-tr181], [enable tr181 device feature])], AC_DEFINE(BBF_TR181),)
AM_CONDITIONAL([BBF_TR181],[test "x$enable_tr181" = "xyes"])

View file

@ -16,7 +16,11 @@
#include "dmdynamicjson.h"
#include "dmdynamiclibrary.h"
#include "dmdynamicvendor.h"
#ifdef BBF_TR181
#include "device.h"
#endif /* BBF_TR181 */
#include "dmbbfcommon.h"
LIST_HEAD(head_package_change);
@ -129,7 +133,7 @@ int usp_fault_map(int fault)
return out_fault;
}
static int dm_ctx_init_custom(struct dmctx *ctx, unsigned int instance_mode, int custom)
static int dm_ctx_init_custom(struct dmctx *ctx, unsigned int instance_mode, DMOBJ *tEntryObj, int custom)
{
if (custom == CTX_INIT_ALL)
bbf_uci_init();
@ -138,7 +142,7 @@ static int dm_ctx_init_custom(struct dmctx *ctx, unsigned int instance_mode, int
INIT_LIST_HEAD(&ctx->set_list_tmp);
INIT_LIST_HEAD(&ctx->list_fault_param);
ctx->instance_mode = instance_mode;
ctx->dm_entryobj = tEntry181Obj;
ctx->dm_entryobj = tEntryObj;
ctx->dm_version = DEFAULT_DMVERSION;
ctx->end_session_flag = 0;
return 0;
@ -162,10 +166,19 @@ void dm_config_ubus(struct ubus_context *ctx)
dmubus_configure(ctx);
}
int dm_ctx_init_entry(struct dmctx *ctx, DMOBJ *tEntryObj, unsigned int instance_mode)
{
return dm_ctx_init_custom(ctx, instance_mode, tEntryObj, CTX_INIT_ALL);
}
int dm_ctx_init(struct dmctx *ctx, unsigned int instance_mode)
{
#ifdef BBF_TR181
dmubus_clean_endlife_entries();
return dm_ctx_init_custom(ctx, instance_mode, CTX_INIT_ALL);
return dm_ctx_init_custom(ctx, instance_mode, tEntry181Obj, CTX_INIT_ALL);
#else
return 0;
#endif /* BBF_TR181 */
}
int dm_ctx_clean(struct dmctx *ctx)
@ -182,7 +195,11 @@ int dm_ctx_init_cache(int time)
int dm_ctx_init_sub(struct dmctx *ctx, unsigned int instance_mode)
{
return dm_ctx_init_custom(ctx, instance_mode, CTX_INIT_SUB);
#ifdef BBF_TR181
return dm_ctx_init_custom(ctx, instance_mode, tEntry181Obj, CTX_INIT_SUB);
#else
return 0;
#endif /* BBF_TR181 */
}
int dm_ctx_clean_sub(struct dmctx *ctx)
@ -197,11 +214,12 @@ int dm_get_supported_dm(struct dmctx *ctx, char *path, bool first_level, schema_
// Load dynamic objects and parameters
load_dynamic_arrays(ctx);
if (strlen(path) == 0)
path = "Device.";
if (strlen(path) == 0) {
path = "";
} else {
if (path[strlen(path) - 1] != '.')
return usp_fault_map(USP_FAULT_INVALID_PATH);
}
ctx->in_param = path;
@ -545,7 +563,9 @@ static void load_dynamic_arrays(struct dmctx *ctx)
static void free_dynamic_arrays(void)
{
#ifdef BBF_TR181
DMOBJ *root = tEntry181Obj;
DMNODE node = {.current_object = ""};
#ifdef BBFDM_ENABLE_JSON_PLUGIN
@ -560,6 +580,7 @@ static void free_dynamic_arrays(void)
free_vendor_dynamic_arrays(tEntry181Obj);
#endif
free_dm_browse_node_dynamic_object_tree(&node, root);
#endif /* BBF_TR181 */
}
void bbf_dm_cleanup(void)
@ -568,3 +589,11 @@ void bbf_dm_cleanup(void)
dm_dynamic_cleanmem(&main_memhead);
free_dynamic_arrays();
}
void dm_cleanup_dynamic_entry(DMOBJ *root)
{
DMNODE node = {.current_object = ""};
dm_dynamic_cleanmem(&main_memhead);
free_dm_browse_node_dynamic_object_tree(&node, root);
}

View file

@ -33,6 +33,7 @@ typedef enum {
int dm_ctx_init(struct dmctx *ctx, unsigned int instance_mode);
int dm_ctx_init_sub(struct dmctx *ctx, unsigned int instance_mode);
int dm_ctx_init_entry(struct dmctx *ctx, DMOBJ tEntryObj[], unsigned int instance_mode);
int dm_entry_param_method(struct dmctx *ctx, int cmd, char *inparam, char *arg1, char *arg2);
int dm_entry_apply(struct dmctx *ctx, int cmd, char *arg1);
int dm_entry_restart_services(void);
@ -62,5 +63,6 @@ void bbf_dm_cleanup(void);
* object illegal access.
*/
int dm_debug_browse_path(char *buff, size_t len);
void dm_cleanup_dynamic_entry(DMOBJ *root);
#endif

1937
docs/api/dmtest.md Normal file

File diff suppressed because it is too large Load diff

View file

@ -9,3 +9,9 @@ autorestart=false
startretries=0
priority=2
command=/bin/bash -c "/usr/sbin/rpcd"
[program:bbf_ubus]
autorestart=false
priority=3
stdout_logfile=/builds/iopsys/bbf/log_file
command=/bin/bash -c "/usr/bin/valgrind --xml=yes --xml-file=/builds/iopsys/bbf/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/bbf/test/dynamicdm_ubus_test/bbf_ubus"

View file

@ -0,0 +1,52 @@
#!/bin/bash
echo "$0 preparation script"
pwd
source ./gitlab-ci/shared.sh
# clean and make
# compile and install libbbf
install_libbbf
#compile and install libbbf_test dynamic extension library
install_libbbf_test
supervisorctl update
supervisorctl restart all
supervisorctl status all
exec_cmd ubus wait_for dmtest
supervisorctl status all
# debug logging
echo "Checking ubus status [$(date '+%d/%m/%Y %H:%M:%S')]"
ubus list
ubus -v list dmtest
echo "Checking system resources"
free -h
df -h
sleep 5
# run functional on dmtest object validation
if [ -f "/usr/share/rpcd/schemas/dmtest.json" ]; then
rm /usr/share/rpcd/schemas/dmtest.json
fi
cp -r ./schemas/dmtest.json /usr/share/rpcd/schemas
ubus-api-validator -t 5 -f ./test/api/json/dmtest.validation.json >> ./api-result.log
check_ret $?
supervisorctl status all
supervisorctl stop all
supervisorctl status
#report part
date +%s > timestamp.log
exec_cmd tap-junit --input ./api-result.log --output report
echo "Checking memory leaks..."
grep -q "Leak" memory-report.xml
error_on_zero $?
echo "Functional libbbf_ubus API test :: PASS"

View file

@ -74,6 +74,15 @@ function install_libbbf_test()
echo "installing libbbf_test"
cp -f test/bbf_test/libbbf_test.so /usr/lib/bbfdm
echo "pre-installation for libbbf_ubus_test"
cp -f test/bbf_test/libbbf_test.so /usr/local/lib
ldconfig
# compile and install libbbf_ubus_test
echo "Compiling libbbf_ubus_test"
make clean -C test/dynamicdm_ubus_test/
make -C test/dynamicdm_ubus_test/
}
function install_libbulkdata()
@ -101,3 +110,14 @@ function install_libperiodicstats()
echo "installing libperiodicstats"
cp -f /opt/dev/periodicstats/libperiodicstats.so /usr/lib/bbfdm
}
function error_on_zero()
{
ret=$1
if [ "$ret" -eq 0 ]; then
echo "Validation of last command failed, ret(${ret})"
exit $ret
fi
}

118
include/libbbf_ubus.h Normal file
View file

@ -0,0 +1,118 @@
/*
* Copyright (C) 2021 Iopsys Software Solutions AB
*
* Author: Suvendhu Hansa <suvendhu.hansa@iopsys.eu>
*
* 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
*
* 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
*/
/**
* \file libbbf_ubus.h
*
* This Library provides APIs to expose the datamodel constructed with the help
* of libbbf API over the ubus directly.
* This library has an external dependency on libbbf_api
*/
#ifndef __LIBBBF_UBUS_H__
#define __LIBBBF_UBUS_H__
#include <libubus.h>
#include "libbbf_api/dmbbf.h"
/*********************************************************************//**
**
** dynamicdm_init
**
** This API is to register the predefined ubus methods to work on provided
** `DMOBJ` tree.
**
** NOTE: dynamicdm_free should be called to deregister and free the allocated
** resources used in this API.
**
** \param ctx - pre-allocated ubus context, should not be NULL
** \param ubus_name - name of the ubus object on which pre-defined usus methods will be registered.
** It should not be NULL or Empty
** \param entry - Object which points to the root node of the tree. More details available in
** libbbf_api documentation.
**
** \return 0 if ubus methods are registered with the given tree, -1 otherwise
**
**************************************************************************/
int dynamicdm_init(struct ubus_context *ctx, char *ubus_name, DMOBJ *entry);
/*********************************************************************//**
**
** dynamicdm_init_plugin_object
**
** This API is to register the predefined ubus methods to work on provided
** `DM_MAP_OBJ` tree.
**
** NOTE: dynamicdm_free_plugin_object should be called to deregister and free
** the allocated resources used in this API.
** This API is for developer purpose and can register a tree with intermediate
** node.
**
** \param ctx - pre-allocated ubus context, should not be NULL
** \param ubus_name - name of the ubus object on which pre-defined usus methods will be registered.
** It should not be NULL or Empty
** \param entry - Object which points to the root node of the tree. More details available in
** libbbf_api documentation.
**
** \return 0 if ubus methods are registered with the given tree, -1 otherwise
**
**************************************************************************/
int dynamicdm_init_plugin_object(struct ubus_context *ctx, char *ubus_name, DM_MAP_OBJ *entry);
/*********************************************************************//**
**
** dynamicdm_free
**
** This is the API responsible to deregister/remove the allocated resources
** used in dynamicdm_init
**
** NOTE: It's the responsibility of the application to call this API before
** termination in order to free the resources if dynamicdm_init has been used.
**
** \param ctx - pre-allocated ubus context, should not be NULL
** \param ubus_name - name of the ubus object on which pre-defined usus methods are registered.
** It should not be NULL or Empty
**
** \return None
**
**************************************************************************/
void dynamicdm_free(struct ubus_context *ctx, const char *ubus_name);
/*********************************************************************//**
**
** dynamicdm_free
**
** This is the API responsible to deregister/remove the allocated resources
** used in dynamicdm_init_plugin_object
**
** NOTE: It's the responsibility of the application to call this API before
** termination in order to free the resources if dynamicdm_init_plugin_object
** has been used.
**
** \param ctx - pre-allocated ubus context, should not be NULL
** \param ubus_name - name of the ubus object on which pre-defined usus methods are registered.
** It should not be NULL or Empty
**
** \return None
**
**************************************************************************/
void dynamicdm_free_plugin_object(struct ubus_context *ctx, const char *ubus_name);
#endif //__LIBBBF_UBUS_H__

38
libbbf_ubus/Makefile.am Normal file
View file

@ -0,0 +1,38 @@
MAINTAINERCLEANFILES = Makefile.in
ACLOCAL_AMFLAGS = -I m4
lib_LTLIBRARIES = libbbf_ubus.la
libbbf_ubus_la_SOURCES = \
../dmentry.c \
../dmbbfcommon.c \
libbbf_ubus.c
libbbf_ubus_la_CFLAGS = \
$(AM_CFLAGS) \
$(LIBUCI_CFLAGS) \
$(LIBUBOX_CFLAGS) \
$(LIBUBUS_CFLAGS)
libbbf_ubus_la_LDFLAGS = \
$(AM_LDFLAGS) \
$(LIBUCI_LDFLAGS) \
$(LIBUBOX_LDFLAGS) \
$(LIBUBUS_LDFLAGS)
libbbf_ubus_la_LIBADD = \
$(AM_LIBS) \
$(LIBUCI_LIBS) \
$(LIBUBOX_LIBS) \
$(LIBUBUS_LIBS) \
$(LIBJSON_LIBS) \
$(LIBTRACE_LIBS) \
$(LBLOBMSG_LIBS) \
$(LIBDLOPEN_LIBS) \
$(LIBCURL_LIBS) \
$(LIBOPENSSL_LIBS) \
$(LIBCRYPTO_LIBS) \
-L../bin/ -lbbf_api
libbbf_ubus_la_CFLAGS+=-I../
libbbf_ubus_la_CFLAGS+=-I../include

71
libbbf_ubus/configure.ac Normal file
View file

@ -0,0 +1,71 @@
AC_INIT([libbbf_ubus], [0.1], [suvendhu.hansa@iopsys.eu])
AM_INIT_AUTOMAKE([foreign subdir-objects])
AC_PROG_CC
AC_PROG_CC_C_O
AC_ENABLE_SHARED
LT_INIT
LIBJSON_LIBS='-ljson-c'
AC_SUBST([LIBJSON_LIBS])
AC_ARG_WITH([uci-include-path],
[AS_HELP_STRING([--with-uci-include-path],
[location of the uci library headers])],
[LIBUCI_CFLAGS="-I$withval"])
AC_SUBST([LIBUCI_CFLAGS])
AC_ARG_WITH([uci-lib-path],
[AS_HELP_STRING([--with-uci-lib-path], [location of the uci library])], [LIBUCI_LDFLAGS="-L$withval"])
AC_SUBST([LIBUCI_LDFLAGS])
LIBUCI_LIBS='-luci'
AC_SUBST([LIBUCI_LIBS])
LIBTRACE_LIBS='-ltrace'
AC_SUBST([LIBTRACE_LIBS])
AC_ARG_WITH([libubox-include-path],
[AS_HELP_STRING([--with-libubox-include-path],
[location of the libubox library headers])],
[LIBUBOX_CFLAGS="-I$withval"])
AC_SUBST([LIBUBOX_CFLAGS])
AC_ARG_WITH([libubox-lib-path],
[AS_HELP_STRING([--with-libubox-lib-path], [location of the libubox library])], [LIBUBOX_LDFLAGS="-L$withval"])
AC_SUBST([LIBUBOX_LDFLAGS])
LIBUBOX_LIBS='-lubox'
AC_SUBST([LIBUBOX_LIBS])
AC_ARG_WITH([libubus-include-path],
[AS_HELP_STRING([--with-libubus-include-path],
[location of the libubus library headers])],
[LIBUBUS_CFLAGS="-I$withval"])
AC_SUBST([LIBUBUS_CFLAGS])
AC_ARG_WITH([libubus-lib-path],
[AS_HELP_STRING([--with-libubus-lib-path], [location of the libubus library])], [LIBUBOX_LDFLAGS="-L$withval"])
AC_SUBST([LIBUBUS_LDFLAGS])
LIBUBUS_LIBS='-lubus'
AC_SUBST([LIBUBUS_LIBS])
LBLOBMSG_LIBS='-lblobmsg_json'
AC_SUBST([LBLOBMSG_LIBS])
LIBDLOPEN_LIBS='-ldl'
AC_SUBST([LIBDLOPEN_LIBS])
LIBCURL_LIBS='-lcurl'
AC_SUBST([LIBCURL_LIBS])
# checks for header files
AC_CHECK_HEADERS([stdlib.h string.h])
# checks for typedefs, structures, and compiler characteristics
AC_TYPE_UINT8_T
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

946
libbbf_ubus/libbbf_ubus.c Normal file
View file

@ -0,0 +1,946 @@
/*
* Copyright (C) 2021 Iopsys Software Solutions AB
*
* Author: Suvendhu Hansa <suvendhu.hansa@iopsys.eu>
*
* 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
*
* 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 <stdio.h>
#include <stdlib.h>
#include <libubox/blobmsg.h>
#include "dmentry.h"
#include "dmbbfcommon.h"
#include "libbbf_ubus.h"
#define PATH_MAX 4096
struct obj_node {
struct ubus_object *ob;
struct ubus_object_type *ob_type;
char *obj_name;
DMOBJ *tUsrObj;
struct obj_node *next;
};
enum {
LIBBBF_UBUS_GET_PATH,
LIBBBF_UBUS_GET_PROTO,
__LIBBBF_UBUS_GET_MAX
};
enum {
LIBBBF_UBUS_SET_PATH,
LIBBBF_UBUS_SET_VALUE,
LIBBBF_UBUS_SET_PROTO,
__LIBBBF_UBUS_SET_MAX
};
enum {
LIBBBF_UBUS_OPERATE_PATH,
LIBBBF_UBUS_OPERATE_INPUT,
__LIBBBF_UBUS_OPERATE_MAX
};
enum {
LIBBBF_UBUS_SUPPORTED_PATH,
LIBBBF_UBUS_SUPPORTED_PROTO,
LIBBBF_UBUS_SUPPORTED_NXT_LEVEL,
LIBBBF_UBUS_SUPPORTED_SCHEMA_TYPE,
__LIBBBF_UBUS_SUPPORTED_MAX
};
enum {
LIBBBF_UBUS_ADD_DEL_PATH,
LIBBBF_UBUS_ADD_DEL_PROTO,
__LIBBBF_UBUS_ADD_DEL_MAX
};
static bool g_dynamicdm_transaction_start = false;
static struct obj_node *g_dynamicdm_head = NULL;
static int libbbf_ubus_supported_dm(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method __attribute__((unused)),
struct blob_attr *msg);
static int libbbf_ubus_get_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method __attribute__((unused)),
struct blob_attr *msg);
static int libbbf_ubus_set_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method __attribute__((unused)),
struct blob_attr *msg);
static int libbbf_ubus_operate(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method __attribute__((unused)),
struct blob_attr *msg);
static int libbbf_ubus_add_del_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method __attribute__((unused)),
struct blob_attr *msg);
static int libbbf_ubus_transaction_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method __attribute__((unused)),
struct blob_attr *msg);
static const struct blobmsg_policy libbbf_ubus_supported_dm_policy[] = {
[LIBBBF_UBUS_SUPPORTED_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
[LIBBBF_UBUS_SUPPORTED_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING },
[LIBBBF_UBUS_SUPPORTED_NXT_LEVEL] = { .name = "next-level", .type = BLOBMSG_TYPE_INT8},
[LIBBBF_UBUS_SUPPORTED_SCHEMA_TYPE] = { .name = "schema_type", .type = BLOBMSG_TYPE_INT32},
};
static const struct blobmsg_policy libbbf_ubus_get_policy[] = {
[LIBBBF_UBUS_GET_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
[LIBBBF_UBUS_GET_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING }
};
static const struct blobmsg_policy libbbf_ubus_set_policy[] = {
[LIBBBF_UBUS_SET_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
[LIBBBF_UBUS_SET_VALUE] = { .name = "value", .type = BLOBMSG_TYPE_STRING },
[LIBBBF_UBUS_SET_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING }
};
static const struct blobmsg_policy libbbf_ubus_operate_policy[] = {
[LIBBBF_UBUS_OPERATE_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
[LIBBBF_UBUS_OPERATE_INPUT] = { .name = "input", .type = BLOBMSG_TYPE_TABLE }
};
static const struct blobmsg_policy libbbf_ubus_add_del_policy[] = {
[LIBBBF_UBUS_ADD_DEL_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
[LIBBBF_UBUS_ADD_DEL_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING }
};
static struct ubus_method libbbf_ubus_methods[] = {
UBUS_METHOD("get_supported_dm", libbbf_ubus_supported_dm, libbbf_ubus_supported_dm_policy),
UBUS_METHOD("get", libbbf_ubus_get_handler, libbbf_ubus_get_policy),
UBUS_METHOD("set", libbbf_ubus_set_handler, libbbf_ubus_set_policy),
UBUS_METHOD("operate", libbbf_ubus_operate, libbbf_ubus_operate_policy),
UBUS_METHOD("add_object", libbbf_ubus_add_del_handler, libbbf_ubus_add_del_policy),
UBUS_METHOD("del_object", libbbf_ubus_add_del_handler, libbbf_ubus_add_del_policy),
UBUS_METHOD_NOARG("transaction_start", libbbf_ubus_transaction_handler),
UBUS_METHOD_NOARG("transaction_abort", libbbf_ubus_transaction_handler),
UBUS_METHOD_NOARG("transaction_commit", libbbf_ubus_transaction_handler),
};
static int get_protocol(const char *val)
{
int type;
if (strcmp("cwmp", val) == 0)
type = BBFDM_CWMP;
else if (strcmp("usp", val) == 0)
type = BBFDM_USP;
else
type = BBFDM_BOTH;
return type;
}
static int get_bbf_proto_type(struct blob_attr *proto)
{
int type;
if (proto) {
const char *val = blobmsg_get_string(proto);
type = get_protocol(val);
} else {
type = BBFDM_BOTH;
}
return type;
}
static void bb_add_string(struct blob_buf *bb, const char *name, const char *value)
{
if (value)
blobmsg_add_string(bb, name, value);
else
blobmsg_add_string(bb, name, "");
}
static struct obj_node* find_obj_node(const char *ubus_name)
{
struct obj_node *temp = g_dynamicdm_head;
if (temp == NULL)
return NULL;
while (strcmp(ubus_name, temp->obj_name) != 0) {
if (temp->next == NULL) {
return NULL;
} else {
temp = temp->next;
}
}
return temp;
}
static DMOBJ* get_entry_object(const char *name)
{
if (!name)
return NULL;
struct obj_node *ob_node = find_obj_node(name);
if (!ob_node)
return NULL;
return ob_node->tUsrObj;
}
static void fill_operate_schema(struct blob_buf *bb, struct dm_parameter *param)
{
blobmsg_add_string(bb, "parameter",param->name);
blobmsg_add_string(bb,"type",param->type);
blobmsg_add_string(bb,"cmd_type",param->additional_data);
if(param->data) {
const char **in, **out = NULL;
operation_args *args = NULL;
void *array = NULL;
int i;
args = (operation_args *) param->data;
in = args->in;
if (in) {
array = blobmsg_open_array(bb, "in");
for (i = 0; in[i] != NULL; i++)
blobmsg_add_string(bb, NULL, in[i]);
blobmsg_close_array(bb, array);
}
out = args->out;
if (out) {
array = blobmsg_open_array(bb, "out");
for (i = 0; out[i] != NULL; i++)
blobmsg_add_string(bb, NULL, out[i]);
blobmsg_close_array(bb, array);
}
}
}
static void fill_event_schema(struct blob_buf *bb, struct dm_parameter *param)
{
blobmsg_add_string(bb, "parameter",param->name);
blobmsg_add_string(bb,"type",param->type);
if(param->data) {
event_args *ev = NULL;
ev = (event_args *)param->data;
if (ev->param) {
const char **in = NULL;
void *key = NULL;
int i;
in = ev->param;
key = blobmsg_open_array(bb, "in");
for (i = 0; in[i] != NULL; i++)
blobmsg_add_string(bb, NULL, in[i]);
blobmsg_close_array(bb, key);
}
}
}
static void fill_param_schema(struct blob_buf *bb, struct dm_parameter *param)
{
blobmsg_add_string(bb, "parameter", param->name);
blobmsg_add_string(bb, "writable", param->data ? param->data : "0");
blobmsg_add_string(bb, "type", param->type);
if (param->additional_data) {
const char **uniq_keys = NULL;
void *key = NULL;
int i;
uniq_keys = (const char **)param->additional_data;
key = blobmsg_open_array(bb, "unique_keys");
for (i = 0; uniq_keys[i] != NULL; i++)
blobmsg_add_string(bb, NULL, uniq_keys[i]);
blobmsg_close_array(bb, key);
}
}
static int handle_add_del_req(struct ubus_context *ctx, const char *ubus_name, struct ubus_request_data *req,
char *path, const char *method, int proto)
{
int fault = 0;
struct dmctx bbf_ctx;
struct blob_buf bb;
char *pkey = "true";
DMOBJ *tEntryObj = get_entry_object(ubus_name);
if (!tEntryObj) {
printf("Failed to get DM entry obj\n\r");
return UBUS_STATUS_UNKNOWN_ERROR;
}
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
if (!g_dynamicdm_transaction_start) {
printf("Transaction not started\n\r");
blobmsg_add_u32(&bb, "fault", usp_fault_map(USP_FAULT_INTERNAL_ERROR));
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
return 0;
}
memset(&bbf_ctx, 0, sizeof(struct dmctx));
set_bbfdatamodel_type(proto);
dm_ctx_init_entry(&bbf_ctx, tEntryObj, 0);
if (strcmp(method, "add_object") == 0) {
fault = dm_entry_param_method(&bbf_ctx, CMD_ADD_OBJECT, path, pkey, NULL);
} else {
fault = dm_entry_param_method(&bbf_ctx, CMD_DEL_OBJECT, path, pkey, NULL);
}
void *array = blobmsg_open_array(&bb, "parameters");
void *table = blobmsg_open_table(&bb, NULL);
bb_add_string(&bb, "parameter", path);
if (fault) {
blobmsg_add_u32(&bb, "fault", fault);
blobmsg_add_u8(&bb, "status", 0);
} else {
if (strcmp(method, "add_object") == 0) {
if (bbf_ctx.addobj_instance) {
blobmsg_add_u8(&bb, "status", 1);
bb_add_string(&bb, "instance", bbf_ctx.addobj_instance);
} else {
blobmsg_add_u8(&bb, "status", 0);
}
} else {
blobmsg_add_u8(&bb, "status", 1);
}
}
blobmsg_close_table(&bb, table);
blobmsg_close_array(&bb, array);
dm_ctx_clean(&bbf_ctx);
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
return 0;
}
static void libbbf_ubus_obj_node_free(struct obj_node *obj)
{
if (!obj)
return;
if (obj->ob_type)
FREE(obj->ob_type);
if (obj->ob)
FREE(obj->ob);
if (obj->obj_name)
FREE(obj->obj_name);
FREE(obj);
}
static int libbbf_ubus_supported_dm(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method __attribute__((unused)),
struct blob_attr *msg)
{
struct blob_attr *tb[__LIBBBF_UBUS_SUPPORTED_MAX];
char path[PATH_MAX] = {0};
bool nxt_lvl = false;
uint32_t schema_type = 0;
struct blob_buf bb;
int fault = 0, proto;
struct dmctx bbf_ctx;
if (blobmsg_parse(libbbf_ubus_supported_dm_policy, __LIBBBF_UBUS_SUPPORTED_MAX, tb, blob_data(msg), blob_len(msg)) == 0) {
if (tb[LIBBBF_UBUS_SUPPORTED_PATH])
snprintf(path, PATH_MAX, "%s", (char *)blobmsg_data(tb[LIBBBF_UBUS_SUPPORTED_PATH]));
if (tb[LIBBBF_UBUS_SUPPORTED_NXT_LEVEL])
nxt_lvl = blobmsg_get_bool(tb[LIBBBF_UBUS_SUPPORTED_NXT_LEVEL]);
if (tb[LIBBBF_UBUS_SUPPORTED_SCHEMA_TYPE])
schema_type = blobmsg_get_u32(tb[LIBBBF_UBUS_SUPPORTED_SCHEMA_TYPE]);
}
DMOBJ *tEntryObj = get_entry_object(obj->name);
if (!tEntryObj) {
printf("Failed to get DM entry obj\n\r");
return UBUS_STATUS_UNKNOWN_ERROR;
}
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
memset(&bbf_ctx, 0, sizeof(struct dmctx));
proto = get_bbf_proto_type(tb[LIBBBF_UBUS_SUPPORTED_PROTO]);
set_bbfdatamodel_type(proto);
dm_ctx_init_entry(&bbf_ctx, tEntryObj, 0);
fault = dm_get_supported_dm(&bbf_ctx, path, nxt_lvl, schema_type);
if(fault) {
blobmsg_add_u32(&bb, "fault", fault);
} else {
struct dm_parameter *param = NULL;
void *array = NULL, *table = NULL;
array = blobmsg_open_array(&bb,"parameters");
list_for_each_entry(param, &bbf_ctx.list_parameter, list) {
int cmd = get_dm_type(param->type);
table = blobmsg_open_table(&bb, NULL);
if (cmd == DMT_COMMAND) {
fill_operate_schema(&bb, param);
} else if (cmd == DMT_EVENT) {
fill_event_schema(&bb, param);
} else {
fill_param_schema(&bb, param);
}
blobmsg_close_table(&bb, table);
}
blobmsg_close_array(&bb, array);
}
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
dm_ctx_clean(&bbf_ctx);
return fault;
}
static void init_dm_path(DMOBJ *tEntryObj)
{
struct dmctx bbf_ctx;
memset(&bbf_ctx, 0, sizeof(struct dmctx));
set_bbfdatamodel_type(BBFDM_BOTH);
dm_ctx_init_entry(&bbf_ctx, tEntryObj, 0);
dm_entry_param_method(&bbf_ctx, CMD_GET_VALUE, "", NULL, NULL);
dm_ctx_clean(&bbf_ctx);
}
static int libbbf_ubus_get_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method __attribute__((unused)),
struct blob_attr *msg)
{
struct blob_attr *tb[__LIBBBF_UBUS_GET_MAX] = {NULL};
char path[PATH_MAX] = {0};
struct dmctx bbf_ctx;
struct blob_buf bb;
int fault = 0, proto;
if (blobmsg_parse(libbbf_ubus_get_policy, __LIBBBF_UBUS_GET_MAX, tb, blob_data(msg), blob_len(msg))) {
printf("Failed to parse blob\n");
return UBUS_STATUS_UNKNOWN_ERROR;
}
if (!(tb[LIBBBF_UBUS_GET_PATH]))
return UBUS_STATUS_INVALID_ARGUMENT;
DMOBJ *tEntryObj = get_entry_object(obj->name);
if (!tEntryObj) {
printf("Failed to get DM entry obj\n\r");
return UBUS_STATUS_UNKNOWN_ERROR;
}
snprintf(path, PATH_MAX, "%s", (char *)blobmsg_data(tb[LIBBBF_UBUS_GET_PATH]));
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
memset(&bbf_ctx, 0, sizeof(struct dmctx));
proto = get_bbf_proto_type(tb[LIBBBF_UBUS_GET_PROTO]);
set_bbfdatamodel_type(proto);
dm_ctx_init_entry(&bbf_ctx, tEntryObj, 0);
fault = dm_entry_param_method(&bbf_ctx, CMD_GET_VALUE, path, NULL, NULL);
if (!fault) {
struct dm_parameter *n = NULL;
void *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, "value", n->data);
bb_add_string(&bb, "type", n->type);
blobmsg_close_table(&bb, table);
}
blobmsg_close_array(&bb, array);
} else {
blobmsg_add_u32(&bb, "fault", fault);
}
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
dm_ctx_clean(&bbf_ctx);
return fault;
}
static int libbbf_ubus_operate(struct ubus_context *ctx, struct ubus_object *obj __attribute__((unused)),
struct ubus_request_data *req, const char *method __attribute__((unused)),
struct blob_attr *msg)
{
struct blob_attr *tb[__LIBBBF_UBUS_OPERATE_MAX] = {NULL};
char path[PATH_MAX] = {0};
char *input = NULL;
struct blob_buf bb;
struct dmctx bbf_ctx;
int fault = 0, len;
if (blobmsg_parse(libbbf_ubus_operate_policy, __LIBBBF_UBUS_OPERATE_MAX, tb, blob_data(msg), blob_len(msg))) {
printf("Failed to parse blob\n\r");
return UBUS_STATUS_UNKNOWN_ERROR;
}
if (!(tb[LIBBBF_UBUS_OPERATE_PATH]))
return UBUS_STATUS_INVALID_ARGUMENT;
if (tb[LIBBBF_UBUS_OPERATE_INPUT])
input = blobmsg_format_json(tb[LIBBBF_UBUS_OPERATE_INPUT], true);
DMOBJ *tEntryObj = get_entry_object(obj->name);
if (!tEntryObj) {
printf("Failed to get DM entry obj\n\r");
if (input)
free(input);
return UBUS_STATUS_UNKNOWN_ERROR;
}
snprintf(path, PATH_MAX, "%s", (char *)blobmsg_data(tb[LIBBBF_UBUS_OPERATE_PATH]));
len = strlen(path);
if (path[len - 1] == '.') {
printf("path can't end with (.)\n\r");
if (input)
free(input);
return UBUS_STATUS_UNKNOWN_ERROR;
}
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
memset(&bbf_ctx, 0, sizeof(struct dmctx));
set_bbfdatamodel_type(BBFDM_USP);
dm_ctx_init_entry(&bbf_ctx, tEntryObj, 0);
fault = dm_entry_param_method(&bbf_ctx, CMD_USP_OPERATE, path, input, NULL);
switch (fault) {
case CMD_NOT_FOUND:
fault = USP_FAULT_INVALID_PATH;
break;
case CMD_INVALID_ARGUMENTS:
fault = USP_FAULT_INVALID_ARGUMENT;
break;
case CMD_FAIL:
fault = USP_FAULT_COMMAND_FAILURE;
break;
case CMD_SUCCESS:
fault = 0;
break;
default:
printf("Case(%d) not found\n\r", fault);
fault = USP_FAULT_INVALID_PATH;
break;
}
void *array = blobmsg_open_array(&bb, "Results");
void *table = blobmsg_open_table(&bb, NULL);
blobmsg_add_string(&bb, "path", path);
if (fault == 0) {
struct dm_parameter *n = NULL;
void *array_in = blobmsg_open_array(&bb, "parameters");
list_for_each_entry(n, &bbf_ctx.list_parameter, list) {
void *table_in = 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_in);
}
blobmsg_close_array(&bb, array_in);
} else {
fault = usp_fault_map(fault);
blobmsg_add_u32(&bb, "fault", fault);
}
blobmsg_close_table(&bb, table);
blobmsg_close_array(&bb, array);
dm_ctx_clean(&bbf_ctx);
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
if (input)
free(input);
return 0;
}
static int libbbf_ubus_add_del_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_attr *tb[__LIBBBF_UBUS_ADD_DEL_MAX] = {NULL};
char path[PATH_MAX] = {0};
int plen, proto;
if (blobmsg_parse(libbbf_ubus_add_del_policy, __LIBBBF_UBUS_ADD_DEL_MAX, tb, blob_data(msg), blob_len(msg))) {
printf("Failed to parse blob");
return UBUS_STATUS_UNKNOWN_ERROR;
}
if (!tb[LIBBBF_UBUS_ADD_DEL_PATH])
return UBUS_STATUS_INVALID_ARGUMENT;
snprintf(path, PATH_MAX, "%s", (char *)blobmsg_data(tb[LIBBBF_UBUS_ADD_DEL_PATH]));
plen = strlen(path);
if (path[plen - 1] != '.') {
if (plen > PATH_MAX - 2) {
printf("path too long(%d) can't append (.)\n\r", plen);
return UBUS_STATUS_UNKNOWN_ERROR;
}
strcat(path, ".");
}
proto = get_bbf_proto_type(tb[LIBBBF_UBUS_ADD_DEL_PROTO]);
return handle_add_del_req(ctx, obj->name, req, path, method, proto);
}
static int libbbf_ubus_set_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_buf bb;
struct blob_attr *tb[__LIBBBF_UBUS_SET_MAX] = {NULL};
char path[PATH_MAX] = {'\0'}, value[PATH_MAX] = {'\0'};
int fault = 0, proto;
void *array = NULL, *table = NULL;
struct dmctx bbf_ctx;
bool fault_occured = false;
if (blobmsg_parse(libbbf_ubus_set_policy, __LIBBBF_UBUS_SET_MAX, tb, blob_data(msg), blob_len(msg))) {
printf("Failed to parse blob");
return UBUS_STATUS_UNKNOWN_ERROR;
}
if (!tb[LIBBBF_UBUS_SET_PATH])
return UBUS_STATUS_INVALID_ARGUMENT;
if (!tb[LIBBBF_UBUS_SET_VALUE])
return UBUS_STATUS_INVALID_ARGUMENT;
DMOBJ *tEntryObj = get_entry_object(obj->name);
if (!tEntryObj) {
printf("Failed to get DM entry obj\n\r");
return UBUS_STATUS_UNKNOWN_ERROR;
}
snprintf(path, PATH_MAX, "%s", (char *)blobmsg_data(tb[LIBBBF_UBUS_SET_PATH]));
snprintf(value, PATH_MAX, "%s", (char *)blobmsg_data(tb[LIBBBF_UBUS_SET_VALUE]));
int plen = strlen(path);
if (path[plen - 1] == '.') {
printf("path can't end with (.)\n\r");
return UBUS_STATUS_INVALID_ARGUMENT;
}
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
if (!g_dynamicdm_transaction_start) {
printf("Transaction not started\n\r");
blobmsg_add_u32(&bb, "fault", usp_fault_map(USP_FAULT_INTERNAL_ERROR));
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
return 0;
}
proto = get_bbf_proto_type(tb[LIBBBF_UBUS_SET_PROTO]);
set_bbfdatamodel_type(proto);
memset(&bbf_ctx, 0, sizeof(struct dmctx));
dm_ctx_init_entry(&bbf_ctx, tEntryObj, 0);
fault = dm_entry_param_method(&bbf_ctx, CMD_SET_VALUE, path, value, NULL);
if (fault) {
if (fault_occured == false) {
fault_occured = true;
array = blobmsg_open_array(&bb, "parameters");
}
}
while (bbf_ctx.list_fault_param.next != &bbf_ctx.list_fault_param) {
struct param_fault *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);
}
//Apply the parameter
fault = dm_entry_apply(&bbf_ctx, CMD_SET_VALUE, NULL);
if (fault == 0 && fault_occured == false) {
blobmsg_add_u8(&bb, "status", true);
if (get_bbfdatamodel_type() == BBFDM_CWMP)
blobmsg_add_u64(&bb, "flag", bbf_ctx.end_session_flag);
} else {
if (!array)
array = blobmsg_open_array(&bb, "parameters");
while (bbf_ctx.list_fault_param.next != &bbf_ctx.list_fault_param) {
struct param_fault *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 (array)
blobmsg_close_array(&bb, array);
ubus_send_reply(ctx, req, bb.head);
// free
blob_buf_free(&bb);
dm_ctx_clean(&bbf_ctx);
return 0;
}
static int libbbf_ubus_transaction_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method __attribute__((unused)),
struct blob_attr *msg)
{
struct dmctx bbf_ctx;
struct blob_buf bb;
DMOBJ *tEntryObj = get_entry_object(obj->name);
if (!tEntryObj) {
printf("Failed to get DM entry obj\n\r");
return UBUS_STATUS_UNKNOWN_ERROR;
}
memset(&bbf_ctx, 0, sizeof(struct dmctx));
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
if (strcmp(method, "transaction_start") == 0) {
if (!g_dynamicdm_transaction_start) {
g_dynamicdm_transaction_start = true;
blobmsg_add_u8(&bb, "status", true);
} else {
printf("Transaction already in process\n");
blobmsg_add_u8(&bb, "status", false);
}
} else if(strcmp(method, "transaction_abort") == 0) {
if (g_dynamicdm_transaction_start) {
g_dynamicdm_transaction_start = false;
dm_ctx_init_entry(&bbf_ctx, tEntryObj, 0);
dm_entry_revert_changes();
dm_ctx_clean(&bbf_ctx);
blobmsg_add_u8(&bb, "status", true);
} else {
printf("Transaction still not started\n\r");
blobmsg_add_u8(&bb, "status", false);
}
} else if (strcmp(method, "transaction_commit") == 0) {
if (g_dynamicdm_transaction_start) {
g_dynamicdm_transaction_start = false;
dm_ctx_init_entry(&bbf_ctx, tEntryObj, 0);
dm_entry_manage_services(&bb, true);
dm_entry_restart_services();
dm_ctx_clean(&bbf_ctx);
blobmsg_add_u8(&bb, "status", true);
} else {
printf("Transaction still not started\n\r");
blobmsg_add_u8(&bb, "status", false);
}
} else {
printf("Unsupported method %s\n\r", method);
}
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
return 0;
}
int dynamicdm_init(struct ubus_context *ctx, char *ubus_name, DMOBJ *entry)
{
if (!ctx || !ubus_name || ubus_name[0] == '\0' || !entry)
return -1;
struct obj_node *new = (struct obj_node *)malloc(sizeof(struct obj_node));
if (!new)
return -1;
memset(new, 0, sizeof(struct obj_node));
new->ob = (struct ubus_object *) calloc(1, sizeof(struct ubus_object));
if (!new->ob) {
printf("Out of memory!!\n\r");
libbbf_ubus_obj_node_free(new);
return -1;
}
new->ob_type = (struct ubus_object_type *) calloc(1, sizeof(struct ubus_object_type));
if (!new->ob_type) {
printf("Out of memory!!\n\r");
libbbf_ubus_obj_node_free(new);
return -1;
}
new->obj_name = strdup(ubus_name);
new->ob_type->name = new->obj_name;
new->ob_type->id = 0;
new->ob_type->methods = libbbf_ubus_methods;
new->ob_type->n_methods = ARRAY_SIZE(libbbf_ubus_methods);
new->ob->name = new->obj_name;
new->ob->type = new->ob_type;
new->ob->methods = libbbf_ubus_methods;
new->ob->n_methods = ARRAY_SIZE(libbbf_ubus_methods);
if (ubus_add_object(ctx, new->ob)) {
printf("Failed to add object.\n\r");
libbbf_ubus_obj_node_free(new);
return -1;
}
new->tUsrObj = entry;
new->next = g_dynamicdm_head;
g_dynamicdm_head = new;
init_dm_path(entry);
return 0;
}
int dynamicdm_init_plugin_object(struct ubus_context *ctx, char *ubus_name, DM_MAP_OBJ *entry)
{
int i;
DMOBJ *tEntryObj = NULL;
if (!entry)
return -1;
for (i = 0; entry[i].path != NULL; i++) {
tEntryObj = (DMOBJ*)realloc(tEntryObj, sizeof(DMOBJ) * (i+1));
if (!tEntryObj) {
printf("No Memory exists\n\r");
return -1;
}
memset(&tEntryObj[i], 0, sizeof(DMOBJ));
tEntryObj[i].obj = entry[i].path;
tEntryObj[i].permission = &DMREAD;
tEntryObj[i].nextobj = entry[i].root_obj;
tEntryObj[i].leaf = entry[i].root_leaf;
tEntryObj[i].bbfdm_type = BBFDM_BOTH;
}
/* Make the last empty entry */
tEntryObj = (DMOBJ*)realloc(tEntryObj, sizeof(DMOBJ) * (i+1));
if (!tEntryObj) {
printf("No Memory exists\n\r");
return -1;
}
memset(&tEntryObj[i], 0, sizeof(DMOBJ));
if (0 != dynamicdm_init(ctx, ubus_name, tEntryObj)) {
FREE(tEntryObj);
return -1;
}
return 0;
}
void dynamicdm_free(struct ubus_context *ctx, const char *ubus_name)
{
struct obj_node *curr = g_dynamicdm_head, *prev = NULL;
if (!ctx|| !ubus_name || ubus_name[0] == '\0')
return;
if (curr == NULL)
return;
while (strcmp(ubus_name, curr->obj_name) != 0) {
if (curr->next == NULL) {
return;
} else {
prev = curr;
curr = curr->next;
}
}
if (curr == g_dynamicdm_head) {
g_dynamicdm_head = g_dynamicdm_head->next;
} else {
prev->next = curr->next;
}
if (curr->tUsrObj)
dm_cleanup_dynamic_entry(curr->tUsrObj);
ubus_remove_object(ctx, curr->ob);
libbbf_ubus_obj_node_free(curr);
}
void dynamicdm_free_plugin_object(struct ubus_context *ctx, const char *ubus_name)
{
if (!ctx || !ubus_name || ubus_name[0] == '\0')
return;
struct obj_node *ob_node = find_obj_node(ubus_name);
if (!ob_node)
return;
dm_cleanup_dynamic_entry(ob_node->tUsrObj);
FREE(ob_node->tUsrObj);
dynamicdm_free(ctx, ubus_name);
}

621
schemas/dmtest.json Normal file
View file

@ -0,0 +1,621 @@
{
"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"
]
},
"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",
"xsd:command",
"xsd:event"
]
},
"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/dmtest.json",
"type": "object",
"title": "dmtest",
"object": "user defined dynamic DM exposed on ubus",
"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/path_t"
},
"proto": {
"$ref": "#/definitions/proto_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",
"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"
}
]
}
},
"required": [
"parameter",
"type"
]
}
]
}
}
}
]
}
}
},
"get": {
"title": "Get handler",
"description": "Query the datamodel object",
"type": "object",
"required": [
"input",
"output"
],
"properties": {
"input": {
"type": "object",
"required": [
"path"
],
"properties": {
"path": {
"$ref": "#/definitions/path_t"
},
"proto": {
"$ref": "#/definitions/proto_t"
}
}
},
"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",
"value",
"type"
],
"properties": {
"parameter": {
"$ref": "#/definitions/path_t"
},
"value": {
"type": "string"
},
"type": {
"$ref": "#/definitions/type_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"
}
}
},
"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",
"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",
"Description": "Any discrepancy in input will result in fault. The type of fault can be determined by fault code"
},
"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/path_t"
},
"proto": {
"$ref": "#/definitions/proto_t"
}
}
},
"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",
"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"
}
}
}
]
}
}
}
]
}
}
},
"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/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\"}"
]
}
}
},
"output": {
"oneof": [
{
"type": "object",
"properties": {
"status": {
"const": "1"
}
}
},
{
"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",
"required": [
"parameters"
],
"properties": {
"parameters": {
"type": "array",
"items": [
{
"type": "object",
"required": [
"parameter"
],
"properties": {
"parameter": {
"$ref": "#/definitions/path_t"
},
"status": {
"type": "boolean"
},
"fault": {
"$ref": "#/definitions/fault_t"
}
}
}
]
}
}
}
]
}
}
},
"operate": {
"title": "Operate handler",
"description": "Operate on object element provided in path",
"type": "object",
"required": [
"input",
"output"
],
"properties": {
"input": {
"type": "object",
"required": [
"path"
],
"properties": {
"path": {
"$ref": "#/definitions/operate_path_t"
},
"input": {
"description": "Input arguments for the operate command as defined in TR-181-2.13",
"examples": [
"{\"path\":\"Device.IP.Diagnostics.IPPing\\(\\)\", \"input\":{\"Host\":\"iopsys.eu\"}}"
],
"type": "object",
"properties": {}
}
}
},
"output": {
"type": "object",
"required": [
"Results"
],
"properties": {
"Results": {
"type": "array",
"items": [
{
"type": "object",
"required": [
"path"
],
"properties": {
"path": {
"$ref": "#/definitions/path_t"
},
"parameters": {
"description": "Output will have status for sync commands and for async commands parameters as defined in TR-181-2.13",
"type": "array",
"items": [
{
"type": "object",
"properties": {
"parameter": {
"type": "string"
},
"value": {
"type": "string"
},
"type": {
"$ref": "#/definitions/type_t"
},
"fault": {
"$ref": "#/definitions/fault_t"
}
}
}
],
"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\"}"
]
}
}
}
]
}
}
}
}
},
"transaction_start": {
"title": "Start a transaction before set/add/del operations",
"type": "object",
"properties": {
"input": {
"type": "object",
"properties": {}
},
"output": {
"type": "object",
"properties": {
"status": {
"type": "boolean"
}
},
"required": [
"status"
]
}
},
"required": [
"output"
]
},
"transaction_abort": {
"title": "Aborts an on-going transaction",
"type": "object",
"properties": {
"input": {
"type": "object",
"properties": {}
},
"output": {
"type": "object",
"properties": {
"status": {
"type": "boolean"
}
},
"required": [
"status"
]
}
},
"required": [
"output"
]
},
"transaction_commit": {
"title": "Commits an on-going transaction",
"type": "object",
"properties": {
"input": {
"type": "object",
"properties": {}
},
"output": {
"type": "object",
"properties": {
"status": {
"type": "boolean"
}
},
"required": [
"status"
]
}
},
"required": [
"output"
]
}
}
}

View file

@ -0,0 +1,104 @@
{
"object": "dmtest",
"methods": [
{
"method": "get",
"args": {
"path": "Device.",
"proto": "usp"
},
"rc": 0
},
{
"method": "transaction_start",
"args": {},
"rc": 0
},
{
"method": "set",
"args": {
"path": "Device..X_IOPSYS_EU_Syslog.ConsoleLogLevel",
"value": "1"
},
"rc": 0
},
{
"method": "transaction_abort",
"args": {},
"rc": 0
},
{
"method": "add_object",
"args": {
"path": "Device.ManagementServer..InformParameter.",
"proto": "cwmp"
},
"rc": 0
},
{
"method": "get_supported_dm",
"args": {
"path":"Device.",
"next-level":false,
"schema_type":1
},
"rc": 0
},
{
"method": "get_supported_dm",
"args": {
"path":"Device."
},
"rc": 0
},
{
"method": "get_supported_dm",
"args": {
"path":"Device.",
"next-level":false,
"schema_type":2
},
"rc": 0
},
{
"method": "get_supported_dm",
"args": {
"path":"Device.",
"next-level":false,
"schema_type":3
},
"rc": 0
},
{
"method": "get_supported_dm",
"args": {
"path":"Device.",
"schema_type":1
},
"rc": 0
},
{
"method": "get_supported_dm",
"args": {},
"rc": 0
},
{
"method": "transaction_start",
"args": {},
"rc": 0
},
{
"method": "transaction_commit",
"args": {},
"rc": 0
},
{
"method": "del_object",
"args": {
"path": "Device.ManagementServer..InformParameter.2",
"proto": "cwmp"
},
"rc": 0
}
]
}

View file

@ -0,0 +1,16 @@
BIN = bbf_ubus
BIN_OBJ = bbf_ubus.o
BIN_CFLAGS = $(CFLAGS) -Wall -Werror -fPIC -I /usr/local/include/
BIN_LDFLAGS = $(LDFLAGS) -lbbf_ubus -lubus -lubox -lbbf_test
%.o: %.c
$(CC) $(BIN_CFLAGS) $(FPIC) -c -o $@ $<
all: $(BIN)
$(BIN): $(BIN_OBJ)
$(CC) -o $@ $^ $(BIN_LDFLAGS)
clean:
rm -fv *.o $(BIN)

View file

@ -0,0 +1,34 @@
#include <stdio.h>
#include <libbbf_ubus/libbbf_ubus.h>
#include <libbbf_api/dmbbf.h>
#include <libubox/uloop.h>
extern DM_MAP_OBJ tDynamicObj[];
int main(int argc, char *argv[])
{
struct ubus_context *ctx = ubus_connect(NULL);
if (!ctx) {
printf("Failed to connect to ubus\n\r");
return -1;
}
printf("Sending entry obj: (%s)\n\r", tDynamicObj[0].path);
ubus_add_uloop(ctx);
if (-1 == dynamicdm_init_plugin_object(ctx, "dmtest", tDynamicObj)) {
printf("Failed to create ubus object\n\r");
return -1;
}
uloop_run();
dynamicdm_free_plugin_object(ctx, "dmtest");
ubus_free(ctx);
uloop_done();
return 0;
}