mesh: Refresh provisioner's capabilities 74/229674/1
authorMichał Lowas-Rzechonek <michal.lowas-rzechonek@silvair.com>
Wed, 1 Apr 2020 10:25:00 +0000 (12:25 +0200)
committerAnupam Roy <anupam.r@samsung.com>
Wed, 1 Apr 2020 21:02:59 +0000 (02:32 +0530)
As provisioner's capabilities might change during application lifetime
(e.g. no network link to download OOB key), let's query the agent again
after application calls AddNode().

Change-Id: I29cbff53383fec85bc9eba00e6729defcd423ce4
Signed-off-by: Anupam Roy <anupam.r@samsung.com>
mesh/agent.c
mesh/agent.h
mesh/manager.c
mesh/prov-initiator.c
mesh/provision.h

index 3ab3893..26ccc3e 100644 (file)
@@ -40,7 +40,8 @@ typedef enum {
        MESH_AGENT_REQUEST_IN_ALPHA,
        MESH_AGENT_REQUEST_STATIC_OOB,
        MESH_AGENT_REQUEST_PRIVATE_KEY,
-       MESH_AGENT_REQUEST_PUBLIC_KEY
+       MESH_AGENT_REQUEST_PUBLIC_KEY,
+       MESH_AGENT_REQUEST_CAPABILITIES,
 } agent_request_type_t;
 
 struct agent_request {
@@ -158,6 +159,25 @@ static void parse_oob_info(struct mesh_agent_prov_caps *caps,
        }
 }
 
+static void parse_properties(struct mesh_agent *agent,
+                                       struct l_dbus_message_iter *properties)
+{
+       const char *key, *uri_string;
+       struct l_dbus_message_iter variant;
+
+       while (l_dbus_message_iter_next_entry(properties, &key, &variant)) {
+               if (!strcmp(key, "Capabilities")) {
+                       parse_prov_caps(&agent->caps, &variant);
+               } else if (!strcmp(key, "URI")) {
+                       l_dbus_message_iter_get_variant(&variant, "s",
+                                                               &uri_string);
+                       /* TODO: compute hash */
+               } else if (!strcmp(key, "OutOfBandInfo")) {
+                       parse_oob_info(&agent->caps, &variant);
+               }
+       }
+}
+
 static void agent_free(void *agent_data)
 {
        struct mesh_agent *agent = agent_data;
@@ -193,6 +213,7 @@ static void agent_free(void *agent_data)
                case MESH_AGENT_REQUEST_VIBRATE:
                case MESH_AGENT_REQUEST_OUT_NUMERIC:
                case MESH_AGENT_REQUEST_OUT_ALPHA:
+               case MESH_AGENT_REQUEST_CAPABILITIES:
                        simple_cb = agent->req->cb;
                        simple_cb(req->user_data, err);
                default:
@@ -235,26 +256,13 @@ struct mesh_agent *mesh_agent_create(const char *path, const char *owner,
                                        struct l_dbus_message_iter *properties)
 {
        struct mesh_agent *agent;
-       const char *key, *uri_string;
-       struct l_dbus_message_iter variant;
 
        agent = l_new(struct mesh_agent, 1);
-
-       while (l_dbus_message_iter_next_entry(properties, &key, &variant)) {
-               if (!strcmp(key, "Capabilities")) {
-                       parse_prov_caps(&agent->caps, &variant);
-               } else if (!strcmp(key, "URI")) {
-                       l_dbus_message_iter_get_variant(&variant, "s",
-                                                               &uri_string);
-                       /* TODO: compute hash */
-               } else if (!strcmp(key, "OutOfBandInfo")) {
-                       parse_oob_info(&agent->caps, &variant);
-               }
-       }
-
        agent->owner = l_strdup(owner);
        agent->path = l_strdup(path);
 
+       parse_properties(agent, properties);
+
        l_queue_push_tail(agents, agent);
 
        return agent;
@@ -289,13 +297,75 @@ static int get_reply_error(struct l_dbus_message *reply)
        if (l_dbus_message_is_error(reply)) {
 
                l_dbus_message_get_error(reply, &name, &desc);
-               l_error("Agent failed output action (%s), %s", name, desc);
+               l_error("Agent failed (%s), %s", name, desc);
                return MESH_ERROR_FAILED;
        }
 
        return MESH_ERROR_NONE;
 }
 
+static void properties_reply(struct l_dbus_message *reply, void *user_data)
+{
+       struct mesh_agent *agent = user_data;
+       struct agent_request *req;
+       mesh_agent_cb_t cb;
+       struct l_dbus_message_iter properties;
+       int err;
+
+       if (!l_queue_find(agents, simple_match, agent) || !agent->req)
+               return;
+
+       req = agent->req;
+
+       err = get_reply_error(reply);
+
+       if (err != MESH_ERROR_NONE)
+               goto fail;
+
+       if (!l_dbus_message_get_arguments(reply, "a{sv}", &properties)) {
+               err = MESH_ERROR_FAILED;
+               goto fail;
+       }
+
+       parse_properties(agent, &properties);
+fail:
+       if (req->cb) {
+               cb = req->cb;
+               cb(req->user_data, err);
+       }
+
+       l_dbus_message_unref(req->msg);
+       l_free(req);
+       agent->req = NULL;
+}
+
+void mesh_agent_refresh(struct mesh_agent *agent, mesh_agent_cb_t cb,
+                                                       void *user_data)
+{
+       struct l_dbus *dbus = dbus_get_bus();
+       struct l_dbus_message *msg;
+       struct l_dbus_message_builder *builder;
+
+       agent->req = create_request(MESH_AGENT_REQUEST_CAPABILITIES, (void *)cb,
+                                                               user_data);
+
+       msg = l_dbus_message_new_method_call(dbus, agent->owner, agent->path,
+                                               L_DBUS_INTERFACE_PROPERTIES,
+                                               "GetAll");
+
+       builder = l_dbus_message_builder_new(msg);
+       l_dbus_message_builder_append_basic(builder, 's',
+                                               MESH_PROVISION_AGENT_INTERFACE);
+       l_dbus_message_builder_finalize(builder);
+       l_dbus_message_builder_destroy(builder);
+
+       l_dbus_send_with_reply(dbus_get_bus(), msg, properties_reply, agent,
+                                                                       NULL);
+
+       agent->req->msg = l_dbus_message_ref(msg);
+}
+
+
 static void simple_reply(struct l_dbus_message *reply, void *user_data)
 {
        struct mesh_agent *agent = user_data;
index 80333ac..6cc3d0f 100644 (file)
@@ -42,6 +42,8 @@ void mesh_agent_init(void);
 void mesh_agent_cleanup(void);
 struct mesh_agent *mesh_agent_create(const char *path, const char *owner,
                                        struct l_dbus_message_iter *properties);
+void mesh_agent_refresh(struct mesh_agent *agent, mesh_agent_cb_t cb,
+                                                       void *user_data);
 
 void mesh_agent_remove(struct mesh_agent *agent);
 void mesh_agent_cancel(struct mesh_agent *agent);
index eea49ff..2eb8605 100644 (file)
@@ -83,6 +83,9 @@ static void free_pending_add_call()
                l_dbus_remove_watch(dbus_get_bus(),
                                                add_pending->disc_watch);
 
+       if (add_pending->msg)
+               l_dbus_message_unref(add_pending->msg);
+
        l_free(add_pending);
        add_pending = NULL;
 }
@@ -214,6 +217,23 @@ static bool add_data_get(void *user_data, uint8_t num_ele)
        return true;
 }
 
