Optimize bbfdmd

* All core Data Model move to core micro-service
* New bbfdmd daemon to use async call to optimize RPCs handling
This commit is contained in:
Amin Ben Romdhane 2025-02-21 09:55:09 +00:00 committed by IOPSYS Dev
parent af2c564ab8
commit f21814dd4e
No known key found for this signature in database
72 changed files with 2246 additions and 4207 deletions

View file

@ -15,8 +15,8 @@ include:
- if: $CI_COMMIT_BRANCH == "devel" - if: $CI_COMMIT_BRANCH == "devel"
stages: stages:
- unit_test
- static_code_analysis - static_code_analysis
- unit_test
- functional_test - functional_test
- deploy - deploy
@ -29,6 +29,7 @@ run_unit_test:
- "./gitlab-ci/install-dependencies.sh ms" - "./gitlab-ci/install-dependencies.sh ms"
- "./gitlab-ci/setup.sh ms" - "./gitlab-ci/setup.sh ms"
- "./gitlab-ci/unit-test.sh" - "./gitlab-ci/unit-test.sh"
artifacts: artifacts:
when: always when: always
paths: paths:

View file

@ -4,9 +4,9 @@ PROJECT(bbfdmd)
ADD_DEFINITIONS(-fstrict-aliasing -Wall -Wextra -Werror -Wformat -Wformat-signedness -g3 -fPIC -D_GNU_SOURCE) ADD_DEFINITIONS(-fstrict-aliasing -Wall -Wextra -Werror -Wformat -Wformat-signedness -g3 -fPIC -D_GNU_SOURCE)
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SOURCE_DIR} -I${CMAKE_SOURCE_DIR}/libbbfdm-api/legacy -I${CMAKE_SOURCE_DIR}/libbbfdm-api/version-2 -I${CMAKE_SOURCE_DIR}/libbbfdm-ubus") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SOURCE_DIR}")
FILE(GLOB BBF_SOURCES *.c) FILE(GLOB BBF_SOURCES *.c)
ADD_EXECUTABLE(bbfdmd ${BBF_SOURCES}) ADD_EXECUTABLE(bbfdmd ${BBF_SOURCES})
TARGET_LINK_LIBRARIES(bbfdmd bbfdm-ubus bbfdm) TARGET_LINK_LIBRARIES(bbfdmd ubus ubox blobmsg_json json-c bbfdm-api-v2)
INSTALL(TARGETS bbfdmd DESTINATION usr/sbin) INSTALL(TARGETS bbfdmd DESTINATION usr/sbin)

View file

