diff options
author | Brian Gix <brian.gix@intel.com> | 2020-01-30 10:59:23 -0800 |
---|---|---|
committer | Brian Gix <brian.gix@intel.com> | 2020-01-30 11:03:47 -0800 |
commit | 8457e6a3ad147c1167862f148cbbf281d879e874 (patch) | |
tree | 2cb7ae100b8b77089b0503527deb4629e82675fb /mesh/rpl.c | |
parent | 17e97efc3fc48116509e97670288af5827b81747 (diff) | |
download | bluez-8457e6a3ad147c1167862f148cbbf281d879e874.tar.gz |
mesh: Add NVM storage of Replay Protection
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.
Diffstat (limited to 'mesh/rpl.c')
-rw-r--r-- | mesh/rpl.c | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/mesh/rpl.c b/mesh/rpl.c new file mode 100644 index 000000000..5a667468e --- /dev/null +++ b/mesh/rpl.c @@ -0,0 +1,289 @@ +/* + * + * 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 + +#define _GNU_SOURCE +#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); +} |