diff --git a/mesh/mesh-defs.h b/mesh/mesh-defs.h
index c30041e..131b350 100644
--- a/mesh/mesh-defs.h
+++ b/mesh/mesh-defs.h
#define VENDOR_ID_MASK 0xffff0000
#define MAX_KEY_IDX 0x0fff
+#define MAX_MODEL_COUNT 0xff
+#define MAX_ELE_COUNT 0xff
#define IS_UNASSIGNED(x) ((x) == UNASSIGNED_ADDRESS)
#define IS_UNICAST(x) (((x) > UNASSIGNED_ADDRESS) && \
diff --git a/mesh/node.c b/mesh/node.c
index 0c2fc72..774d03d 100644
--- a/mesh/node.c
+++ b/mesh/node.c
#define DEFAULT_CRPL 10
#define DEFAULT_SEQUENCE_NUMBER 0
+#define REQUEST_TYPE_JOIN 0
+#define REQUEST_TYPE_ATTACH 1
+
struct node_element {
char *path;
struct l_queue *models;
uint8_t beacon;
};
-struct attach_obj_request {
- node_ready_func_t cb;
- struct mesh_node *node;
+struct managed_obj_request {
+ void *data;
+ void *cb;
void *user_data;
-};
-
-struct join_obj_request {
- node_join_ready_func_t cb;
- const uint8_t *uuid;
+ uint8_t type;
};
static struct l_queue *nodes;
l_queue_foreach(nodes, attach_io, io);
}
+/* Register node object with D-Bus */
static bool register_node_object(struct mesh_node *node)
{
node->path = l_malloc(strlen(MESH_NODE_PATH_PREFIX) + 5);
while (l_dbus_message_iter_next_entry(&ids, &vendor_id,
&mod_id)) {
struct mesh_model *mod;
-
mod = l_queue_find(ele->models, match_model_id,
L_UINT_TO_PTR((vendor_id << 16) | mod_id));
if (!mod)
static bool get_element_properties(struct mesh_node *node, const char *path,
struct l_dbus_message_iter *properties,
- bool create_new)
+ bool is_new)
{
struct node_element *ele;
const char *key;
return false;
}
- if (!create_new) {
+ if (!is_new) {
/* Validate composition: check the element index */
ele = l_queue_find(node->elements, match_element_idx,
L_UINT_TO_PTR(idx));
l_dbus_message_iter_get_variant(&var, "q", &loc);
/* Validate composition: location match */
- if (!create_new && (ele->location != loc))
+ if (!is_new && (ele->location != loc))
return false;
ele->location = loc;
} else if (!strcmp(key, "Models")) {
- if (create_new)
+ if (is_new)
get_models_from_properties(ele, &var, false);
else if (!validate_model_property(ele, &var, &mod_cnt,
false))
} else if (!strcmp(key, "VendorModels")) {
- if (create_new)
+ if (is_new)
get_models_from_properties(ele, &var, true);
else if (!validate_model_property(ele, &var,
&vendor_cnt, true))
return false;
+
}
}
- if (create_new) {
+ if (is_new) {
l_queue_push_tail(node->elements, ele);
} else {
/* Account for internal Configuration Server model */
return true;
}
-static void get_managed_objects_attach_cb(struct l_dbus_message *msg,
- void *user_data)
-{
- struct l_dbus_message_iter objects, interfaces;
- struct attach_obj_request *req = user_data;
- struct mesh_node *node = req->node;
- const char *path;
- uint8_t num_ele;
-
- if (l_dbus_message_is_error(msg)) {
- l_error("Failed to get app's dbus objects");
- goto fail;
- }
-
- if (!l_dbus_message_get_arguments(msg, "a{oa{sa{sv}}}", &objects)) {
- l_error("Failed to parse app's dbus objects");
- goto fail;
- }
-
- num_ele = 0;
-
- while (l_dbus_message_iter_next_entry(&objects, &path, &interfaces)) {
- struct l_dbus_message_iter properties;
- const char *interface;
-
- while (l_dbus_message_iter_next_entry(&interfaces, &interface,
- &properties)) {
- if (strcmp(MESH_ELEMENT_INTERFACE, interface))
- continue;
-
- if (!get_element_properties(node, path, &properties,
- false))
- goto fail;
-
- num_ele++;
- }
- }
-
- /*
- * Check that the number of element objects matches the expected number
- * of elements on the node
- */
- if (num_ele != node->num_ele)
- goto fail;
-
- /* Register node object with D-Bus */
- register_node_object(node);
-
- if (node->path) {
- struct l_dbus *bus = dbus_get_bus();
-
- node->disc_watch = l_dbus_add_disconnect_watch(bus, node->owner,
- app_disc_cb, node, NULL);
- req->cb(req->user_data, MESH_ERROR_NONE, node);
-
- return;
- }
-fail:
- req->cb(req->user_data, MESH_ERROR_FAILED, NULL);
-
- l_queue_foreach(node->elements, free_element_path, NULL);
- l_free(node->app_path);
- node->app_path = NULL;
-
- l_free(node->owner);
- node->owner = NULL;
-}
-
-/* Establish relationship between application and mesh node */
-int node_attach(const char *app_path, const char *sender, uint64_t token,
- node_ready_func_t cb, void *user_data)
-{
- struct attach_obj_request *req;
- struct mesh_node *node;
-
- node = l_queue_find(nodes, match_token, (void *) &token);
- if (!node)
- return MESH_ERROR_NOT_FOUND;
-
- /* Check if the node is already in use */
- if (node->owner) {
- l_warn("The node is already in use");
- return MESH_ERROR_ALREADY_EXISTS;
- }
-
- node->app_path = l_strdup(app_path);
- node->owner = l_strdup(sender);
-
- req = l_new(struct attach_obj_request, 1);
- req->node = node;
- req->cb = cb;
- req->user_data = user_data;
-
- l_dbus_method_call(dbus_get_bus(), sender, app_path,
- L_DBUS_INTERFACE_OBJECT_MANAGER,
- "GetManagedObjects", NULL,
- get_managed_objects_attach_cb,
- req, l_free);
- return MESH_ERROR_NONE;
-
-}
-
-static bool get_app_properties(struct mesh_node *node, const char *path,
- struct l_dbus_message_iter *properties)
-{
- const char *key;
- struct l_dbus_message_iter variant;
-
- l_debug("path %s", path);
-
- if (!node->comp)
- node->comp = l_new(struct node_composition, 1);
-
- while (l_dbus_message_iter_next_entry(properties, &key, &variant)) {
-
- if (!strcmp(key, "CompanyID")) {
- if (!l_dbus_message_iter_get_variant(&variant, "q",
- &node->comp->cid))
- return false;
- } else if (!strcmp(key, "ProductID")) {
- if (!l_dbus_message_iter_get_variant(&variant, "q",
- &node->comp->pid))
- return false;
- } else if (!strcmp(key, "VersionID")) {
- if (!l_dbus_message_iter_get_variant(&variant, "q",
- &node->comp->vid))
- return false;
- }
- }
-
- return true;
-}
-
static void convert_node_to_storage(struct mesh_node *node,
struct mesh_db_node *db_node)
{
add_internal_model(node, CONFIG_SRV_MODEL, PRIMARY_ELE_IDX);
}
-static void get_managed_objects_join_cb(struct l_dbus_message *msg,
- void *user_data)
+static bool get_app_properties(struct mesh_node *node, const char *path,
+ struct l_dbus_message_iter *properties,
+ bool is_new)
+{
+ const char *key;
+ struct l_dbus_message_iter variant;
+ uint16_t value;
+
+ l_debug("path %s", path);
+
+ if (is_new)
+ node->comp = l_new(struct node_composition, 1);
+
+ while (l_dbus_message_iter_next_entry(properties, &key, &variant)) {
+
+ if (!strcmp(key, "CompanyID")) {
+ if (!l_dbus_message_iter_get_variant(&variant, "q",
+ &value))
+ return false;
+
+ if (!is_new && node->comp->cid != value)
+ return false;
+
+ node->comp->cid = value;
+
+ } else if (!strcmp(key, "ProductID")) {
+ if (!l_dbus_message_iter_get_variant(&variant, "q",
+ &value))
+ return false;
+
+ if (!is_new && node->comp->pid != value)
+ return false;
+
+ node->comp->pid = value;
+
+ } else if (!strcmp(key, "VersionID")) {
+ if (!l_dbus_message_iter_get_variant(&variant, "q",
+ &value))
+ return false;
+
+ if (!is_new && node->comp->vid != value)
+ return false;
+
+ node->comp->vid = value;
+ }
+ }
+
+ return true;
+}
+
+static void get_managed_objects_cb(struct l_dbus_message *msg, void *user_data)
{
struct l_dbus_message_iter objects, interfaces;
- struct join_obj_request *req = user_data;
+ struct managed_obj_request *req = user_data;
const char *path;
struct mesh_node *node = NULL;
void *agent = NULL;
+ bool have_app = false;
+ bool is_new;
+ uint8_t num_ele;
if (l_dbus_message_is_error(msg)) {
l_error("Failed to get app's dbus objects");
goto fail;
}
- node = l_new(struct mesh_node, 1);
- node->elements = l_queue_new();
+ is_new = (req->type != REQUEST_TYPE_ATTACH);
+
+ if (is_new) {
+ node = l_new(struct mesh_node, 1);
+ node->elements = l_queue_new();
+ } else {
+ node = req->data;
+ }
+
+ num_ele = 0;
while (l_dbus_message_iter_next_entry(&objects, &path, &interfaces)) {
struct l_dbus_message_iter properties;
bool res;
if (!strcmp(MESH_ELEMENT_INTERFACE, interface)) {
+
+ if (num_ele == MAX_ELE_COUNT)
+ goto fail;
+
res = get_element_properties(node, path,
- &properties, true);
+ &properties, is_new);
if (!res)
goto fail;
- node->num_ele++;
- continue;
-
- }
+ num_ele++;
- if (!strcmp(MESH_APPLICATION_INTERFACE, interface)) {
+ } else if (!strcmp(MESH_APPLICATION_INTERFACE,
+ interface)) {
res = get_app_properties(node, path,
- &properties);
+ &properties, is_new);
if (!res)
goto fail;
- continue;
- }
+ have_app = true;
- if (!strcmp(MESH_PROVISION_AGENT_INTERFACE,
+ } else if (!strcmp(MESH_PROVISION_AGENT_INTERFACE,
interface)) {
const char *sender;
}
}
- if (!node->comp){
+ if (!have_app) {
l_error("Interface %s not found", MESH_APPLICATION_INTERFACE);
goto fail;
}
- if (!agent) {
- l_error("Interface %s not found",
- MESH_PROVISION_AGENT_INTERFACE);
- goto fail;
- }
-
- if (!node->num_ele) {
+ if (num_ele == 0) {
l_error("Interface %s not found", MESH_ELEMENT_INTERFACE);
goto fail;
}
goto fail;
}
- set_defaults(node);
- memcpy(node->dev_uuid, req->uuid, 16);
+ if (req->type == REQUEST_TYPE_JOIN) {
+ node_join_ready_func_t cb = req->cb;
- if (!create_node_config(node))
- goto fail;
+ if (!agent) {
+ l_error("Interface %s not found",
+ MESH_PROVISION_AGENT_INTERFACE);
+ goto fail;
+ }
+ node->num_ele = num_ele;
+ set_defaults(node);
+ memcpy(node->dev_uuid, req->data, 16);
+
+ if (!create_node_config(node))
+ goto fail;
+
+ cb(node, agent);
+ } else {
+ node_ready_func_t cb = req->cb;
+
+ if (num_ele != node->num_ele)
+ goto fail;
+
+ if (register_node_object(node)) {
+ struct l_dbus *bus = dbus_get_bus();
- req->cb(node, agent);
+ node->disc_watch = l_dbus_add_disconnect_watch(bus,
+ node->owner, app_disc_cb, node, NULL);
+ cb(req->user_data, MESH_ERROR_NONE, node);
+ } else
+ goto fail;
+ }
return;
fail:
if (agent)
mesh_agent_remove(agent);
- if (node)
+ if (is_new && node)
free_node_resources(node);
- req->cb(NULL, NULL);
+ if (req->type == REQUEST_TYPE_JOIN) {
+ node_join_ready_func_t cb = req->cb;
+
+ cb(NULL, NULL);
+
+ } else {
+ node_ready_func_t cb = req->cb;
+
+ l_queue_foreach(node->elements, free_element_path, NULL);
+ l_free(node->app_path);
+ node->app_path = NULL;
+
+ l_free(node->owner);
+ node->owner = NULL;
+ cb(req->user_data, MESH_ERROR_FAILED, node);
+ }
+}
+
+/* Establish relationship between application and mesh node */
+int node_attach(const char *app_path, const char *sender, uint64_t token,
+ node_ready_func_t cb, void *user_data)
+{
+ struct managed_obj_request *req;
+ struct mesh_node *node;
+
+ node = l_queue_find(nodes, match_token, (void *) &token);
+ if (!node)
+ return MESH_ERROR_NOT_FOUND;
+
+ /* Check if the node is already in use */
+ if (node->owner) {
+ l_warn("The node is already in use");
+ return MESH_ERROR_ALREADY_EXISTS;
+ }
+
+ node->app_path = l_strdup(app_path);
+ node->owner = l_strdup(sender);
+
+ req = l_new(struct managed_obj_request, 1);
+ req->data = node;
+ req->cb = cb;
+ req->user_data = user_data;
+ req->type = REQUEST_TYPE_ATTACH;
+
+ l_dbus_method_call(dbus_get_bus(), sender, app_path,
+ L_DBUS_INTERFACE_OBJECT_MANAGER,
+ "GetManagedObjects", NULL,
+ get_managed_objects_cb,
+ req, l_free);
+ return MESH_ERROR_NONE;
+
}
+
/* Create a temporary pre-provisioned node */
void node_join(const char *app_path, const char *sender, const uint8_t *uuid,
node_join_ready_func_t cb)
{
- struct join_obj_request *req;
+ struct managed_obj_request *req;
l_debug("");
- req = l_new(struct join_obj_request, 1);
- req->uuid = uuid;
+ req = l_new(struct managed_obj_request, 1);
+ req->data = (void *) uuid;
req->cb = cb;
+ req->type = REQUEST_TYPE_JOIN;
l_dbus_method_call(dbus_get_bus(), sender, app_path,
L_DBUS_INTERFACE_OBJECT_MANAGER,
"GetManagedObjects", NULL,
- get_managed_objects_join_cb,
+ get_managed_objects_cb,
req, l_free);
}