@ -1,21 +1,179 @@
/* /*
* bbfdmd.c: BBFDMD deamon * Copyright (C) 2023-2025 iopsys Software Solutions AB
* *
* Copyright (C) 2023-2024 IOPSYS Software Solutions AB. All rights reserved. * 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: Vivek Dutta <vivek.dutta@iopsys.eu> * Author: Vivek Dutta <vivek.dutta@iopsys.eu>
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
* *
* See LICENSE file for license related information.
*/ */
#include <sys/prctl.h> #include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <libubus.h>
#include <libubox/blobmsg_json.h>
#include "common.h" #include "common.h"
#include "bbfdm-ubus.h" #include "service.h"
#include "get.h"
#include "cli.h" #include "cli.h"
#include "../../libbbfdm/device.h" extern struct list_head registered_services;
extern int g_log_level;
static const struct blobmsg_policy bbfdm_policy[] = {
[BBFDM_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
[BBFDM_VALUE] = { .name = "value", .type = BLOBMSG_TYPE_STRING },
[BBFDM_INPUT] = { .name = "optional", .type = BLOBMSG_TYPE_TABLE}
};
static int bbfdm_handler_async(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method, struct blob_attr *msg)
{
struct blob_attr *tb[__BBFDM_MAX];
service_entry_t *service = NULL;
if (blobmsg_parse(bbfdm_policy, __BBFDM_MAX, tb, blob_data(msg), blob_len(msg))) {
BBFDM_ERR("Failed to parse input message");
return UBUS_STATUS_UNKNOWN_ERROR;
}
if (!tb[BBFDM_PATH]) {
BBFDM_ERR("%s: path must be defined", method);
return UBUS_STATUS_INVALID_ARGUMENT;
}
struct async_request_context *context = calloc(1, sizeof(struct async_request_context));
if (!context) {
BBFDM_ERR("Failed to allocate memory");
return UBUS_STATUS_UNKNOWN_ERROR;
}
BBFDM_INFO("ubus method|%s|, name|%s|", method, obj->name);
snprintf(context->requested_path, sizeof(context->requested_path), "%s", blobmsg_get_string(tb[BBFDM_PATH]));
snprintf(context->ubus_method, sizeof(context->ubus_method), "%s", method);
context->ubus_ctx = ctx;
memset(&context->tmp_bb, 0, sizeof(struct blob_buf));
blob_buf_init(&context->tmp_bb, 0);
if (strcmp(method, "get") == 0) {
INIT_LIST_HEAD(&context->linker_list);
// Send linker cleanup event for all services
send_linker_cleanup_event(ctx);
// Event handler to wait for linker response
context->linker_handler.cb = linker_response_callback;
ubus_register_event_handler(ctx, &context->linker_handler, "bbfdm.linker.response");
}
unsigned int requested_proto = get_proto_type_option_value(tb[BBFDM_INPUT]);
ubus_defer_request(ctx, req, &context->request_data);
list_for_each_entry(service, &registered_services, list) {
if (!is_path_match(context->requested_path, requested_proto, service))
continue;
run_async_call(context, service->name, msg);
}
context->service_list_processed = true;
if (context->path_matched == false)
send_response(context);
return 0;
}
static int bbfdm_handler_sync(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method, struct blob_attr *msg)
{
struct blob_attr *tb[__BBFDM_MAX];
service_entry_t *service = NULL;
char requested_path[MAX_PATH_LENGTH];
struct blob_buf bb = {0};
if (blobmsg_parse(bbfdm_policy, __BBFDM_MAX, tb, blob_data(msg), blob_len(msg))) {
BBFDM_ERR("Failed to parse input message");
return UBUS_STATUS_UNKNOWN_ERROR;
}
if (!tb[BBFDM_PATH]) {
BBFDM_ERR("%s: path must be defined", method);
return UBUS_STATUS_INVALID_ARGUMENT;
}
BBFDM_INFO("ubus method|%s|, name|%s|", method, obj->name);
snprintf(requested_path, sizeof(requested_path), "%s", blobmsg_get_string(tb[BBFDM_PATH]));
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
unsigned int requested_proto = get_proto_type_option_value(tb[BBFDM_INPUT]);
list_for_each_entry(service, &registered_services, list) {
if (!is_path_match(requested_path, requested_proto, service))
continue;
run_sync_call(service->name, method, msg, &bb);
}
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
return 0;
}
static int bbfdm_services_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method, struct blob_attr *msg __attribute__((unused)))
{
struct blob_buf bb;
BBFDM_INFO("ubus method|%s|, name|%s|", method, obj->name);
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
list_registered_services(&bb);
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
return 0;
}
static struct ubus_method bbfdm_methods[] = {
UBUS_METHOD("get", bbfdm_handler_async, bbfdm_policy),
UBUS_METHOD("schema", bbfdm_handler_async, bbfdm_policy),
UBUS_METHOD("instances", bbfdm_handler_async, bbfdm_policy),
UBUS_METHOD("operate", bbfdm_handler_async, bbfdm_policy),
UBUS_METHOD("set", bbfdm_handler_sync, bbfdm_policy),
UBUS_METHOD("add", bbfdm_handler_sync, bbfdm_policy),
UBUS_METHOD("del", bbfdm_handler_sync, bbfdm_policy),
UBUS_METHOD_NOARG("services", bbfdm_services_handler)
};
static struct ubus_object_type bbfdm_object_type = UBUS_OBJECT_TYPE(BBFDM_UBUS_OBJECT, bbfdm_methods);
static struct ubus_object bbfdm_object = {
.name = BBFDM_UBUS_OBJECT,
.type = &bbfdm_object_type,
.methods = bbfdm_methods,
.n_methods = ARRAY_SIZE(bbfdm_methods)
};
static void usage(char *prog) static void usage(char *prog)
{ {
@ -30,13 +188,10 @@ static void usage(char *prog)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
struct bbfdm_context bbfdm_ctx = {0}; struct ubus_context ubus_ctx = {0};
char *cli_argv[4] = {0}; char *cli_argv[4] = {0};
int log_level = 3; // Default is LOG_ERR
int err = 0, ch, cli_argc = 0, i; int err = 0, ch, cli_argc = 0, i;
memset(&bbfdm_ctx, 0, sizeof(struct bbfdm_context));
while ((ch = getopt(argc, argv, "hc:l:")) != -1) { while ((ch = getopt(argc, argv, "hc:l:")) != -1) {
switch (ch) { switch (ch) {
case 'c': case 'c':
@ -47,9 +202,9 @@ int main(int argc, char **argv)
break; break;
case 'l': case 'l':
if (optarg) { if (optarg) {
log_level = (int)strtod(optarg, NULL); g_log_level = (int)strtod(optarg, NULL);
if (log_level < 0 || log_level > 7) if (g_log_level < 0 || g_log_level > 7)
log_level = 3; g_log_level = 3;
} }
break; break;
case 'h': case 'h':
@ -61,24 +216,42 @@ int main(int argc, char **argv)
} }
if (cli_argc) { if (cli_argc) {
return bbfdm_cli_exec_command(cli_argc, cli_argv); return bbfdmd_cli_exec_command(cli_argc, cli_argv);
} }
bbfdm_ubus_set_log_level(log_level); openlog(BBFDM_UBUS_OBJECT, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
bbfdm_ubus_load_data_model(tDynamicObj);
openlog(BBFDM_DEFAULT_UBUS_OBJ, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1); setlogmask(LOG_UPTO(g_log_level));
err = bbfdm_ubus_regiter_init(&bbfdm_ctx); err = ubus_connect_ctx(&ubus_ctx, NULL);
if (err != 0) if (err != UBUS_STATUS_OK) {
goto exit; BBFDM_ERR("Failed to connect to ubus");
return -1;
}
BBF_INFO("Waiting on uloop...."); uloop_init();
ubus_add_uloop(&ubus_ctx);
err = register_services(&ubus_ctx);
if (err) {
BBFDM_ERR("Failed to load micro-services");
goto end;
}
err = ubus_add_object(&ubus_ctx, &bbfdm_object);
if (err != UBUS_STATUS_OK) {
BBFDM_ERR("Failed to add ubus object: %s", ubus_strerror(err));
goto end;
}
BBFDM_INFO("Waiting on uloop....");
uloop_run(); uloop_run();
exit: end:
if (err != -5) // Error code is not -5, indicating that ubus_ctx is connected, proceed with shutdown BBFDM_ERR("Free context");
bbfdm_ubus_regiter_free(&bbfdm_ctx); unregister_services();
uloop_done();
ubus_shutdown(&ubus_ctx);
closelog(); closelog();

View file

@ -1,20 +1,22 @@
/* /*
* cli.c: Cli command for bbfdmd * Copyright (C) 2023-2025 iopsys Software Solutions AB
* *
* Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved. * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation
* *
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
* *
* See LICENSE file for license related information.
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <libubus.h>
#include "common.h" #include "common.h"
#include "plugin.h"
#define UNUSED __attribute__((unused))
typedef struct { typedef struct {
char *cmd; char *cmd;
@ -28,7 +30,7 @@ typedef struct {
char *usage; char *usage;
} cli_cmd_t; } cli_cmd_t;
static int cli_exec_help(cli_data_t *cli_data UNUSED, const char *path UNUSED, const char *value UNUSED); static int cli_exec_help(cli_data_t *cli_data __attribute__((unused)), const char *path __attribute__((unused)), const char *value __attribute__((unused)));
static int cli_exec_cmd(cli_data_t *cli_data, const char *path, const char *value); static int cli_exec_cmd(cli_data_t *cli_data, const char *path, const char *value);
cli_cmd_t cli_commands[] = { cli_cmd_t cli_commands[] = {
@ -138,10 +140,8 @@ static void __ubus_callback(struct ubus_request *req, int msgtype __attribute__(
} else if (strcmp(cli_data->cmd, "instances") == 0) { } else if (strcmp(cli_data->cmd, "instances") == 0) {
printf("%s\n", name); printf("%s\n", name);
} else if (strcmp(cli_data->cmd, "schema") == 0) { } else if (strcmp(cli_data->cmd, "schema") == 0) {
char *type = tb[2] ? blobmsg_get_string(tb[2]) : ""; char *type = tb[2] ? blobmsg_get_string(tb[2]) : "xsd:string";
int cmd = get_dm_type(type); printf("%s %s\n", name, type);
printf("%s %s %s\n", name, type, (cmd != DMT_EVENT && cmd != DMT_COMMAND) ? data : "0");
} }
cli_data->ubus_status = true; cli_data->ubus_status = true;
@ -151,7 +151,6 @@ static void __ubus_callback(struct ubus_request *req, int msgtype __attribute__(
static int cli_exec_cmd(cli_data_t *cli_data, const char *path, const char *value) static int cli_exec_cmd(cli_data_t *cli_data, const char *path, const char *value)
{ {
struct blob_buf b = {0}; struct blob_buf b = {0};
void *table = NULL;
int err = EXIT_SUCCESS; int err = EXIT_SUCCESS;
memset(&b, 0, sizeof(struct blob_buf)); memset(&b, 0, sizeof(struct blob_buf));
@ -159,21 +158,17 @@ static int cli_exec_cmd(cli_data_t *cli_data, const char *path, const char *valu
blob_buf_init(&b, 0); blob_buf_init(&b, 0);
blobmsg_add_string(&b, "path", path); blobmsg_add_string(&b, "path", path);
if (value) blobmsg_add_string(&b, "value", value); blobmsg_add_string(&b, "value", value ? value : "");
table = blobmsg_open_table(&b, "optional"); int e = bbfdm_ubus_invoke(BBFDM_UBUS_OBJECT, cli_data->cmd, b.head, __ubus_callback, cli_data);
blobmsg_add_string(&b, "format", "raw");
blobmsg_close_table(&b, table);
int e = bbfdm_ubus_invoke(BBFDM_DEFAULT_UBUS_OBJ, cli_data->cmd, b.head, __ubus_callback, cli_data);
if (e < 0) { if (e < 0) {
printf("ERROR: ubus invoke for [object:%s method:%s] exit with error(%d)\n", BBFDM_DEFAULT_UBUS_OBJ, cli_data->cmd, e); printf("ERROR: ubus invoke for [object:%s method:%s] exit with error(%d)\n", BBFDM_UBUS_OBJECT, cli_data->cmd, e);
err = EXIT_FAILURE; err = EXIT_FAILURE;
} }
if (cli_data->ubus_status == false) { if (cli_data->ubus_status == false) {
printf("ERROR: ubus call for [object:%s method:%s] exit with error\n", BBFDM_DEFAULT_UBUS_OBJ, cli_data->cmd); printf("ERROR: ubus call for [object:%s method:%s] exit with error\n", BBFDM_UBUS_OBJECT, cli_data->cmd);
err = EXIT_FAILURE; err = EXIT_FAILURE;
} }
@ -182,7 +177,7 @@ static int cli_exec_cmd(cli_data_t *cli_data, const char *path, const char *valu
return err; return err;
} }
static int cli_exec_help(cli_data_t *cli_data UNUSED, const char *path UNUSED, const char *value UNUSED) static int cli_exec_help(cli_data_t *cli_data __attribute__((unused)), const char *path __attribute__((unused)), const char *value __attribute__((unused)))
{ {
cli_cmd_t *cli_cmd; cli_cmd_t *cli_cmd;
@ -236,7 +231,7 @@ end:
return err; return err;
} }
int bbfdm_cli_exec_command(int argc, char *argv[]) int bbfdmd_cli_exec_command(int argc, char *argv[])
{ {
cli_data_t cli_data = {0}; cli_data_t cli_data = {0};

View file

@ -1,11 +1,17 @@
/* /*
* cli.c: Cli command for bbfdmd * Copyright (C) 2023-2025 iopsys Software Solutions AB
* *
* Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved. * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation
* *
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
* *
* See LICENSE file for license related information.
*/ */
int bbfdm_cli_exec_command(int argc, char *argv[]); #ifndef BBFDMD_CLI_H
#define BBFDMD_CLI_H
int bbfdmd_cli_exec_command(int argc, char *argv[]);
#endif /* BBFDMD_CLI_H */

140
bbfdmd/ubus/common.c Normal file
View file

@ -0,0 +1,140 @@
/*
* Copyright (C) 2025 iopsys Software Solutions AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation
*
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
*
*/
#include <string.h>
#include <libubox/blobmsg_json.h>
#include "common.h"
int g_log_level = LOG_ERR;
unsigned int get_proto_type(const char *proto)
{
int type = BBFDMD_BOTH;
if (proto) {
if (strcmp(proto, "cwmp") == 0)
type = BBFDMD_CWMP;
else if (strcmp(proto, "usp") == 0)
type = BBFDMD_USP;
else
type = BBFDMD_BOTH;
}
return type;
}
unsigned int get_proto_type_option_value(struct blob_attr *msg)
{
struct blob_attr *tb[1] = {0};
const struct blobmsg_policy p[1] = {
{ "proto", BLOBMSG_TYPE_STRING }
};
int proto = BBFDMD_BOTH;
if (!msg)
return proto;
blobmsg_parse(p, 1, tb, blobmsg_data(msg), blobmsg_len(msg));
if (tb[0]) {
const char *val = blobmsg_get_string(tb[0]);
proto = get_proto_type(val);
}
return proto;
}
bool proto_matches(unsigned int dm_type, const enum bbfdmd_type_enum type)
{
return (dm_type == BBFDMD_BOTH || type == BBFDMD_BOTH || dm_type == type) && type != BBFDMD_NONE;
}
static void sync_callback(struct ubus_request *req, int type __attribute__((unused)), struct blob_attr *msg)
{
struct blob_attr *attr = NULL;
int remaining = 0;
if (!req || !msg)
return;
struct blob_buf *bb_response = (struct blob_buf *)req->priv;
if (!bb_response)
return;
blob_for_each_attr(attr, msg, remaining) {
blobmsg_add_field(bb_response, blobmsg_type(attr), blobmsg_name(attr), blobmsg_data(attr), blobmsg_len(attr));
}
}
void run_sync_call(const char *ubus_obj, const char *ubus_method, struct blob_attr *msg, struct blob_buf *bb_response)
{
struct blob_buf req_buf = {0};
struct blob_attr *attr = NULL;
int remaining = 0;
if (!ubus_obj || !ubus_method || !msg || !bb_response)
return;
memset(&req_buf, 0, sizeof(struct blob_buf));
blob_buf_init(&req_buf, 0);
blob_for_each_attr(attr, msg, remaining) {
if (strcmp(ubus_method, "set") == 0 &&
strcmp(blobmsg_name(attr), "value") == 0 &&
blobmsg_type(attr) == BLOBMSG_TYPE_STRING &&
strncmp(BBFDM_ROOT_OBJECT, blobmsg_get_string(attr), strlen(BBFDM_ROOT_OBJECT)) == 0) {
char value_in[MAX_PATH_LENGTH];
char *reference_value = get_reference_data(blobmsg_get_string(attr), "reference_value");
snprintf(value_in, sizeof(value_in), "%s=>%s##", blobmsg_get_string(attr), reference_value ? reference_value : "");
BBFDM_FREE(reference_value);
blobmsg_add_string(&req_buf, blobmsg_name(attr), value_in);
} if (strcmp(ubus_method, "set") == 0 &&
strcmp(blobmsg_name(attr), "obj_path") == 0 &&
blobmsg_type(attr) == BLOBMSG_TYPE_TABLE) {
struct blob_attr *__attr = NULL;
int rem = 0;
void *table = blobmsg_open_table(&req_buf, "obj_path");
blobmsg_for_each_attr(__attr, attr, rem) {
if (blobmsg_type(__attr) == BLOBMSG_TYPE_STRING && strncmp(BBFDM_ROOT_OBJECT, blobmsg_get_string(__attr), strlen(BBFDM_ROOT_OBJECT)) == 0) {
char value_in[MAX_PATH_LENGTH];
char *reference_value = get_reference_data(blobmsg_get_string(__attr), "reference_value");
snprintf(value_in, sizeof(value_in), "%s=>%s##", blobmsg_get_string(__attr), reference_value ? reference_value : "");
BBFDM_FREE(reference_value);
blobmsg_add_string(&req_buf, blobmsg_name(__attr), value_in);
} else {
blobmsg_add_string(&req_buf, blobmsg_name(__attr), blobmsg_get_string(__attr));
}
}
blobmsg_close_table(&req_buf, table);
} else {
blobmsg_add_field(&req_buf, blobmsg_type(attr), blobmsg_name(attr), blobmsg_data(attr), blobmsg_len(attr));
}
}
if (g_log_level == LOG_DEBUG) {
char *json_str = blobmsg_format_json_indent(req_buf.head, true, -1);
BBFDM_DEBUG("### ubus call %s %s '%s' ###", ubus_obj, ubus_method, json_str);
BBFDM_FREE(json_str);
}
BBFDM_UBUS_INVOKE_SYNC(ubus_obj, ubus_method, req_buf.head, 2000, sync_callback, bb_response);
blob_buf_free(&req_buf);
}

42
bbfdmd/ubus/common.h Normal file
View file

@ -0,0 +1,42 @@
/*
* Copyright (C) 2025 iopsys Software Solutions AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation
*
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
*
*/
#ifndef BBFDMD_COMMON_H
#define BBFDMD_COMMON_H
#include "libbbfdm-api/version-2/bbfdm_api.h"
#define BBFDM_ROOT_OBJECT "Device."
#define BBFDM_UBUS_OBJECT "bbfdm"
#define BBFDM_ADD_EVENT "AddObj"
#define BBFDM_DEL_EVENT "DelObj"
#define BBFDM_EVENT_NAME "event"
#define BBFDM_MICROSERVICE_INPUT_PATH "/etc/bbfdm/services"
#define MAX_PATH_LENGTH 1024
#define SERVICE_CALL_TIMEOUT 5000 // 5 secs
#define SERVICE_CALL_OPERATE_TIMEOUT 1800000 // 30 mins
enum bbfdmd_type_enum {
BBFDMD_NONE = 0,
BBFDMD_CWMP = 1<<0,
BBFDMD_USP = 1<<1,
BBFDMD_BOTH = BBFDMD_CWMP | BBFDMD_USP,
};
unsigned int get_proto_type(const char *proto);
unsigned int get_proto_type_option_value(struct blob_attr *msg);
bool proto_matches(unsigned int dm_type, const enum bbfdmd_type_enum type);
char *get_reference_data(const char *path, const char *method_name);
void run_sync_call(const char *ubus_obj, const char *ubus_method, struct blob_attr *msg, struct blob_buf *bb_response);
#endif /* BBFDMD_COMMON_H */

350
bbfdmd/ubus/get.c Normal file
View file

@ -0,0 +1,350 @@
/*
* Copyright (C) 2025 iopsys Software Solutions AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation
*
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
*
*/
#include <libubus.h>
#include <libubox/blobmsg_json.h>
#include "common.h"
#include "service.h"
#include "get.h"
extern int g_log_level;
static void add_linker_entry(struct async_request_context *ctx, const char *linker_path, const char *linker_value)
{
struct linker_args *linker = calloc(1, sizeof(struct linker_args));
if (!linker)
return;
list_add_tail(&linker->list, &ctx->linker_list);
linker->path = strdup(linker_path ? linker_path : "");
linker->value = strdup(linker_value ? linker_value : "");
}
static void free_linker_entries(struct async_request_context *ctx)
{
struct linker_args *linker = NULL, *tmp = NULL;
list_for_each_entry_safe(linker, tmp, &ctx->linker_list, list) {
list_del(&linker->list);
BBFDM_FREE(linker->path);
BBFDM_FREE(linker->value);
BBFDM_FREE(linker);
}
}
static void fill_blob_param(struct blob_buf *bb, const char *path, const char *data, const char *type)
{
if (!bb || !path || !data || !type)
return;
void *table = blobmsg_open_table(bb, NULL);
blobmsg_add_string(bb, "path", path);
blobmsg_add_string(bb, "data", data);
blobmsg_add_string(bb, "type", type);
blobmsg_close_table(bb, table);
}
static void resolve_reference_path(struct async_request_context *ctx, char *ref_path, char *output, size_t output_len)
{
char *token = NULL, *saveptr = NULL;
char buffer[MAX_PATH_LENGTH] = {0};
if (!ref_path || !output || !output_len) {
BBFDM_ERR("Invalid arguments");
return;
}
// Initialize output buffer
output[0] = 0;
// Return if reference path is empty
if (strlen(ref_path) == 0)
return;
snprintf(buffer, sizeof(buffer), "%s", ref_path);
for (token = strtok_r(buffer, ",", &saveptr); token; token = strtok_r(NULL, ",", &saveptr)) {
// Reference is found, don't need to parse the list
if (!strchr(token, '[')) {
snprintf(output, output_len, "%s", token);
return;
}
struct linker_args *linker = NULL;
list_for_each_entry(linker, &ctx->linker_list, list) {
// Reference is found in the resolved list
if (strcmp(linker->path, token) == 0 && strlen(linker->value) != 0) {
snprintf(output, output_len, "%s", linker->value);
return;
}
}
// Reference is not found in the resolved list
{
// Try to get reference value from micro-services directly
char *reference_path = get_reference_data(token, "reference_path");
// Add path to list in order to be used by other parameters
add_linker_entry(ctx, token, reference_path ? reference_path : "");
// Reference value is found
if (reference_path != NULL) {
snprintf(output, output_len, "%s", reference_path);
BBFDM_FREE(reference_path);
return;
}
}
}
BBFDM_ERR("Can't resolve reference path '%s' -> Set its value to empty", ref_path);
}
static void prepare_and_send_response(struct async_request_context *ctx)
{
struct blob_attr *attr = NULL;
struct blob_buf bb = {0};
int remaining = 0;
if (!ctx)
return;
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
void *array = blobmsg_open_array(&bb, "results");
if (ctx->path_matched == false) {
void *table = blobmsg_open_table(&bb, NULL);
blobmsg_add_string(&bb, "path", ctx->requested_path);
blobmsg_add_u32(&bb, "fault", 9005);
blobmsg_add_string(&bb, "fault_msg", "Invalid parameter name");
blobmsg_close_table(&bb, table);
} else {
blobmsg_for_each_attr(attr, ctx->tmp_bb.head, remaining) {
if (strcmp(ctx->ubus_method, "get") == 0) {
struct blob_attr *fields[4];
const struct blobmsg_policy policy[4] = {
{ "path", BLOBMSG_TYPE_STRING },
{ "data", BLOBMSG_TYPE_STRING },
{ "type", BLOBMSG_TYPE_STRING },
{ "reference", BLOBMSG_TYPE_BOOL },
};
blobmsg_parse(policy, 4, fields, blobmsg_data(attr), blobmsg_len(attr));
bool is_reference = fields[3] ? blobmsg_get_u8(fields[3]) : false;
if (is_reference) {
char buffer[1024] = {0};
char *path = fields[0] ? blobmsg_get_string(fields[0]) : "";
char *data = fields[1] ? blobmsg_get_string(fields[1]) : "";
char *type = fields[2] ? blobmsg_get_string(fields[2]) : "";
resolve_reference_path(ctx, data, buffer, sizeof(buffer));
fill_blob_param(&bb, path, buffer, type);
} else {
blobmsg_add_blob(&bb, attr);
}
} else {
blobmsg_add_blob(&bb, attr);
}
}
}
blobmsg_close_array(&bb, array);
ubus_send_reply(ctx->ubus_ctx, &ctx->request_data, bb.head);
blob_buf_free(&bb);
}
void send_response(struct async_request_context *ctx)
{
prepare_and_send_response(ctx);
if (strcmp(ctx->ubus_method, "get") == 0) {
ubus_unregister_event_handler(ctx->ubus_ctx, &ctx->linker_handler);
send_linker_cleanup_event(ctx->ubus_ctx);
free_linker_entries(ctx);
}
ubus_complete_deferred_request(ctx->ubus_ctx, &ctx->request_data, UBUS_STATUS_OK);
blob_buf_free(&ctx->tmp_bb);
BBFDM_FREE(ctx);
}
static struct blob_attr *get_results_array(struct blob_attr *msg)
{
struct blob_attr *tb[1] = {0};
const struct blobmsg_policy p[1] = {
{ "results", BLOBMSG_TYPE_ARRAY }
};
if (msg == NULL)
return NULL;
blobmsg_parse(p, 1, tb, blobmsg_data(msg), blobmsg_len(msg));
return tb[0];
}
static void append_response_data(struct ubus_request_tracker *tracker, struct blob_attr *msg)
{
struct blob_attr *attr = NULL;
int remaining = 0;
if (!tracker || !msg)
return;
struct blob_attr *results = get_results_array(msg);
if (!results)
return;
blobmsg_for_each_attr(attr, results, remaining) {
blobmsg_add_blob(&tracker->ctx->tmp_bb, attr);
}
}
static void handle_request_timeout(struct uloop_timeout *timeout)
{
struct ubus_request_tracker *tracker = container_of(timeout, struct ubus_request_tracker, timeout);
BBFDM_ERR("Timeout occurred for request: '%s'", tracker->request_name);
ubus_abort_request(tracker->ctx->ubus_ctx, &tracker->async_request);
tracker->ctx->pending_requests--;
if (tracker->ctx->pending_requests == 0 && tracker->ctx->service_list_processed) {
BBFDM_ERR("All requests completed after timeout");
send_response(tracker->ctx);
}
BBFDM_FREE(tracker);
}
static void ubus_result_callback(struct ubus_request *req, int type __attribute__((unused)), struct blob_attr *msg __attribute__((unused)))
{
struct ubus_request_tracker *tracker = container_of(req, struct ubus_request_tracker, async_request);
if (msg) {
BBFDM_DEBUG("Response from object '%s'", tracker->request_name);
append_response_data(tracker, msg);
}
}
static void ubus_request_complete(struct ubus_request *req, int ret)
{
struct ubus_request_tracker *tracker = container_of(req, struct ubus_request_tracker, async_request);
BBFDM_DEBUG("Request completed for '%s' with status: '%d'", tracker->request_name, ret);
uloop_timeout_cancel(&tracker->timeout);
tracker->ctx->pending_requests--;
if (tracker->ctx->pending_requests == 0 && tracker->ctx->service_list_processed) {
BBFDM_DEBUG("Result Callback: All requests completed");
send_response(tracker->ctx);
}
BBFDM_FREE(tracker);
}
void run_async_call(struct async_request_context *ctx, const char *ubus_obj, struct blob_attr *msg)
{
struct blob_buf req_buf = {0};
struct blob_attr *attr = NULL;
int remaining = 0;
uint32_t id = 0;
if (!ctx || !ubus_obj || !msg) {
BBFDM_ERR("Invalid arguments");
return;
}
if (ubus_lookup_id(ctx->ubus_ctx, ubus_obj, &id)) {
BBFDM_ERR("Failed to lookup object: %s", ubus_obj);
return;
}
struct ubus_request_tracker *tracker = calloc(1, sizeof(struct ubus_request_tracker));
if (!tracker) {
BBFDM_ERR("Failed to allocate memory for request tracker");
return;
}
tracker->ctx = ctx;
ctx->pending_requests++;
ctx->path_matched = true;
memset(&req_buf, 0, sizeof(struct blob_buf));
blob_buf_init(&req_buf, 0);
blob_for_each_attr(attr, msg, remaining) {
blobmsg_add_field(&req_buf, blobmsg_type(attr), blobmsg_name(attr), blobmsg_data(attr), blobmsg_len(attr));
}
snprintf(tracker->request_name, sizeof(tracker->request_name), "%s->%s", ubus_obj, ctx->ubus_method);
tracker->timeout.cb = handle_request_timeout;
uloop_timeout_set(&tracker->timeout, !strcmp(ctx->ubus_method, "operate") ? SERVICE_CALL_OPERATE_TIMEOUT : SERVICE_CALL_TIMEOUT);
if (g_log_level == LOG_DEBUG) {
char *json_str = blobmsg_format_json_indent(req_buf.head, true, -1);
BBFDM_DEBUG("### ubus call %s %s '%s' ###", ubus_obj, ctx->ubus_method, json_str);
BBFDM_FREE(json_str);
}
if (ubus_invoke_async(ctx->ubus_ctx, id, ctx->ubus_method, req_buf.head, &tracker->async_request)) {
BBFDM_ERR("Failed to invoke async method for object: %s", tracker->request_name);
uloop_timeout_cancel(&tracker->timeout);
BBFDM_FREE(tracker);
} else {
tracker->async_request.data_cb = ubus_result_callback;
tracker->async_request.complete_cb = ubus_request_complete;
ubus_complete_request_async(ctx->ubus_ctx, &tracker->async_request);
}
blob_buf_free(&req_buf);
}
void send_linker_cleanup_event(struct ubus_context *ctx)
{
struct blob_buf bb = {0};
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
ubus_send_event(ctx, "bbfdm.linker.cleanup", bb.head);
blob_buf_free(&bb);
}
void linker_response_callback(struct ubus_context *ctx __attribute__((unused)), struct ubus_event_handler *ev, const char *type __attribute__((unused)), struct blob_attr *msg)
{
struct async_request_context *context = NULL;
struct blob_attr *attr = NULL;
size_t rem = 0;
if (!msg)
return;
context = container_of(ev, struct async_request_context, linker_handler);
if (context == NULL) {
BBFDM_ERR("Failed to get the request context");
return;
}
blobmsg_for_each_attr(attr, msg, rem) {
BBFDM_DEBUG("LINKER RESPONSE: '%s' <=> '%s'", blobmsg_name(attr), blobmsg_get_string(attr));
add_linker_entry(context, blobmsg_name(attr), blobmsg_get_string(attr));
}
}

54
bbfdmd/ubus/get.h Normal file
View file

@ -0,0 +1,54 @@
/*
* Copyright (C) 2025 iopsys Software Solutions AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation
*
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
*
*/
#ifndef BBFDMD_GET_H
#define BBFDMD_GET_H
enum {
BBFDM_PATH,
BBFDM_VALUE,
BBFDM_INPUT,
__BBFDM_MAX
};
struct linker_args {
struct list_head list;
char *path;
char *value;
};
struct async_request_context {
struct ubus_context *ubus_ctx;
struct ubus_request_data request_data;
struct ubus_event_handler linker_handler;
struct list_head linker_list;
struct blob_buf tmp_bb;
bool service_list_processed;
bool path_matched;
int pending_requests;
char requested_path[MAX_PATH_LENGTH];
char ubus_method[32];
};
struct ubus_request_tracker {
struct async_request_context *ctx;
struct ubus_request async_request;
struct uloop_timeout timeout;
char request_name[128];
};
void send_linker_cleanup_event(struct ubus_context *ctx);
void linker_response_callback(struct ubus_context *ctx, struct ubus_event_handler *ev, const char *type, struct blob_attr *msg);
void run_async_call(struct async_request_context *ctx, const char *ubus_obj, struct blob_attr *msg);
void send_response(struct async_request_context *ctx);
#endif /* BBFDMD_GET_H */

319
bbfdmd/ubus/service.c Normal file
View file

@ -0,0 +1,319 @@
/*
* Copyright (C) 2025 iopsys Software Solutions AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation
*
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
*
*/
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stddef.h>
#include <dirent.h>
#include <json-c/json.h>
#include <libubox/blobmsg_json.h>
#include "common.h"
#include "service.h"
LIST_HEAD(registered_services);
extern int g_log_level;
static void add_service_to_list(const char *name, int service_proto, service_object_t *objects, size_t count, bool is_unified)
{
service_entry_t *service = NULL;
if (!name || !objects || count == 0) {
BBFDM_ERR("Invalid service registration parameters");
return;
}
service = calloc(1, sizeof(service_entry_t));
list_add_tail(&service->list, &registered_services);
service->name = strdup(name);
service->protocol = service_proto;
service->objects = objects;
service->object_count = count;
service->is_unified = is_unified;
}
static int load_service_from_file(struct ubus_context *ubus_ctx, const char *filename, const char *file_path)
{
size_t num_objs = 0;
if (!filename || !file_path) {
BBFDM_ERR("Invalid filename or file path");
return -1;
}
json_object *json_root = json_object_from_file(file_path);
if (!json_root) {
BBFDM_ERR("Failed to read JSON file: %s", file_path);
return -1;
}
json_object *daemon_config = NULL;
json_object_object_get_ex(json_root, "daemon", &daemon_config);
if (!daemon_config) {
BBFDM_ERR("Failed to find daemon object");
json_object_put(json_root);
return -1;
}
json_object *enable_jobj = NULL;
json_object_object_get_ex(daemon_config, "enable", &enable_jobj);
bool enable = enable_jobj ? json_object_get_boolean(enable_jobj) : false;
if (!enable) {
BBFDM_INFO("Service is disabled, Skipping service");
json_object_put(json_root);
return -1;
}
char service_name[MAX_PATH_LENGTH] = {0};
snprintf(service_name, sizeof(service_name), "%s.%.*s", BBFDM_UBUS_OBJECT, (int)(strlen(filename) - 5), filename);
uint32_t ubus_id;
if (ubus_lookup_id(ubus_ctx, service_name, &ubus_id)) {
BBFDM_ERR("Failed to lookup UBUS object: %s", service_name);
}
json_object *unified_daemon_jobj = NULL;
json_object_object_get_ex(daemon_config, "unified_daemon", &unified_daemon_jobj);
bool is_unified = unified_daemon_jobj ? json_object_get_boolean(unified_daemon_jobj) : false;
json_object *proto_jobj = NULL;
json_object_object_get_ex(daemon_config, "proto", &proto_jobj);
int service_proto = get_proto_type(proto_jobj ? json_object_get_string(proto_jobj) : "");
json_object *services_array = NULL;
if (!json_object_object_get_ex(daemon_config, "services", &services_array) || json_object_get_type(services_array) != json_type_array) {
json_object_put(json_root);
return -1;
}
size_t service_count = json_object_array_length(services_array);
if (service_count == 0) {
BBFDM_ERR("Skipping service '%s' due to no objects defined", service_name);
json_object_put(json_root);
return -1;
}
service_object_t *objects = calloc(service_count, sizeof(service_object_t));
for (size_t i = 0; i < service_count; i++) {
json_object *service_obj = json_object_array_get_idx(services_array, i);
json_object *parent_dm = NULL, *object = NULL, *proto = NULL;
json_object_object_get_ex(service_obj, "parent_dm", &parent_dm);
json_object_object_get_ex(service_obj, "object", &object);
json_object_object_get_ex(service_obj, "proto", &proto);
snprintf(objects[num_objs].parent_path, sizeof(objects[num_objs].parent_path), "%s", parent_dm ? json_object_get_string(parent_dm) : "");
snprintf(objects[num_objs].object_name, sizeof(objects[num_objs].object_name), "%s", object ? json_object_get_string(object) : "");
if (strlen(objects[num_objs].parent_path) == 0 || strlen(objects[num_objs].object_name) == 0) {
BBFDM_ERR("Skip empty registration parent_dm[%s] or object[%s]", objects[num_objs].parent_path, objects[num_objs].object_name);
continue;
}
objects[num_objs].protocol = get_proto_type(proto ? json_object_get_string(proto) : "");
num_objs++;
}
BBFDM_INFO("Registering [%s :: %lu :: %d]", service_name, num_objs, is_unified);
add_service_to_list(service_name, service_proto, objects, num_objs, is_unified);
json_object_put(json_root);
return 0;
}
static int filter(const struct dirent *entry)
{
return entry->d_name[0] != '.';
}
static int compare(const struct dirent **a, const struct dirent **b)
{
size_t len_a = strlen((*a)->d_name);
size_t len_b = strlen((*b)->d_name);
if (len_a < len_b) // Sort by length (shorter first)
return -1;
if (len_a > len_b)
return 1;
return strcasecmp((*a)->d_name, (*b)->d_name); // If lengths are equal, sort alphabetically
}
int register_services(struct ubus_context *ubus_ctx)
{
struct dirent **namelist;
int num_files = scandir(BBFDM_MICROSERVICE_INPUT_PATH, &namelist, filter, compare);
for (int i = 0; i < num_files; i++) {
char file_path[512] = {0};
snprintf(file_path, sizeof(file_path), "%s/%s", BBFDM_MICROSERVICE_INPUT_PATH, namelist[i]->d_name);
if (!bbfdm_file_exists(file_path) || !bbfdm_is_regular_file(file_path)) {
BBFDM_FREE(namelist[i]);
continue;
}
if (load_service_from_file(ubus_ctx, namelist[i]->d_name, file_path)) {
BBFDM_ERR("Failed to load service: %s", namelist[i]->d_name);
}
BBFDM_FREE(namelist[i]);
}
BBFDM_FREE(namelist);
return 0;
}
void unregister_services(void)
{
service_entry_t *service = NULL, *tmp = NULL;
list_for_each_entry_safe(service, tmp, &registered_services, list) {
list_del(&service->list);
BBFDM_FREE(service->name);
BBFDM_FREE(service->objects);
BBFDM_FREE(service);
}
}
void list_registered_services(struct blob_buf *bb)
{
service_entry_t *service = NULL;
if (!bb)
return;
void *array = blobmsg_open_array(bb, "registered_services");
list_for_each_entry(service, &registered_services, list) {
void *table = blobmsg_open_table(bb, NULL);
blobmsg_add_string(bb, "name", service->name ? service->name : "");
blobmsg_add_string(bb, "proto", service->protocol == BBFDMD_USP ? "usp" : service->protocol == BBFDMD_CWMP ? "cwmp" : "both");
blobmsg_add_u8(bb, "unified_daemon", service->is_unified);
void *objects_array = blobmsg_open_array(bb, "objects");
for (size_t i = 0; i < service->object_count; i++) {
void *obj_table = blobmsg_open_table(bb, NULL);
blobmsg_add_string(bb, "parent_dm", service->objects[i].parent_path);
blobmsg_add_string(bb, "object", service->objects[i].object_name);
blobmsg_add_string(bb, "proto", service->objects[i].protocol == BBFDMD_USP ? "usp" : service->objects[i].protocol == BBFDMD_CWMP ? "cwmp" : "both");
blobmsg_close_table(bb, obj_table);
}
blobmsg_close_array(bb, objects_array);
blobmsg_close_table(bb, table);
}
blobmsg_close_array(bb, array);
}
bool is_path_match(const char *requested_path, unsigned int requested_proto, service_entry_t *service)
{
if (!proto_matches(requested_proto, service->protocol))
return false;
if (strlen(requested_path) == 0 || strcmp(requested_path, BBFDM_ROOT_OBJECT) == 0)
return true;
if (strncmp(BBFDM_ROOT_OBJECT, requested_path, strlen(BBFDM_ROOT_OBJECT)) != 0)
return false;
for (size_t idx = 0; idx < service->object_count; idx++) {
char current_obj[MAX_PATH_LENGTH] = {0};
if (!proto_matches(requested_proto, service->objects[idx].protocol))
continue;
snprintf(current_obj, sizeof(current_obj), "%s%s", service->objects[idx].parent_path, service->objects[idx].object_name);
if (strncmp(current_obj, requested_path, strlen(current_obj)) == 0)
return true;
if (strncmp(requested_path, current_obj, strlen(requested_path)) == 0)
return true;
}
return false;
}
static char *get_ubus_object_name(const char *path)
{
service_entry_t *service = NULL;
list_for_each_entry(service, &registered_services, list) {
if (!is_path_match(path, BBFDMD_BOTH, service))
continue;
return service->name;
}
return NULL;
}
static void reference_data_callback(struct ubus_request *req, int type __attribute__((unused)), struct blob_attr *msg)
{
struct blob_attr *fields[1];
const struct blobmsg_policy policy[1] = {
{ "data", BLOBMSG_TYPE_STRING },
};
if (!req || !msg)
return;
char *reference_data = (char *)req->priv;
if (!reference_data)
return;
blobmsg_parse(policy, 1, fields, blobmsg_data(msg), blobmsg_len(msg));
if (fields[0]) {
snprintf(reference_data, MAX_PATH_LENGTH - 1, "%s", blobmsg_get_string(fields[0]));
BBFDM_DEBUG("reference_data '%s'", reference_data);
}
}
char *get_reference_data(const char *path, const char *method_name)
{
struct blob_buf req_buf = {0};
char reference_value[MAX_PATH_LENGTH] = {0};
if (!path)
return NULL;
char *ubus_obj = get_ubus_object_name(path);
if (!ubus_obj)
return NULL;
reference_value[0] = 0;
memset(&req_buf, 0, sizeof(struct blob_buf));
blob_buf_init(&req_buf, 0);
blobmsg_add_string(&req_buf, "path", path);
if (g_log_level == LOG_DEBUG) {
char *json_str = blobmsg_format_json_indent(req_buf.head, true, -1);
BBFDM_DEBUG("### ubus call %s %s '%s' ###", ubus_obj, method_name, json_str);
BBFDM_FREE(json_str);
}
BBFDM_UBUS_INVOKE_SYNC(ubus_obj, method_name, req_buf.head, 2000, reference_data_callback, &reference_value);
blob_buf_free(&req_buf);
return (reference_value[0] != 0) ? strdup(reference_value) : NULL;
}

36
bbfdmd/ubus/service.h Normal file
View file

@ -0,0 +1,36 @@
/*
* Copyright (C) 2025 iopsys Software Solutions AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation
*
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
*
*/
#ifndef BBFDMD_SERVICE_H
#define BBFDMD_SERVICE_H
typedef struct {
enum bbfdmd_type_enum protocol;
char parent_path[MAX_PATH_LENGTH - 256];
char object_name[256];
} service_object_t;
typedef struct service_entry {
struct list_head list;
char *name;
enum bbfdmd_type_enum protocol;
bool is_unified;
size_t object_count;
service_object_t *objects;
} service_entry_t;
int register_services(struct ubus_context *ctx);
void unregister_services(void);
void list_registered_services(struct blob_buf *bb);
bool is_path_match(const char *requested_path, unsigned int requested_proto, service_entry_t *service);
#endif /* BBFDMD_SERVICE_H */

View file

@ -1,7 +1,7 @@
/* /*
* dm_service.c: dm-service deamon * dm_service.c: dm-service deamon
* *
* Copyright (C) 2024 IOPSYS Software Solutions AB. All rights reserved. * Copyright (C) 2024-2025 IOPSYS Software Solutions AB. All rights reserved.
* *
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
* *
@ -28,7 +28,7 @@ int main(int argc, char **argv)
{ {
struct bbfdm_context bbfdm_ctx = {0}; struct bbfdm_context bbfdm_ctx = {0};
char proc_name[64] = {0}; char proc_name[64] = {0};
int log_level = 3; // Default is LOG_ERR int log_level = LOG_ERR;
int err = 0, ch; int err = 0, ch;
memset(&bbfdm_ctx, 0, sizeof(struct bbfdm_context)); memset(&bbfdm_ctx, 0, sizeof(struct bbfdm_context));
@ -53,7 +53,7 @@ int main(int argc, char **argv)
} }
} }
if (dm_is_micro_service() == false) { if (strlen(bbfdm_ctx.config.service_name) == 0) {
fprintf(stderr, "Failed to start micro-service without providing the name using '-m' option\n"); fprintf(stderr, "Failed to start micro-service without providing the name using '-m' option\n");
exit(-1); exit(-1);
} }

View file

@ -742,31 +742,6 @@
} }
} }
} }
},
"notify_event": {
"title": "notify occurance of an event on ubus",
"type": "object",
"required": [
"input"
],
"properties": {
"input": {
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"type": "string"
},
"input": {
"type": "array",
"properties": {}
}
}
},
"output": {}
}
} }
} }
} }

View file

@ -19,12 +19,10 @@ install_cmph
install_libeasy install_libeasy
install_libethernet install_libethernet
# Make sure that all plugins are removed
[ ! -d "${BBFDM_PLUGIN_DIR}" ] && mkdir -p "${BBFDM_PLUGIN_DIR}"
rm -f ${BBFDM_PLUGIN_DIR}/*
[ ! -d "${BBFDM_MS_DIR}" ] && mkdir -p "${BBFDM_MS_DIR}" [ ! -d "${BBFDM_MS_DIR}" ] && mkdir -p "${BBFDM_MS_DIR}"
rm -f ${BBFDM_MS_DIR}/* rm -rf ${BBFDM_MS_DIR}/*
mkdir -p ${BBFDM_MS_DIR}/core
if [ -z "${1}" ]; then if [ -z "${1}" ]; then
./tools/generate_dm.py tools/tools_input.json ./tools/generate_dm.py tools/tools_input.json

View file

@ -8,12 +8,17 @@ source ./gitlab-ci/shared.sh
exec_cmd apt update exec_cmd apt update
exec_cmd pip3 install xlwt exec_cmd pip3 install xlwt
# Make sure that all plugins are removed # Create directories for micro-service configuration and shared files
[ ! -d "${BBFDM_PLUGIN_DIR}" ] && mkdir -p "${BBFDM_PLUGIN_DIR}" [ ! -d "${BBFDM_MS_CONF}" ] && mkdir -p "${BBFDM_MS_CONF}"
rm -f ${BBFDM_PLUGIN_DIR}/* [ ! -d "${BBFDM_MS_DIR}" ] && mkdir -p "${BBFDM_MS_DIR}"
# Make sure that all generated files are removed
rm -rf ${BBFDM_MS_DIR}/*
rm -f ${BBFDM_MS_CONF}/*
rm -f ${BBFDM_DMMAP_DIR}/*
rm -f ${BBFDM_LOG_FILE} rm -f ${BBFDM_LOG_FILE}
# compile and install libbbf # compile and install Core Data Model as a micro-service
install_libbbf ${1} install_libbbf ${1}
#compile and install libbbf_test dynamic extension library #compile and install libbbf_test dynamic extension library
@ -23,10 +28,6 @@ install_libbbf_test ${1}
if [ -z "${1}" ]; then if [ -z "${1}" ]; then
echo "Skip installation of micro-services ...." echo "Skip installation of micro-services ...."
else else
# Create directories for micro-service configuration and shared files
mkdir -p /etc/bbfdm/services
mkdir -p /usr/share/bbfdm/micro_services
#install SYSMNGR Data Model as a micro-service #install SYSMNGR Data Model as a micro-service
echo "Installing System Manager (SYSMNGR) Data Model as a micro-service" echo "Installing System Manager (SYSMNGR) Data Model as a micro-service"
install_sysmngr_as_micro_service install_sysmngr_as_micro_service
@ -39,5 +40,7 @@ else
echo "Installing Network Data Model (netmngr) as a micro-service" echo "Installing Network Data Model (netmngr) as a micro-service"
install_netmngr_as_micro_service install_netmngr_as_micro_service
#install Ethernet Data Model as a micro-service
echo "Installing Ethernet Data Model (ethmngr) as a micro-service"
install_ethmngr_as_micro_service install_ethmngr_as_micro_service
fi fi

View file

@ -10,6 +10,10 @@ command=/bin/bash -c "/usr/bin/valgrind --xml=yes --xml-file=/tmp/memory-netmngr
priority=7 priority=7
command=/bin/bash -c "/usr/bin/valgrind --xml=yes --xml-file=/tmp/memory-wifidmd-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 /usr/sbin/dm-service -m wifidmd" command=/bin/bash -c "/usr/bin/valgrind --xml=yes --xml-file=/tmp/memory-wifidmd-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 /usr/sbin/dm-service -m wifidmd"
[program:core]
priority=8
command=/bin/bash -c "/usr/bin/valgrind --xml=yes --xml-file=/tmp/memory-core-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 /usr/sbin/dm-service -m core"
[program:ethmngr] [program:ethmngr]
priority=10 priority=10
command=/bin/bash -c "/usr/bin/valgrind --xml=yes --xml-file=/tmp/memory-ethmngr-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 /usr/sbin/ethmngr" command=/bin/bash -c "/usr/bin/valgrind --xml=yes --xml-file=/tmp/memory-ethmngr-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 /usr/sbin/ethmngr"

View file

@ -5,6 +5,10 @@ echo "# Preparation script ..."
# link '/bin/sh' to bash instead of dash # link '/bin/sh' to bash instead of dash
ln -sf bash /bin/sh ln -sf bash /bin/sh
#cleanup
rm -f /etc/config/*
rm -rf /tmp/bbfdm/.bbfdm/* /tmp/bbfdm/.cwmp/* /tmp/bbfdm/.usp/*
echo "Installing bbfdm rpcd utilities" echo "Installing bbfdm rpcd utilities"
cp -r ./test/files/etc/* /etc/ cp -r ./test/files/etc/* /etc/
cp -r ./test/files/usr/* /usr/ cp -r ./test/files/usr/* /usr/

View file

@ -1,7 +1,8 @@
#!/bin/bash #!/bin/bash
BBFDM_PLUGIN_DIR="/usr/share/bbfdm/plugins"
BBFDM_MS_DIR="/usr/share/bbfdm/micro_services" BBFDM_MS_DIR="/usr/share/bbfdm/micro_services"
BBFDM_MS_CONF="/etc/bbfdm/services"
BBFDM_DMMAP_DIR="etc/bbfdm/dmmap/"
BBFDM_LOG_FILE="/tmp/bbfdm.log" BBFDM_LOG_FILE="/tmp/bbfdm.log"
if [ -z "${CI_PROJECT_PATH}" ]; then if [ -z "${CI_PROJECT_PATH}" ]; then
@ -43,43 +44,15 @@ function exec_cmd_verbose()
fi fi
} }
generate_input_schema() function install_ms()
{ {
service_name="$1" exec_cmd cp -f "${1}" ${BBFDM_MS_DIR}/${2}.so
schema='{
"daemon": {
"enable": "1",
"service_name": "'"$service_name"'",
"config": {
"loglevel": "4"
}
}
}'
echo "$schema"
} }
generate_input_schema_with_output_name() function install_ms_plugin()
{ {
service_name="$1" exec_cmd mkdir -p ${BBFDM_MS_DIR}/${2}
output_name="$2" exec_cmd cp -f "${1}" ${BBFDM_MS_DIR}/${2}/
schema='{
"daemon": {
"enable": "1",
"service_name": "'"$service_name"'",
"config": {
"loglevel": "4"
},
"output": {
"name": "'"$output_name"'"
}
}
}'
echo "$schema"
}
function install_plugin()
{
exec_cmd cp -f "${1}" ${BBFDM_PLUGIN_DIR}/
} }
function install_libbbf() function install_libbbf()
@ -107,6 +80,7 @@ function install_libbbf()
echo "371d530c95a17d1ca223a29b7a6cdc97e1135c1e0959b51106cca91a0b148b5e42742d372a359760742803f2a44bd88fca67ccdcfaeed26d02ce3b6049cb1e04" > /etc/bbfdm/.secure_hash echo "371d530c95a17d1ca223a29b7a6cdc97e1135c1e0959b51106cca91a0b148b5e42742d372a359760742803f2a44bd88fca67ccdcfaeed26d02ce3b6049cb1e04" > /etc/bbfdm/.secure_hash
cd .. cd ..
exec_cmd cp utilities/bbf_configd /usr/sbin/ exec_cmd cp utilities/bbf_configd /usr/sbin/
install_ms /usr/lib/libcore.so core
} }
function install_libbbf_test() function install_libbbf_test()
@ -117,21 +91,17 @@ function install_libbbf_test()
exec_cmd_verbose make -C test/bbf_test/ exec_cmd_verbose make -C test/bbf_test/
echo "installing libbbf_test" echo "installing libbbf_test"
install_plugin ./test/bbf_test/libbbf_test.so install_ms_plugin ./test/bbf_test/libbbf_test.so core
} }
function install_wifidmd_as_micro_service() function install_wifidmd_as_micro_service()
{ {
[ -d "/opt/dev/wifidmd" ] && return 0 [ -d "/opt/dev/wifidmd" ] && return 0
exec_cmd git clone https://dev.iopsys.eu/bbf/wifidmd.git /opt/dev/wifidmd exec_cmd git clone -b devel https://dev.iopsys.eu/bbf/wifidmd.git /opt/dev/wifidmd
exec_cmd make -C /opt/dev/wifidmd/src/ clean && make -C /opt/dev/wifidmd/src/ CFLAGS="-D'BBF_VENDOR_PREFIX=\"X_IOPSYS_EU_\"'" exec_cmd make -C /opt/dev/wifidmd/src/ clean && make -C /opt/dev/wifidmd/src/ CFLAGS="-D'BBF_VENDOR_PREFIX=\"X_IOPSYS_EU_\"'" WIFIDMD_WIFI_DATAELEMENTS='y'
exec_cmd cp -f /opt/dev/wifidmd/src/libwifi.so /usr/share/bbfdm/micro_services/wifidmd.so install_ms /opt/dev/wifidmd/src/libwifi.so wifidmd
exec_cmd mkdir -p /usr/share/bbfdm/micro_services/wifidmd
exec_cmd cp -f /opt/dev/wifidmd/src/libdataelements.so /usr/share/bbfdm/micro_services/wifidmd
generate_input_schema_with_output_name "wifidmd" "WiFi" > /etc/bbfdm/services/wifidmd.json
} }
function install_libeasy() function install_libeasy()
@ -172,45 +142,45 @@ function install_ethmngr_as_micro_service()
exec_cmd git clone https://dev.iopsys.eu/hal/ethmngr.git /opt/dev/ethmngr exec_cmd git clone https://dev.iopsys.eu/hal/ethmngr.git /opt/dev/ethmngr
exec_cmd make -C /opt/dev/ethmngr exec_cmd make -C /opt/dev/ethmngr
exec_cmd cp /opt/dev/ethmngr/ethmngr /usr/sbin/ethmngr exec_cmd cp -f /opt/dev/ethmngr/ethmngr /usr/sbin/ethmngr
} }
function install_netmngr_as_micro_service() function install_netmngr_as_micro_service()
{ {
[ -d "/opt/dev/netmngr" ] && return 0 [ -d "/opt/dev/netmngr" ] && return 0
exec_cmd git clone https://dev.iopsys.eu/network/netmngr.git /opt/dev/netmngr exec_cmd git clone -b devel https://dev.iopsys.eu/network/netmngr.git /opt/dev/netmngr
exec_cmd apt install iproute2 -y
exec_cmd make -C /opt/dev/netmngr/src/ clean exec_cmd make -C /opt/dev/netmngr/src/ clean
exec_cmd make -C /opt/dev/netmngr/src/ NETMNGR_GRE_OBJ=y NETMNGR_IP_OBJ=y NETMNGR_ROUTING_OBJ=y NETMNGR_PPP_OBJ=y NETMNGR_ROUTER_ADVERTISEMENT_OBJ=y NETMNGR_IPV6RD_OBJ=y exec_cmd make -C /opt/dev/netmngr/src/ NETMNGR_GRE_OBJ=y NETMNGR_IP_OBJ=y NETMNGR_ROUTING_OBJ=y NETMNGR_PPP_OBJ=y NETMNGR_ROUTER_ADVERTISEMENT_OBJ=y NETMNGR_IPV6RD_OBJ=y
exec_cmd cp -f /opt/dev/netmngr/src/libnetmngr.so /usr/share/bbfdm/micro_services/netmngr.so install_ms /opt/dev/netmngr/src/libnetmngr.so netmngr
exec_cmd cp -f /opt/dev/netmngr/src/libinterface_stack.so /usr/share/bbfdm/plugins
exec_cmd mkdir -p /usr/share/bbfdm/micro_services/netmngr
generate_input_schema_with_output_name "netmngr" "Network" > /etc/bbfdm/services/netmngr.json
exec_cmd git clone https://dev.iopsys.eu/bbf/tr143d.git /opt/dev/tr143d exec_cmd git clone https://dev.iopsys.eu/bbf/tr143d.git /opt/dev/tr143d
exec_cmd make -C /opt/dev/tr143d/src/ clean && make -C /opt/dev/tr143d/src/ exec_cmd make -C /opt/dev/tr143d/src/ clean && make -C /opt/dev/tr143d/src/
exec_cmd cp -f /opt/dev/tr143d/src/libtr143d.so /usr/share/bbfdm/micro_services/netmngr exec_cmd cp -f utilities/files/usr/share/bbfdm/scripts/bbf_api /usr/share/bbfdm/scripts/
exec_cmd cp -rf /opt/dev/tr143d/scripts/* /usr/share/bbfdm/scripts/
install_ms_plugin /opt/dev/tr143d/src/libtr143d.so netmngr
exec_cmd git clone https://dev.iopsys.eu/bbf/tr471d.git /opt/dev/tr471d exec_cmd git clone https://dev.iopsys.eu/bbf/tr471d.git /opt/dev/tr471d
exec_cmd make -C /opt/dev/tr471d/src/ clean && make -C /opt/dev/tr471d/src/ exec_cmd make -C /opt/dev/tr471d/src/ clean && make -C /opt/dev/tr471d/src/
exec_cmd cp -f /opt/dev/tr471d/src/libtr471d.so /usr/share/bbfdm/micro_services/netmngr install_ms_plugin /opt/dev/tr471d/src/libtr471d.so netmngr
exec_cmd git clone https://dev.iopsys.eu/bbf/twamp-light.git /opt/dev/twamp exec_cmd git clone https://dev.iopsys.eu/bbf/twamp-light.git /opt/dev/twamp
exec_cmd make -C /opt/dev/twamp clean && make -C /opt/dev/twamp exec_cmd make -C /opt/dev/twamp clean && make -C /opt/dev/twamp
exec_cmd cp -f /opt/dev/twamp/libtwamp.so /usr/share/bbfdm/micro_services/netmngr install_ms_plugin /opt/dev/twamp/libtwamp.so netmngr
exec_cmd git clone https://dev.iopsys.eu/bbf/udpecho.git /opt/dev/udpecho exec_cmd git clone https://dev.iopsys.eu/bbf/udpecho.git /opt/dev/udpecho
exec_cmd make -C /opt/dev/udpecho/src/ clean && make -C /opt/dev/udpecho/src/ exec_cmd make -C /opt/dev/udpecho/src/ clean && make -C /opt/dev/udpecho/src/
exec_cmd cp -f /opt/dev/udpecho/src/libudpechoserver.so /usr/share/bbfdm/micro_services/netmngr install_ms_plugin /opt/dev/udpecho/src/libudpechoserver.so netmngr
} }
function install_sysmngr_as_micro_service() function install_sysmngr_as_micro_service()
{ {
[ -d "/opt/dev/sysmngr" ] && return 0 [ -d "/opt/dev/sysmngr" ] && return 0
exec_cmd git clone https://dev.iopsys.eu/system/sysmngr.git /opt/dev/sysmngr exec_cmd git clone -b devel https://dev.iopsys.eu/system/sysmngr.git /opt/dev/sysmngr
exec_cmd make -C /opt/dev/sysmngr/src/ clean && \ exec_cmd make -C /opt/dev/sysmngr/src/ clean && \
exec_cmd make -C /opt/dev/sysmngr/src/ \ exec_cmd make -C /opt/dev/sysmngr/src/ \
@ -225,7 +195,7 @@ function install_sysmngr_as_micro_service()
SYSMNGR_VENDOR_EXTENSIONS='y' \ SYSMNGR_VENDOR_EXTENSIONS='y' \
SYSMNGR_FWBANK_UBUS_SUPPORT='y' SYSMNGR_FWBANK_UBUS_SUPPORT='y'
exec_cmd cp /opt/dev/sysmngr/src/sysmngr /usr/sbin/ exec_cmd cp -f /opt/dev/sysmngr/src/sysmngr /usr/sbin/
exec_cmd mkdir /etc/sysmngr exec_cmd mkdir /etc/sysmngr
} }

View file

@ -19,7 +19,7 @@ echo "Validate BBF Data Model JSON Plugin"
check_ret $? check_ret $?
echo "Validating plugins" echo "Validating plugins"
for plugin in $(ls -1 test/files/usr/share/bbfdm/plugins/*); do for plugin in $(ls -1 test/files/usr/share/bbfdm/micro_services/core/*); do
echo "Validating ${plugin} JSON Plugin" echo "Validating ${plugin} JSON Plugin"
./tools/validate_json_plugin.py ${plugin} ./tools/validate_json_plugin.py ${plugin}
check_ret $? check_ret $?

View file

@ -222,6 +222,22 @@ int bbf_set_alias(struct dmctx *ctx, struct uci_section *s, const char *option_n
return 0; return 0;
} }
static void send_linker_request_event(struct ubus_context *ctx, const char *path)
{
struct blob_buf bb;
if (DM_STRLEN(path) == 0)
return;
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
blobmsg_add_string(&bb, "path", path);
ubus_send_event(ctx, "bbfdm.linker.request", bb.head);
blob_buf_free(&bb);
}
int bbfdm_get_references(struct dmctx *ctx, int match_action, const char *base_path, const char *key_name, char *key_value, char *out, size_t out_len) int bbfdm_get_references(struct dmctx *ctx, int match_action, const char *base_path, const char *key_name, char *key_value, char *out, size_t out_len)
{ {
char param_path[1024] = {0}; char param_path[1024] = {0};
@ -261,20 +277,20 @@ int bbfdm_get_references(struct dmctx *ctx, int match_action, const char *base_p
} }
snprintf(&out[len], out_len - len, "%s%s", len ? (match_action == MATCH_FIRST ? "," : ";") : "", value); snprintf(&out[len], out_len - len, "%s%s", len ? (match_action == MATCH_FIRST ? "," : ";") : "", value);
goto end; return 0;
} }
if (dm_is_micro_service() == true) { // It's a micro-service instance
if (out_len - len < strlen(base_path) + strlen(key_name) + strlen(key_value) + 9) { // 9 = 'path[key_name==\"key_value\"].' if (out_len - len < strlen(base_path) + strlen(key_name) + strlen(key_value) + 9) { // 9 = 'path[key_name==\"key_value\"].'
BBF_ERR("Buffer overflow detected. The output buffer is not large enough to hold the additional data!!!"); BBF_ERR("Buffer overflow detected. The output buffer is not large enough to hold the additional data!!!");
return -1; return -1;
} }
snprintf(&out[len], out_len - len, "%s%s[%s==\"%s\"].", len ? (match_action == MATCH_FIRST ? "," : ";") : "", base_path, key_name, key_value); snprintf(param_path, sizeof(param_path), "%s[%s==\"%s\"].", base_path, key_name, key_value);
}
send_linker_request_event(ctx->ubus_ctx, param_path);
snprintf(&out[len], out_len - len, "%s%s", len ? (match_action == MATCH_FIRST ? "," : ";") : "", param_path);
end:
return 0; return 0;
} }
@ -317,68 +333,6 @@ int bbfdm_get_reference_linker(struct dmctx *ctx, char *reference_path, struct d
return 0; return 0;
} }
static char *bbfdm_get_reference_value(const char *reference_path)
{
unsigned int reference_path_dot_num = count_occurrences(reference_path, '.');
json_object *res = NULL;
json_object *in_args = json_object_new_object();
json_object_object_add(in_args, "proto", json_object_new_string("usp"));
json_object_object_add(in_args, "format", json_object_new_string("raw"));
dmubus_call("bbfdm", "get",
UBUS_ARGS{
{"path", reference_path, String},
{"optional", json_object_to_json_string(in_args), Table}
},
2, &res);
json_object_put(in_args);
if (!res)
return NULL;
json_object *res_array = dmjson_get_obj(res, 1, "results");
if (!res_array)
return NULL;
size_t nbre_obj = json_object_array_length(res_array);
if (nbre_obj == 0)
return NULL;
for (size_t i = 0; i < nbre_obj; i++) {
json_object *res_obj = json_object_array_get_idx(res_array, i);
char *fault = dmjson_get_value(res_obj, 1, "fault");
if (DM_STRLEN(fault))
return NULL;
char *path = dmjson_get_value(res_obj, 1, "path");
unsigned int path_dot_num = count_occurrences(path, '.');
if (path_dot_num > reference_path_dot_num)
continue;
json_object *flags_array = dmjson_get_obj(res_obj, 1, "flags");
if (flags_array) {
size_t nbre_falgs = json_object_array_length(flags_array);
for (size_t j = 0; j < nbre_falgs; j++) {
json_object *flag_obj = json_object_array_get_idx(flags_array, j);
const char *flag = json_object_get_string(flag_obj);
if (DM_LSTRCMP(flag, "Linker") == 0) {
char *data = dmjson_get_value(res_obj, 1, "data");
return data ? dmstrdup(data) : "";
}
}
}
}
return NULL;
}
int bbfdm_operate_reference_linker(struct dmctx *ctx, const char *reference_path, char **reference_value) int bbfdm_operate_reference_linker(struct dmctx *ctx, const char *reference_path, char **reference_value)
{ {
if (!ctx) { if (!ctx) {
@ -401,8 +355,5 @@ int bbfdm_operate_reference_linker(struct dmctx *ctx, const char *reference_path
if (DM_STRLEN(*reference_value) != 0) if (DM_STRLEN(*reference_value) != 0)
return 0; return 0;
if (dm_is_micro_service() == true) // It's a micro-service instance
*reference_value = bbfdm_get_reference_value(reference_path);
return 0; return 0;
} }

View file

@ -28,6 +28,8 @@
#include "libbbfdm-api/version-2/bbfdm_api.h" #include "libbbfdm-api/version-2/bbfdm_api.h"
#define ROOT_NODE "Device."
extern struct dm_permession_s DMREAD; extern struct dm_permession_s DMREAD;
extern struct dm_permession_s DMWRITE; extern struct dm_permession_s DMWRITE;
extern struct dm_permession_s DMSYNC; extern struct dm_permession_s DMSYNC;
@ -177,21 +179,12 @@ struct dmctx {
bool iscommand; bool iscommand;
bool isevent; bool isevent;
bool isinfo; bool isinfo;
bool disable_mservice_browse;
int (*method_param)(DMPARAM_ARGS); int (*method_param)(DMPARAM_ARGS);
int (*method_obj)(DMOBJECT_ARGS); int (*method_obj)(DMOBJECT_ARGS);
int (*checkobj)(DMOBJECT_ARGS); int (*checkobj)(DMOBJECT_ARGS);
int (*checkleaf)(DMOBJECT_ARGS); int (*checkleaf)(DMOBJECT_ARGS);
struct list_head *memhead;
struct blob_buf bb;
DMOBJ *dm_entryobj;
struct uci_context *config_uci_ctx;
struct uci_context *dmmap_uci_ctx;
struct uci_context *varstate_uci_ctx;
int faultcode; int faultcode;
int setaction; int setaction;
unsigned int dm_type; unsigned int dm_type;
@ -204,6 +197,16 @@ struct dmctx {
char *addobj_instance; char *addobj_instance;
char *linker; char *linker;
char *linker_param; char *linker_param;
struct blob_buf bb;
DMOBJ *dm_entryobj;
struct uci_context *config_uci_ctx;
struct uci_context *dmmap_uci_ctx;
struct uci_context *varstate_uci_ctx;
struct ubus_context *ubus_ctx;
struct list_head *memhead;
char *inst_buf[16]; char *inst_buf[16];
char fault_msg[256]; char fault_msg[256];
}; };
@ -220,7 +223,6 @@ typedef struct dmnode {
unsigned char browse_type; unsigned char browse_type;
int max_instance; int max_instance;
int num_of_entries; int num_of_entries;
bool is_ubus_service;
} DMNODE; } DMNODE;
typedef struct { typedef struct {
@ -387,7 +389,6 @@ enum bbfdm_type_enum {
enum { enum {
INDX_JSON_MOUNT, INDX_JSON_MOUNT,
INDX_LIBRARY_MOUNT, INDX_LIBRARY_MOUNT,
INDX_SERVICE_MOUNT,
__INDX_DYNAMIC_MAX __INDX_DYNAMIC_MAX
}; };

File diff suppressed because it is too large Load diff

View file

@ -27,9 +27,6 @@
#include "dmmem.h" #include "dmmem.h"
#include "dmapi.h" #include "dmapi.h"
bool dm_is_micro_service(void);
void dm_set_micro_service(void);
int get_number_of_entries(struct dmctx *ctx, void *data, char *instance, int (*browseinstobj)(struct dmctx *ctx, struct dmnode *node, void *data, char *instance)); int get_number_of_entries(struct dmctx *ctx, void *data, char *instance, int (*browseinstobj)(struct dmctx *ctx, struct dmnode *node, void *data, char *instance));
char *handle_instance(struct dmctx *dmctx, DMNODE *parent_node, struct uci_section *s, const char *inst_opt, const char *alias_opt); char *handle_instance(struct dmctx *dmctx, DMNODE *parent_node, struct uci_section *s, const char *inst_opt, const char *alias_opt);
char *handle_instance_without_section(struct dmctx *dmctx, DMNODE *parent_node, int inst_nbr); char *handle_instance_without_section(struct dmctx *dmctx, DMNODE *parent_node, int inst_nbr);
@ -40,7 +37,6 @@ void fill_blob_event(struct blob_buf *bb, const char *path, const char *type, vo
void fill_blob_operate(struct blob_buf *bb, const char *path, const char *data, const char *type, void *in_out); void fill_blob_operate(struct blob_buf *bb, const char *path, const char *data, const char *type, void *in_out);
int string_to_bool(const char *v, bool *b); int string_to_bool(const char *v, bool *b);
char *get_value_by_reference(struct dmctx *ctx, char *value);
int dm_entry_get_value(struct dmctx *dmctx); int dm_entry_get_value(struct dmctx *dmctx);
int dm_entry_get_name(struct dmctx *ctx); int dm_entry_get_name(struct dmctx *ctx);
int dm_entry_get_supported_dm(struct dmctx *ctx); int dm_entry_get_supported_dm(struct dmctx *ctx);

View file

@ -49,6 +49,7 @@ void bbf_ctx_init(struct dmctx *ctx, DMOBJ *tEntryObj)
ctx->dm_entryobj = tEntryObj; ctx->dm_entryobj = tEntryObj;
dm_init_mem(ctx); dm_init_mem(ctx);
dm_uci_init(ctx); dm_uci_init(ctx);
dm_ubus_init(ctx);
} }
void bbf_ctx_clean(struct dmctx *ctx) void bbf_ctx_clean(struct dmctx *ctx)
@ -57,7 +58,7 @@ void bbf_ctx_clean(struct dmctx *ctx)
dm_uci_exit(ctx); dm_uci_exit(ctx);
dm_clean_mem(ctx); dm_clean_mem(ctx);
dmubus_free(); dm_ubus_free(ctx);
} }
void bbf_ctx_init_sub(struct dmctx *ctx, DMOBJ *tEntryObj) void bbf_ctx_init_sub(struct dmctx *ctx, DMOBJ *tEntryObj)
@ -273,13 +274,10 @@ int adm_entry_get_reference_param(struct dmctx *ctx, char *param, char *linker,
{ {
struct dmctx dmctx = {0}; struct dmctx dmctx = {0};
*value = dmstrdup(""); if (DM_STRLEN(param) == 0 || DM_STRLEN(linker) == 0)
if (!param || !linker || *linker == 0)
return 0; return 0;
bbf_ctx_init_sub(&dmctx, ctx->dm_entryobj); dmctx.dm_entryobj = ctx->dm_entryobj;
dmctx.iswildcard = 1; dmctx.iswildcard = 1;
dmctx.inparam_isparam = 1; dmctx.inparam_isparam = 1;
dmctx.in_param = param; dmctx.in_param = param;
@ -287,9 +285,8 @@ int adm_entry_get_reference_param(struct dmctx *ctx, char *param, char *linker,
dm_entry_get_reference_param(&dmctx); dm_entry_get_reference_param(&dmctx);
*value = dmctx.linker_param ? dmctx.linker_param : dmstrdup(""); *value = dmctx.linker_param;
bbf_ctx_clean_sub(&dmctx);
return 0; return 0;
} }
@ -317,7 +314,7 @@ int adm_entry_get_reference_value(struct dmctx *ctx, const char *param, char **v
return 0; return 0;
} }
bool adm_entry_object_exists(struct dmctx *ctx, const char *param) // To be removed later!!!!!!!!!!!! (After moving all Objects outside bbfdm core) bool adm_entry_object_exists(struct dmctx *ctx, const char *param) // To be removed later
{ {
struct dmctx dmctx = {0}; struct dmctx dmctx = {0};
char linker[256] = {0}; char linker[256] = {0};

View file

@ -30,12 +30,8 @@ void bbf_global_clean(DMOBJ *dm_entryobj);
int dm_validate_allowed_objects(struct dmctx *ctx, struct dm_reference *reference, char *objects[]); int dm_validate_allowed_objects(struct dmctx *ctx, struct dm_reference *reference, char *objects[]);
bool adm_entry_object_exists(struct dmctx *ctx, const char *param); // To be removed later!!!!!!!!!!!! (After moving all Objects outside bbfdm core) bool adm_entry_object_exists(struct dmctx *ctx, const char *param); // To be removed later
void bbf_entry_services(unsigned int proto, bool is_commit, bool reload_required); void bbf_entry_services(unsigned int proto, bool is_commit, bool reload_required);
void get_list_of_registered_service(struct list_head *srvlist, struct blob_buf *bb);
bool load_service(DMOBJ *main_dm, struct list_head *srv_list, const char *srv_name, const char *srv_parent_dm, const char *srv_obj, bool is_unified, uint8_t proto);
void free_services_from_list(struct list_head *clist);
#endif //__DMENTRY_H__ #endif //__DMENTRY_H__

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2023 iopsys Software Solutions AB * Copyright (C) 2023-2025 iopsys Software Solutions AB
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU Lesser General Public License version 2.1
@ -14,141 +14,6 @@
#include "plugin/json_plugin.h" #include "plugin/json_plugin.h"
#include "plugin/dotso_plugin.h" #include "plugin/dotso_plugin.h"
extern struct list_head global_memhead;
struct service
{
bool is_unified_daemon;
enum bbfdm_type_enum proto;
struct list_head list;
char *name;
char *parent_dm;
char *object;
};
static bool add_service_to_main_tree(DMOBJ *main_dm, const char *srv_name, const char *srv_parent_dm, const char *srv_obj, uint8_t proto)
{
DMOBJ *dm_entryobj = find_entry_obj(main_dm, srv_parent_dm);
if (!dm_entryobj)
return false;
// Disable service object if it already exists in the main tree
disable_entry_obj(dm_entryobj, srv_obj, srv_parent_dm, srv_name);
if (dm_entryobj->nextdynamicobj == NULL) {
dm_entryobj->nextdynamicobj = calloc(__INDX_DYNAMIC_MAX, sizeof(struct dm_dynamic_obj));
dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].idx_type = INDX_JSON_MOUNT;
dm_entryobj->nextdynamicobj[INDX_LIBRARY_MOUNT].idx_type = INDX_LIBRARY_MOUNT;
dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].idx_type = INDX_SERVICE_MOUNT;
}
if (dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj == NULL) {
dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj = calloc(2, sizeof(DMOBJ *));
}
if (dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0] == NULL) {
dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0] = dm_dynamic_calloc(&global_memhead, 2, sizeof(struct dm_obj_s));
((dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0])[0]).obj = dm_dynamic_strdup(&global_memhead, srv_obj);
((dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0])[0]).checkdep = dm_dynamic_strdup(&global_memhead, srv_name);
((dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0])[0]).bbfdm_type = proto;
} else {
int idx = get_entry_obj_idx(dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0]);
dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0] = dm_dynamic_realloc(&global_memhead, dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0], (idx + 2) * sizeof(struct dm_obj_s));
memset(dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0] + (idx + 1), 0, sizeof(struct dm_obj_s));
((dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0])[idx]).obj = dm_dynamic_strdup(&global_memhead, srv_obj);
((dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0])[idx]).checkdep = dm_dynamic_strdup(&global_memhead, srv_name);
((dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0])[idx]).bbfdm_type = proto;
}
return true;
}
static bool is_service_registered(struct list_head *srvlist, const char *srv_name, const char *srv_parent_dm, const char *srv_obj)
{
struct service *srv = NULL;
list_for_each_entry(srv, srvlist, list) {
if (DM_STRCMP(srv->name, srv_name) == 0 &&
DM_STRCMP(srv->parent_dm, srv_parent_dm) == 0 &&
DM_STRCMP(srv->object, srv_obj) == 0)
return true;
}
return false;
}
static void add_service_to_list(struct list_head *srvlist, const char *srv_name, const char *srv_parent_dm, const char *srv_object, uint8_t proto, bool is_unified)
{
struct service *srv = NULL;
srv = calloc(1, sizeof(struct service));
list_add_tail(&srv->list, srvlist);
srv->name = strdup(srv_name);
srv->parent_dm = strdup(srv_parent_dm);
srv->object = strdup(srv_object);
srv->is_unified_daemon = is_unified;
srv->proto = proto;
}
void free_services_from_list(struct list_head *clist)
{
struct service *srv = NULL, *tmp = NULL;
list_for_each_entry_safe(srv, tmp, clist, list) {
list_del(&srv->list);
free(srv->name);
free(srv->parent_dm);
free(srv->object);
free(srv);
}
}
bool load_service(DMOBJ *main_dm, struct list_head *srv_list, const char *srv_name, const char *srv_parent_dm, const char *srv_obj, bool is_unified, uint8_t proto)
{
if (!main_dm || !srv_list || !srv_name || !srv_parent_dm || !srv_obj) {
BBF_ERR("Invalid arguments: main_dm, srv_list, srv_name, srv_parent_dm, and srv_obj must not be NULL.");
return false;
}
if (is_service_registered(srv_list, srv_name, srv_parent_dm, srv_obj)) {
BBF_DEBUG("Service registration failed: Service '%s' with parent DM '%s' and object '%s' is already registered.",
srv_name, srv_parent_dm, srv_obj);
return false;
}
if (!add_service_to_main_tree(main_dm, srv_name, srv_parent_dm, srv_obj, proto)) {
BBF_ERR("Failed to add service '%s' to main tree with parent DM '%s' and object '%s'.",
srv_name, srv_parent_dm, srv_obj);
return false;
}
add_service_to_list(srv_list, srv_name, srv_parent_dm, srv_obj, proto, is_unified);
return true;
}
void get_list_of_registered_service(struct list_head *srvlist, struct blob_buf *bb)
{
struct service *srv = NULL;
void *table = NULL;
list_for_each_entry(srv, srvlist, list) {
table = blobmsg_open_table(bb, NULL);
blobmsg_add_string(bb, "name", srv->name);
blobmsg_add_string(bb, "parent_dm", srv->parent_dm);
blobmsg_add_string(bb, "object", srv->object);
if (srv->proto == BBFDM_USP) {
blobmsg_add_string(bb, "proto", "usp");
} else if (srv->proto == BBFDM_CWMP) {
blobmsg_add_string(bb, "proto", "cwmp");
} else {
blobmsg_add_string(bb, "proto", "both");
}
blobmsg_add_u8(bb, "unified_daemon", srv->is_unified_daemon);
blobmsg_close_table(bb, table);
}
}
static void free_all_dynamic_nodes(DMOBJ *entryobj) static void free_all_dynamic_nodes(DMOBJ *entryobj)
{ {
for (; (entryobj && entryobj->obj); entryobj++) { for (; (entryobj && entryobj->obj); entryobj++) {
@ -356,47 +221,45 @@ int get_leaf_idx(DMLEAF **entryleaf)
return idx; return idx;
} }
static int filter(const struct dirent *entry)
{
return entry->d_name[0] != '.';
}
static int compare(const struct dirent **a, const struct dirent **b)
{
return strcasecmp((*a)->d_name, (*b)->d_name);
}
void load_plugins(DMOBJ *dm_entryobj, const char *plugin_path) void load_plugins(DMOBJ *dm_entryobj, const char *plugin_path)
{ {
struct dirent **namelist;
if (DM_STRLEN(plugin_path) == 0) // If empty, return without further action if (DM_STRLEN(plugin_path) == 0) // If empty, return without further action
return; return;
if (!folder_exists(plugin_path)) { if (!folder_exists(plugin_path)) {
BBF_ERR("(%s) doesn't exist", plugin_path); BBF_ERR("Folder plugin (%s) doesn't exist", plugin_path);
return; return;
} }
struct dirent *ent = NULL; int num_files = scandir(plugin_path, &namelist, filter, compare);
int num_files = 0;
char *files[256];
DIR *dir = opendir(plugin_path);
if (dir == NULL) {
BBF_ERR("Cannot open (%s) directory", plugin_path);
return;
}
while ((ent = readdir(dir)) != NULL && num_files < 256) {
files[num_files++] = strdup(ent->d_name);
}
closedir(dir);
qsort(files, num_files, sizeof(char *), compare_strings);
for (int i = 0; i < num_files; i++) { for (int i = 0; i < num_files; i++) {
char buf[512] = {0}; char file_path[512] = {0};
snprintf(buf, sizeof(buf), "%s/%s", plugin_path, files[i]); snprintf(file_path, sizeof(file_path), "%s/%s", plugin_path, namelist[i]->d_name);
if (DM_LSTRSTR(files[i], ".json")) { if (DM_LSTRSTR(namelist[i]->d_name, ".json")) {
load_json_plugins(dm_entryobj, buf); load_json_plugins(dm_entryobj, file_path);
} else if (DM_LSTRSTR(files[i], ".so")) { } else if (DM_LSTRSTR(namelist[i]->d_name, ".so")) {
load_dotso_plugins(dm_entryobj, buf); load_dotso_plugins(dm_entryobj, file_path);
} }
free(files[i]); FREE(namelist[i]);
} }
FREE(namelist);
} }
void free_plugins(DMOBJ *dm_entryobj) void free_plugins(DMOBJ *dm_entryobj)

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2023 iopsys Software Solutions AB * Copyright (C) 2023-2025 iopsys Software Solutions AB
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU Lesser General Public License version 2.1

View file

@ -43,19 +43,6 @@ static json_object *json_res = NULL;
static const struct dm_ubus_cache_entry * dm_ubus_cache_lookup(unsigned hash); static const struct dm_ubus_cache_entry * dm_ubus_cache_lookup(unsigned hash);
static struct ubus_context *dm_libubus_init()
{
return ubus_connect(NULL);
}
static void dm_libubus_free()
{
if (ubus_ctx) {
ubus_free(ubus_ctx);
ubus_ctx = NULL;
}
}
static void prepare_blob_message(struct blob_buf *b, const struct ubus_arg u_args[], int u_args_size) static void prepare_blob_message(struct blob_buf *b, const struct ubus_arg u_args[], int u_args_size)
{ {
if (!b) if (!b)
@ -102,13 +89,10 @@ static int __dm_ubus_call_internal(const char *obj, const char *method, int time
json_res = NULL; json_res = NULL;
if (ubus_ctx == NULL) {
ubus_ctx = dm_libubus_init();
if (ubus_ctx == NULL) { if (ubus_ctx == NULL) {
BBF_ERR("UBUS context is null"); BBF_ERR("UBUS context is null");
return -1; return -1;
} }
}
if (ubus_lookup_id(ubus_ctx, obj, &id)) { if (ubus_lookup_id(ubus_ctx, obj, &id)) {
BBF_ERR("Failed to lookup UBUS object ID for '%s' using method '%s'", obj, method); BBF_ERR("Failed to lookup UBUS object ID for '%s' using method '%s'", obj, method);
@ -332,12 +316,9 @@ static int dmubus_call_blob_internal(const char *obj, const char *method, json_o
if (resp) *resp = NULL; if (resp) *resp = NULL;
if (ubus_ctx == NULL) { if (ubus_ctx == NULL) {
ubus_ctx = dm_libubus_init(); BBF_ERR("UBUS context is null");
if (ubus_ctx == NULL) {
printf("UBUS context is null\n\r");
return -1; return -1;
} }
}
memset(&blob, 0, sizeof(struct blob_buf)); memset(&blob, 0, sizeof(struct blob_buf));
blob_buf_init(&blob, 0); blob_buf_init(&blob, 0);
@ -387,20 +368,17 @@ int dmubus_call_blob_set(const char *obj, const char *method, json_object *value
static int dmubus_call_blob_msg_internal(const char *obj, const char *method, struct blob_buf *data, int timeout, json_object **resp) static int dmubus_call_blob_msg_internal(const char *obj, const char *method, struct blob_buf *data, int timeout, json_object **resp)
{ {
uint32_t id = 0; uint32_t id = 0;
int rc = -1; int rc;
json_res = NULL; json_res = NULL;
if (resp) if (resp)
*resp = NULL; *resp = NULL;
if (ubus_ctx == NULL) {
ubus_ctx = dm_libubus_init();
if (ubus_ctx == NULL) { if (ubus_ctx == NULL) {
BBF_ERR("UBUS context is null"); BBF_ERR("UBUS context is null");
return -1; return -1;
} }
}
if (ubus_lookup_id(ubus_ctx, obj, &id)) { if (ubus_lookup_id(ubus_ctx, obj, &id)) {
BBF_ERR("Failed to lookup UBUS object ID for '%s' using method '%s'", obj, method); BBF_ERR("Failed to lookup UBUS object ID for '%s' using method '%s'", obj, method);
@ -533,8 +511,8 @@ int dmubus_call(const char *obj, const char *method, struct ubus_arg u_args[], i
int dmubus_call_blocking(const char *obj, const char *method, struct ubus_arg u_args[], int u_args_size, json_object **req_res) int dmubus_call_blocking(const char *obj, const char *method, struct ubus_arg u_args[], int u_args_size, json_object **req_res)
{ {
int rc = 0;
struct blob_buf bmsg; struct blob_buf bmsg;
int rc;
memset(&bmsg, 0, sizeof(struct blob_buf)); memset(&bmsg, 0, sizeof(struct blob_buf));
prepare_blob_message(&bmsg, u_args, u_args_size); prepare_blob_message(&bmsg, u_args, u_args_size);
@ -578,8 +556,7 @@ bool dmubus_object_method_exists(const char *object)
return false; return false;
if (ubus_ctx == NULL) { if (ubus_ctx == NULL) {
ubus_ctx = dm_libubus_init(); BBF_ERR("UBUS context is null");
if (ubus_ctx == NULL)
return false; return false;
} }
@ -601,8 +578,17 @@ bool dmubus_object_method_exists(const char *object)
return true; return true;
} }
void dmubus_free() void dm_ubus_init(struct dmctx *bbf_ctx)
{
bbf_ctx->ubus_ctx = ubus_ctx = ubus_connect(NULL);
}
void dm_ubus_free(struct dmctx *bbf_ctx)
{ {
dm_ubus_cache_entry_free(); dm_ubus_cache_entry_free();
dm_libubus_free();
if (bbf_ctx->ubus_ctx) {
ubus_free(bbf_ctx->ubus_ctx);
bbf_ctx->ubus_ctx = ubus_ctx = NULL;
}
} }

View file

@ -62,7 +62,8 @@ int dmubus_call_blob_set(const char *obj, const char *method, json_object *value
int dmubus_call_blob_msg_set(const char *obj, const char *method, struct blob_buf *blob_msg); int dmubus_call_blob_msg_set(const char *obj, const char *method, struct blob_buf *blob_msg);
void dmubus_free(); void dm_ubus_init(struct dmctx *bbf_ctx);
void dm_ubus_free(struct dmctx *bbf_ctx);
bool dmubus_object_method_exists(const char *obj); bool dmubus_object_method_exists(const char *obj);

View file

@ -674,7 +674,7 @@ static char *handle_reference_value(struct dmctx *ctx, struct json_object *linke
char *pref = NULL; char *pref = NULL;
adm_entry_get_reference_param(ctx, linker_path, key_value, &pref); adm_entry_get_reference_param(ctx, linker_path, key_value, &pref);
return pref; return pref ? pref : dmstrdup("");
} else { } else {
char buf_ref[256 + 32] = {0}; char buf_ref[256 + 32] = {0};
@ -2084,7 +2084,6 @@ static void create_parse_obj(DMOBJ *dm_entryobj, char *obj_path, json_object *jo
dm_entryobj->nextdynamicobj = calloc(__INDX_DYNAMIC_MAX, sizeof(struct dm_dynamic_obj)); dm_entryobj->nextdynamicobj = calloc(__INDX_DYNAMIC_MAX, sizeof(struct dm_dynamic_obj));
dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].idx_type = INDX_JSON_MOUNT; dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].idx_type = INDX_JSON_MOUNT;
dm_entryobj->nextdynamicobj[INDX_LIBRARY_MOUNT].idx_type = INDX_LIBRARY_MOUNT; dm_entryobj->nextdynamicobj[INDX_LIBRARY_MOUNT].idx_type = INDX_LIBRARY_MOUNT;
dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].idx_type = INDX_SERVICE_MOUNT;
} }
if (dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj == NULL) { if (dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj == NULL) {
@ -2114,7 +2113,6 @@ static void create_parse_param(DMOBJ *dm_entryobj, char *obj_path, char *param,
dm_entryobj->dynamicleaf = calloc(__INDX_DYNAMIC_MAX, sizeof(struct dm_dynamic_obj)); dm_entryobj->dynamicleaf = calloc(__INDX_DYNAMIC_MAX, sizeof(struct dm_dynamic_obj));
dm_entryobj->dynamicleaf[INDX_JSON_MOUNT].idx_type = INDX_JSON_MOUNT; dm_entryobj->dynamicleaf[INDX_JSON_MOUNT].idx_type = INDX_JSON_MOUNT;
dm_entryobj->dynamicleaf[INDX_LIBRARY_MOUNT].idx_type = INDX_LIBRARY_MOUNT; dm_entryobj->dynamicleaf[INDX_LIBRARY_MOUNT].idx_type = INDX_LIBRARY_MOUNT;
dm_entryobj->dynamicleaf[INDX_SERVICE_MOUNT].idx_type = INDX_SERVICE_MOUNT;
} }
if (dm_entryobj->dynamicleaf[INDX_JSON_MOUNT].nextleaf == NULL) { if (dm_entryobj->dynamicleaf[INDX_JSON_MOUNT].nextleaf == NULL) {

View file

@ -8,7 +8,7 @@ FILE(GLOB BBFDM_API_SOURCES *.c)
ADD_LIBRARY(bbfdm-api-v2 SHARED ${BBFDM_API_SOURCES}) ADD_LIBRARY(bbfdm-api-v2 SHARED ${BBFDM_API_SOURCES})
TARGET_LINK_LIBRARIES(bbfdm-api-v2 uci ubus) TARGET_LINK_LIBRARIES(bbfdm-api-v2 uci ubus ubox)
INSTALL(TARGETS bbfdm-api-v2 INSTALL(TARGETS bbfdm-api-v2
LIBRARY DESTINATION usr/lib) LIBRARY DESTINATION usr/lib)

View file

@ -92,3 +92,19 @@ int bbfdm_ubus_invoke_async(struct ubus_context *ubus_ctx, const char *obj, cons
ubus_complete_request_async(ubus_ctx, req); ubus_complete_request_async(ubus_ctx, req);
return 0; return 0;
} }
int bbfdm_ubus_send_event(struct bbfdm_ctx *bbfdm_ctx, const char *obj, struct blob_attr *msg)
{
if (!bbfdm_ctx || !bbfdm_ctx->ubus_ctx) {
BBFDM_ERR("Invalid context or UBUS context is NULL");
return -1;
}
int ret = ubus_send_event(bbfdm_ctx->ubus_ctx, obj, msg);
if (ret != 0) {
BBFDM_ERR("UBUS send event failed for obj='%s', error code=%d", obj, ret);
}
return ret;
}

View file

@ -98,6 +98,38 @@ int bbfdm_ubus_invoke_async(struct ubus_context *ubus_ctx, const char *obj, cons
bbfdm_free_ctx(&ctx); \ bbfdm_free_ctx(&ctx); \
} while (0) } while (0)
/**
* @brief Sends an event to a UBUS object.
*
* This function sends an event to the specified UBUS object with the provided
* message data. The event is transmitted using the UBUS system.
*
* @param[in] bbfdm_ctx Pointer to the BBFDM context.
* @param[in] obj Name of the UBUS object to send the event to.
* @param[in] msg Pointer to a `blob_attr` message containing event data.
* @return 0 on success, -1 on failure.
*/
int bbfdm_ubus_send_event(struct bbfdm_ctx *bbfdm_ctx, const char *obj, struct blob_attr *msg);
/**
* @brief Sends an event to a UBUS object.
*
* This macro simplifies the process of initializing a context, sending an event,
* and cleaning up the context.
*
* @param obj The name of the UBUS object to send the event to.
* @param msg Pointer to a `blob_attr` message containing event data.
* @return Always returns 0.
*/
#define BBFDM_UBUS_SEND_EVENT(obj, msg) \
do { \
struct bbfdm_ctx ctx = {0}; \
memset(&ctx, 0, sizeof(struct bbfdm_ctx)); \
bbfdm_init_ctx(&ctx); \
bbfdm_ubus_send_event(&ctx, obj, msg); \
bbfdm_free_ctx(&ctx); \
} while (0)
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

File diff suppressed because it is too large Load diff

View file

@ -13,25 +13,22 @@ struct bbfdm_async_req {
struct ubus_context *ctx; struct ubus_context *ctx;
struct ubus_request_data req; struct ubus_request_data req;
struct uloop_process process; struct uloop_process process;
bool is_operate;
void *result; void *result;
}; };
typedef struct bbfdm_config { typedef struct bbfdm_config {
struct list_head list_objs; // Micro-service list of objects to expose
char service_name[32]; // Service name for micro-service identification char service_name[32]; // Service name for micro-service identification
char in_type[32]; // Input type, Possible values: { 'JSON', 'DotSo' } char in_name[128]; // Service plugin path
char in_name[128]; // plugin path char in_plugin_dir[128]; // Service extra/internal plugin directory path
char in_plugin_dir[128]; // extra plugin directory path
char out_name[128]; // Ubus name to use char out_name[128]; // Ubus name to use
char out_parent_dm[32]; // Parent device for micro-service
char out_root_obj[32]; // Ubus name to use as root data model
} bbfdm_config_t; } bbfdm_config_t;
struct bbfdm_context { struct bbfdm_context {
bbfdm_config_t config; bbfdm_config_t config;
struct ubus_context ubus_ctx; struct ubus_context ubus_ctx;
struct list_head event_handlers; struct list_head event_handlers;
struct list_head linker_list;
struct list_head obj_list;
}; };
struct ev_handler_node { struct ev_handler_node {
@ -47,8 +44,6 @@ typedef struct bbfdm_data {
struct list_head *plist; struct list_head *plist;
struct dmctx bbf_ctx; struct dmctx bbf_ctx;
struct blob_buf bb; struct blob_buf bb;
uint8_t depth;
bool is_raw;
} bbfdm_data_t; } bbfdm_data_t;
int bbfdm_ubus_regiter_init(struct bbfdm_context *bbfdm_ctx); int bbfdm_ubus_regiter_init(struct bbfdm_context *bbfdm_ctx);
@ -58,6 +53,4 @@ void bbfdm_ubus_set_service_name(struct bbfdm_context *bbfdm_ctx, const char *sr
void bbfdm_ubus_set_log_level(int log_level); void bbfdm_ubus_set_log_level(int log_level);
void bbfdm_ubus_load_data_model(DM_MAP_OBJ *DynamicObj); void bbfdm_ubus_load_data_model(DM_MAP_OBJ *DynamicObj);
void bbfdm_schedule_instance_refresh_timer(struct ubus_context *ctx, int start_in_sec); // To be removed later
#endif /* BBFDM_UBUS_H */ #endif /* BBFDM_UBUS_H */

View file

@ -12,64 +12,6 @@
#include "common.h" #include "common.h"
#include "get_helper.h" #include "get_helper.h"
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;
BBF_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, 0, NULL))
ret = true;
} else {
if (strtol(path, NULL, 10))
ret = true;
}
return ret;
}
// RE utilities
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(bbfdm_data_t *data) bool validate_msglen(bbfdm_data_t *data)
{ {
size_t data_len = blob_pad_len(data->bbf_ctx.bb.head); size_t data_len = blob_pad_len(data->bbf_ctx.bb.head);
@ -85,39 +27,6 @@ bool validate_msglen(bbfdm_data_t *data)
return true; return true;
} }
int get_dm_type(char *dm_type)
{
if (dm_type == NULL)
return DMT_STRING;
if (DM_STRCMP(dm_type, DMT_TYPE[DMT_STRING]) == 0)
return DMT_STRING;
else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_UNINT]) == 0)
return DMT_UNINT;
else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_INT]) == 0)
return DMT_INT;
else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_UNLONG]) == 0)
return DMT_UNLONG;
else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_LONG]) == 0)
return DMT_LONG;
else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_BOOL]) == 0)
return DMT_BOOL;
else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_TIME]) == 0)
return DMT_TIME;
else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_HEXBIN]) == 0)
return DMT_HEXBIN;
else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_BASE64]) == 0)
return DMT_BASE64;
else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_COMMAND]) == 0)
return DMT_COMMAND;
else if (DM_STRCMP(dm_type, DMT_TYPE[DMT_EVENT]) == 0)
return DMT_EVENT;
else
return DMT_STRING;
return DMT_STRING;
}
// glibc doesn't guarantee a 0 termianted string on strncpy // glibc doesn't guarantee a 0 termianted string on strncpy
// strncpy with always 0 terminated string // strncpy with always 0 terminated string
void strncpyt(char *dst, const char *src, size_t n) void strncpyt(char *dst, const char *src, size_t n)

