mesh: Add Composition page storage to node.json
authorBrian Gix <brian.gix@intel.com>
Fri, 3 Jul 2020 21:51:49 +0000 (14:51 -0700)
committerAbhay Agarwal <ay.agarwal@samsung.com>
Mon, 28 Dec 2020 06:20:04 +0000 (11:50 +0530)
Mesh supports multiple Composition Pages, although only one is defined
in the current specification. This change allows saving and retrieval of
any pages, numbered 0-255.

Change-Id: I8d1d20ac9221ab9ce3465488984a088dc2570641
Signed-off-by: anuj.bhumiya <anuj.bhumiya@samsung.com>
mesh/cfgmod-server.c
mesh/mesh-config-json.c
mesh/mesh-config.h
mesh/node.c
mesh/node.h

index 3532b55..a0588f3 100644 (file)
 
 #define CFG_MAX_MSG_LEN 380
 
+/* Supported composition pages, sorted high to low */
+/* Only page 0 is currently supported */
+static const uint8_t supported_pages[] = {
+       0
+};
+
 static void send_pub_status(struct mesh_node *node, uint16_t net_idx,
                        uint16_t src, uint16_t dst,
                        uint8_t status, uint16_t ele_addr, uint32_t mod_id,
@@ -701,6 +707,33 @@ static void node_reset(void *user_data)
        node_remove(node);
 }
 
+static uint16_t get_composition(struct mesh_node *node, uint8_t page,
+                                                               uint8_t *buf)
+{
+       const uint8_t *comp;
+       uint16_t len = 0;
+       size_t i;
+
+       for (i = 0; i < sizeof(supported_pages); i++) {
+               if (page < supported_pages[i])
+                       continue;
+
+               page = supported_pages[i];
+               comp = node_get_comp(node, page, &len);
+
+               if (!page || len)
+                       break;
+       }
+
+       if (!len)
+               return 0;
+
+       *buf++ = page;
+       memcpy(buf, comp, len);
+
+       return len + 1;
+}
+
 static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx,
                                uint16_t net_idx, const uint8_t *data,
                                uint16_t size, const void *user_data)
@@ -746,16 +779,9 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx,
                if (size != 1)
                        return false;
 
-               /* Only page 0 is currently supported */
-               if (pkt[0] != 0) {
-                       l_debug("Unsupported page number %d", pkt[0]);
-                       l_debug("Returning page number 0");
-               }
                long_msg = l_malloc(CFG_MAX_MSG_LEN);
                n = mesh_model_opcode_set(OP_DEV_COMP_STATUS, long_msg);
-               long_msg[n++] = 0;
-               n += node_generate_comp(node, long_msg + n,
-                                                       CFG_MAX_MSG_LEN - n);
+               n += get_composition(node, pkt[0], long_msg + n);
 
                break;
 
index 160f53f..27d5289 100644 (file)
@@ -431,6 +431,54 @@ static bool read_device_key(json_object *jobj, uint8_t key_buf[16])
        return true;
 }
 
+static bool read_comp_pages(json_object *jobj, struct mesh_config_node *node)
+{
+       json_object *jarray, *jentry;
+       struct mesh_config_comp_page *page;
+       int len;
+       int i;
+
+       if (!json_object_object_get_ex(jobj, "pages", &jarray))
+               return true;
+
+       if (json_object_get_type(jarray) != json_type_array)
+               return false;
+
+       len = json_object_array_length(jarray);
+
+       for (i = 0; i < len; i++) {
+               size_t clen;
+               char *str;
+
+               jentry = json_object_array_get_idx(jarray, i);
+               str = (char *)json_object_get_string(jentry);
+               clen = strlen(str);
+
+               if (clen < ((MIN_COMP_SIZE * 2) + 1))
+                       continue;
+
+               clen = (clen / 2) - 1;
+
+               page = l_malloc(sizeof(struct mesh_config_comp_page) + clen);
+
+               if (!str2hex(str + 2, clen * 2, page->data, clen))
+                       goto parse_fail;
+
+               if (sscanf(str, "%02hhx", &page->page_num) != 1)
+                       goto parse_fail;
+
+               page->len = clen;
+
+               l_queue_push_tail(node->pages, page);
+       }
+
+       return true;
+
+parse_fail:
+       l_free(page);
+       return false;
+}
+
 static bool read_app_keys(json_object *jobj, struct mesh_config_node *node)
 {
        json_object *jarray;
@@ -1385,6 +1433,11 @@ static bool read_node(json_object *jnode, struct mesh_config_node *node)
                return false;
        }
 
