D-Bus spec mandates that GetManagedObjects method of org.freedesktop.DBus.ObjectManager interface returns *children* only: https://dbus.freedesktop.org/doc/dbus-specification.html > All returned object paths are children of the object path implementing > this interface, i.e. their object paths start with the ObjectManager's > object path plus '/' Both test scripts and ELL abuse this by returning application interfaces via ObjectManager attached to the same path, but other D-Bus implementations do not, making Attach() fail because mandatory interfaces cannot be found. This patch fixes the issue by scanning hierarchy returned by GetManagedObjects for object implementing org.bluez.mesh.Application1 interface and keeping that as node's app_path. --- doc/mesh-api.txt | 52 ++++++++++++++++++++++++++---------------------- mesh/node.c | 22 +++++++++++--------- mesh/node.h | 8 ++++---- 3 files changed, 45 insertions(+), 37 deletions(-) diff --git a/doc/mesh-api.txt b/doc/mesh-api.txt index 30b7452e2..ebff8492a 100644 --- a/doc/mesh-api.txt +++ b/doc/mesh-api.txt @@ -8,13 +8,13 @@ Interface org.bluez.mesh.Network1 Object path /org/bluez/mesh Methods: - void Join(object app_defined_root, array{byte}[16] uuid) + void Join(object app_root, array{byte}[16] uuid) This is the first method that an application has to call to become a provisioned node on a mesh network. The call will initiate broadcasting of Unprovisioned Device Beacon. - The app_defined_root parameter is a D-Bus object root path of + The app_root parameter is a D-Bus object root path of the application that implements org.bluez.mesh.Application1 interface. The application represents a node where child mesh elements have their own objects that implement @@ -22,7 +22,7 @@ Methods: also contains a provision agent object that implements org.bluez.mesh.ProvisionAgent1 interface. The standard DBus.ObjectManager interface must be available on the - app_defined_root path. + app_root path. The uuid parameter is a 16-byte array that contains Device UUID. This UUID must be unique (at least from the daemon perspective), @@ -39,18 +39,18 @@ Methods: method. object node, array{byte, array{(uint16, dict)}} configuration - Attach(object app_defined_root, uint64 token) + Attach(object app_root, uint64 token) This is the first method that an application must call to get access to mesh node functionalities. - The app_defined_root parameter is a D-Bus object root path of + The app_root parameter is a D-Bus object root path of the application that implements org.bluez.mesh.Application1 interface. The application represents a node where child mesh elements have their own objects that implement org.bluez.mesh.Element1 interface. The standard DBus.ObjectManager interface must be available on the - app_defined_root path. + app_root path. The token parameter is a 64-bit number that has been assigned to the application when it first got provisioned/joined mesh @@ -701,30 +701,34 @@ Mesh Application Hierarchy ========================== Service unique name Interface org.bluez.mesh.Application1 -Object path <app_defined_root> +Object path <app_root> An application is a collection of elements that host SIG defined and vendor specific models. It is expected that an application implements -org.freedesktop.DBus.ObjectManager interface. +org.freedesktop.DBus.ObjectManager interface at app_root path. An example mesh application hierarchy may look like this: - -> /com/example - | - org.freedesktop.DBus.ObjectManager - | - org.bluez.mesh.Application1 - | - org.bluez.mesh.Attention1 (optional) - | - org.bluez.mesh.Provisioner1 (optional,Provisioner) - | - -> /com/example/agent - | | - org.bluez.mesh.ProvisionAgent1 - | - -> /com/example/ele00 - | | - org.bluez.mesh.Element1 - -> /com/example/ele01 - | | - org.bluez.mesh.Element1 - ... - -> /com/example/elexx - | | - org.bluez.mesh.Element1 +-> /com/example + | - org.freedesktop.DBus.ObjectManager + | + -> /com/example/application + | - org.bluez.mesh.Application1 + | - org.bluez.mesh.Attention1 (optional) + | - org.bluez.mesh.Provisioner1 (optional,Provisioner) + | + -> /com/example/agent + | - org.bluez.mesh.ProvisionAgent1 + | + -> /com/example/ele00 + | - org.bluez.mesh.Element1 + | + -> /com/example/ele01 + | - org.bluez.mesh.Element1 + | + ... + -> /com/example/elexx + - org.bluez.mesh.Element1 Methods: void JoinComplete(uint64 token) diff --git a/mesh/node.c b/mesh/node.c index c8a1dae78..28afe608f 100644 --- a/mesh/node.c +++ b/mesh/node.c @@ -1522,6 +1522,11 @@ static void get_managed_objects_cb(struct l_dbus_message *msg, void *user_data) goto fail; } else if (!strcmp(MESH_APPLICATION_INTERFACE, interface)) { + if (have_app) + goto fail; + + req->node->app_path = l_strdup(path); + res = get_app_properties(node, path, &properties); if (!res) @@ -1665,7 +1670,7 @@ fail: } /* Establish relationship between application and mesh node */ -int node_attach(const char *app_path, const char *sender, uint64_t token, +int node_attach(const char *app_root, const char *sender, uint64_t token, node_ready_func_t cb, void *user_data) { struct managed_obj_request *req; @@ -1688,14 +1693,13 @@ int node_attach(const char *app_path, const char *sender, uint64_t token, * application. Existing node is passed in req->attach. */ req->node = node_new(node->uuid); - req->node->app_path = l_strdup(app_path); req->node->owner = l_strdup(sender); req->ready_cb = cb; req->pending_msg = user_data; req->attach = node; req->type = REQUEST_TYPE_ATTACH; - l_dbus_method_call(dbus_get_bus(), sender, app_path, + l_dbus_method_call(dbus_get_bus(), sender, app_root, L_DBUS_INTERFACE_OBJECT_MANAGER, "GetManagedObjects", NULL, get_managed_objects_cb, @@ -1706,7 +1710,7 @@ int node_attach(const char *app_path, const char *sender, uint64_t token, /* Create a temporary pre-provisioned node */ -void node_join(const char *app_path, const char *sender, const uint8_t *uuid, +void node_join(const char *app_root, const char *sender, const uint8_t *uuid, node_join_ready_func_t cb) { struct managed_obj_request *req; @@ -1718,14 +1722,14 @@ void node_join(const char *app_path, const char *sender, const uint8_t *uuid, req->join_ready_cb = cb; req->type = REQUEST_TYPE_JOIN; - l_dbus_method_call(dbus_get_bus(), sender, app_path, + l_dbus_method_call(dbus_get_bus(), sender, app_root, L_DBUS_INTERFACE_OBJECT_MANAGER, "GetManagedObjects", NULL, get_managed_objects_cb, req, l_free); } -bool node_import(const char *app_path, const char *sender, const uint8_t *uuid, +bool node_import(const char *app_root, const char *sender, const uint8_t *uuid, const uint8_t dev_key[16], const uint8_t net_key[16], uint16_t net_idx, bool kr, bool ivu, uint32_t iv_index, uint16_t unicast, @@ -1752,7 +1756,7 @@ bool node_import(const char *app_path, const char *sender, const uint8_t *uuid, req->type = REQUEST_TYPE_IMPORT; - l_dbus_method_call(dbus_get_bus(), sender, app_path, + l_dbus_method_call(dbus_get_bus(), sender, app_root, L_DBUS_INTERFACE_OBJECT_MANAGER, "GetManagedObjects", NULL, get_managed_objects_cb, @@ -1760,7 +1764,7 @@ bool node_import(const char *app_path, const char *sender, const uint8_t *uuid, return true; } -void node_create(const char *app_path, const char *sender, const uint8_t *uuid, +void node_create(const char *app_root, const char *sender, const uint8_t *uuid, node_ready_func_t cb, void *user_data) { struct managed_obj_request *req; @@ -1773,7 +1777,7 @@ void node_create(const char *app_path, const char *sender, const uint8_t *uuid, req->pending_msg = user_data; req->type = REQUEST_TYPE_CREATE; - l_dbus_method_call(dbus_get_bus(), sender, app_path, + l_dbus_method_call(dbus_get_bus(), sender, app_root, L_DBUS_INTERFACE_OBJECT_MANAGER, "GetManagedObjects", NULL, get_managed_objects_cb, diff --git a/mesh/node.h b/mesh/node.h index 7448756ae..c718c038d 100644 --- a/mesh/node.h +++ b/mesh/node.h @@ -31,7 +31,7 @@ typedef void (*node_join_ready_func_t) (struct mesh_node *node, struct mesh_agent *agent); void node_remove(struct mesh_node *node); -void node_join(const char *app_path, const char *sender, const uint8_t *uuid, +void node_join(const char *app_root, const char *sender, const uint8_t *uuid, node_join_ready_func_t cb); uint8_t *node_uuid_get(struct mesh_node *node); struct mesh_net *node_get_net(struct mesh_node *node); @@ -82,13 +82,13 @@ const char *node_get_app_path(struct mesh_node *node); bool node_add_pending_local(struct mesh_node *node, void *info); void node_attach_io_all(struct mesh_io *io); void node_attach_io(struct mesh_node *node, struct mesh_io *io); -int node_attach(const char *app_path, const char *sender, uint64_t token, +int node_attach(const char *app_root, const char *sender, uint64_t token, node_ready_func_t cb, void *user_data); void node_build_attach_reply(struct mesh_node *node, struct l_dbus_message *reply); -void node_create(const char *app_path, const char *sender, const uint8_t *uuid, +void node_create(const char *app_root, const char *sender, const uint8_t *uuid, node_ready_func_t cb, void *user_data); -bool node_import(const char *app_path, const char *sender, const uint8_t *uuid, +bool node_import(const char *app_root, const char *sender, const uint8_t *uuid, const uint8_t dev_key[16], const uint8_t net_key[16], uint16_t net_idx, bool kr, bool ivu, uint32_t iv_index, uint16_t unicast, -- 2.19.1