View file

@ -17,17 +17,8 @@
#include <libbbfdm-api/legacy/dmcommon.h> #include <libbbfdm-api/legacy/dmcommon.h>
#include "bbfdm-ubus.h" #include "bbfdm-ubus.h"
#define STRINGIFY(x) #x
#define TO_STR(x) STRINGIFY(x)
#define ROOT_NODE "Device."
#define BBF_EVENT_NAME "event"
#define MAX_DM_KEY_LEN 256
#define MAX_DM_PATH 1024 #define MAX_DM_PATH 1024
#define MAX_DM_VALUE 4096 #define MAX_DM_VALUE 4096
#define DM_VALUE_SEP ","
#define DELIM '.'
#ifdef BBFDM_MAX_MSG_LEN #ifdef BBFDM_MAX_MSG_LEN
#define DEF_IPC_DATA_LEN (BBFDM_MAX_MSG_LEN - 128) // Configured Len - 128 bytes #define DEF_IPC_DATA_LEN (BBFDM_MAX_MSG_LEN - 128) // Configured Len - 128 bytes
@ -35,21 +26,11 @@
#define DEF_IPC_DATA_LEN (10 * 1024 * 1024 - 128) // 10M - 128 bytes #define DEF_IPC_DATA_LEN (10 * 1024 * 1024 - 128) // 10M - 128 bytes
#endif #endif
#define GLOB_CHAR "[[+*]+"
#define GLOB_EXPR "[=><]+"
extern DMOBJ *DEAMON_DM_ROOT_OBJ; extern DMOBJ *DEAMON_DM_ROOT_OBJ;
extern DM_MAP_OBJ *INTERNAL_ROOT_TREE; extern DM_MAP_OBJ *INTERNAL_ROOT_TREE;
bool is_node_instance(char *path);
int count_delim(const char *path);
bool get_boolean_string(char *value);
bool validate_msglen(bbfdm_data_t *data); bool validate_msglen(bbfdm_data_t *data);
int get_dm_type(char *dm_type);
int get_resolved_paths(struct dmctx *bbf_ctx, char *qpath, struct list_head *resolved_paths);
void strncpyt(char *dst, const char *src, size_t n); void strncpyt(char *dst, const char *src, size_t n);
#endif /* COMMON_H */ #endif /* COMMON_H */