+       if (!read_comp_pages(jnode, node)) {
+               l_info("Failed to read Composition Pages");
+               return false;
+       }
+
        if (!parse_elements(jvalue, node)) {
                l_info("Failed to parse elements");
                return false;
@@ -1890,6 +1943,113 @@ bool mesh_config_model_pub_del(struct mesh_config *cfg, uint16_t addr,
        return save_config(cfg->jnode, cfg->node_dir_path);
 }
 
+static void del_page(json_object *jarray, uint8_t page)
+{
+       char buf[3];
+       int i, len;
+
+       if (!jarray)
+               return;
+
+       snprintf(buf, 3, "%2.2x", page);
+
+       len = json_object_array_length(jarray);
+
+       for (i = 0; i < len; i++) {
+               json_object *jentry;
+               char *str;
+
+               jentry = json_object_array_get_idx(jarray, i);
+               str = (char *)json_object_get_string(jentry);
+
+               /* Delete matching page(s) */
+               if (!memcmp(str, buf, 2))
+                       json_object_array_del_idx(jarray, i, 1);
+       }
+}
+
+bool mesh_config_comp_page_add(struct mesh_config *cfg, uint8_t page,
+                                               uint8_t *data, uint16_t size)
+{
+       json_object *jnode, *jstring, *jarray = NULL;
+       char *buf;
+       int len;
+
+       if (!cfg)
+               return false;
+
+       jnode = cfg->jnode;
+
+       json_object_object_get_ex(jnode, "pages", &jarray);
+
+       len = (size * 2) + 3;
+       buf = l_malloc(len);
+       snprintf(buf, len, "%2.2x", page);
+       hex2str(data, size, buf + 2, len - 2);
+
+       if (jarray && jarray_has_string(jarray, buf, len)) {
+               l_free(buf);
+               return true;
+       } else if (!jarray) {
+               jarray = json_object_new_array();
+               json_object_object_add(jnode, "pages", jarray);
+       } else
+               del_page(jarray, page);
+
+       jstring = json_object_new_string(buf);
+       json_object_array_add(jarray, jstring);
+       l_free(buf);
+
+       return save_config(jnode, cfg->node_dir_path);
+}
+
+bool mesh_config_comp_page_mv(struct mesh_config *cfg, uint8_t old, uint8_t nw)
+{
+       json_object *jnode, *jarray = NULL;
+       uint8_t *data;
+       char *str;
+       char old_buf[3];
+       int i, len, dlen = 0;
+       bool status = true;
+
+       if (!cfg || old == nw)
+               return false;
+
+       jnode = cfg->jnode;
+
+       json_object_object_get_ex(jnode, "pages", &jarray);
+
+       if (!jarray)
+               return false;
+
+       snprintf(old_buf, 3, "%2.2x", old);
+       data = l_malloc(MAX_MSG_LEN);
+
+       len = json_object_array_length(jarray);
+
+       for (i = 0; i < len; i++) {
+               json_object *jentry;
+
+               jentry = json_object_array_get_idx(jarray, i);
+               str = (char *)json_object_get_string(jentry);
+
+               /* Delete matching page(s) but save data*/
+               if (!memcmp(str, old_buf, 2)) {
+                       dlen = strlen(str + 2);
+                       str2hex(str + 2, dlen, data, MAX_MSG_LEN);
+                       dlen /= 2;
+                       json_object_array_del_idx(jarray, i, 1);
+               }
+       }
+
+       if (dlen)
+               status = mesh_config_comp_page_add(cfg, nw, data, dlen);
+
+       l_free(data);
+
+       return status;
+}
+
 bool mesh_config_model_sub_add(struct mesh_config *cfg, uint16_t ele_addr,
                                                uint32_t mod_id, bool vendor,
                                                struct mesh_config_sub *sub)
@@ -2213,6 +2373,7 @@ static bool load_node(const char *fname, const uint8_t uuid[16],
        node.elements = l_queue_new();
        node.netkeys = l_queue_new();
        node.appkeys = l_queue_new();
+       node.pages = l_queue_new();
 
        result = read_node(jnode, &node);
 
@@ -2239,6 +2400,7 @@ static bool load_node(const char *fname, const uint8_t uuid[16],
        l_free(node.net_transmit);
        l_queue_destroy(node.netkeys, l_free);
        l_queue_destroy(node.appkeys, l_free);
+       l_queue_destroy(node.pages, l_free);
        l_queue_destroy(node.elements, free_element);
 
        if (!result)
index 9f30e69..7dfa9f2 100644 (file)
@@ -17,6 +17,8 @@
  *
  */
 
+#define MIN_COMP_SIZE 14
+
 struct mesh_config;
 
 struct mesh_config_sub {
@@ -88,10 +90,17 @@ struct mesh_config_transmit {
        uint8_t count;
 };
 
+struct mesh_config_comp_page {
+       uint16_t len;
+       uint8_t page_num;
+       uint8_t data[];
+};
+
 struct mesh_config_node {
        struct l_queue *elements;
        struct l_queue *netkeys;
        struct l_queue *appkeys;
+       struct l_queue *pages;
        uint32_t seq_number;
        uint32_t iv_index;
        bool iv_update;
@@ -139,6 +148,9 @@ bool mesh_config_write_relay_mode(struct mesh_config *cfg, uint8_t mode,
 bool mesh_config_write_ttl(struct mesh_config *cfg, uint8_t ttl);
 bool mesh_config_write_mode(struct mesh_config *cfg, const char *keyword,
                                                                int value);
+bool mesh_config_comp_page_add(struct mesh_config *cfg, uint8_t page,
+                                               uint8_t *data, uint16_t size);
+bool mesh_config_comp_page_mv(struct mesh_config *cfg, uint8_t old, uint8_t nw);
 bool mesh_config_model_binding_add(struct mesh_config *cfg, uint16_t ele_addr,
                                                bool vendor, uint32_t mod_id,
                                                        uint16_t app_idx);
index ebb7a60..eb05007 100644 (file)
@@ -46,8 +46,6 @@
 #include "mesh/manager.h"
 #include "mesh/node.h"
 
-#define MIN_COMP_SIZE 14
-
 #define MESH_NODE_PATH_PREFIX "/node"
 
 /* Default values for a new locally created node */
@@ -81,6 +79,7 @@ struct node_composition {
 struct mesh_node {
        struct mesh_net *net;
        struct l_queue *elements;
+       struct l_queue *pages;
        char *app_path;
        char *owner;
        char *obj_path;
@@ -266,6 +265,7 @@ static struct mesh_node *node_new(const uint8_t uuid[16])
        node = l_new(struct mesh_node, 1);
        node->net = mesh_net_new(node);
        node->elements = l_queue_new();
+       node->pages = l_queue_new();
        memcpy(node->uuid, uuid, sizeof(node->uuid));
        set_defaults(node);
 
@@ -335,6 +335,7 @@ static void free_node_resources(void *data)
        /* Free dynamic resources */
        free_node_dbus_resources(node);
        l_queue_destroy(node->elements, element_free);
+       l_queue_destroy(node->pages, l_free);
        mesh_agent_remove(node->agent);
        mesh_config_release(node->cfg);
        mesh_net_free(node->net);
@@ -573,8 +574,15 @@ static bool init_from_storage(struct mesh_config_node *db_node,
 
        l_queue_foreach(db_node->netkeys, set_net_key, node);
 
-       if (db_node->appkeys)
-               l_queue_foreach(db_node->appkeys, set_appkey, node);
+       l_queue_foreach(db_node->appkeys, set_appkey, node);
+
+       while (l_queue_length(db_node->pages)) {
+               struct mesh_config_comp_page *page;
+
+               /* Move the composition pages to the node struct */
+               page = l_queue_pop_head(db_node->pages);
+               l_queue_push_tail(node->pages, page);
+       }
 
        mesh_net_set_seq_num(node->net, node->seq_number);
        mesh_net_set_default_ttl(node->net, node->ttl);
@@ -893,7 +901,8 @@ uint8_t node_friend_mode_get(struct mesh_node *node)
        return node->friend;
 }
 
-uint16_t node_generate_comp(struct mesh_node *node, uint8_t *buf, uint16_t sz)
+static uint16_t node_generate_comp(struct mesh_node *node, uint8_t *buf,
+                                                               uint16_t sz)
 {
        uint16_t n, features;
        uint16_t num_ele = 0;
@@ -1007,6 +1016,78 @@ element_done:
        return n;
 }
 
+static bool match_page(const void *a, const void *b)
+{
+       const struct mesh_config_comp_page *page = a;
+       uint8_t page_num = L_PTR_TO_UINT(b);
+
+       return page->page_num == page_num;
+}
+
+bool node_set_comp(struct mesh_node *node, uint8_t page_num,
+                                       const uint8_t *data, uint16_t len)
+{
+       struct mesh_config_comp_page *page;
+
+       if (!node || len < MIN_COMP_SIZE)
+               return false;
+
+       page = l_queue_remove_if(node->pages, match_page,
+                                               L_UINT_TO_PTR(page_num));
+
+       l_free(page);
+
+       page = l_malloc(sizeof(struct mesh_config_comp_page) + len);
+       page->len = len;
+       page->page_num = page_num;
+       memcpy(page->data, data, len);
+       l_queue_push_tail(node->pages, page);
+
+       mesh_config_comp_page_add(node->cfg, page_num, page->data, len);
+
+       return true;
+}
+
+const uint8_t *node_get_comp(struct mesh_node *node, uint8_t page_num,
+                                                               uint16_t *len)
+{
+       struct mesh_config_comp_page *page = NULL;
+
+       if (node)
+               page = l_queue_find(node->pages, match_page,
+                                               L_UINT_TO_PTR(page_num));
+
+       if (!page) {
+               *len = 0;
+               return NULL;
+       }
+
+       *len = page->len;
+       return page->data;
+}
+
+bool node_replace_comp(struct mesh_node *node, uint8_t retire, uint8_t with)
+{
+       struct mesh_config_comp_page *old_page, *keep;
+
+       if (!node)
+               return false;
+
+       keep = l_queue_find(node->pages, match_page, L_UINT_TO_PTR(with));
+
+       if (!keep)
+               return false;
+
+       old_page = l_queue_remove_if(node->pages, match_page,
+                                                       L_UINT_TO_PTR(retire));
+
+       l_free(old_page);
+       keep->page_num = retire;
+       mesh_config_comp_page_mv(node->cfg, with, retire);
+
+       return true;
+}
+
 static void attach_io(void *a, void *b)
 {
        struct mesh_node *node = a;
@@ -1502,27 +1583,30 @@ static void update_model_options(struct mesh_node *node,
 
 static bool check_req_node(struct managed_obj_request *req)
 {
-       uint8_t node_comp[MAX_MSG_LEN - 2];
-       uint8_t attach_comp[MAX_MSG_LEN - 2];
-       uint16_t offset = 10;
-       uint16_t node_len = node_generate_comp(req->node, node_comp,
-                                                       sizeof(node_comp));
+       struct mesh_node *node;
+       const int offset = 8;
+       uint16_t node_len, len;
+       uint8_t comp[MAX_MSG_LEN - 2];
+       const uint8_t *node_comp;
 
-       if (!node_len)
-               return false;
+       if (req->type == REQUEST_TYPE_ATTACH)
+               node = req->attach;
+       else
+               node = req->node;
 
-       if (req->type == REQUEST_TYPE_ATTACH) {
-               uint16_t attach_len = node_generate_comp(req->attach,
-                                       attach_comp, sizeof(attach_comp));
+       node_comp = node_get_comp(node, 0, &node_len);
+       len = node_generate_comp(node, comp, sizeof(comp));
 
-               /* Verify only element/models composition */
-               if (node_len != attach_len ||
-                               memcmp(&node_comp[offset], &attach_comp[offset],
-                                                       node_len - offset)) {
-                       l_debug("Failed to verify app's composition data");
-                       return false;
-               }
-       }
+       /* If no page 0 exists, save it and return */
+       if (req->type != REQUEST_TYPE_ATTACH || !node_len || !node_comp)
+               return node_set_comp(node, 0, comp, len);
+
+       if (node_len != len || memcmp(&node_comp[offset], &comp[offset],
+                                                       node_len - offset))
+               return false;
+
+       else if (memcmp(node_comp, comp, node_len))
+               return node_set_comp(node, 0, comp, len);
 
        return true;
 }
index b1a9cd5..0f267b9 100644 (file)
@@ -66,7 +66,11 @@ struct l_queue *node_get_element_models(struct mesh_node *node, uint8_t ele_idx,
 uint16_t node_get_crpl(struct mesh_node *node);
 bool node_init_from_storage(struct mesh_node *node, const uint8_t uuid[16],
                                        struct mesh_config_node *db_node);
-uint16_t node_generate_comp(struct mesh_node *node, uint8_t *buf, uint16_t sz);
+const uint8_t *node_get_comp(struct mesh_node *node, uint8_t page_num,
+                                                               uint16_t *len);
+bool node_set_comp(struct mesh_node *node, uint8_t page_num,
+                                       const uint8_t *data, uint16_t len);
+bool node_replace_comp(struct mesh_node *node, uint8_t retire, uint8_t with);
 uint8_t node_lpn_mode_get(struct mesh_node *node);
 bool node_relay_mode_set(struct mesh_node *node, bool enable, uint8_t cnt,
                                                        uint16_t interval);