From: "Gix, Brian" <brian.gix@intel.com>
To: "linux-bluetooth@vger.kernel.org" <linux-bluetooth@vger.kernel.org>
Cc: "michal.lowas-rzechonek@silvair.com"
<michal.lowas-rzechonek@silvair.com>,
"Stotland, Inga" <inga.stotland@intel.com>
Subject: Re: [PATCH BlueZ v6 1/2] mesh: Reconfigure node storage tree
Date: Mon, 13 May 2019 19:32:47 +0000 [thread overview]
Message-ID: <1557775965.22613.0.camel@intel.com> (raw)
In-Reply-To: <20190509213321.19822-2-brian.gix@intel.com>
Patch-set applied
On Thu, 2019-05-09 at 14:33 -0700, Brian Gix wrote:
> Add a tree structure to a nodes data storage, in order to safely handle
> Replay Protection list, Refactor local Sequence Numbers, and add Key
> storage for Config Client nodes.
> ---
> mesh/README | 34 +++++++++++++-
> mesh/node.c | 16 ++++---
> mesh/node.h | 4 +-
> mesh/storage.c | 144 ++++++++++++++++++++++++++++++++++-----------------------
> 4 files changed, 131 insertions(+), 67 deletions(-)
>
> diff --git a/mesh/README b/mesh/README
> index ca223a6d8..82fd5a017 100644
> --- a/mesh/README
> +++ b/mesh/README
> @@ -36,8 +36,40 @@ Each subdirectory contains the following files:
> provisioner/configuration client
> - node.json.bak:
> a backup that the last known good node configuration.
> + - seq_num:
> + File containing next sequence number to use
> + - seq_num.bak:
> + Backup of the sequence number. This may be larger than the
> + actual sequence number being used at runtime, to prevent re-use
> + of sequence numbers in the event of an unexpected restart.
> + - ./rpl/:
> + Directory to store the sequence numbers of remote nodes, as
> + required by Replay Protection List (RPL) parameters.
> + - xxxx:
> + Files named for remote Unicast addresses, and contain
> + last received iv_index + seq_num from each SRC address.
> + - ./dev_keys/:
> + Directory to store remote Device keys. This is only created/used
> + by Configuration Client (Network administration) nodes.
> + - xxxx:
> + Files named for remote Unicast addresses, and contains
> + 16 octet key.
> + - ./net_keys/:
> + Directory to store network subnet keys. This is only
> + created/used by Configuration Client (Network administration)
> + nodes.
> + - xxx:
> + Files named for subnet index, and contains key refresh
> + phase, and old/new versions of the key.
> + - ./app_keys/:
> + Directory to store application keys. This is only created/used
> + by Configuration Client (Network administration) nodes.
> + - xxx:
> + Files named for application index, and contains bound
> + subnet index, and old/new versions of the key.
>
> -The files are in JSON format.
> +The node.json and node.json.bak are in JSON format. All other files are stored
> +in little endian binary format.
>
> Information
> ===========
> diff --git a/mesh/node.c b/mesh/node.c
> index 5904b116c..6f95c8d1c 100644
> --- a/mesh/node.c
> +++ b/mesh/node.c
> @@ -79,7 +79,7 @@ struct mesh_node {
> char *owner;
> char *path;
> void *jconfig;
> - char *cfg_file;
> + char *node_path;
> uint32_t disc_watch;
> time_t upd_sec;
> uint32_t seq_number;
> @@ -236,6 +236,7 @@ static void free_node_resources(void *data)
> l_free(node->comp);
> l_free(node->app_path);
> l_free(node->owner);
> + l_free(node->node_path);
>
> if (node->disc_watch)
> l_dbus_remove_watch(dbus_get_bus(), node->disc_watch);
> @@ -259,7 +260,7 @@ void node_remove(struct mesh_node *node)
>
> l_queue_remove(nodes, node);
>
> - if (node->cfg_file)
> + if (node->node_path)
> storage_remove_node_config(node);
>
> free_node_resources(node);
> @@ -395,7 +396,7 @@ static void cleanup_node(void *data)
> struct mesh_net *net = node->net;
>
> /* Save local node configuration */
> - if (node->cfg_file) {
> + if (node->node_path) {
>
> /* Preserve the last sequence number */
> storage_write_sequence_number(net, mesh_net_get_seq_num(net));
> @@ -1859,14 +1860,15 @@ void *node_jconfig_get(struct mesh_node *node)
> return node->jconfig;
> }
>
> -void node_cfg_file_set(struct mesh_node *node, char *cfg)
> +void node_path_set(struct mesh_node *node, char *path)
> {
> - node->cfg_file = cfg;
> + l_free(node->node_path);
> + node->node_path = l_strdup(path);
> }
>
> -char *node_cfg_file_get(struct mesh_node *node)
> +char *node_path_get(struct mesh_node *node)
> {
> - return node->cfg_file;
> + return node->node_path;
> }
>
> struct mesh_net *node_get_net(struct mesh_node *node)
> diff --git a/mesh/node.h b/mesh/node.h
> index 1be4de1da..1194ff837 100644
> --- a/mesh/node.h
> +++ b/mesh/node.h
> @@ -95,5 +95,5 @@ bool node_dbus_init(struct l_dbus *bus);
> void node_cleanup_all(void);
> void node_jconfig_set(struct mesh_node *node, void *jconfig);
> void *node_jconfig_get(struct mesh_node *node);
> -void node_cfg_file_set(struct mesh_node *node, char *cfg);
> -char *node_cfg_file_get(struct mesh_node *node);
> +void node_path_set(struct mesh_node *node, char *path);
> +char *node_path_get(struct mesh_node *node);
> diff --git a/mesh/storage.c b/mesh/storage.c
> index 2580cbe7f..f4e23bf49 100644
> --- a/mesh/storage.c
> +++ b/mesh/storage.c
> @@ -28,6 +28,7 @@
> #include <unistd.h>
> #include <dirent.h>
> #include <libgen.h>
> +#include <ftw.h>
>
> #include <sys/types.h>
> #include <sys/stat.h>
> @@ -49,13 +50,30 @@
>
> struct write_info {
> json_object *jnode;
> - const char *config_name;
> + const char *node_path;
> void *user_data;
> mesh_status_func_t cb;
> };
>
> +static const char *cfg_name = "/node.json";
> +static const char *bak_ext = ".bak";
> +static const char *tmp_ext = ".tmp";
> static const char *storage_dir;
>
> +/* This is a thread-safe always malloced version of dirname which will work
> + * regardless of which underlying dirname() implementation is used.
> + */
> +static char *alloc_dirname(const char *path)
> +{
> + char *tmp = l_strdup(path);
> + char *dir;
> +
> + dir = dirname(tmp);
> + strncpy(tmp, dir, strlen(path) + 1);
> +
> + return tmp;
> +}
> +
> static bool read_node_cb(struct mesh_db_node *db_node, void *user_data)
> {
> struct mesh_node *node = user_data;
> @@ -166,7 +184,7 @@ static bool parse_node(struct mesh_node *node, json_object *jnode)
> return true;
> }
>
> -static bool parse_config(char *in_file, char *out_file, const uint8_t uuid[16])
> +static bool parse_config(char *in_file, char *out_dir, const uint8_t uuid[16])
> {
> int fd;
> char *str;
> @@ -213,7 +231,7 @@ static bool parse_config(char *in_file, char *out_file, const uint8_t uuid[16])
> }
>
> node_jconfig_set(node, jnode);
> - node_cfg_file_set(node, out_file);
> + node_path_set(node, out_dir);
>
> done:
> close(fd);
> @@ -430,15 +448,12 @@ static bool save_config(json_object *jnode, const char *config_name)
> static void idle_save_config(void *user_data)
> {
> struct write_info *info = user_data;
> - size_t len = strlen(info->config_name) + 5;
> - char *tmp = l_malloc(len);
> - char *bak = l_malloc(len);
> + char *tmp, *bak, *cfg;
> bool result = false;
>
> - strncpy(tmp, info->config_name, len);
> - strncpy(bak, info->config_name, len);
> - tmp = strncat(tmp, ".tmp", 5);
> - bak = strncat(bak, ".bak", 5);
> + cfg = l_strdup_printf("%s%s", info->node_path, cfg_name);
> + tmp = l_strdup_printf("%s%s", cfg, tmp_ext);
> + bak = l_strdup_printf("%s%s", cfg, bak_ext);
> remove(tmp);
>
> l_debug("Storage-Wrote");
> @@ -446,13 +461,14 @@ static void idle_save_config(void *user_data)
>
> if (result) {
> remove(bak);
> - rename(info->config_name, bak);
> - rename(tmp, info->config_name);
> + rename(cfg, bak);
> + rename(tmp, cfg);
> }
>
> remove(tmp);
> l_free(tmp);
> l_free(bak);
> + l_free(cfg);
>
> if (info->cb)
> info->cb(info->user_data, result);
> @@ -467,7 +483,7 @@ void storage_save_config(struct mesh_node *node, bool no_wait,
>
> info = l_new(struct write_info, 1);
> info->jnode = node_jconfig_get(node);
> - info->config_name = node_cfg_file_get(node);
> + info->node_path = node_path_get(node);
> info->cb = cb;
> info->user_data = user_data;
>
> @@ -517,6 +533,7 @@ bool storage_load_nodes(const char *dir_name)
> {
> DIR *dir;
> struct dirent *entry;
> + size_t path_len = strlen(dir_name) + strlen(cfg_name) + strlen(bak_ext);
>
> create_dir(dir_name);
> dir = opendir(dir_name);
> @@ -529,33 +546,37 @@ bool storage_load_nodes(const char *dir_name)
> storage_dir = dir_name;
>
> while ((entry = readdir(dir)) != NULL) {
> - char *cfg;
> - char *bak;
> + char *dir, *cfg, *bak;
> uint8_t uuid[16];
> + size_t node_len;
>
> if (entry->d_type != DT_DIR)
> continue;
>
> - if (!str2hex(entry->d_name, strlen(entry->d_name), uuid, sizeof(uuid)))
> + /* Check path length */
> + node_len = strlen(entry->d_name);
> + if (path_len + node_len + 1 >= PATH_MAX)
> continue;
>
> - cfg = l_strdup_printf("%s/%s/node.json", dir_name, entry->d_name);
> -
> - if (parse_config(cfg, cfg, uuid))
> + if (!str2hex(entry->d_name, node_len, uuid, sizeof(uuid)))
> continue;
>
> - /* Fall-back to Backup version */
> - bak = l_strdup_printf("%s/%s/node.json.bak", dir_name, entry->d_name);
> + dir = l_strdup_printf("%s/%s", dir_name, entry->d_name);
> + cfg = l_strdup_printf("%s%s", dir, cfg_name);
>
> - if (parse_config(bak, cfg, uuid)) {
> - remove(cfg);
> - rename(bak, cfg);
> - l_free(cfg);
> - continue;
> - }
> + if (!parse_config(cfg, dir, uuid)) {
>
> + /* Fall-back to Backup version */
> + bak = l_strdup_printf("%s%s", cfg, bak_ext);
> +
> + if (parse_config(bak, dir, uuid)) {
> + remove(cfg);
> + rename(bak, cfg);
> + }
> + l_free(bak);
> + }
> l_free(cfg);
> - l_free(bak);
> + l_free(dir);
> }
>
> return true;
> @@ -566,8 +587,8 @@ bool storage_create_node_config(struct mesh_node *node, void *data)
> struct mesh_db_node *db_node = data;
> char uuid[33];
> char name_buf[PATH_MAX];
> - char *filename;
> json_object *jnode;
> + size_t max_len = strlen(cfg_name) + strlen(bak_ext);
>
> if (!storage_dir)
> return false;
> @@ -578,25 +599,26 @@ bool storage_create_node_config(struct mesh_node *node, void *data)
> return false;
>
> if (!hex2str(node_uuid_get(node), 16, uuid, sizeof(uuid)))
> - return false;
> + goto fail;
>
> snprintf(name_buf, PATH_MAX, "%s/%s", storage_dir, uuid);
>
> + if (strlen(name_buf) + max_len >= PATH_MAX)
> + goto fail;
> +
> /* Create a new directory and node.json file */
> if (mkdir(name_buf, 0755) != 0)
> goto fail;
>
> - filename = l_strdup_printf("%s/node.json", name_buf);
> + node_path_set(node, name_buf);
>
> - l_debug("New node config %s", filename);
> + snprintf(name_buf, PATH_MAX, "%s/%s%s", storage_dir, uuid, cfg_name);
> + l_debug("New node config %s", name_buf);
>
> - if (!save_config(jnode, filename)) {
> - l_free(filename);
> + if (!save_config(jnode, name_buf))
> goto fail;
> - }
>
> node_jconfig_set(node, jnode);
> - node_cfg_file_set(node, filename);
>
> return true;
> fail:
> @@ -604,13 +626,29 @@ fail:
> return false;
> }
>
> +static int del_fobject(const char *fpath, const struct stat *sb, int typeflag,
> + struct FTW *ftwbuf)
> +{
> + switch (typeflag) {
> + case FTW_DP:
> + rmdir(fpath);
> + l_debug("RMDIR %s", fpath);
> + break;
> +
> + case FTW_SL:
> + default:
> + remove(fpath);
> + l_debug("RM %s", fpath);
> + break;
> + }
> + return 0;
> +}
> +
> /* Permanently remove node configuration */
> void storage_remove_node_config(struct mesh_node *node)
> {
> - char *cfg;
> + char *node_path, *mesh_path, *mesh_name;
> struct json_object *jnode;
> - const char *dir_name;
> - char *bak;
>
> if (!node)
> return;
> @@ -621,25 +659,17 @@ void storage_remove_node_config(struct mesh_node *node)
> json_object_put(jnode);
> node_jconfig_set(node, NULL);
>
> - /* Delete node configuration file */
> - cfg = node_cfg_file_get(node);
> - if (!cfg)
> - return;
> -
> - l_debug("Delete node config file %s", cfg);
> - remove(cfg);
> -
> - /* Delete the backup file */
> - bak = l_strdup_printf("%s.bak", cfg);
> - remove(bak);
> - l_free(bak);
> + node_path = node_path_get(node);
> + l_debug("Delete node config %s", node_path);
>
> - /* Delete the node directory */
> - dir_name = dirname(cfg);
> + /* Make sure path name of node follows expected guidelines */
> + mesh_path = alloc_dirname(node_path);
> + mesh_name = basename(mesh_path);
> + if (strcmp(mesh_name, "mesh"))
> + goto done;
>
> - l_debug("Delete directory %s", dir_name);
> - rmdir(dir_name);
> + nftw(node_path, del_fobject, 5, FTW_DEPTH | FTW_PHYS);
>
> - l_free(cfg);
> - node_cfg_file_set(node, NULL);
> +done:
> + l_free(mesh_path);
> }
next prev parent reply other threads:[~2019-05-13 19:32 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-05-09 21:33 [PATCH BlueZ v6 0/2] mesh: node dir Restructure, and keyring Brian Gix
2019-05-09 21:33 ` [PATCH BlueZ v6 1/2] mesh: Reconfigure node storage tree Brian Gix
2019-05-13 19:32 ` Gix, Brian [this message]
2019-05-09 21:33 ` [PATCH BlueZ v6 2/2] mesh: Add key storage Brian Gix
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1557775965.22613.0.camel@intel.com \
--to=brian.gix@intel.com \
--cc=inga.stotland@intel.com \
--cc=linux-bluetooth@vger.kernel.org \
--cc=michal.lowas-rzechonek@silvair.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).