View file

@ -90,7 +90,6 @@ static void bbfdm_event_handler(struct ubus_context *ctx, struct ubus_event_hand
.iscommand = false, .iscommand = false,
.isevent = true, .isevent = true,
.isinfo = false, .isinfo = false,
.disable_mservice_browse = true,
.dm_type = BBFDM_USP .dm_type = BBFDM_USP
}; };
@ -107,7 +106,7 @@ static void bbfdm_event_handler(struct ubus_context *ctx, struct ubus_event_hand
if (!e_args) if (!e_args)
goto end; goto end;
snprintf(e_args->method_name, sizeof(e_args->method_name), "%s.%s", DM_STRLEN(u->config.out_root_obj) ? u->config.out_root_obj : u->config.out_name, BBF_EVENT_NAME); snprintf(e_args->method_name, sizeof(e_args->method_name), "%s.event", BBFDM_DEFAULT_UBUS_OBJ);
e_args->blob_data = (struct blob_attr *)calloc(1, blob_data_len); e_args->blob_data = (struct blob_attr *)calloc(1, blob_data_len);
@ -155,7 +154,6 @@ int register_events_to_ubus(struct ubus_context *ctx, struct list_head *ev_list)
.iscommand = false, .iscommand = false,
.isevent = true, .isevent = true,
.isinfo = false, .isinfo = false,
.disable_mservice_browse = true,
.dm_type = BBFDM_USP .dm_type = BBFDM_USP
}; };

