diff --git a/bbfdmd/ubus/bbfdmd.c b/bbfdmd/ubus/bbfdmd.c index b3e7440aa9024ff19e4ad7de1b17becc734f2090..8074d2f3c0c165bfe9b1dd8c43da8c0bfa02c710 100644 --- a/bbfdmd/ubus/bbfdmd.c +++ b/bbfdmd/ubus/bbfdmd.c @@ -27,8 +27,7 @@ extern struct list_head registered_services; extern int g_log_level; -static void bbfdm_ubus_add_event_cb(struct ubus_context *ctx __attribute__((unused)), - struct ubus_event_handler *ev __attribute__((unused)), +static void bbfdm_ubus_add_event_cb(struct ubus_context *ctx, struct ubus_event_handler *ev __attribute__((unused)), const char *type, struct blob_attr *msg) { const struct blobmsg_policy policy = { @@ -58,19 +57,75 @@ static void bbfdm_ubus_add_event_cb(struct ubus_context *ctx __attribute__((unus service->is_blacklisted = false; service->consecutive_timeouts = 0; service_found = true; + fill_service_schema(ctx, 5000, service->name, &service->dm_schema); BBFDM_ERR("Service '%s' found in registry. Resetting blacklist and timeout counters.", path); break; } + } - if (!service_found) { - BBFDM_ERR("Newly registered service '%s' is not recognized in the registry." - " Possible missing configuration JSON file under '%s'.", - path, BBFDM_MICROSERVICE_INPUT_PATH); - } + if (!service_found) { + BBFDM_ERR("Newly registered service '%s' is not recognized in the registry." + " Possible missing configuration JSON file under '%s'.", + path, BBFDM_MICROSERVICE_INPUT_PATH); } } } +static void bbfdm_handle_schema_request(struct ubus_context *ctx, struct ubus_request_data *req, + const char *requested_path, unsigned int requested_proto) +{ + struct blob_buf bb = {0}; + bool schema_found = false; + int len = strlen(requested_path); + + memset(&bb, 0, sizeof(struct blob_buf)); + blob_buf_init(&bb, 0); + + void *array = blobmsg_open_array(&bb, "results"); + + if (len > 0 && requested_path[len - 1] == '.') { + service_entry_t *service = NULL; + + list_for_each_entry(service, ®istered_services, list) { + + if (service->is_blacklisted || + !service_path_match(requested_path, requested_proto, service) || + !service->dm_schema) + continue; + + struct blob_attr *attr = NULL; + size_t remaining = 0; + const struct blobmsg_policy policy[] = { + { "path", BLOBMSG_TYPE_STRING }, + }; + + blobmsg_for_each_attr(attr, service->dm_schema->head, remaining) { + struct blob_attr *fields[1]; + + blobmsg_parse(policy, 1, fields, blobmsg_data(attr), blobmsg_len(attr)); + + char *path = fields[0] ? blobmsg_get_string(fields[0]) : ""; + + if (strlen(path) == 0) + continue; + + if (strncmp(requested_path, path, len) == 0) { + blobmsg_add_blob(&bb, attr); + schema_found = true; + } + } + } + } + + if (!schema_found) + print_fault_message(&bb, requested_path, 7026, "Path is not present in the data model schema"); + + blobmsg_close_array(&bb, array); + + ubus_send_reply(ctx, req, bb.head); + blob_buf_free(&bb); +} + static const struct blobmsg_policy bbfdm_policy[] = { [BBFDM_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING }, [BBFDM_VALUE] = { .name = "value", .type = BLOBMSG_TYPE_STRING }, @@ -83,6 +138,7 @@ static int bbfdm_handler_async(struct ubus_context *ctx, struct ubus_object *obj struct blob_attr *tb[__BBFDM_MAX]; service_entry_t *service = NULL; unsigned int requested_proto = BBFDMD_BOTH; + bool raw_format = false; if (blobmsg_parse(bbfdm_policy, __BBFDM_MAX, tb, blob_data(msg), blob_len(msg))) { BBFDM_ERR("Failed to parse input message"); @@ -94,24 +150,33 @@ static int bbfdm_handler_async(struct ubus_context *ctx, struct ubus_object *obj return UBUS_STATUS_INVALID_ARGUMENT; } - struct async_request_context *context = calloc(1, sizeof(struct async_request_context)); + char *requested_path = blobmsg_get_string(tb[BBFDM_PATH]); + fill_optional_input(tb[BBFDM_INPUT], &requested_proto, &raw_format); + + if (strcmp(method, "schema") == 0 && requested_proto != BBFDMD_CWMP) { + BBFDM_INFO("START: ubus method|%s|, name|%s|, path|%s|, proto|%u|", method, obj->name, requested_path, requested_proto); + bbfdm_handle_schema_request(ctx, req, requested_path, requested_proto); + BBFDM_INFO("END: ubus method|%s|, name|%s|, path|%s|, proto|%u|", method, obj->name, requested_path, requested_proto); + return 0; + } + + struct async_request_context *context = (struct async_request_context *)calloc(1, sizeof(struct async_request_context)); if (!context) { BBFDM_ERR("Failed to allocate memory"); return UBUS_STATUS_UNKNOWN_ERROR; } - BBFDM_INFO("START: ubus method|%s|, name|%s|", method, obj->name); + BBFDM_INFO("START: ubus method|%s|, name|%s|, path|%s|, proto|%u|", method, obj->name, requested_path, requested_proto); - snprintf(context->requested_path, sizeof(context->requested_path), "%s", blobmsg_get_string(tb[BBFDM_PATH])); + snprintf(context->requested_path, sizeof(context->requested_path), "%s", requested_path); snprintf(context->ubus_method, sizeof(context->ubus_method), "%s", method); context->ubus_ctx = ctx; + context->raw_format = raw_format; memset(&context->tmp_bb, 0, sizeof(struct blob_buf)); blob_buf_init(&context->tmp_bb, 0); - fill_optional_input(tb[BBFDM_INPUT], &requested_proto, &context->raw_format); - ubus_defer_request(ctx, req, &context->request_data); list_for_each_entry(service, ®istered_services, list) { @@ -119,7 +184,7 @@ static int bbfdm_handler_async(struct ubus_context *ctx, struct ubus_object *obj if (service->is_blacklisted) continue; - if (!is_path_match(context->requested_path, requested_proto, service)) + if (!service_path_match(context->requested_path, requested_proto, service)) continue; run_async_call(context, service, msg); @@ -167,7 +232,7 @@ static int bbfdm_handler_sync(struct ubus_context *ctx, struct ubus_object *obj, if (service->is_blacklisted) continue; - if (!is_path_match(requested_path, requested_proto, service)) + if (!service_path_match(requested_path, requested_proto, service)) continue; run_sync_call(service->name, method, msg, &bb); diff --git a/bbfdmd/ubus/common.c b/bbfdmd/ubus/common.c index d0fba17b043f95a6c0bdb5976be691d89604e88c..701c26201c5c216d6fe6a21dcb325a7fde839c71 100644 --- a/bbfdmd/ubus/common.c +++ b/bbfdmd/ubus/common.c @@ -88,11 +88,40 @@ struct blob_attr *get_results_array(struct blob_attr *msg) return tb[0]; } -bool proto_matches(unsigned int dm_type, const enum bbfdmd_type_enum type) +bool str_match(const char *string, const char *pattern, size_t nmatch, regmatch_t pmatch[]) +{ + regex_t re; + + if (!string || !pattern) + return false; + + if (regcomp(&re, pattern, REG_EXTENDED) != 0) + return false; + + int status = regexec(&re, string, nmatch, pmatch, 0); + + regfree(&re); + + return (status != 0) ? false : true; +} + +bool proto_match(unsigned int dm_type, const enum bbfdmd_type_enum type) { return (dm_type == BBFDMD_BOTH || type == BBFDMD_BOTH || dm_type == type) && type != BBFDMD_NONE; } +void print_fault_message(struct blob_buf *blob_buf, const char *path, uint32_t fault_code, const char *fault_msg) +{ + if (!blob_buf || !path || !fault_msg) + return; + + void *table = blobmsg_open_table(blob_buf, NULL); + blobmsg_add_string(blob_buf, "path", path); + blobmsg_add_u32(blob_buf, "fault", fault_code); + blobmsg_add_string(blob_buf, "fault_msg", fault_msg); + blobmsg_close_table(blob_buf, table); +} + static void sync_callback(struct ubus_request *req, int type __attribute__((unused)), struct blob_attr *msg) { struct blob_attr *attr = NULL; diff --git a/bbfdmd/ubus/common.h b/bbfdmd/ubus/common.h index 3d20e8b0e9247364bb044cb2e0ad3df2d73dcdcd..ae074a5c8be0aa73f0f98f436cb26b65ecb5d54b 100644 --- a/bbfdmd/ubus/common.h +++ b/bbfdmd/ubus/common.h @@ -12,6 +12,7 @@ #ifndef BBFDMD_COMMON_H #define BBFDMD_COMMON_H +#include <regex.h> #include "libbbfdm-api/version-2/bbfdm_api.h" #define BBFDM_ROOT_OBJECT "Device." @@ -36,7 +37,10 @@ void fill_optional_input(struct blob_attr *msg, unsigned int *proto, bool *raw_f struct blob_attr *get_results_array(struct blob_attr *msg); -bool proto_matches(unsigned int dm_type, const enum bbfdmd_type_enum type); +bool str_match(const char *string, const char *pattern, size_t nmatch, regmatch_t pmatch[]); +bool proto_match(unsigned int dm_type, const enum bbfdmd_type_enum type); + +void print_fault_message(struct blob_buf *blob_buf, const char *path, uint32_t fault_code, const char *fault_msg); void run_sync_call(const char *ubus_obj, const char *ubus_method, struct blob_attr *msg, struct blob_buf *bb_response); diff --git a/bbfdmd/ubus/get.c b/bbfdmd/ubus/get.c index 854852e99194fb3613c06470132b7e058ebebbaf..92679d2b609d9a1f16a27d70fee8530d3d5a7840 100644 --- a/bbfdmd/ubus/get.c +++ b/bbfdmd/ubus/get.c @@ -21,9 +21,11 @@ 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) + struct linker_args *linker = (struct linker_args *)calloc(1, sizeof(struct linker_args)); + if (!linker) { + BBFDM_ERR("Failed to allocate memory"); return; + } list_add_tail(&linker->list, &ctx->linker_list); linker->path = strdup(linker_path ? linker_path : ""); @@ -218,11 +220,7 @@ static void prepare_and_send_response(struct async_request_context *ctx) void *array = blobmsg_open_array(&bb_raw, "results"); if (ctx->path_matched == false) { - void *table = blobmsg_open_table(&bb_raw, NULL); - blobmsg_add_string(&bb_raw, "path", ctx->requested_path); - blobmsg_add_u32(&bb_raw, "fault", 9005); - blobmsg_add_string(&bb_raw, "fault_msg", "Invalid parameter name"); - blobmsg_close_table(&bb_raw, table); + print_fault_message(&bb_raw, ctx->requested_path, 9005, "Invalid parameter name"); } else { blobmsg_for_each_attr(attr, ctx->tmp_bb.head, remaining) { if (strcmp(ctx->ubus_method, "get") == 0) { @@ -292,7 +290,7 @@ void send_response(struct async_request_context *ctx) ubus_complete_deferred_request(ctx->ubus_ctx, &ctx->request_data, UBUS_STATUS_OK); blob_buf_free(&ctx->tmp_bb); - BBFDM_INFO("END: ubus method|%s|, name|bbfdm|", ctx->ubus_method); + BBFDM_INFO("END: ubus method|%s|, name|bbfdm|, path|%s|", ctx->ubus_method, ctx->requested_path); BBFDM_FREE(ctx); } @@ -316,7 +314,7 @@ static void append_response_data(struct ubus_request_tracker *tracker, struct bl 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); + BBFDM_ERR("Timeout occurred for request: '%s %s'", tracker->request_name, tracker->ctx->requested_path); ubus_abort_request(tracker->ctx->ubus_ctx, &tracker->async_request); tracker->ctx->pending_requests--; @@ -344,7 +342,7 @@ static void ubus_result_callback(struct ubus_request *req, int type __attribute_ 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); + BBFDM_DEBUG("Response from object '%s %s'", tracker->request_name, tracker->ctx->requested_path); append_response_data(tracker, msg); } } @@ -352,7 +350,7 @@ static void ubus_result_callback(struct ubus_request *req, int type __attribute_ 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); + BBFDM_DEBUG("Request completed for '%s %s' with status: '%d'", tracker->request_name, tracker->ctx->requested_path, ret); uloop_timeout_cancel(&tracker->timeout); tracker->ctx->pending_requests--; @@ -385,7 +383,7 @@ void run_async_call(struct async_request_context *ctx, service_entry_t *service, return; } - struct ubus_request_tracker *tracker = calloc(1, sizeof(struct ubus_request_tracker)); + struct ubus_request_tracker *tracker = (struct ubus_request_tracker *)calloc(1, sizeof(struct ubus_request_tracker)); if (!tracker) { BBFDM_ERR("Failed to allocate memory for request tracker"); return; diff --git a/bbfdmd/ubus/pretty_print.c b/bbfdmd/ubus/pretty_print.c index caf61eaba168061d05611783453ed6aa2d5a7039..4da60b18e08f618446f03ec1de46220865f74a0b 100644 --- a/bbfdmd/ubus/pretty_print.c +++ b/bbfdmd/ubus/pretty_print.c @@ -9,7 +9,6 @@ * */ -#include <regex.h> #include <sys/param.h> #include <libubus.h> #include <libubox/blobmsg_json.h> @@ -81,23 +80,6 @@ static void free_pv_list(struct list_head *pv_list) } } -static bool match(const char *string, const char *pattern, size_t nmatch, regmatch_t pmatch[]) -{ - regex_t re; - - if (!string || !pattern) - return 0; - - if (regcomp(&re, pattern, REG_EXTENDED) != 0) - return 0; - - int status = regexec(&re, string, nmatch, pmatch, 0); - - regfree(&re); - - return (status != 0) ? false : true; -} - static bool is_node_instance(const char *path) { if (!path) @@ -473,7 +455,7 @@ static void prepare_result_blob(struct blob_buf *bb, struct list_head *pv_list) static bool is_res_required(const char *str, size_t s_len, size_t *start, size_t *len) { - if (match(str, GLOB_CHAR, 0, NULL)) { + if (str_match(str, GLOB_CHAR, 0, NULL)) { char *star = strchr(str, '*'); *start = (star) ? (size_t)labs(star - str) : s_len; diff --git a/bbfdmd/ubus/service.c b/bbfdmd/ubus/service.c index 51129b5e847ae78a9d149c42c01bc51b66543cfa..c5904f48c792eb42a58e7ef484ddbae4f0b7ad49 100644 --- a/bbfdmd/ubus/service.c +++ b/bbfdmd/ubus/service.c @@ -22,9 +22,7 @@ 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) +static void add_service_to_list(const char *name, struct blob_buf *dm_schema, int service_proto, service_object_t *objects, size_t count, bool is_unified) { service_entry_t *service = NULL; @@ -33,16 +31,83 @@ static void add_service_to_list(const char *name, int service_proto, service_obj return; } - service = calloc(1, sizeof(service_entry_t)); + service = (service_entry_t *)calloc(1, sizeof(service_entry_t)); + if (!service) { + BBFDM_ERR("Failed to allocate memory"); + return; + } + list_add_tail(&service->list, ®istered_services); service->name = strdup(name); + service->dm_schema = dm_schema; service->protocol = service_proto; service->objects = objects; service->object_count = count; service->is_unified = is_unified; } +static void receive_schema_result(struct ubus_request *req, int type __attribute__((unused)), struct blob_attr *msg) +{ + struct blob_attr *attr = NULL; + int remaining = 0; + + if (msg == NULL || req == NULL) + return; + + struct blob_buf *srv_schema = (struct blob_buf *)req->priv; + if (!srv_schema) + return; + + struct blob_attr *results = get_results_array(msg); + if (!results) + return; + + blobmsg_for_each_attr(attr, results, remaining) { + blobmsg_add_blob(srv_schema, attr); + } +} + +void fill_service_schema(struct ubus_context *ubus_ctx, int ubus_timeout, const char *service_name, struct blob_buf **service_schema) +{ + uint32_t ubus_id; + + if (!ubus_ctx || !service_name || !service_schema) + return; + + if (*service_schema != NULL) { + blob_buf_free(*service_schema); + BBFDM_FREE(*service_schema); + } + + if (!ubus_lookup_id(ubus_ctx, service_name, &ubus_id)) { + struct blob_buf bb = {0}; + + *service_schema = (struct blob_buf *)calloc(1, sizeof(struct blob_buf)); + if (*service_schema == NULL) { + BBFDM_ERR("Failed to allocate memory"); + return; + } + + blob_buf_init(*service_schema, 0); + + memset(&bb, 0, sizeof(struct blob_buf)); + blob_buf_init(&bb, 0); + + blobmsg_add_string(&bb, "path", BBFDM_ROOT_OBJECT); + + int err = ubus_invoke(ubus_ctx, ubus_id, "schema", bb.head, receive_schema_result, (void *)*service_schema, ubus_timeout); + + if (err != 0) { + BBFDM_ERR("UBUS invoke failed [object: %s, method: schema] with error (%d)", service_name, err); + } + + blob_buf_free(&bb); + } else { + BBFDM_WARNING("Failed to lookup UBUS object: %s", service_name); + } +} + static int load_service_from_file(struct ubus_context *ubus_ctx, const char *filename, const char *file_path) { size_t num_objs = 0; @@ -75,13 +140,11 @@ static int load_service_from_file(struct ubus_context *ubus_ctx, const char *fil return -1; } + struct blob_buf *service_schema = NULL; 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_WARNING("Failed to lookup UBUS object: %s", service_name); - } + snprintf(service_name, sizeof(service_name), "%s.%.*s", BBFDM_UBUS_OBJECT, (int)(strlen(filename) - 5), filename); + fill_service_schema(ubus_ctx, 2000, service_name, &service_schema); json_object *unified_daemon_jobj = NULL; json_object_object_get_ex(daemon_config, "unified_daemon", &unified_daemon_jobj); @@ -104,7 +167,12 @@ static int load_service_from_file(struct ubus_context *ubus_ctx, const char *fil return -1; } - service_object_t *objects = calloc(service_count, sizeof(service_object_t)); + service_object_t *objects = (service_object_t *)calloc(service_count, sizeof(service_object_t)); + if (!objects) { + BBFDM_ERR("Failed to allocate memory"); + json_object_put(json_root); + return -1; + } for (size_t i = 0; i < service_count; i++) { json_object *service_obj = json_object_array_get_idx(services_array, i); @@ -127,7 +195,7 @@ static int load_service_from_file(struct ubus_context *ubus_ctx, const char *fil } 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); + add_service_to_list(service_name, service_schema, service_proto, objects, num_objs, is_unified); json_object_put(json_root); return 0; } @@ -184,6 +252,12 @@ void unregister_services(void) list_for_each_entry_safe(service, tmp, ®istered_services, list) { list_del(&service->list); + + if (service->dm_schema) { + blob_buf_free(service->dm_schema); + BBFDM_FREE(service->dm_schema); + } + BBFDM_FREE(service->name); BBFDM_FREE(service->objects); BBFDM_FREE(service); @@ -236,9 +310,9 @@ void list_registered_services(struct blob_buf *bb) blobmsg_close_array(bb, array); } -bool is_path_match(const char *requested_path, unsigned int requested_proto, service_entry_t *service) +bool service_path_match(const char *requested_path, unsigned int requested_proto, service_entry_t *service) { - if (!proto_matches(requested_proto, service->protocol)) + if (!proto_match(requested_proto, service->protocol)) return false; if (strlen(requested_path) == 0 || strcmp(requested_path, BBFDM_ROOT_OBJECT) == 0) @@ -250,7 +324,7 @@ bool is_path_match(const char *requested_path, unsigned int requested_proto, ser 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)) + if (!proto_match(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); diff --git a/bbfdmd/ubus/service.h b/bbfdmd/ubus/service.h index db1decff8a3405ace7cc82949af9c7a91c3f4774..eed9cfbb450af4b26f56f55d3c6f8d41dfac1a7a 100644 --- a/bbfdmd/ubus/service.h +++ b/bbfdmd/ubus/service.h @@ -20,6 +20,7 @@ typedef struct { typedef struct service_entry { struct list_head list; + struct blob_buf *dm_schema; char *name; enum bbfdmd_type_enum protocol; bool is_unified; @@ -32,7 +33,8 @@ typedef struct service_entry { int register_services(struct ubus_context *ctx); void unregister_services(void); void list_registered_services(struct blob_buf *bb); +void fill_service_schema(struct ubus_context *ubus_ctx, int ubus_timeout, const char *service_name, struct blob_buf **service_schema); -bool is_path_match(const char *requested_path, unsigned int requested_proto, service_entry_t *service); +bool service_path_match(const char *requested_path, unsigned int requested_proto, service_entry_t *service); #endif /* BBFDMD_SERVICE_H */