Applied, Thanks On Tue, 2019-12-17 at 15:54 +0100, Michał Lowas-Rzechonek wrote: > 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,