File diff suppressed because it is too large Load diff

View file

@ -3,34 +3,23 @@
enum { enum {
DM_GET_PATH, DM_GET_PATH,
DM_GET_PATHS,
DM_GET_MAXDEPTH,
DM_GET_OPTIONAL, DM_GET_OPTIONAL,
__DM_GET_MAX __DM_GET_MAX
}; };
enum { enum {
DM_INSTANCES_PATH, DM_INSTANCES_PATH,
DM_INSTANCES_PATHS,
DM_INSTANCES_FIRST_LEVEL,
DM_INSTANCES_OPTIONAL, DM_INSTANCES_OPTIONAL,
__DM_INSTANCES_MAX __DM_INSTANCES_MAX
}; };
enum { enum {
DM_SCHEMA_PATH, DM_SCHEMA_PATH,
DM_SCHEMA_PATHS,
DM_SCHEMA_FIRST_LEVEL, DM_SCHEMA_FIRST_LEVEL,
DM_SCHEMA_OPTIONAL, DM_SCHEMA_OPTIONAL,
__DM_SCHEMA_MAX __DM_SCHEMA_MAX
}; };
void bbfdm_get_value(bbfdm_data_t *data, void *output); void bbfdm_get(bbfdm_data_t *data, int method);
void bbfdm_get_names(bbfdm_data_t *data);
void bbfdm_get_instances(bbfdm_data_t *data);
void bbfdm_get_supported_dm(bbfdm_data_t *data);
#endif /* GET_H */ #endif /* GET_H */

