mesh: Add NVM storage of Replay Protection 48/223848/1
authorBrian Gix <brian.gix@intel.com>
Thu, 30 Jan 2020 18:59:23 +0000 (10:59 -0800)
committerAbhay Agarwal <ay.agarwal@samsung.com>
Mon, 3 Feb 2020 11:50:48 +0000 (17:20 +0530)
Mesh specification requires that Replay Protection be preserved
across node restarts.  This adds that storage in
<node_uuid>/rpl/<iv_index>/<src>

Realtime access remains in an l_queue structure, and stored as
messages are processed.

Change-Id: I38c5992946ef788859d5859a6bd71a514706b44b
Signed-off-by: Abhay Agarwal <ay.agarwal@samsung.com>
Makefile.mesh
mesh/net.c
mesh/rpl.c [new file with mode: 0644]
mesh/rpl.h [new file with mode: 0644]

index 54f2f67..af0fd03 100644 (file)
@@ -32,6 +32,7 @@ mesh_sources = mesh/mesh.h mesh/mesh.c \
                                mesh/manager.h mesh/manager.c \
                                mesh/pb-adv.h mesh/pb-adv.c \
                                mesh/keyring.h mesh/keyring.c \
+                               mesh/rpl.h mesh/rpl.c \
                                mesh/mesh-defs.h
 libexec_PROGRAMS += mesh/bluetooth-meshd
 
index f7fe0ee..9d1e614 100644 (file)
@@ -34,6 +34,7 @@
 #include "mesh/mesh-config.h"
 #include "mesh/model.h"
 #include "mesh/appkey.h"
+#include "mesh/rpl.h"
 
 #define abs_diff(a, b) ((a) > (b) ? (a) - (b) : (b) - (a))
 
@@ -254,12 +255,6 @@ struct net_beacon_data {
        bool processed;
 };
 
-struct mesh_rpl {
-       uint32_t iv_index;
-       uint32_t seq;
-       uint16_t src;
-};
-
 #define FAST_CACHE_SIZE 8
 static struct l_queue *fast_cache;
 static struct l_queue *nets;
@@ -2712,6 +2707,9 @@ static void update_iv_ivu_state(struct mesh_net *net, uint32_t iv_index,
                struct mesh_config *cfg = node_config_get(net->node);
 
                mesh_config_write_iv_index(cfg, iv_index, ivu);
+
+               /* Cleanup Replay Protection List NVM */
+               rpl_init(net->node, iv_index);
        }
 
        net->iv_index = iv_index;