+static void add_start(void *user_data, int err)
+{
+       struct l_dbus_message *reply;
+
+       l_info("Start callback");
+
+       if (err == MESH_ERROR_NONE)
+               reply = l_dbus_message_new_method_return(add_pending->msg);
+       else
+               reply = dbus_error(add_pending->msg, MESH_ERROR_FAILED,
+                               "Failed to start provisioning initiator");
+
+       l_dbus_send(dbus_get_bus(), reply);
+
+       add_pending->msg = NULL;
+}
+
 static struct l_dbus_message *add_node_call(struct l_dbus *dbus,
                                                struct l_dbus_message *msg,
                                                void *user_data)
@@ -246,6 +266,7 @@ static struct l_dbus_message *add_node_call(struct l_dbus *dbus,
        /* Invoke Prov Initiator */
 
        add_pending = l_new(struct add_data, 1);
+       add_pending->msg = l_dbus_message_ref(msg);
        memcpy(add_pending->uuid, uuid, 16);
        add_pending->node = node;
        add_pending->agent = node_get_agent(node);
@@ -258,20 +279,14 @@ static struct l_dbus_message *add_node_call(struct l_dbus *dbus,
                goto fail;
        }
 
-
-       if (!initiator_start(PB_ADV, uuid, 99, 60, add_pending->agent,
-                               add_data_get, add_cmplt, node, add_pending)) {
-               reply = dbus_error(msg, MESH_ERROR_FAILED,
-                               "Failed to start provisioning initiator");
-               goto fail;
-       }
+       initiator_start(PB_ADV, uuid, 99, 60, add_pending->agent, add_start,
+                               add_data_get, add_cmplt, node, add_pending);
 
        add_pending->disc_watch = l_dbus_add_disconnect_watch(dbus,
                                                node_get_owner(node),
                                                prov_disc_cb, NULL, NULL);
 
-       return l_dbus_message_new_method_return(msg);
-
+       return NULL;
 fail:
        l_free(add_pending);
        add_pending = NULL;
index f2ebff6..17bda65 100644 (file)
@@ -36,6 +36,7 @@
 #include "mesh/pb-adv.h"
 #include "mesh/mesh.h"
 #include "mesh/agent.h"
+#include "mesh/error.h"
 
 /* Quick size sanity check */
 static const uint16_t expected_pdu_size[] = {
@@ -77,6 +78,7 @@ enum int_state {
 #define MAT_SECRET     (MAT_REMOTE_PUBLIC | MAT_LOCAL_PRIVATE)
 
 struct mesh_prov_initiator {
+       mesh_prov_initiator_start_func_t start_cb;
        mesh_prov_initiator_complete_func_t complete_cb;
        mesh_prov_initiator_data_req_func_t data_req_cb;
        prov_trans_tx_t trans_tx;
@@ -102,6 +104,7 @@ struct mesh_prov_initiator {
        uint8_t private_key[32];
        uint8_t secret[32];
        uint8_t rand_auth_workspace[48];
+       uint8_t uuid[16];
 };
 
 static struct mesh_prov_initiator *prov = NULL;
@@ -814,17 +817,45 @@ static void int_prov_ack(void *user_data, uint8_t msg_num)
        }
 }
 
+static void initiator_open_cb(void *user_data, int err)
+{
+       bool result;
+
+       if (!prov)
+               return;
+
+       if (err != MESH_ERROR_NONE)
+               goto fail;
+
+       /* Always register for PB-ADV */
+       result = pb_adv_reg(true, int_prov_open, int_prov_close, int_prov_rx,
+                                               int_prov_ack, prov->uuid, prov);
+
+       if (!result) {
+               err = MESH_ERROR_FAILED;
+               goto fail;
+       }
+
+       if (!prov)
+               return;
+
+       prov->start_cb(prov->caller_data, MESH_ERROR_NONE);
+       return;
+fail:
+       prov->start_cb(prov->caller_data, err);
+       initiator_free();
+}
+
 bool initiator_start(enum trans_type transport,
                uint8_t uuid[16],
                uint16_t max_ele,
                uint32_t timeout, /* in seconds from mesh.conf */
                struct mesh_agent *agent,
+               mesh_prov_initiator_start_func_t start_cb,
                mesh_prov_initiator_data_req_func_t data_req_cb,
                mesh_prov_initiator_complete_func_t complete_cb,
                void *node, void *caller_data)
 {
-       bool result;
-
        /* Invoked from Add() method in mesh-api.txt, to add a
         * remote unprovisioned device network.
         */
@@ -837,19 +868,15 @@ bool initiator_start(enum trans_type transport,
        prov->node = node;
        prov->agent = agent;
        prov->complete_cb = complete_cb;
+       prov->start_cb = start_cb;
        prov->data_req_cb = data_req_cb;
        prov->caller_data = caller_data;
        prov->previous = -1;
+       memcpy(prov->uuid, uuid, 16);
 
-       /* Always register for PB-ADV */
-       result = pb_adv_reg(true, int_prov_open, int_prov_close, int_prov_rx,
-                                               int_prov_ack, uuid, prov);
-
-       if (result)
-               return true;
+       mesh_agent_refresh(prov->agent, initiator_open_cb, prov);
 
-       initiator_free();
-       return false;
+       return true;
 }
 
 void initiator_cancel(void *user_data)
index 43f53f9..1d78ed8 100644 (file)
@@ -100,6 +100,8 @@ typedef bool (*mesh_prov_acceptor_complete_func_t)(void *user_data,
                                        uint8_t status,
                                        struct mesh_prov_node_info *info);
 
+typedef void (*mesh_prov_initiator_start_func_t)(void *user_data, int err);
+
 typedef bool (*mesh_prov_initiator_data_req_func_t)(void *user_data,
                                                        uint8_t num_elem);
 
@@ -120,6 +122,7 @@ bool initiator_start(enum trans_type transport,
                uint16_t max_ele,
                uint32_t timeout, /* in seconds from mesh.conf */
                struct mesh_agent *agent,
+               mesh_prov_initiator_start_func_t start_cb,
                mesh_prov_initiator_data_req_func_t data_req_cb,
                mesh_prov_initiator_complete_func_t complete_cb,
                void *node, void *caller_data);