View file

@ -16,7 +16,6 @@
#include "get_helper.h" #include "get_helper.h"
#include "common.h" #include "common.h"
#include "pretty_print.h"
DMOBJ *DEAMON_DM_ROOT_OBJ = NULL; DMOBJ *DEAMON_DM_ROOT_OBJ = NULL;
DM_MAP_OBJ *INTERNAL_ROOT_TREE = NULL; DM_MAP_OBJ *INTERNAL_ROOT_TREE = NULL;
@ -60,12 +59,36 @@ void bbf_sub_cleanup(struct dmctx *dm_ctx)
bbf_ctx_clean_sub(dm_ctx); bbf_ctx_clean_sub(dm_ctx);
} }
bool match_with_path_list(struct list_head *plist, char *entry)
{
struct pathNode *node;
list_for_each_entry(node, plist, list) {
if (strncmp(node->path, entry, strlen(node->path)) == 0)
return true;
}
return false;
}
bool present_in_path_list(struct list_head *plist, char *entry) bool present_in_path_list(struct list_head *plist, char *entry)
{ {
struct pathNode *pos; struct pathNode *node;
list_for_each_entry(pos, plist, list) { list_for_each_entry(node, plist, list) {
if (!strcmp(pos->path, entry)) if (!strcmp(node->path, entry))
return true;
}
return false;
}
bool present_in_pv_list(struct list_head *pv_list, char *entry)
{
struct pvNode *node = NULL;
list_for_each_entry(node, pv_list, list) {
if (!strcmp(node->param, entry))
return true; return true;
} }
@ -138,7 +161,7 @@ void free_path_list(struct list_head *plist)
void fill_err_code_table(bbfdm_data_t *data, int fault) void fill_err_code_table(bbfdm_data_t *data, int fault)
{ {
void *table = blobmsg_open_table(&data->bb, NULL); void *table = blobmsg_open_table(&data->bb, NULL);
blobmsg_add_string(&data->bb, "path", data->bbf_ctx.in_param ? data->bbf_ctx.in_param : ""); bb_add_string(&data->bb, "path", data->bbf_ctx.in_param);
blobmsg_add_u32(&data->bb, "fault", bbf_fault_map(&data->bbf_ctx, fault)); blobmsg_add_u32(&data->bb, "fault", bbf_fault_map(&data->bbf_ctx, fault));
bb_add_string(&data->bb, "fault_msg", data->bbf_ctx.fault_msg); bb_add_string(&data->bb, "fault_msg", data->bbf_ctx.fault_msg);
blobmsg_close_table(&data->bb, table); blobmsg_close_table(&data->bb, table);
@ -148,104 +171,9 @@ void fill_err_code_array(bbfdm_data_t *data, int fault)
{ {
void *array = blobmsg_open_array(&data->bb, "results"); void *array = blobmsg_open_array(&data->bb, "results");
void *table = blobmsg_open_table(&data->bb, NULL); void *table = blobmsg_open_table(&data->bb, NULL);
blobmsg_add_string(&data->bb, "path", data->bbf_ctx.in_param); bb_add_string(&data->bb, "path", data->bbf_ctx.in_param);
blobmsg_add_u32(&data->bb, "fault", bbf_fault_map(&data->bbf_ctx, fault)); blobmsg_add_u32(&data->bb, "fault", bbf_fault_map(&data->bbf_ctx, fault));
bb_add_string(&data->bb, "fault_msg", data->bbf_ctx.fault_msg); bb_add_string(&data->bb, "fault_msg", data->bbf_ctx.fault_msg);
blobmsg_close_table(&data->bb, table); blobmsg_close_table(&data->bb, table);
blobmsg_close_array(&data->bb, array); blobmsg_close_array(&data->bb, array);
} }
static int CountConsecutiveDigits(char *p)
{
char c;
int num_digits;
num_digits = 0;
c = *p++;
while ((c >= '0') && (c <= 9))
{
num_digits++;
c = *p++;
}
return num_digits;
}
static int compare_path(const void *arg1, const void *arg2)
{
const struct pvNode *pv1 = (const struct pvNode *)arg1;
const struct pvNode *pv2 = (const struct pvNode *)arg2;
char *s1 = pv1->param;
char *s2 = pv2->param;
char c1, c2;
int num_digits_s1;
int num_digits_s2;
int delta;
// Skip all characters which are the same
while (true) {
c1 = *s1;
c2 = *s2;
// Exit if reached the end of either string
if ((c1 == '\0') || (c2 == '\0')) {
// NOTE: The following comparision puts s1 before s2, if s1 terminates before s2 (and vice versa)
return (int)c1 - (int)c2;
}
// Exit if the characters do not match
if (c1 != c2) {
break;
}
// As characters match, move to next characters
s1++;
s2++;
}
// If the code gets here, then we have reached a character which is different
// Determine the number of digits in the rest of the string (this may be 0 if the first character is not a digit)
num_digits_s1 = CountConsecutiveDigits(s1);
num_digits_s2 = CountConsecutiveDigits(s2);
// Determine if the number of digits in s1 is greater than in s2 (if so, s1 comes after s2)
delta = num_digits_s1 - num_digits_s2;
if (delta != 0) {
return delta;
}
// If the code gets here, then the strings contain either no digits, or the same number of digits,
// so just compare the characters (this also works if the characters are digits)
return (int)c1 - (int)c2;
}
// Returns a pointer to the sorted array of PVs, memory need to be freed by caller
struct pvNode *sort_pv_path(struct list_head *pv_list, size_t pv_count)
{
if (!pv_list)
return NULL;
if (list_empty(pv_list) || pv_count == 0)
return NULL;
struct pvNode *arr = (struct pvNode *)calloc(pv_count, sizeof(struct pvNode));
if (arr == NULL)
return NULL;
struct pvNode *pv = NULL;
size_t i = 0;
list_for_each_entry(pv, pv_list, list) {
if (i == pv_count)
break;
memcpy(&arr[i], pv, sizeof(struct pvNode));
i++;
}
qsort(arr, pv_count, sizeof(struct pvNode), compare_path);
return arr;
}

View file

@ -24,11 +24,12 @@ void bbf_cleanup(struct dmctx *dm_ctx);
void bbf_sub_init(struct dmctx *dm_ctx); void bbf_sub_init(struct dmctx *dm_ctx);
void bbf_sub_cleanup(struct dmctx *dm_ctx); void bbf_sub_cleanup(struct dmctx *dm_ctx);
bool present_in_path_list(struct list_head *plist, char *entry); bool present_in_pv_list(struct list_head *pv_list, char *entry);
void add_pv_list(const char *para, const char *val, const char *type, struct list_head *pv_list); void add_pv_list(const char *para, const char *val, const char *type, struct list_head *pv_list);
void free_pv_list(struct list_head *pv_list); void free_pv_list(struct list_head *pv_list);
bool match_with_path_list(struct list_head *plist, char *entry);
bool present_in_path_list(struct list_head *plist, char *entry);
void add_path_list(const char *param, struct list_head *plist); void add_path_list(const char *param, struct list_head *plist);
void free_path_list(struct list_head *plist); void free_path_list(struct list_head *plist);
@ -37,6 +38,4 @@ void fill_err_code_array(bbfdm_data_t *data, int fault);
void bb_add_string(struct blob_buf *bb, const char *name, const char *value); void bb_add_string(struct blob_buf *bb, const char *name, const char *value);
struct pvNode *sort_pv_path(struct list_head *pv_list, size_t pv_count);
#endif /* GET_HELPER_H */ #endif /* GET_HELPER_H */

View file

@ -10,9 +10,7 @@
*/ */
#include "common.h" #include "common.h"
#include "operate.h"
#include "get_helper.h" #include "get_helper.h"
#include "pretty_print.h"
#include <libubus.h> #include <libubus.h>
@ -20,71 +18,31 @@ void bbfdm_operate_cmd(bbfdm_data_t *data, void *output)
{ {
int fault = 0; int fault = 0;
memset(&data->bb, 0, sizeof(struct blob_buf));
bbf_init(&data->bbf_ctx); bbf_init(&data->bbf_ctx);
blob_buf_init(&data->bb, 0);
void *global_array = blobmsg_open_array(&data->bb, "results"); void *array = blobmsg_open_array(&data->bbf_ctx.bb, "results");
void *global_table = blobmsg_open_table(&data->bb, NULL); void *table = blobmsg_open_table(&data->bbf_ctx.bb, NULL);
blobmsg_add_string(&data->bb, "path", data->bbf_ctx.in_param); bb_add_string(&data->bbf_ctx.bb, "path", data->bbf_ctx.in_param);
blobmsg_add_string(&data->bb, "data", data->bbf_ctx.linker); bb_add_string(&data->bbf_ctx.bb, "data", data->bbf_ctx.linker);
void *output_array = blobmsg_open_array(&data->bbf_ctx.bb, "output");
fault = bbfdm_cmd_exec(&data->bbf_ctx, BBF_OPERATE); fault = bbfdm_cmd_exec(&data->bbf_ctx, BBF_OPERATE);
if (fault == 0) { if (fault) {
void *table = NULL, *array = NULL; blobmsg_add_u32(&data->bbf_ctx.bb, "fault", fault);
struct blob_attr *cur = NULL; bb_add_string(&data->bbf_ctx.bb, "fault_msg", data->bbf_ctx.fault_msg);
size_t rem = 0;
if (data->is_raw) {
array = blobmsg_open_array(&data->bb, "output");
blobmsg_for_each_attr(cur, data->bbf_ctx.bb.head, rem) {
blobmsg_add_blob(&data->bb, cur);
}
blobmsg_close_array(&data->bb, array);
} else {
LIST_HEAD(pv_local);
blobmsg_for_each_attr(cur, data->bbf_ctx.bb.head, rem) {
struct blob_attr *tb[3] = {0};
const struct blobmsg_policy p[3] = {
{ "path", BLOBMSG_TYPE_STRING },
{ "data", BLOBMSG_TYPE_STRING },
{ "type", BLOBMSG_TYPE_STRING }
};
blobmsg_parse(p, 3, tb, blobmsg_data(cur), blobmsg_len(cur));
char *op_name = (tb[0]) ? blobmsg_get_string(tb[0]) : "";
char *op_data = (tb[1]) ? blobmsg_get_string(tb[1]) : "";
char *op_type = (tb[2]) ? blobmsg_get_string(tb[2]) : "";
add_pv_list(op_name, op_data, op_type, &pv_local);
} }
array = blobmsg_open_array(&data->bb, "output"); blobmsg_close_array(&data->bbf_ctx.bb, output_array);
table = blobmsg_open_table(&data->bb, NULL); blobmsg_close_table(&data->bbf_ctx.bb, table);
prepare_result_blob(&data->bb, &pv_local);
blobmsg_close_table(&data->bb, table);
blobmsg_close_array(&data->bb, array);
free_pv_list(&pv_local); blobmsg_close_array(&data->bbf_ctx.bb, array);
}
} else { if (output) {
blobmsg_add_u32(&data->bb, "fault", fault); memcpy(output, data->bbf_ctx.bb.head, blob_pad_len(data->bbf_ctx.bb.head));
bb_add_string(&data->bb, "fault_msg", data->bbf_ctx.fault_msg); } else if (data->ctx && data->req) {
ubus_send_reply(data->ctx, data->req, data->bbf_ctx.bb.head);
} }
blobmsg_close_table(&data->bb, global_table);
blobmsg_close_array(&data->bb, global_array);
if (output)
memcpy(output, data->bb.head, blob_pad_len(data->bb.head));
else
ubus_send_reply(data->ctx, data->req, data->bb.head);
blob_buf_free(&data->bb);
bbf_cleanup(&data->bbf_ctx); bbf_cleanup(&data->bbf_ctx);
} }

View file

@ -1,7 +1,7 @@
/* /*
* plugin.c: Plugin file bbfdmd * plugin.c: Plugin file bbfdmd
* *
* Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved. * Copyright (C) 2023-2025 IOPSYS Software Solutions AB. All rights reserved.
* *
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
* *
@ -17,7 +17,6 @@
#include "libbbfdm-api/legacy/plugin/json_plugin.h" #include "libbbfdm-api/legacy/plugin/json_plugin.h"
extern struct list_head loaded_json_files; extern struct list_head loaded_json_files;
extern struct list_head json_list; extern struct list_head json_list;
extern struct list_head json_memhead; extern struct list_head json_memhead;
@ -37,34 +36,9 @@ static uint8_t find_number_of_objects(DM_MAP_OBJ *dynamic_obj)
return len; return len;
} }
static void fill_dotso_micro_service_out_args(bbfdm_config_t *config, DMOBJ *entryobj, char *parent_dm) int bbfdm_load_internal_plugin(struct bbfdm_context *bbfdm_ctx, DM_MAP_OBJ *dynamic_obj, DMOBJ **main_entry)
{ {
char ms_name[128] = {0}; if (!dynamic_obj || !main_entry) {
if (!config || !entryobj || !parent_dm)
return;
strncpyt(config->out_parent_dm, parent_dm, sizeof(config->out_parent_dm));
for (; (entryobj && entryobj->obj); entryobj++) {
add_path_list(entryobj->obj, &config->list_objs);
int len = DM_STRLEN(ms_name);
if (len == 0) {
snprintf(ms_name, sizeof(ms_name), "%s.%s", config->out_root_obj, entryobj->obj);
} else {
snprintf(ms_name + len, sizeof(ms_name) - len, "_%s", entryobj->obj);
}
}
if (DM_STRLEN(config->out_name) == 0)
strncpyt(config->out_name, ms_name, sizeof(config->out_name));
}
int bbfdm_load_internal_plugin(struct bbfdm_context *bbfdm_ctx, DM_MAP_OBJ *dynamic_obj, bbfdm_config_t *config, DMOBJ **main_entry)
{
if (!dynamic_obj || !config || !main_entry) {
BBF_ERR("Input validation failed"); BBF_ERR("Input validation failed");
return -1; return -1;
} }
@ -92,9 +66,14 @@ int bbfdm_load_internal_plugin(struct bbfdm_context *bbfdm_ctx, DM_MAP_OBJ *dyna
return -1; return -1;
} }
// Fill out arguments if it is running as micro-service if (dynamic_obj[i].root_obj != NULL && bbfdm_ctx != NULL) {
if (dm_is_micro_service() == true) struct dm_obj_s *entryobj = dynamic_obj[i].root_obj;
fill_dotso_micro_service_out_args(config, dynamic_obj[i].root_obj, node_obj); for (; (entryobj && entryobj->obj); entryobj++) {
char path[MAX_DM_PATH] = {0};
snprintf(path, sizeof(path), "%s%s.", node_obj, entryobj->obj);
add_path_list(path, &bbfdm_ctx->obj_list);
}
}
node_obj[len-1] = 0; node_obj[len-1] = 0;
@ -112,9 +91,9 @@ int bbfdm_load_internal_plugin(struct bbfdm_context *bbfdm_ctx, DM_MAP_OBJ *dyna
return 0; return 0;
} }
int bbfdm_load_dotso_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle, const char *file_path, bbfdm_config_t *config, DMOBJ **main_entry) int bbfdm_load_dotso_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle, const char *file_path, DMOBJ **main_entry)
{ {
if (!lib_handle || !file_path || !strlen(file_path) || !config || !main_entry) { if (!lib_handle || !file_path || !strlen(file_path) || !main_entry) {
BBF_ERR("Input validation failed"); BBF_ERR("Input validation failed");
return -1; return -1;
} }
@ -132,7 +111,7 @@ int bbfdm_load_dotso_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle,
//Dynamic Object //Dynamic Object
*(void **) (&dynamic_obj) = dlsym(handle, "tDynamicObj"); *(void **) (&dynamic_obj) = dlsym(handle, "tDynamicObj");
return bbfdm_load_internal_plugin(bbfdm_ctx, dynamic_obj, config, main_entry); return bbfdm_load_internal_plugin(bbfdm_ctx, dynamic_obj, main_entry);
} }
int bbfdm_free_dotso_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle) int bbfdm_free_dotso_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle)
@ -159,28 +138,11 @@ int bbfdm_free_dotso_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle)
return 0; return 0;
} }
static void fill_json_micro_service_out_args(bbfdm_config_t *config, char *parent_dm, char *obj, char *ms_name, size_t ms_name_len) static int bbfdm_load_json_plugin(struct bbfdm_context *bbfdm_ctx, struct list_head *json_plugin, struct list_head *json_list,
{ struct list_head *json_memhead, const char *file_path, DMOBJ **main_entry)
if (!config || !obj)
return;
strncpyt(config->out_parent_dm, parent_dm, sizeof(config->out_parent_dm));
add_path_list(obj, &config->list_objs);
int len = DM_STRLEN(ms_name);
if (len == 0) {
snprintf(ms_name, ms_name_len, "%s.%s", config->out_root_obj, obj);
} else {
snprintf(ms_name + len, ms_name_len - len, "_%s", obj);
}
}
int bbfdm_load_json_plugin(struct list_head *json_plugin, struct list_head *json_list, struct list_head *json_memhead,
const char *file_path, bbfdm_config_t *config, DMOBJ **main_entry)
{ {
DMOBJ *dm_entryobj = NULL; DMOBJ *dm_entryobj = NULL;
int json_plugin_version = JSON_VERSION_0; int json_plugin_version = JSON_VERSION_0;
char ms_name[128] = {0};
uint8_t idx = 0; uint8_t idx = 0;
if (!file_path || !strlen(file_path) || !main_entry) { if (!file_path || !strlen(file_path) || !main_entry) {
@ -218,7 +180,7 @@ int bbfdm_load_json_plugin(struct list_head *json_plugin, struct list_head *json
return -1; return -1;
} }
char obj_prefix[1024] = {0}; char obj_prefix[512] = {0};
json_plugin_find_prefix_obj(node_obj, obj_prefix, sizeof(obj_prefix)); json_plugin_find_prefix_obj(node_obj, obj_prefix, sizeof(obj_prefix));
int obj_prefix_len = strlen(obj_prefix); int obj_prefix_len = strlen(obj_prefix);
@ -234,9 +196,9 @@ int bbfdm_load_json_plugin(struct list_head *json_plugin, struct list_head *json
return -1; return -1;
} }
// Fill out arguments if it is running as micro-service char path[MAX_DM_PATH] = {0};
if (dm_is_micro_service() == true) snprintf(path, sizeof(path), "%s%s.", obj_prefix, obj_name);
fill_json_micro_service_out_args(config, obj_prefix, obj_name, ms_name, sizeof(ms_name)); add_path_list(path, &bbfdm_ctx->obj_list);
// Remove '.' from object prefix // Remove '.' from object prefix
if (obj_prefix[obj_prefix_len - 1] == '.') if (obj_prefix[obj_prefix_len - 1] == '.')
@ -264,9 +226,6 @@ int bbfdm_load_json_plugin(struct list_head *json_plugin, struct list_head *json
idx++; idx++;
} }
if (DM_STRLEN(config->out_name) == 0)
strncpyt(config->out_name, ms_name, sizeof(config->out_name));
*main_entry = dm_entryobj; *main_entry = dm_entryobj;
return 0; return 0;
} }
@ -276,7 +235,7 @@ int bbfdm_free_json_plugin(void)
return free_json_plugins(); return free_json_plugins();
} }
int bbfdm_load_external_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle, bbfdm_config_t *config, DMOBJ **main_entry) int bbfdm_load_external_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle, DMOBJ **main_entry)
{ {
char file_path[128] = {0}; char file_path[128] = {0};
int err = -1; int err = -1;
@ -293,10 +252,10 @@ int bbfdm_load_external_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handl
BBF_ERR("Input file without extension"); BBF_ERR("Input file without extension");
} else if (strcasecmp(ext, ".json") == 0) { } else if (strcasecmp(ext, ".json") == 0) {
BBF_INFO("Loading JSON plugin %s", file_path); BBF_INFO("Loading JSON plugin %s", file_path);
err = bbfdm_load_json_plugin(&loaded_json_files, &json_list, &json_memhead, file_path, config, main_entry); err = bbfdm_load_json_plugin(bbfdm_ctx, &loaded_json_files, &json_list, &json_memhead, file_path, main_entry);
} else if (strcasecmp(ext, ".so") == 0) { } else if (strcasecmp(ext, ".so") == 0) {
BBF_INFO("Loading DotSo plugin %s", file_path); BBF_INFO("Loading DotSo plugin %s", file_path);
err = bbfdm_load_dotso_plugin(bbfdm_ctx, lib_handle, file_path, config, main_entry); err = bbfdm_load_dotso_plugin(bbfdm_ctx, lib_handle, file_path, main_entry);
} else { } else {
BBF_ERR("Input type %s not supported", ext); BBF_ERR("Input type %s not supported", ext);
} }

View file

@ -10,14 +10,12 @@
#ifndef PLUGIN_H #ifndef PLUGIN_H
int bbfdm_load_internal_plugin(struct bbfdm_context *bbfdm_ctx, DM_MAP_OBJ *Dynamic_Obj, bbfdm_config_t *config, DMOBJ **main_entry); int bbfdm_load_internal_plugin(struct bbfdm_context *bbfdm_ctx, DM_MAP_OBJ *Dynamic_Obj, DMOBJ **main_entry);
int bbfdm_load_external_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle, bbfdm_config_t *config, DMOBJ **main_entry); int bbfdm_load_external_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle, DMOBJ **main_entry);
int bbfdm_load_dotso_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle, const char *file_path, bbfdm_config_t *config, DMOBJ **main_entry); int bbfdm_load_dotso_plugin(struct bbfdm_context *bbfdm_ctx, void **lib_handle, const char *file_path, DMOBJ **main_entry);
int bbfdm_free_dotso_plugin(struct bbfdm_context *bbfdm_ctx, void *lib_handle); int bbfdm_free_dotso_plugin(struct bbfdm_context *bbfdm_ctx, void *lib_handle);
int bbfdm_load_json_plugin(struct list_head *json_plugin, struct list_head *json_list, struct list_head *json_memhead,
const char *file_path, bbfdm_config_t *config, DMOBJ **main_entry);
int bbfdm_free_json_plugin(void); int bbfdm_free_json_plugin(void);
#endif /* PLUGIN_H */ #endif /* PLUGIN_H */

View file

@ -1,444 +0,0 @@
/*
* pretty_print.c: utils for pretty printing of results
*
* Copyright (C) 2020-2023 IOPSYS Software Solutions AB. All rights reserved.
*
* Author: Vivek Dutta <vivek.dutta@iopsys.eu>
*
* See LICENSE file for license related information.
*/
#include "common.h"
#include "get_helper.h"
#include "pretty_print.h"
// private function and structures
struct resultstack {
void *cookie;
char *key;
struct list_head list;
};
static bool is_search_by_reference(char *path)
{
BBF_DEBUG("Entry |%s|", path);
if (match(path, "[+]+", 0, NULL)) {
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)
{
BBF_DEBUG("Entry |%s|", str);
if (match(str, GLOB_CHAR, 0, NULL)) {
size_t s_len = 0, b_len = 0, p_len = 0;
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, 0, NULL))
return true;
if (match(temp_char, "[*+]+", 0, NULL))
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;
BBF_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, struct dmctx *bbf_ctx, struct list_head *pv_local)
{
struct blob_attr *cur = NULL;
size_t rem = 0;
uint8_t count;
size_t plen = get_glob_len(bbf_ctx->in_param);
size_t path_len = DM_STRLEN(path);
if (path_len == 0)
return;
blobmsg_for_each_attr(cur, bbf_ctx->bb.head, rem) {
struct blob_attr *tb[3] = {0};
const struct blobmsg_policy p[3] = {
{ "path", BLOBMSG_TYPE_STRING },
{ "data", BLOBMSG_TYPE_STRING },
{ "type", BLOBMSG_TYPE_STRING }
};
blobmsg_parse(p, 3, tb, blobmsg_data(cur), blobmsg_len(cur));
char *name = (tb[0]) ? blobmsg_get_string(tb[0]) : "";
char *data = (tb[1]) ? blobmsg_get_string(tb[1]) : "";
char *type = (tb[2]) ? blobmsg_get_string(tb[2]) : "";
if (match(name, path, 0, NULL)) {
if (is_search_by_reference(bbf_ctx->in_param))
plen = 0;
if (maxdepth > 4 || maxdepth == 0) {
add_pv_list(name + plen, data, type, pv_local);
} else {
count = count_delim(name + path_len);
if (count < maxdepth)
add_pv_list(name + plen, data, 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;
BBF_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) {
BBF_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 *)calloc(1, sizeof(*rnode));
if (!rnode) {
BBF_ERR("Out of memory!");
return;
}
INIT_LIST_HEAD(&rnode->list);
list_add(&rnode->list, rlist);
rnode->key = (key) ? strdup(key) : strdup("");
rnode->cookie = cookie;
BBF_DEBUG("## ResSTACK ADD (%s) ##", rnode->key);
}
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;
size_t count = 0;
list_for_each_entry(pv, pv_list, list) {
count++;
}
struct pvNode *sortedPV = sort_pv_path(pv_list, count);
if (sortedPV == NULL)
return;
for (size_t i = 0; i < count; i++) {
pv = &sortedPV[i];
ptr = pv->param;
if (list_empty(&result_stack)) {
BBF_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;
BBF_DEBUG("GROUP (%s), ptr(%s), len(%zu)", 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
BBF_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;
}
}
}
}
}
free(sortedPV);
// 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_raw_result(struct blob_buf *bb, struct dmctx *bbf_ctx, struct list_head *rslvd)
{
struct pathNode *iter = NULL;
struct blob_attr *cur = NULL;
size_t rem = 0;
list_for_each_entry(iter, rslvd, list) {
if (DM_STRLEN(iter->path) == 0)
continue;
blobmsg_for_each_attr(cur, bbf_ctx->bb.head, rem) {
struct blob_attr *tb[1] = {0};
const struct blobmsg_policy p[1] = {
{ "path", BLOBMSG_TYPE_STRING }
};
blobmsg_parse(p, 1, tb, blobmsg_data(cur), blobmsg_len(cur));
char *name = (tb[0]) ? blobmsg_get_string(tb[0]) : "";
if (match(name, iter->path, 0, NULL)) {
blobmsg_add_blob(bb, cur);
}
}
}
}
void prepare_pretty_result(uint8_t maxdepth, struct blob_buf *bb, struct dmctx *bbf_ctx, struct list_head *rslvd)
{
struct pathNode *iter = NULL;
LIST_HEAD(pv_local);
BBF_DEBUG("################### DATA to PROCESS ##################");
list_for_each_entry(iter, rslvd, list) {
BBF_DEBUG("## %s ##", iter->path);
resulting(maxdepth, iter->path, bbf_ctx, &pv_local);
}
BBF_DEBUG("######################################################");
prepare_result_blob(bb, &pv_local);
free_pv_list(&pv_local);
}

View file

@ -1,18 +0,0 @@
/*
* pretty_print.h: utils for pretty printing of results
*
* Copyright (C) 2020-2023 IOPSYS Software Solutions AB. All rights reserved.
*
* Author: Vivek Dutta <vivek.dutta@iopsys.eu>
*
* See LICENSE file for license related information.
*/
#ifndef PRETTY_PRINT_H
#define PRETTY_PRINT_H
void prepare_result_blob(struct blob_buf *bb, struct list_head *pv_list);
void prepare_raw_result(struct blob_buf *bb, struct dmctx *bbf_ctx, struct list_head *rslvd);
void prepare_pretty_result(uint8_t maxdepth, struct blob_buf *bb, struct dmctx *bbf_ctx, struct list_head *rslvd);
#endif /* PRETTY_PRINT_H */

View file

@ -17,10 +17,9 @@
int bbfdm_set_value(bbfdm_data_t *data) int bbfdm_set_value(bbfdm_data_t *data)
{ {
struct pvNode *pv = NULL; struct pvNode *pv = NULL;
void *array = NULL;
int fault = 0; int fault = 0;
array = blobmsg_open_array(&data->bb, "results"); void *array = blobmsg_open_array(&data->bb, "results");
list_for_each_entry(pv, data->plist, list) { list_for_each_entry(pv, data->plist, list) {
data->bbf_ctx.in_param = pv->param; data->bbf_ctx.in_param = pv->param;
@ -43,39 +42,8 @@ int bbfdm_set_value(bbfdm_data_t *data)
return fault; return fault;
} }
static int set_resolved_paths(bbfdm_data_t *data, char *path, char *value, char *type, struct list_head *pv_list) int fill_pvlist_set(char *param_name, char *param_value, char *data_type, struct blob_attr *blob_table, struct list_head *pv_list)
{ {
int fault = 0;
if (!path || !value || !pv_list)
return -1;
LIST_HEAD(resolved_paths);
bbf_sub_init(&data->bbf_ctx);
fault = get_resolved_paths(&data->bbf_ctx, path, &resolved_paths);
if (!fault) {
struct pathNode *p;
list_for_each_entry(p, &resolved_paths, list) {
add_pv_list(p->path, value, type, pv_list);
}
}
bbf_sub_cleanup(&data->bbf_ctx);
free_path_list(&resolved_paths);
return fault;
}
int fill_pvlist_set(bbfdm_data_t *data, char *param_name, char *param_value, char *type, struct blob_attr *blob_table, struct list_head *pv_list)
{
struct blob_attr *attr;
struct blobmsg_hdr *hdr;
char path[MAX_DM_PATH], value[MAX_DM_VALUE];
int fault = 0;
size_t plen = DM_STRLEN(param_name); size_t plen = DM_STRLEN(param_name);
if (plen == 0) if (plen == 0)
return USP_FAULT_INVALID_PATH; return USP_FAULT_INVALID_PATH;
@ -86,18 +54,21 @@ int fill_pvlist_set(bbfdm_data_t *data, char *param_name, char *param_value, cha
if (param_name[plen - 1] == '.') if (param_name[plen - 1] == '.')
return USP_FAULT_INVALID_PATH; return USP_FAULT_INVALID_PATH;
fault = set_resolved_paths(data, param_name, param_value, type, pv_list); add_pv_list(param_name, param_value, data_type, pv_list);
if (fault) return 0;
return fault;
blob__table: blob__table:
if (!blob_table) if (!blob_table)
return 0; return 0;
struct blob_attr *attr;
struct blobmsg_hdr *hdr;
size_t tlen = (size_t)blobmsg_data_len(blob_table); size_t tlen = (size_t)blobmsg_data_len(blob_table);
__blob_for_each_attr(attr, blobmsg_data(blob_table), tlen) { __blob_for_each_attr(attr, blobmsg_data(blob_table), tlen) {
char path[MAX_DM_PATH] = {0}, value[MAX_DM_VALUE] = {0};
hdr = blob_data(attr); hdr = blob_data(attr);
switch (blob_id(attr)) { switch (blob_id(attr)) {
@ -122,9 +93,7 @@ blob__table:
} }
snprintf(path, MAX_DM_PATH, "%s%s", param_name, (char *)hdr->name); snprintf(path, MAX_DM_PATH, "%s%s", param_name, (char *)hdr->name);
fault = set_resolved_paths(data, path, value, NULL, pv_list); add_pv_list(path, value, NULL, pv_list);
if (fault)
return fault;
} }
return 0; return 0;

View file

@ -10,7 +10,7 @@ enum {
__DM_SET_MAX, __DM_SET_MAX,
}; };
int fill_pvlist_set(bbfdm_data_t *data, char *param_name, char *param_value, char *type, struct blob_attr *blob_table, struct list_head *pv_list); int fill_pvlist_set(char *param_name, char *param_value, char *data_type, struct blob_attr *blob_table, struct list_head *pv_list);
int bbfdm_set_value(bbfdm_data_t *data); int bbfdm_set_value(bbfdm_data_t *data);
#endif /* SET_H */ #endif /* SET_H */

View file

@ -7,11 +7,11 @@ ADD_DEFINITIONS(-Wall -Werror -g3 -D_GNU_SOURCE -DBBF_VENDOR_PREFIX="${BBF_VENDO
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SOURCE_DIR} -I${CMAKE_CURRENT_SOURCE_DIR} -I${CMAKE_SOURCE_DIR}/libbbfdm-api/version-2") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SOURCE_DIR} -I${CMAKE_CURRENT_SOURCE_DIR} -I${CMAKE_SOURCE_DIR}/libbbfdm-api/version-2")
FILE(GLOB BBF_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.c) FILE(GLOB BBF_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.c)
ADD_LIBRARY(bbfdm STATIC ${BBF_SOURCES}) ADD_LIBRARY(core SHARED ${BBF_SOURCES})
TARGET_LINK_LIBRARIES(bbfdm uci ubus ubox json-c blobmsg_json m bbfdm-api ssl crypto) TARGET_LINK_LIBRARIES(core uci ubus ubox json-c blobmsg_json m bbfdm-api ssl crypto)
INSTALL(TARGETS bbfdm INSTALL(TARGETS core
LIBRARY DESTINATION usr/lib LIBRARY DESTINATION usr/lib
) )
@ -19,7 +19,6 @@ INSTALL(DIRECTORY DESTINATION etc/bbfdm)
INSTALL(DIRECTORY DESTINATION etc/bbfdm/dmmap) INSTALL(DIRECTORY DESTINATION etc/bbfdm/dmmap)
INSTALL(DIRECTORY DESTINATION usr/share/bbfdm) INSTALL(DIRECTORY DESTINATION usr/share/bbfdm)
INSTALL(DIRECTORY DESTINATION usr/share/bbfdm/scripts) INSTALL(DIRECTORY DESTINATION usr/share/bbfdm/scripts)
INSTALL(DIRECTORY DESTINATION usr/share/bbfdm/plugins)
INSTALL(DIRECTORY DESTINATION usr/share/bbfdm/micro_services) INSTALL(DIRECTORY DESTINATION usr/share/bbfdm/micro_services)
INSTALL(DIRECTORY DESTINATION usr/libexec/rpcd) INSTALL(DIRECTORY DESTINATION usr/libexec/rpcd)

View file

@ -91,12 +91,11 @@ DM_MAP_OBJ tDynamicObj[] = {
/* *** Device. *** */ /* *** Device. *** */
DMOBJ tDMRootObj[] = { DMOBJ tDMRootObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/ /* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys*/
{"LANConfigSecurity", &DMREAD, NULL, NULL, "file:/etc/config/users", NULL, NULL, NULL, NULL, tLANConfigSecurityParams, NULL, BBFDM_BOTH, NULL}, {"LANConfigSecurity", &DMREAD, NULL, NULL, "file:/etc/config/users", NULL, NULL, NULL, NULL, tLANConfigSecurityParams, NULL, BBFDM_BOTH},
{"Schedules", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tSchedulesObj, tSchedulesParams, NULL, BBFDM_BOTH, NULL}, {"Schedules", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tSchedulesObj, tSchedulesParams, NULL, BBFDM_BOTH},
{"Security", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tSecurityObj, tSecurityParams, NULL, BBFDM_BOTH, NULL}, {"Security", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tSecurityObj, tSecurityParams, NULL, BBFDM_CWMP},
{"Services", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, BBFDM_BOTH, NULL}, {"GatewayInfo", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tGatewayInfoParams, NULL, BBFDM_CWMP},
{"GatewayInfo", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tGatewayInfoParams, NULL, BBFDM_CWMP, NULL},
{0} {0}
}; };

View file

@ -299,20 +299,20 @@ static int get_SecurityCertificate_SignatureAlgorithm(char *refparam, struct dmc
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
/* *** Device.Security. *** */ /* *** Device.Security. *** */
DMOBJ tSecurityObj[] = { DMOBJ tSecurityObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/ /* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys*/
{"Certificate", &DMREAD, NULL, NULL, NULL, browseSecurityCertificateInst, NULL, NULL, NULL, tSecurityCertificateParams, NULL, BBFDM_CWMP, NULL}, {"Certificate", &DMREAD, NULL, NULL, NULL, browseSecurityCertificateInst, NULL, NULL, NULL, tSecurityCertificateParams, NULL, BBFDM_CWMP},
{0} {0}
}; };
DMLEAF tSecurityParams[] = { DMLEAF tSecurityParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ /* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/
{"CertificateNumberOfEntries", &DMREAD, DMT_UNINT, get_Security_CertificateNumberOfEntries, NULL, BBFDM_CWMP}, {"CertificateNumberOfEntries", &DMREAD, DMT_UNINT, get_Security_CertificateNumberOfEntries, NULL, BBFDM_CWMP},
{0} {0}
}; };
/* *** Device.Security.Certificate.{i}. *** */ /* *** Device.Security.Certificate.{i}. *** */
DMLEAF tSecurityCertificateParams[] = { DMLEAF tSecurityCertificateParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ /* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/
//{"Enable", &DMWRITE, DMT_BOOL, get_SecurityCertificate_Enable, set_SecurityCertificate_Enable, BBFDM_CWMP}, //{"Enable", &DMWRITE, DMT_BOOL, get_SecurityCertificate_Enable, set_SecurityCertificate_Enable, BBFDM_CWMP},
{"LastModif", &DMREAD, DMT_TIME, get_SecurityCertificate_LastModif, NULL, BBFDM_CWMP}, {"LastModif", &DMREAD, DMT_TIME, get_SecurityCertificate_LastModif, NULL, BBFDM_CWMP},
{"SerialNumber", &DMREAD, DMT_STRING, get_SecurityCertificate_SerialNumber, NULL, BBFDM_CWMP, DM_FLAG_UNIQUE}, {"SerialNumber", &DMREAD, DMT_STRING, get_SecurityCertificate_SerialNumber, NULL, BBFDM_CWMP, DM_FLAG_UNIQUE},

View file

@ -1,6 +1,6 @@
CC = gcc CC = gcc
CFLAGS = -g -Wall CFLAGS = -g -Wall
LDFLAGS = -lcmocka -lbbfdm-api -lbbfdm -lubox -lblobmsg_json -ljson-c -lssl -lcrypto --coverage LDFLAGS = -lcmocka -lbbfdm-api -lcore -lubox -lblobmsg_json -ljson-c -lssl -lcrypto --coverage
UNIT_TESTS = unit_test_bbfd UNIT_TESTS = unit_test_bbfd
FUNCTIONAL_TESTS = functional_test_bbfd FUNCTIONAL_TESTS = functional_test_bbfd
FUNCTIONAL_API_TESTS = functional_api_test_bbfd FUNCTIONAL_API_TESTS = functional_api_test_bbfd

View file

@ -12,6 +12,7 @@ static int setup_teardown(void **state)
{ {
dm_init_mem(&bbf_ctx); dm_init_mem(&bbf_ctx);
dm_uci_init(&bbf_ctx); dm_uci_init(&bbf_ctx);
dm_ubus_init(&bbf_ctx);
bbf_ctx.dm_type = BBFDM_USP; bbf_ctx.dm_type = BBFDM_USP;
return 0; return 0;
} }
@ -20,7 +21,7 @@ static int group_teardown(void **state)
{ {
dm_uci_exit(&bbf_ctx); dm_uci_exit(&bbf_ctx);
dm_clean_mem(&bbf_ctx); dm_clean_mem(&bbf_ctx);
dmubus_free(); dm_ubus_free(&bbf_ctx);
return 0; return 0;
} }

View file

@ -42,7 +42,7 @@ static int teardown_commit(void **state)
static int group_init(void **state) static int group_init(void **state)
{ {
bbf_global_init(TR181_ROOT_TREE, "/usr/share/bbfdm/plugins"); bbf_global_init(TR181_ROOT_TREE, "/usr/share/bbfdm/micro_services/core");
return 0; return 0;
} }

View file

@ -54,7 +54,7 @@ static int teardown_revert(void **state)
static int group_init(void **state) static int group_init(void **state)
{ {
bbf_global_init(TR181_ROOT_TREE, "/usr/share/bbfdm/plugins"); bbf_global_init(TR181_ROOT_TREE, "/usr/share/bbfdm/micro_services/core");
return 0; return 0;
} }

View file

@ -0,0 +1,41 @@
{
"daemon": {
"enable": "1",
"service_name": "core",
"unified_daemon": false,
"services": [
{
"parent_dm": "Device.",
"object": "LANConfigSecurity"
},
{
"parent_dm": "Device.",
"object": "Schedules"
},
{
"parent_dm": "Device.",
"object": "Security",
"proto": "cwmp"
},
{
"parent_dm": "Device.",
"object": "GatewayInfo"
},
{
"parent_dm": "Device.",
"object": "RootDataModelVersion"
},
{
"parent_dm": "Device.",
"object": "Reboot()"
},
{
"parent_dm": "Device.",
"object": "FactoryReset()"
}
],
"config": {
"loglevel": "3"
}
}
}

View file

@ -23,6 +23,14 @@
{ {
"parent_dm": "Device.", "parent_dm": "Device.",
"object": "RouterAdvertisement" "object": "RouterAdvertisement"
},
{
"parent_dm": "Device.",
"object": "IPv6rd"
},
{
"parent_dm": "Device.",
"object": "InterfaceStack"
} }
], ],
"config": { "config": {

View file

@ -0,0 +1,2 @@
reset reason: REBOOT
reset triggered: upgrade

View file

@ -5,7 +5,7 @@
"method": "get", "method": "get",
"args": { "args": {
"path": "Device.DeviceInfo.Manufacturer", "path": "Device.DeviceInfo.Manufacturer",
"optional": {"format":"raw", "proto":"usp"} "optional": {"proto":"usp"}
}, },
"rc": 0 "rc": 0
}, },
@ -13,7 +13,7 @@
"method": "get", "method": "get",
"args": { "args": {
"path": "Device.DeviceInfo.Manufacturer", "path": "Device.DeviceInfo.Manufacturer",
"optional": {"format":"raw", "proto":"cwmp"} "optional": {"proto":"cwmp"}
}, },
"rc": 0 "rc": 0
}, },
@ -21,7 +21,7 @@
"method": "get", "method": "get",
"args": { "args": {
"path":"Device.WiFi.SSID.*.Alias", "path":"Device.WiFi.SSID.*.Alias",
"optional": {"format":"raw", "proto":"cwmp"} "optional": {"proto":"cwmp"}
}, },
"rc": 0 "rc": 0
}, },
@ -29,7 +29,7 @@
"method": "get", "method": "get",
"args": { "args": {
"path": "Device.DeviceInfo.Manufacturer", "path": "Device.DeviceInfo.Manufacturer",
"optional": {"format":"raw", "proto":"both"} "optional": {"proto":"both"}
}, },
"rc": 0 "rc": 0
}, },
@ -40,15 +40,6 @@
}, },
"rc": 0 "rc": 0
}, },
{
"method": "get",
"args": {
"path": "Device.DeviceInfo.Manufacturer",
"optional": {"format":"raw", "proto":"usp"},
"maxdepth": "1"
},
"rc": 0
},
{ {
"method": "get", "method": "get",
"args": { "args": {
@ -78,7 +69,7 @@
"method": "instances", "method": "instances",
"args": { "args": {
"path": "Device.WiFi.SSID.", "path": "Device.WiFi.SSID.",
"optional": {"format":"raw", "proto":"usp"} "optional": {"proto":"usp"}
}, },
"rc": 0 "rc": 0
}, },
@ -104,14 +95,6 @@
}, },
"rc": 0 "rc": 0
}, },
{
"method": "get",
"args": {
"paths": ["Device.WiFi.SSID.1.SSID","Device.WiFi.SSID.2.SSID"],
"proto": "usp"
},
"rc": 0
},
{ {
"method": "set", "method": "set",
"args": { "args": {

View file

@ -1,33 +0,0 @@
#!/usr/bin/python3
import subprocess
import json
TEST_NAME = "BUG_3536"
print("Running: " + TEST_NAME)
def bbf_get(path, proto = ""):
path_arg = "{\"path\":\"" + path + "\", \"optional\":{\"format\":\"raw\", \"proto\":\"" + proto + "\"}}"
cmd = ['ubus', 'call', 'bbfdm', '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(bbf_get("Device", "usp"))
assert output["results"][0]["fault"] == 7026, "Wrong fault code"
# check fault code of invalid path
output = json.loads(bbf_get("Device", "cwmp"))
assert output["results"][0]["fault"] == 9005, "Wrong fault code for cwmp"
# check fault code of invalid path
output = json.loads(bbf_get("Device"))
assert output["results"][0]["fault"] == 9005, "Wrong fault code for default proto"
print("PASS: " + TEST_NAME)

View file

@ -15,12 +15,11 @@ if sock.exists():
else: else:
assert ubus.connect() assert ubus.connect()
out = ubus.call('bbfdm', 'get', {"path":"Device.", "optional":{"format":"raw"}})
assert isinstance(out[0]["results"][0], dict), "FAIL: get Device. on bbf with raw format"
# Check get operation for Device. path succeed
out = ubus.call('bbfdm', 'get', {"path":"Device."}) out = ubus.call('bbfdm', 'get', {"path":"Device."})
assert isinstance(out[0]['Device'], dict), "FAIL: get Device. on bbf with pretty format" assert isinstance(out[0]["results"][0], dict), "FAIL: get Device."
out = ubus.call('bbfdm', 'get', {"path":"Device"})
assert out[0]["results"][0]["fault"] == 9005, "FAIL: get Device"
ubus.disconnect() ubus.disconnect()
print("PASS: " + TEST_NAME) print("PASS: " + TEST_NAME)

View file

@ -1,30 +0,0 @@
#!/usr/bin/python3
import ubus
import json
import pathlib
TEST_NAME = "Validate ubus event bbf"
print("Running: " + TEST_NAME)
def callback(event, data):
print("PASS: " + TEST_NAME)
ubus.disconnect()
exit(0)
sock = pathlib.Path('/var/run/ubus/ubus.sock')
if sock.exists ():
assert ubus.connect('/var/run/ubus/ubus.sock')
else:
assert ubus.connect()
ubus.listen(("bbfdm.event", callback))
ubus.call("bbfdm", "notify_event", {"name":"Device.LocalAgent.TransferComplete!", "input":[{"path":"Command","data":"Backup()","type":"xsd:string"},{"path":"CommandKey","data":"","type":"xsd:string"}]})
ubus.loop()
ubus.disconnect()
print("FAIL: " + TEST_NAME)

View file

@ -54,7 +54,6 @@ int main(int argc, char **argv)
DMOBJ *CLI_DM_ROOT_OBJ = NULL; DMOBJ *CLI_DM_ROOT_OBJ = NULL;
void *cli_lib_handle = NULL; void *cli_lib_handle = NULL;
struct dmctx bbfdm_ctx = {0}; struct dmctx bbfdm_ctx = {0};
bbfdm_config_t bbfdm_config = {0};
char *plugin_path = NULL, *plugin_dir = NULL, *dm_path = NULL; char *plugin_path = NULL, *plugin_dir = NULL, *dm_path = NULL;
unsigned int proto = BBFDM_BOTH; unsigned int proto = BBFDM_BOTH;
int err = 0, ch; int err = 0, ch;
@ -83,9 +82,9 @@ int main(int argc, char **argv)
} }
if (plugin_path == NULL) { if (plugin_path == NULL) {
err = bbfdm_load_internal_plugin(NULL, tDynamicObj, &bbfdm_config, &CLI_DM_ROOT_OBJ); err = bbfdm_load_internal_plugin(NULL, tDynamicObj, &CLI_DM_ROOT_OBJ);
} else { } else {
err = bbfdm_load_dotso_plugin(NULL, &cli_lib_handle, plugin_path, &bbfdm_config, &CLI_DM_ROOT_OBJ); err = bbfdm_load_dotso_plugin(NULL, &cli_lib_handle, plugin_path, &CLI_DM_ROOT_OBJ);
} }
if (err || !CLI_DM_ROOT_OBJ) { if (err || !CLI_DM_ROOT_OBJ) {

View file

@ -13,8 +13,8 @@ $(LIB): $(LIB_OBJS)
$(CC) $(LIB_CFLAGS) $(LIB_LDFLAGS) -shared -o $@ $^ $(CC) $(LIB_CFLAGS) $(LIB_LDFLAGS) -shared -o $@ $^
install: install:
cp -f $(LIB) /usr/share/bbfdm/plugins/ cp -f $(LIB) /usr/share/bbfdm/micro_services/core/
cp -f *.json /usr/share/bbfdm/plugins cp -f *.json /usr/share/bbfdm/micro_services/core/
clean: clean:
rm -fv *.o $(LIB) rm -fv *.o $(LIB)

View file

@ -12,7 +12,7 @@ import glob
# Constants # Constants
BBF_ERROR_CODE = 0 BBF_ERROR_CODE = 0
CURRENT_PATH = os.getcwd() CURRENT_PATH = os.getcwd()
BBF_PLUGIN_DIR = "/usr/share/bbfdm/plugins/" BBF_MS_CORE_DIR = "/usr/share/bbfdm/micro_services/core/"
BBF_MS_DIR = "/usr/share/bbfdm/micro_services/" BBF_MS_DIR = "/usr/share/bbfdm/micro_services/"
DM_JSON_FILE = os.path.join(CURRENT_PATH, "tools", "datamodel.json") DM_JSON_FILE = os.path.join(CURRENT_PATH, "tools", "datamodel.json")
@ -151,7 +151,7 @@ def generate_shared_library(dm_name, source_files, vendor_prefix,
if is_microservice: if is_microservice:
outdir = BBF_MS_DIR outdir = BBF_MS_DIR
else: else:
outdir = BBF_PLUGIN_DIR outdir = BBF_MS_CORE_DIR
output_library = outdir + dm_name output_library = outdir + dm_name
@ -233,7 +233,7 @@ def build_and_install_dmcli():
"-lbbfdm-ubus", "-lbbfdm-ubus",
"-lubox", "-lubox",
"-lblobmsg_json", "-lblobmsg_json",
"-lbbfdm", "-lcore",
"-ljson-c", "-ljson-c",
"-lssl", "-lssl",
"-lcrypto", "-lcrypto",
@ -257,7 +257,7 @@ def fill_list_dm(proto, dm_list, dm_name=None):
if dm_name: if dm_name:
command = f"dm-cli -l {dm_name}" command = f"dm-cli -l {dm_name}"
else: else:
command = "dm-cli -p /usr/share/bbfdm/plugins" command = "dm-cli -p /usr/share/bbfdm/micro_services/core"
# Add the appropriate flag (-c or -u) based on the proto value # Add the appropriate flag (-c or -u) based on the proto value
if proto == "cwmp": if proto == "cwmp":
@ -411,7 +411,7 @@ def download_and_build_plugins(plugins, vendor_prefix):
if filename.endswith('.c'): if filename.endswith('.c'):
LIST_FILES.append(filename) LIST_FILES.append(filename)
elif filename.endswith('.json'): elif filename.endswith('.json'):
install_json_plugin(filename, "/usr/share/bbfdm/plugins/"+f"{plugin_index}_{name}.json", prefix) install_json_plugin(filename, "/usr/share/bbfdm/micro_services/core/"+f"{plugin_index}_{name}.json", prefix)
else: else:
BBF_ERROR_CODE += 1 BBF_ERROR_CODE += 1
print(f"# Unknown file format {filename} {BBF_ERROR_CODE}") print(f"# Unknown file format {filename} {BBF_ERROR_CODE}")

View file

@ -358,20 +358,13 @@
"proto": "git", "proto": "git",
"version": "devel", "version": "devel",
"dm_files": [ "dm_files": [
"src/wifi.c" "src/wifi.c",
"src/dataelements.c"
], ],
"extra_dependencies": [ "extra_dependencies": [
"-lm" "-lm"
] ]
}, },
{
"repo": "https://dev.iopsys.eu/bbf/wifidmd.git",
"proto": "git",
"version": "devel",
"dm_files": [
"src/dataelements.c"
]
},
{ {
"repo": "https://dev.iopsys.eu/hal/mcastmngr.git", "repo": "https://dev.iopsys.eu/hal/mcastmngr.git",
"proto": "git", "proto": "git",
@ -410,14 +403,6 @@
"test/obuspa_core_dm.json" "test/obuspa_core_dm.json"
] ]
}, },
{
"repo": "https://dev.iopsys.eu/network/netmngr.git",
"proto": "git",
"version": "devel",
"dm_files": [
"src/interfacestack.c"
]
},
{ {
"repo": "https://dev.iopsys.eu/network/netmngr.git", "repo": "https://dev.iopsys.eu/network/netmngr.git",
"proto": "git", "proto": "git",
@ -438,7 +423,8 @@
"src/routeradvertisement.c", "src/routeradvertisement.c",
"src/routing.c", "src/routing.c",
"src/ipv6rd.c", "src/ipv6rd.c",
"src/common.c" "src/common.c",
"src/interfacestack.c"
] ]
}, },
{ {