@@ -3769,8 +3767,11 @@ bool net_msg_in_replay_cache(struct mesh_net *net, uint16_t idx,
        if (!net || !net->node)
                return true;
 
-       if (!net->replay_cache)
+       if (!net->replay_cache) {
                net->replay_cache = l_queue_new();
+               rpl_init(net->node, net->iv_index);
+               rpl_get_list(net->node, net->replay_cache);
+       }
 
        l_debug("Test Replay src: %4.4x seq: %6.6x iv: %8.8x",
                                                src, seq, iv_index);
@@ -3782,6 +3783,7 @@ bool net_msg_in_replay_cache(struct mesh_net *net, uint16_t idx,
                if (iv_index > rpe->iv_index) {
                        rpe->seq = seq;
                        rpe->iv_index = iv_index;
+                       rpl_put_entry(net->node, src, iv_index, seq);
                        return false;
                }
 
@@ -3797,6 +3799,8 @@ bool net_msg_in_replay_cache(struct mesh_net *net, uint16_t idx,
 
                rpe->seq = seq;
 
+               rpl_put_entry(net->node, src, iv_index, seq);
+
                return false;
        }
 
@@ -3811,6 +3815,9 @@ bool net_msg_in_replay_cache(struct mesh_net *net, uint16_t idx,
                        return true;
        }
 
+       if (!rpl_put_entry(net->node, src, iv_index, seq))
+               return true;
+
        rpe = l_new(struct mesh_rpl, 1);
        rpe->src = src;
        rpe->seq = seq;
diff --git a/mesh/rpl.c b/mesh/rpl.c
new file mode 100644 (file)
index 0000000..ad43a29
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2020  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef TIZEN_FEATURE_BLUEZ_MODIFY
+#define _GNU_SOURCE
+#endif
+
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include <sys/stat.h>
+
+#include <ell/ell.h>
+
+#include "mesh/mesh-defs.h"
+
+#include "mesh/node.h"
+#include "mesh/net.h"
+#include "mesh/util.h"
+#include "mesh/rpl.h"
+
+const char *rpl_dir = "/rpl";
+
+bool rpl_put_entry(struct mesh_node *node, uint16_t src, uint32_t iv_index,
+                                                               uint32_t seq)
+{
+       const char *node_path;
+       char src_file[PATH_MAX];
+       char seq_txt[7];
+       bool result = false;
+       DIR *dir;
+       int fd;
+
+       if (!node || !IS_UNICAST(src))
+               return false;
+
+       node_path = node_get_storage_dir(node);
+
+       if (strlen(node_path) + strlen(rpl_dir) + 15 >= PATH_MAX)
+               return false;
+
+       snprintf(src_file, PATH_MAX, "%s%s/%8.8x", node_path, rpl_dir,
+                                                               iv_index);
+       dir = opendir(src_file);
+
+       if (!dir)
+               mkdir(src_file, 0755);
+       else
+               closedir(dir);
+
+       snprintf(src_file, PATH_MAX, "%s%s/%8.8x/%4.4x", node_path, rpl_dir,
+                                                               iv_index, src);
+
+       fd = open(src_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+       if (fd >= 0) {
+               snprintf(seq_txt, 7, "%6.6x", seq);
+               if (write(fd, seq_txt, 6) == 6)
+                       result = true;
+
+               close(fd);
+       }
+
+       if (!result)
+               return false;
+
+       /* Delete RPL entry from old iv_index (if it exists) */
+       iv_index--;
+       snprintf(src_file, PATH_MAX, "%s%s/%8.8x/%4.4x", node_path, rpl_dir,
+                                                               iv_index, src);
+       remove(src_file);
+
+
+       return result;
+}
+
+void rpl_del_entry(struct mesh_node *node, uint16_t src)
+{
+       const char *node_path;
+       char rpl_path[PATH_MAX];
+       struct dirent *entry;
+       DIR *dir;
+
+       if (!node || !IS_UNICAST(src))
+               return;
+
+       node_path = node_get_storage_dir(node);
+
+       if (strlen(node_path) + strlen(rpl_dir) + 15 >= PATH_MAX)
+               return;
+
+       snprintf(rpl_path, PATH_MAX, "%s%s", node_path, rpl_dir);
+       dir = opendir(rpl_path);
+
+       if (!dir)
+               return;
+
+       /* Remove all instances of src address */
+       while ((entry = readdir(dir)) != NULL) {
+               if (entry->d_type == DT_DIR && entry->d_name[0] != '.') {
+                       snprintf(rpl_path, PATH_MAX, "%s%s/%s/%4.4x",
+                                       node_path, rpl_dir, entry->d_name, src);
+                       remove(rpl_path);
+               }
+       }
+
+       closedir(dir);
+}
+
+static bool match_src(const void *a, const void *b)
+{
+       const struct mesh_rpl *rpl = a;
+       uint16_t src = L_PTR_TO_UINT(b);
+
+       return rpl->src == src;
+}
+
+static void get_entries(const char *iv_path, struct l_queue *rpl_list)
+{
+       struct mesh_rpl *rpl;
+       struct dirent *entry;
+       DIR *dir;
+       int fd;
+       const char *iv_txt;
+       char src_path[PATH_MAX];
+       char seq_txt[7];
+       uint32_t iv_index, seq;
+       uint16_t src;
+
+       dir = opendir(iv_path);
+
+       if (!dir)
+               return;
+
+       iv_txt = basename(iv_path);
+       if (sscanf(iv_txt, "%08x", &iv_index) != 1)
+               return;
+
+       memset(seq_txt, 0, sizeof(seq_txt));
+
+       while ((entry = readdir(dir)) != NULL) {
+               /* RPL sequences are stored in src files under iv_index */
+               if (entry->d_type == DT_REG) {
+                       if (sscanf(entry->d_name, "%04hx", &src) != 1)
+                               continue;
+
+                       snprintf(src_path, PATH_MAX, "%s/%4.4x", iv_path, src);
+                       fd = open(src_path, O_RDONLY);
+
+                       if (fd < 0)
+                               continue;
+
+                       if (read(fd, seq_txt, 6) == 6 &&
+                                       sscanf(seq_txt, "%06x", &seq) == 1) {
+
+                               rpl = l_queue_find(rpl_list, match_src,
+                                               L_UINT_TO_PTR(src));
+
+                               if (rpl) {
+                                       /* Replace older entries */
+                                       if (rpl->iv_index < iv_index) {
+                                               rpl->iv_index = iv_index;
+                                               rpl->seq = seq;
+                                       }
+                               } else if (seq <= SEQ_MASK && IS_UNICAST(src)) {
+                                       rpl = l_new(struct mesh_rpl, 1);
+                                       rpl->src = src;
+                                       rpl->iv_index = iv_index;
+                                       rpl->seq = seq;
+
+                                       l_queue_push_head(rpl_list, rpl);
+                               }
+                       }
+                       close(fd);
+               }
+       }
+
+       closedir(dir);
+}
+
+bool rpl_get_list(struct mesh_node *node, struct l_queue *rpl_list)
+{
+       const char *node_path;
+       struct dirent *entry;
+       char *rpl_path;
+       size_t len;
+       DIR *dir;
+
+       if (!node || !rpl_list)
+               return false;
+
+       node_path = node_get_storage_dir(node);
+
+       len = strlen(node_path) + strlen(rpl_dir) + 14;
+
+       if (len > PATH_MAX)
+               return false;
+
+       rpl_path = l_malloc(len);
+       snprintf(rpl_path, len, "%s%s", node_path, rpl_dir);
+
+       dir = opendir(rpl_path);
+
+       if (!dir) {
+               l_error("Failed to read RPL dir: %s", rpl_path);
+               l_free(rpl_path);
+               return false;
+       }
+
+       while ((entry = readdir(dir)) != NULL) {
+               /* RPL sequences are stored in files under iv_indexs */
+               if (entry->d_type == DT_DIR && entry->d_name[0] != '.') {
+                       snprintf(rpl_path, len, "%s%s/%s",
+                                       node_path, rpl_dir, entry->d_name);
+                       get_entries(rpl_path, rpl_list);
+               }
+       }
+
+       l_free(rpl_path);
+       closedir(dir);
+
+       return true;
+}
+
+void rpl_init(struct mesh_node *node, uint32_t cur)
+{
+       uint32_t old = cur - 1;
+       const char *node_path;
+       struct dirent *entry;
+       char path[PATH_MAX];
+       DIR *dir;
+
+       if (!node)
+               return;
+
+       node_path = node_get_storage_dir(node);
+
+       if (strlen(node_path) + strlen(rpl_dir) + 10 >= PATH_MAX)
+               return;
+
+       /* Make sure path exists */
+       snprintf(path, PATH_MAX, "%s%s", node_path, rpl_dir);
+       mkdir(path, 0755);
+
+       dir = opendir(path);
+       if (!dir)
+               return;
+
+       /* Cleanup any stale or malformed trees */
+       while ((entry = readdir(dir)) != NULL) {
+               if (entry->d_type == DT_DIR && entry->d_name[0] != '.') {
+                       uint32_t val;
+                       bool del = false;
+
+                       if (strlen(entry->d_name) != 8)
+                               del = true;
+                       else if (sscanf(entry->d_name, "%08x", &val) != 1)
+                               del = true;
+
+                       /* Delete all invalid iv_index trees */
+                       if (del || (val != cur && val != old)) {
+                               snprintf(path, PATH_MAX, "%s%s/%s",
+                                       node_path, rpl_dir, entry->d_name);
+                               del_path(path);
+                       }
+               }
+       }
+
+       closedir(dir);
+}
diff --git a/mesh/rpl.h b/mesh/rpl.h
new file mode 100644 (file)
index 0000000..17d2e3f
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2020  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ */
+
+struct mesh_rpl {
+       uint32_t iv_index;
+       uint32_t seq;
+       uint16_t src;
+};
+
+bool rpl_put_entry(struct mesh_node *node, uint16_t src, uint32_t iv_index,
+                                                               uint32_t seq);
+void rpl_del_entry(struct mesh_node *node, uint16_t src);
+bool rpl_get_list(struct mesh_node *node, struct l_queue *rpl_list);
+void rpl_init(struct mesh_node *node, uint32_t iv_index);