mirror of
https://git.kernel.org/pub/scm/bluetooth/bluez.git
synced 2024-11-15 16:24:28 +08:00
fc53175b8a
This makes meshctl use bt_shell to manage the menus and command handling.
1599 lines
33 KiB
C
1599 lines
33 KiB
C
/*
|
|
*
|
|
* BlueZ - Bluetooth protocol stack for Linux
|
|
*
|
|
* Copyright (C) 2017 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.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <glib.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include <json-c/json.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <glib.h>
|
|
|
|
#include "src/shared/util.h"
|
|
#include "src/shared/shell.h"
|
|
|
|
#include "mesh/mesh-net.h"
|
|
#include "mesh/crypto.h"
|
|
#include "mesh/keys.h"
|
|
#include "mesh/net.h"
|
|
#include "mesh/node.h"
|
|
#include "mesh/util.h"
|
|
#include "mesh/prov-db.h"
|
|
|
|
#define CHECK_KEY_IDX_RANGE(x) (((x) >= 0) && ((x) <= 4095))
|
|
|
|
static const char *prov_filename;
|
|
static const char *local_filename;
|
|
|
|
static char* prov_file_read(const char *filename)
|
|
{
|
|
int fd;
|
|
char *str;
|
|
struct stat st;
|
|
ssize_t sz;
|
|
|
|
if (!filename)
|
|
return NULL;
|
|
|
|
fd = open(filename,O_RDONLY);
|
|
if (!fd)
|
|
return NULL;
|
|
|
|
if (fstat(fd, &st) == -1) {
|
|
close(fd);
|
|
return NULL;
|
|
}
|
|
|
|
str = (char *) g_malloc0(st.st_size + 1);
|
|
if (!str) {
|
|
close(fd);
|
|
return NULL;
|
|
}
|
|
|
|
sz = read(fd, str, st.st_size);
|
|
if (sz != st.st_size)
|
|
bt_shell_printf("Incomplete read: %d vs %d\n", (int)sz,
|
|
(int)(st.st_size));
|
|
|
|
close(fd);
|
|
|
|
return str;
|
|
}
|
|
|
|
static void prov_file_write(json_object *jmain, bool local)
|
|
{
|
|
FILE *outfile;
|
|
const char *out_str;
|
|
const char *out_filename;
|
|
|
|
if (local)
|
|
out_filename = local_filename;
|
|
else
|
|
out_filename = prov_filename;
|
|
|
|
outfile = fopen(out_filename, "wr");
|
|
if (!outfile) {
|
|
bt_shell_printf("Failed to open file %s for writing\n", out_filename);
|
|
return;
|
|
}
|
|
|
|
out_str = json_object_to_json_string_ext(jmain,
|
|
JSON_C_TO_STRING_PRETTY);
|
|
|
|
fwrite(out_str, sizeof(char), strlen(out_str), outfile);
|
|
fclose(outfile);
|
|
}
|
|
|
|
static void put_uint16(json_object *jobject, const char *desc, uint16_t value)
|
|
{
|
|
json_object *jstring;
|
|
char buf[5];
|
|
|
|
snprintf(buf, 5, "%4.4x", value);
|
|
jstring = json_object_new_string(buf);
|
|
json_object_object_add(jobject, desc, jstring);
|
|
}
|
|
|
|
static void put_uint32(json_object *jobject, const char *desc, uint32_t value)
|
|
{
|
|
json_object *jstring;
|
|
char buf[9];
|
|
|
|
snprintf(buf, 9, "%8.8x", value);
|
|
jstring = json_object_new_string(buf);
|
|
json_object_object_add(jobject, desc, jstring);
|
|
}
|
|
|
|
static void put_uint16_array_entry(json_object *jarray, uint16_t value)
|
|
{
|
|
json_object *jstring;
|
|
char buf[5];
|
|
|
|
snprintf(buf, 5, "%4.4x", value);
|
|
jstring = json_object_new_string(buf);
|
|
json_object_array_add(jarray, jstring);
|
|
}
|
|
|
|
static void put_uint32_array_entry(json_object *jarray, uint32_t value)
|
|
{
|
|
json_object *jstring;
|
|
char buf[9];
|
|
|
|
snprintf(buf, 9, "%8.8x", value);
|
|
jstring = json_object_new_string(buf);
|
|
json_object_array_add(jarray, jstring);
|
|
}
|
|
|
|
static void put_uint16_list(json_object *jarray, GList *list)
|
|
{
|
|
GList *l;
|
|
|
|
if (!list)
|
|
return;
|
|
|
|
for (l = list; l; l = l->next) {
|
|
uint32_t ivalue = GPOINTER_TO_UINT(l->data);
|
|
put_uint16_array_entry(jarray, ivalue);
|
|
}
|
|
}
|
|
|
|
static void add_node_idxs(json_object *jnode, const char *desc,
|
|
GList *idxs)
|
|
{
|
|
json_object *jarray;
|
|
|
|
jarray = json_object_new_array();
|
|
|
|
put_uint16_list(jarray, idxs);
|
|
|
|
json_object_object_add(jnode, desc, jarray);
|
|
}
|
|
|
|
static bool parse_unicast_range(json_object *jobject)
|
|
{
|
|
int cnt;
|
|
int i;
|
|
|
|
cnt = json_object_array_length(jobject);
|
|
|
|
for (i = 0; i < cnt; ++i) {
|
|
json_object *jrange;
|
|
json_object *jvalue;
|
|
uint16_t low, high;
|
|
char *str;
|
|
|
|
jrange = json_object_array_get_idx(jobject, i);
|
|
json_object_object_get_ex(jrange, "lowAddress", &jvalue);
|
|
str = (char *)json_object_get_string(jvalue);
|
|
if (sscanf(str, "%04hx", &low) != 1)
|
|
return false;
|
|
|
|
json_object_object_get_ex(jrange, "highAddress", &jvalue);
|
|
str = (char *)json_object_get_string(jvalue);
|
|
if (sscanf(str, "%04hx", &high) != 1)
|
|
return false;
|
|
|
|
if(high < low)
|
|
return false;
|
|
|
|
net_add_address_pool(low, high);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static int parse_node_keys(struct mesh_node *node, json_object *jidxs,
|
|
bool is_app_key)
|
|
{
|
|
int idx_cnt;
|
|
int i;
|
|
|
|
idx_cnt = json_object_array_length(jidxs);
|
|
for (i = 0; i < idx_cnt; ++i) {
|
|
int idx;
|
|
json_object *jvalue;
|
|
|
|
jvalue = json_object_array_get_idx(jidxs, i);
|
|
if (!jvalue)
|
|
break;
|
|
idx = json_object_get_int(jvalue);
|
|
if (!CHECK_KEY_IDX_RANGE(idx))
|
|
break;
|
|
|
|
if (is_app_key)
|
|
node_app_key_add(node, idx);
|
|
else
|
|
node_net_key_add(node, idx);
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
static bool parse_composition_models(struct mesh_node *node, int index,
|
|
json_object *jmodels)
|
|
{
|
|
int model_cnt;
|
|
int i;
|
|
|
|
model_cnt = json_object_array_length(jmodels);
|
|
|
|
for (i = 0; i < model_cnt; ++i) {
|
|
json_object *jmodel;
|
|
char *str;
|
|
uint32_t model_id;
|
|
int len;
|
|
|
|
jmodel = json_object_array_get_idx(jmodels, i);
|
|
str = (char *)json_object_get_string(jmodel);
|
|
len = strlen(str);
|
|
|
|
if (len != 4 && len != 8)
|
|
return false;
|
|
|
|
if (sscanf(str, "%08x", &model_id) != 1)
|
|
return false;
|
|
if (len == 4)
|
|
model_id += 0xffff0000;
|
|
|
|
node_set_model(node, index, model_id);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool parse_composition_elements(struct mesh_node *node,
|
|
json_object *jelements)
|
|
{
|
|
int el_cnt;
|
|
int i;
|
|
|
|
el_cnt = json_object_array_length(jelements);
|
|
node_set_num_elements(node, el_cnt);
|
|
|
|
for (i = 0; i < el_cnt; ++i) {
|
|
json_object *jelement;
|
|
json_object *jmodels;
|
|
json_object *jvalue;
|
|
int index;
|
|
|
|
jelement = json_object_array_get_idx(jelements, i);
|
|
json_object_object_get_ex(jelement, "elementIndex", &jvalue);
|
|
if (jvalue) {
|
|
index = json_object_get_int(jvalue);
|
|
if (index >= el_cnt) {
|
|
return false;
|
|
}
|
|
} else
|
|
return false;
|
|
|
|
if (!node_set_element(node, index))
|
|
return false;
|
|
|
|
json_object_object_get_ex(jelement, "models", &jmodels);
|
|
if (!jmodels)
|
|
continue;
|
|
|
|
if(!parse_composition_models(node, index, jmodels))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool parse_model_pub(struct mesh_node *node, int ele_idx,
|
|
uint32_t model_id, json_object *jpub)
|
|
{
|
|
json_object *jvalue;
|
|
struct mesh_publication pub;
|
|
char *str;
|
|
|
|
memset(&pub, 0, sizeof(struct mesh_publication));
|
|
|
|
/* Read only required fields */
|
|
json_object_object_get_ex(jpub, "address", &jvalue);
|
|
if (!jvalue)
|
|
return false;
|
|
|
|
str = (char *)json_object_get_string(jvalue);
|
|
if (sscanf(str, "%04hx", &pub.u.addr16) != 1)
|
|
return false;
|
|
|
|
json_object_object_get_ex(jpub, "index", &jvalue);
|
|
if (!jvalue)
|
|
return false;
|
|
|
|
str = (char *)json_object_get_string(jvalue);
|
|
if (sscanf(str, "%04hx", &pub.app_idx) != 1)
|
|
return false;
|
|
|
|
|
|
json_object_object_get_ex(jpub, "ttl", &jvalue);
|
|
pub.ttl = json_object_get_int(jvalue);
|
|
|
|
if (!node_model_pub_set(node, ele_idx, model_id, &pub))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool parse_bindings(struct mesh_node *node, int ele_idx,
|
|
uint32_t model_id, json_object *jbindings)
|
|
{
|
|
int cnt;
|
|
int i;
|
|
|
|
cnt = json_object_array_length(jbindings);
|
|
|
|
for (i = 0; i < cnt; ++i) {
|
|
int key_idx;
|
|
json_object *jvalue;
|
|
|
|
jvalue = json_object_array_get_idx(jbindings, i);
|
|
if (!jvalue)
|
|
return true;
|
|
|
|
key_idx = json_object_get_int(jvalue);
|
|
if (!CHECK_KEY_IDX_RANGE(key_idx))
|
|
return false;
|
|
|
|
if (!node_add_binding(node, ele_idx, model_id, key_idx))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool parse_configuration_models(struct mesh_node *node, int ele_idx,
|
|
json_object *jmodels, uint32_t target_id, json_object **jtarget)
|
|
{
|
|
int model_cnt;
|
|
int i;
|
|
|
|
if (jtarget)
|
|
*jtarget = NULL;
|
|
|
|
model_cnt = json_object_array_length(jmodels);
|
|
|
|
for (i = 0; i < model_cnt; ++i) {
|
|
json_object *jmodel;
|
|
json_object *jvalue;
|
|
json_object *jarray;
|
|
char *str;
|
|
int len;
|
|
uint32_t model_id;
|
|
|
|
jmodel = json_object_array_get_idx(jmodels, i);
|
|
|
|
json_object_object_get_ex(jmodel, "modelId", &jvalue);
|
|
str = (char *)json_object_get_string(jvalue);
|
|
|
|
len = strlen(str);
|
|
|
|
if (len != 4 && len != 8)
|
|
return false;
|
|
|
|
if (sscanf(str, "%08x", &model_id) != 1)
|
|
return false;
|
|
if (len == 4)
|
|
model_id += 0xffff0000;
|
|
|
|
if (jtarget && model_id == target_id) {
|
|
*jtarget = jmodel;
|
|
return true;
|
|
}
|
|
|
|
json_object_object_get_ex(jmodel, "bind", &jarray);
|
|
if (jarray && !parse_bindings(node, ele_idx, model_id, jarray))
|
|
return false;
|
|
|
|
json_object_object_get_ex(jmodel, "publish", &jvalue);
|
|
|
|
if (jvalue && !parse_model_pub(node, ele_idx, model_id, jvalue))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool parse_configuration_elements(struct mesh_node *node,
|
|
json_object *jelements, bool local)
|
|
{
|
|
int el_cnt;
|
|
int i;
|
|
|
|
el_cnt = json_object_array_length(jelements);
|
|
node_set_num_elements(node, el_cnt);
|
|
|
|
for (i = 0; i < el_cnt; ++i) {
|
|
json_object *jelement;
|
|
json_object *jmodels;
|
|
json_object *jvalue;
|
|
int index;
|
|
uint16_t addr;
|
|
|
|
jelement = json_object_array_get_idx(jelements, i);
|
|
json_object_object_get_ex(jelement, "elementIndex", &jvalue);
|
|
if (jvalue) {
|
|
index = json_object_get_int(jvalue);
|
|
if (index >= el_cnt) {
|
|
return false;
|
|
}
|
|
} else
|
|
return false;
|
|
|
|
if (index == 0) {
|
|
char *str;
|
|
|
|
json_object_object_get_ex(jelement, "unicastAddress",
|
|
&jvalue);
|
|
str = (char *)json_object_get_string(jvalue);
|
|
if (sscanf(str, "%04hx", &addr) != 1)
|
|
return false;
|
|
|
|
if (!local && !net_reserve_address_range(addr, el_cnt))
|
|
return false;
|
|
|
|
node_set_primary(node, addr);
|
|
}
|
|
|
|
json_object_object_get_ex(jelement, "models", &jmodels);
|
|
if (!jmodels)
|
|
continue;
|
|
|
|
if(!parse_configuration_models(node, index, jmodels, 0, NULL))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static void add_key(json_object *jobject, const char *desc, uint8_t* key)
|
|
{
|
|
json_object *jstring;
|
|
char hexstr[33];
|
|
|
|
hex2str(key, 16, hexstr, 33);
|
|
jstring = json_object_new_string(hexstr);
|
|
json_object_object_add(jobject, desc, jstring);
|
|
}
|
|
|
|
static json_object *find_node_by_primary(json_object *jmain, uint16_t primary)
|
|
{
|
|
json_object *jarray;
|
|
int i, len;
|
|
|
|
json_object_object_get_ex(jmain, "nodes", &jarray);
|
|
|
|
if (!jarray)
|
|
return NULL;
|
|
len = json_object_array_length(jarray);
|
|
|
|
for (i = 0; i < len; ++i) {
|
|
json_object *jnode;
|
|
json_object *jconfig;
|
|
json_object *jelements;
|
|
json_object *jelement;
|
|
json_object *jvalue;
|
|
char *str;
|
|
uint16_t addr;
|
|
|
|
jnode = json_object_array_get_idx(jarray, i);
|
|
if (!jnode)
|
|
return NULL;
|
|
|
|
json_object_object_get_ex(jnode, "configuration", &jconfig);
|
|
if (!jconfig)
|
|
return NULL;
|
|
|
|
json_object_object_get_ex(jconfig, "elements", &jelements);
|
|
if (!jelements)
|
|
return NULL;
|
|
|
|
jelement = json_object_array_get_idx(jelements, 0);
|
|
if (!jelement)
|
|
return NULL;
|
|
|
|
json_object_object_get_ex(jelement, "unicastAddress",
|
|
&jvalue);
|
|
str = (char *)json_object_get_string(jvalue);
|
|
if (sscanf(str, "%04hx", &addr) != 1)
|
|
return NULL;
|
|
|
|
if (addr == primary)
|
|
return jnode;
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
void prov_db_print_node_composition(struct mesh_node *node)
|
|
{
|
|
char *in_str;
|
|
const char *comp_str;
|
|
json_object *jmain;
|
|
json_object *jnode;
|
|
json_object *jcomp;
|
|
uint16_t primary = node_get_primary(node);
|
|
const char *filename;
|
|
bool res = false;
|
|
|
|
if (!node || !node_get_composition(node))
|
|
return;
|
|
|
|
if (node == node_get_local_node())
|
|
filename = local_filename;
|
|
else
|
|
filename = prov_filename;
|
|
|
|
in_str = prov_file_read(filename);
|
|
if (!in_str)
|
|
return;
|
|
|
|
jmain = json_tokener_parse(in_str);
|
|
if (!jmain)
|
|
goto done;
|
|
|
|
jnode = find_node_by_primary(jmain, primary);
|
|
if (!jnode)
|
|
goto done;
|
|
|
|
json_object_object_get_ex(jnode, "composition", &jcomp);
|
|
if (!jcomp)
|
|
goto done;
|
|
|
|
comp_str = json_object_to_json_string_ext(jcomp,
|
|
JSON_C_TO_STRING_PRETTY);
|
|
|
|
res = true;
|
|
|
|
done:
|
|
if (res)
|
|
bt_shell_printf("\tComposition data for node %4.4x %s\n",
|
|
primary, comp_str);
|
|
else
|
|
bt_shell_printf("\tComposition data for node %4.4x not present\n",
|
|
primary);
|
|
g_free(in_str);
|
|
|
|
if (jmain)
|
|
json_object_put(jmain);
|
|
}
|
|
|
|
bool prov_db_add_node_composition(struct mesh_node *node, uint8_t *data,
|
|
uint16_t len)
|
|
{
|
|
char *in_str;
|
|
json_object *jmain;
|
|
json_object *jnode;
|
|
json_object *jcomp;
|
|
json_object *jbool;
|
|
json_object *jfeatures;
|
|
json_object *jelements;
|
|
struct mesh_node_composition *comp;
|
|
uint8_t num_ele;
|
|
int i;
|
|
uint16_t primary = node_get_primary(node);
|
|
bool res = NULL;
|
|
|
|
comp = node_get_composition(node);
|
|
if (!comp)
|
|
return false;
|
|
|
|
in_str = prov_file_read(prov_filename);
|
|
if (!in_str)
|
|
return false;
|
|
|
|
jmain = json_tokener_parse(in_str);
|
|
if (!jmain)
|
|
goto done;
|
|
|
|
jnode = find_node_by_primary(jmain, primary);
|
|
if (!jnode)
|
|
goto done;
|
|
|
|
jcomp = json_object_new_object();
|
|
|
|
put_uint16(jcomp, "cid", comp->cid);
|
|
put_uint16(jcomp, "pid", comp->pid);
|
|
put_uint16(jcomp, "vid", comp->pid);
|
|
put_uint16(jcomp, "crpl", comp->crpl);
|
|
|
|
jfeatures = json_object_new_object();
|
|
jbool = json_object_new_boolean(comp->relay);
|
|
json_object_object_add(jfeatures, "relay", jbool);
|
|
jbool = json_object_new_boolean(comp->proxy);
|
|
json_object_object_add(jfeatures, "proxy", jbool);
|
|
jbool = json_object_new_boolean(comp->friend);
|
|
json_object_object_add(jfeatures, "friend", jbool);
|
|
jbool = json_object_new_boolean(comp->lpn);
|
|
json_object_object_add(jfeatures, "lpn", jbool);
|
|
json_object_object_add(jcomp, "features", jfeatures);
|
|
|
|
data += 11;
|
|
len -= 11;
|
|
|
|
num_ele = node_get_num_elements(node);
|
|
|
|
jelements = json_object_new_array();
|
|
|
|
for (i = 0; i < num_ele; ++i) {
|
|
json_object *jelement;
|
|
json_object *jmodels;
|
|
json_object *jint;
|
|
uint32_t mod_id;
|
|
uint16_t vendor_id;
|
|
uint8_t m, v;
|
|
|
|
jelement = json_object_new_object();
|
|
|
|
/* Element Index */
|
|
jint = json_object_new_int(i);
|
|
json_object_object_add(jelement, "elementIndex", jint);
|
|
|
|
/* Location */
|
|
put_uint16(jelement, "location", get_le16(data));
|
|
data += 2;
|
|
m = *data++;
|
|
v = *data++;
|
|
len -= 4;
|
|
|
|
/* Models */
|
|
jmodels = json_object_new_array();
|
|
while (len >= 2 && m--) {
|
|
mod_id = get_le16(data);
|
|
data += 2;
|
|
len -= 2;
|
|
put_uint16_array_entry(jmodels, (uint16_t) mod_id);
|
|
}
|
|
|
|
while (len >= 4 && v--) {
|
|
mod_id = get_le16(data + 2);
|
|
vendor_id = get_le16(data);
|
|
mod_id |= (vendor_id << 16);
|
|
data += 4;
|
|
len -= 4;
|
|
put_uint32_array_entry(jmodels, mod_id);
|
|
}
|
|
|
|
json_object_object_add(jelement, "models", jmodels);
|
|
json_object_array_add(jelements, jelement);
|
|
}
|
|
|
|
json_object_object_add(jcomp, "elements", jelements);
|
|
|
|
json_object_object_add(jnode, "composition", jcomp);
|
|
|
|
prov_file_write(jmain, false);
|
|
|
|
res = true;;
|
|
done:
|
|
|
|
g_free(in_str);
|
|
|
|
if(jmain)
|
|
json_object_put(jmain);
|
|
|
|
return res;
|
|
}
|
|
|
|
bool prov_db_node_set_ttl(struct mesh_node *node, uint8_t ttl)
|
|
{
|
|
char *in_str;
|
|
json_object *jmain;
|
|
json_object *jnode;
|
|
json_object *jconfig;
|
|
json_object *jvalue;
|
|
uint16_t primary = node_get_primary(node);
|
|
const char *filename;
|
|
bool local = node == node_get_local_node();
|
|
bool res = false;
|
|
|
|
if (local)
|
|
filename = local_filename;
|
|
else
|
|
filename = prov_filename;
|
|
|
|
in_str = prov_file_read(filename);
|
|
if (!in_str)
|
|
return false;
|
|
|
|
jmain = json_tokener_parse(in_str);
|
|
if (!jmain)
|
|
goto done;
|
|
|
|
if (local)
|
|
json_object_object_get_ex(jmain, "node", &jnode);
|
|
else
|
|
jnode = find_node_by_primary(jmain, primary);
|
|
|
|
if (!jnode)
|
|
goto done;
|
|
|
|
json_object_object_get_ex(jnode, "configuration", &jconfig);
|
|
if (!jconfig)
|
|
goto done;
|
|
|
|
json_object_object_del(jconfig, "defaultTTL");
|
|
|
|
jvalue = json_object_new_int(ttl);
|
|
json_object_object_add(jconfig, "defaultTTL", jvalue);
|
|
|
|
prov_file_write(jmain, local);
|
|
|
|
res = true;
|
|
done:
|
|
|
|
g_free(in_str);
|
|
|
|
if(jmain)
|
|
json_object_put(jmain);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
static void set_local_iv_index(json_object *jobj, uint32_t idx, bool update)
|
|
{
|
|
json_object *jvalue;
|
|
|
|
json_object_object_del(jobj, "IVindex");
|
|
jvalue = json_object_new_int(idx);
|
|
json_object_object_add(jobj, "IVindex", jvalue);
|
|
|
|
json_object_object_del(jobj, "IVupdate");
|
|
jvalue = json_object_new_int((update) ? 1 : 0);
|
|
json_object_object_add(jobj, "IVupdate", jvalue);
|
|
|
|
}
|
|
|
|
bool prov_db_local_set_iv_index(uint32_t iv_index, bool update, bool prov)
|
|
{
|
|
char *in_str;
|
|
json_object *jmain;
|
|
json_object *jnode;
|
|
bool res = false;
|
|
|
|
in_str = prov_file_read(local_filename);
|
|
if (!in_str)
|
|
return false;
|
|
|
|
jmain = json_tokener_parse(in_str);
|
|
if (!jmain)
|
|
goto done;
|
|
|
|
json_object_object_get_ex(jmain, "node", &jnode);
|
|
set_local_iv_index(jnode, iv_index, update);
|
|
prov_file_write(jmain, true);
|
|
|
|
g_free(in_str);
|
|
json_object_put(jmain);
|
|
|
|
/* If provisioner, save to global DB as well */
|
|
if (prov) {
|
|
in_str = prov_file_read(prov_filename);
|
|
if (!in_str)
|
|
return false;
|
|
|
|
jmain = json_tokener_parse(in_str);
|
|
if (!jmain)
|
|
goto done;
|
|
|
|
set_local_iv_index(jmain, iv_index, update);
|
|
prov_file_write(jmain, false);
|
|
}
|
|
|
|
res = true;
|
|
done:
|
|
|
|
g_free(in_str);
|
|
|
|
if(jmain)
|
|
json_object_put(jmain);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
bool prov_db_local_set_seq_num(uint32_t seq_num)
|
|
{
|
|
char *in_str;
|
|
json_object *jmain;
|
|
json_object *jnode;
|
|
json_object *jvalue;
|
|
bool res = false;
|
|
|
|
in_str = prov_file_read(local_filename);
|
|
if (!in_str)
|
|
return false;
|
|
|
|
jmain = json_tokener_parse(in_str);
|
|
if (!jmain)
|
|
goto done;
|
|
|
|
json_object_object_get_ex(jmain, "node", &jnode);
|
|
|
|
json_object_object_del(jnode, "sequenceNumber");
|
|
jvalue = json_object_new_int(seq_num);
|
|
json_object_object_add(jnode, "sequenceNumber", jvalue);
|
|
|
|
prov_file_write(jmain, true);
|
|
|
|
res = true;
|
|
done:
|
|
|
|
g_free(in_str);
|
|
|
|
if(jmain)
|
|
json_object_put(jmain);
|
|
|
|
return res;
|
|
}
|
|
|
|
bool prov_db_node_set_iv_seq(struct mesh_node *node, uint32_t iv, uint32_t seq)
|
|
{
|
|
char *in_str;
|
|
json_object *jmain;
|
|
json_object *jnode;
|
|
json_object *jvalue;
|
|
uint16_t primary = node_get_primary(node);
|
|
bool res = false;
|
|
|
|
in_str = prov_file_read(prov_filename);
|
|
if (!in_str)
|
|
return false;
|
|
|
|
jmain = json_tokener_parse(in_str);
|
|
if (!jmain)
|
|
goto done;
|
|
|
|
jnode = find_node_by_primary(jmain, primary);
|
|
if (!jnode)
|
|
goto done;
|
|
|
|
json_object_object_del(jnode, "IVindex");
|
|
|
|
jvalue = json_object_new_int(iv);
|
|
json_object_object_add(jnode, "IVindex", jvalue);
|
|
|
|
json_object_object_del(jnode, "sequenceNumber");
|
|
|
|
jvalue = json_object_new_int(seq);
|
|
json_object_object_add(jnode, "sequenceNumber", jvalue);
|
|
|
|
prov_file_write(jmain, false);
|
|
|
|
res = true;
|
|
done:
|
|
|
|
g_free(in_str);
|
|
|
|
if(jmain)
|
|
json_object_put(jmain);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
bool prov_db_node_keys(struct mesh_node *node, GList *idxs, const char *desc)
|
|
{
|
|
char *in_str;
|
|
json_object *jmain;
|
|
json_object *jnode;
|
|
json_object *jconfig;
|
|
json_object *jidxs;
|
|
uint16_t primary = node_get_primary(node);
|
|
const char *filename;
|
|
bool local = (node == node_get_local_node());
|
|
bool res = false;
|
|
|
|
if (local)
|
|
filename = local_filename;
|
|
else
|
|
filename = prov_filename;
|
|
|
|
in_str = prov_file_read(filename);
|
|
if (!in_str)
|
|
return false;
|
|
|
|
jmain = json_tokener_parse(in_str);
|
|
if (!jmain)
|
|
goto done;
|
|
|
|
jnode = find_node_by_primary(jmain, primary);
|
|
if (!jnode)
|
|
goto done;
|
|
|
|
json_object_object_get_ex(jnode, "configuration", &jconfig);
|
|
if (!jconfig)
|
|
goto done;
|
|
|
|
json_object_object_del(jconfig, desc);
|
|
|
|
if (idxs) {
|
|
jidxs = json_object_new_array();
|
|
put_uint16_list(jidxs, idxs);
|
|
json_object_object_add(jconfig, desc, jidxs);
|
|
}
|
|
|
|
prov_file_write(jmain, local);
|
|
|
|
res = true;
|
|
done:
|
|
|
|
g_free(in_str);
|
|
|
|
if(jmain)
|
|
json_object_put(jmain);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
static json_object *get_jmodel_obj(struct mesh_node *node, uint8_t ele_idx,
|
|
uint32_t model_id, json_object **jmain)
|
|
{
|
|
char *in_str;
|
|
json_object *jnode;
|
|
json_object *jconfig;
|
|
json_object *jelements, *jelement;
|
|
json_object *jmodels, *jmodel = NULL;
|
|
uint16_t primary = node_get_primary(node);
|
|
const char *filename;
|
|
bool local = (node == node_get_local_node());
|
|
|
|
if (local)
|
|
filename = local_filename;
|
|
else
|
|
filename = prov_filename;
|
|
|
|
in_str = prov_file_read(filename);
|
|
if (!in_str)
|
|
return NULL;
|
|
|
|
*jmain = json_tokener_parse(in_str);
|
|
if (!(*jmain))
|
|
goto done;
|
|
|
|
if (local)
|
|
json_object_object_get_ex(*jmain, "node", &jnode);
|
|
else
|
|
jnode = find_node_by_primary(*jmain, primary);
|
|
|
|
if (!jnode)
|
|
goto done;
|
|
|
|
/* Configuration is mandatory for nodes in provisioning database */
|
|
json_object_object_get_ex(jnode, "configuration", &jconfig);
|
|
if (!jconfig)
|
|
goto done;
|
|
|
|
json_object_object_get_ex(jconfig, "elements", &jelements);
|
|
if (!jelements) {
|
|
goto done;
|
|
}
|
|
|
|
jelement = json_object_array_get_idx(jelements, ele_idx);
|
|
if (!jelement) {
|
|
goto done;
|
|
}
|
|
|
|
json_object_object_get_ex(jelement, "models", &jmodels);
|
|
|
|
if (!jmodels) {
|
|
jmodels = json_object_new_array();
|
|
json_object_object_add(jelement, "models", jmodels);
|
|
} else {
|
|
parse_configuration_models(node, ele_idx, jmodels,
|
|
model_id, &jmodel);
|
|
}
|
|
|
|
if (!jmodel) {
|
|
jmodel = json_object_new_object();
|
|
|
|
if ((model_id & 0xffff0000) == 0xffff0000)
|
|
put_uint16(jmodel, "modelId", model_id & 0xffff);
|
|
else
|
|
put_uint32(jmodel, "modelId", model_id);
|
|
|
|
json_object_array_add(jmodels, jmodel);
|
|
}
|
|
|
|
done:
|
|
|
|
g_free(in_str);
|
|
|
|
if(!jmodel && *jmain)
|
|
json_object_put(*jmain);
|
|
|
|
return jmodel;
|
|
|
|
}
|
|
|
|
bool prov_db_add_binding(struct mesh_node *node, uint8_t ele_idx,
|
|
uint32_t model_id, uint16_t app_idx)
|
|
{
|
|
json_object *jmain;
|
|
json_object *jmodel;
|
|
json_object *jvalue;
|
|
json_object *jbindings = NULL;
|
|
bool local = (node == node_get_local_node());
|
|
|
|
jmodel = get_jmodel_obj(node, ele_idx, model_id, &jmain);
|
|
|
|
if (!jmodel)
|
|
return false;
|
|
|
|
json_object_object_get_ex(jmodel, "bind", &jbindings);
|
|
|
|
if (!jbindings) {
|
|
jbindings = json_object_new_array();
|
|
json_object_object_add(jmodel, "bind", jbindings);
|
|
}
|
|
|
|
jvalue = json_object_new_int(app_idx);
|
|
json_object_array_add(jbindings, jvalue);
|
|
|
|
prov_file_write(jmain, local);
|
|
|
|
json_object_put(jmain);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool prov_db_node_set_model_pub(struct mesh_node *node, uint8_t ele_idx,
|
|
uint32_t model_id,
|
|
struct mesh_publication *pub)
|
|
{
|
|
json_object *jmain;
|
|
json_object *jmodel;
|
|
json_object *jpub;
|
|
json_object *jvalue;
|
|
bool local = (node == node_get_local_node());
|
|
|
|
jmodel = get_jmodel_obj(node, ele_idx, model_id, &jmain);
|
|
|
|
if (!jmodel)
|
|
return false;
|
|
|
|
json_object_object_del(jmodel, "publish");
|
|
if (!pub)
|
|
goto done;
|
|
|
|
jpub = json_object_new_object();
|
|
|
|
/* Save only required fields */
|
|
put_uint16(jpub, "address", pub->u.addr16);
|
|
put_uint16(jpub, "index", pub->app_idx);
|
|
jvalue = json_object_new_int(pub->ttl);
|
|
json_object_object_add(jpub, "ttl", jvalue);
|
|
|
|
json_object_object_add(jmodel, "publish", jpub);
|
|
|
|
done:
|
|
prov_file_write(jmain, local);
|
|
|
|
json_object_put(jmain);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool prov_db_add_new_node(struct mesh_node *node)
|
|
{
|
|
char *in_str;
|
|
json_object *jmain;
|
|
json_object *jarray;
|
|
json_object *jnode;
|
|
json_object *jconfig;
|
|
json_object *jelements;
|
|
uint8_t num_ele;
|
|
uint16_t primary;
|
|
int i;
|
|
bool first_node;
|
|
bool res = false;
|
|
|
|
in_str = prov_file_read(prov_filename);
|
|
if (!in_str)
|
|
return false;
|
|
|
|
jmain = json_tokener_parse(in_str);
|
|
if (!jmain)
|
|
goto done;
|
|
json_object_object_get_ex(jmain, "nodes", &jarray);
|
|
|
|
if (!jarray) {
|
|
jarray = json_object_new_array();
|
|
first_node = true;
|
|
} else
|
|
first_node = false;
|
|
|
|
jnode = json_object_new_object();
|
|
|
|
/* Device key */
|
|
add_key(jnode, "deviceKey", node_get_device_key(node));
|
|
|
|
/* Net key */
|
|
jconfig = json_object_new_object();
|
|
add_node_idxs(jconfig, "netKeys", node_get_net_keys(node));
|
|
|
|
num_ele = node_get_num_elements(node);
|
|
if (num_ele == 0)
|
|
goto done;
|
|
|
|
jelements = json_object_new_array();
|
|
|
|
primary = node_get_primary(node);
|
|
if (IS_UNASSIGNED(primary))
|
|
goto done;
|
|
|
|
for (i = 0; i < num_ele; ++i) {
|
|
json_object *jelement;
|
|
json_object *jint;
|
|
|
|
jelement = json_object_new_object();
|
|
|
|
/* Element Index */
|
|
jint = json_object_new_int(i);
|
|
json_object_object_add(jelement, "elementIndex", jint);
|
|
|
|
/* Unicast */
|
|
put_uint16(jelement, "unicastAddress", primary + i);
|
|
|
|
json_object_array_add(jelements, jelement);
|
|
}
|
|
|
|
json_object_object_add(jconfig, "elements", jelements);
|
|
|
|
json_object_object_add(jnode, "configuration", jconfig);
|
|
|
|
json_object_array_add(jarray, jnode);
|
|
|
|
if (first_node)
|
|
json_object_object_add(jmain, "nodes", jarray);
|
|
|
|
prov_file_write(jmain, false);
|
|
|
|
res = true;
|
|
done:
|
|
|
|
g_free(in_str);
|
|
|
|
if (jmain)
|
|
json_object_put(jmain);
|
|
|
|
return res;
|
|
}
|
|
|
|
static bool parse_node_composition(struct mesh_node *node, json_object *jcomp)
|
|
{
|
|
json_object *jvalue;
|
|
json_object *jelements;
|
|
json_bool enable;
|
|
char *str;
|
|
struct mesh_node_composition comp;
|
|
|
|
json_object_object_get_ex(jcomp, "cid", &jvalue);
|
|
if (!jvalue)
|
|
return false;
|
|
|
|
str = (char *)json_object_get_string(jvalue);
|
|
|
|
if (sscanf(str, "%04hx", &comp.cid) != 1)
|
|
return false;
|
|
|
|
json_object_object_get_ex(jcomp, "pid", &jvalue);
|
|
if (!jvalue)
|
|
return false;
|
|
|
|
str = (char *)json_object_get_string(jvalue);
|
|
|
|
if (sscanf(str, "%04hx", &comp.vid) != 1)
|
|
return false;
|
|
|
|
json_object_object_get_ex(jcomp, "vid", &jvalue);
|
|
if (!jvalue)
|
|
return false;
|
|
|
|
str = (char *)json_object_get_string(jvalue);
|
|
|
|
if (sscanf(str, "%04hx", &comp.vid) != 1)
|
|
return false;
|
|
|
|
json_object_object_get_ex(jcomp, "crpl", &jvalue);
|
|
if (!jvalue)
|
|
return false;
|
|
|
|
str = (char *)json_object_get_string(jvalue);
|
|
|
|
if (sscanf(str, "%04hx", &comp.crpl) != 1)
|
|
return false;
|
|
|
|
/* Extract features */
|
|
json_object_object_get_ex(jcomp, "relay", &jvalue);
|
|
enable = json_object_get_boolean(jvalue);
|
|
comp.relay = (enable) ? true : false;
|
|
|
|
json_object_object_get_ex(jcomp, "proxy", &jvalue);
|
|
enable = json_object_get_boolean(jvalue);
|
|
comp.proxy = (enable) ? true : false;
|
|
|
|
json_object_object_get_ex(jcomp, "friend", &jvalue);
|
|
enable = json_object_get_boolean(jvalue);
|
|
comp.friend = (enable) ? true : false;
|
|
|
|
json_object_object_get_ex(jcomp, "lowPower", &jvalue);
|
|
enable = json_object_get_boolean(jvalue);
|
|
comp.lpn = (enable) ? true : false;
|
|
|
|
if (!node_set_composition(node, &comp))
|
|
return false;
|
|
|
|
json_object_object_get_ex(jcomp, "elements", &jelements);
|
|
if (!jelements)
|
|
return false;
|
|
|
|
return parse_composition_elements(node, jelements);
|
|
}
|
|
|
|
static bool parse_node(json_object *jnode, bool local)
|
|
{
|
|
json_object *jconfig;
|
|
json_object *jelements;
|
|
json_object *jidxs;
|
|
json_object *jvalue;
|
|
json_object *jint;
|
|
uint8_t key[16];
|
|
char *value_str;
|
|
uint32_t idx;
|
|
struct mesh_node *node;
|
|
|
|
/* Device key */
|
|
if (!json_object_object_get_ex(jnode, "deviceKey", &jvalue) ||
|
|
!jvalue) {
|
|
if (!mesh_get_random_bytes(key, 16))
|
|
return false;
|
|
|
|
add_key(jnode, "deviceKey", key);
|
|
} else {
|
|
value_str = (char *)json_object_get_string(jvalue);
|
|
if (!str2hex(value_str, strlen(value_str), key, 16))
|
|
return false;;
|
|
}
|
|
|
|
node = node_new();
|
|
|
|
if (!node)
|
|
return false;
|
|
|
|
node_set_device_key(node, key);
|
|
|
|
json_object_object_get_ex(jnode, "IVindex", &jint);
|
|
if (jint)
|
|
idx = json_object_get_int(jint);
|
|
else
|
|
idx = 0;
|
|
|
|
node_set_iv_index(node, idx);
|
|
if (local) {
|
|
bool update = false;
|
|
json_object_object_get_ex(jnode, "IVupdate", &jint);
|
|
if (jint)
|
|
update = json_object_get_int(jint) ? true : false;
|
|
net_set_iv_index(idx, update);
|
|
}
|
|
|
|
if (json_object_object_get_ex(jnode, "sequenceNumber", &jint) &&
|
|
jint) {
|
|
int seq = json_object_get_int(jint);
|
|
node_set_sequence_number(node, seq);
|
|
}
|
|
|
|
/* Composition is mandatory for local node */
|
|
json_object_object_get_ex(jnode, "composition", &jconfig);
|
|
if ((jconfig && !parse_node_composition(node, jconfig)) ||
|
|
(!jconfig && local)) {
|
|
node_free(node);
|
|
return false;
|
|
}
|
|
|
|
/* Configuration is mandatory for nodes in provisioning database */
|
|
json_object_object_get_ex(jnode, "configuration", &jconfig);
|
|
if (!jconfig) {
|
|
if (local) {
|
|
/* This is an unprovisioned local device */
|
|
goto done;
|
|
} else {
|
|
node_free(node);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
json_object_object_get_ex(jconfig, "elements", &jelements);
|
|
if (!jelements) {
|
|
node_free(node);
|
|
return false;
|
|
}
|
|
|
|
if (!parse_configuration_elements(node, jelements, local)) {
|
|
node_free(node);
|
|
return false;;
|
|
}
|
|
|
|
json_object_object_get_ex(jconfig, "netKeys", &jidxs);
|
|
if (!jidxs || (parse_node_keys(node, jidxs, false) == 0)) {
|
|
node_free(node);
|
|
return false;
|
|
}
|
|
|
|
json_object_object_get_ex(jconfig, "appKeys", &jidxs);
|
|
if (jidxs)
|
|
parse_node_keys(node, jidxs, true);
|
|
|
|
json_object_object_get_ex(jconfig, "defaultTTL", &jvalue);
|
|
if (jvalue) {
|
|
int ttl = json_object_get_int(jvalue);
|
|
node_set_default_ttl(node, ttl &TTL_MASK);
|
|
}
|
|
|
|
done:
|
|
if (local && !node_set_local_node(node)) {
|
|
node_free(node);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool prov_db_show(const char *filename)
|
|
{
|
|
char *str;
|
|
|
|
str = prov_file_read(filename);
|
|
if (!str)
|
|
return false;
|
|
|
|
bt_shell_printf("%s\n", str);
|
|
g_free(str);
|
|
return true;
|
|
}
|
|
|
|
static bool read_json_db(const char *filename, bool provisioner, bool local)
|
|
{
|
|
char *str;
|
|
json_object *jmain;
|
|
json_object *jarray;
|
|
json_object *jprov;
|
|
json_object *jvalue;
|
|
json_object *jtemp;
|
|
uint8_t key[16];
|
|
int value_int;
|
|
char *value_str;
|
|
int len;
|
|
int i;
|
|
uint32_t index;
|
|
bool refresh = false;
|
|
bool res = false;
|
|
|
|
str = prov_file_read(filename);
|
|
if (!str) return false;
|
|
|
|
jmain = json_tokener_parse(str);
|
|
if (!jmain)
|
|
goto done;
|
|
|
|
if (local) {
|
|
json_object *jnode;
|
|
bool result;
|
|
|
|
json_object_object_get_ex(jmain, "node", &jnode);
|
|
if (!jnode) {
|
|
bt_shell_printf("Cannot find \"node\" object");
|
|
goto done;
|
|
} else
|
|
result = parse_node(jnode, true);
|
|
|
|
/*
|
|
* If local node is provisioner, the rest of mesh settings
|
|
* are read from provisioning database.
|
|
*/
|
|
if (provisioner) {
|
|
res = result;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
/* IV index */
|
|
json_object_object_get_ex(jmain, "IVindex", &jvalue);
|
|
if (!jvalue)
|
|
goto done;
|
|
|
|
index = json_object_get_int(jvalue);
|
|
|
|
json_object_object_get_ex(jmain, "IVupdate", &jvalue);
|
|
if (!jvalue)
|
|
goto done;
|
|
|
|
value_int = json_object_get_int(jvalue);
|
|
|
|
net_set_iv_index(index, value_int);
|
|
|
|
/* Network key(s) */
|
|
json_object_object_get_ex(jmain, "netKeys", &jarray);
|
|
if (!jarray)
|
|
goto done;
|
|
|
|
len = json_object_array_length(jarray);
|
|
bt_shell_printf("# netkeys = %d\n", len);
|
|
|
|
for (i = 0; i < len; ++i) {
|
|
uint32_t idx;
|
|
|
|
jtemp = json_object_array_get_idx(jarray, i);
|
|
json_object_object_get_ex(jtemp, "index", &jvalue);
|
|
if (!jvalue)
|
|
goto done;
|
|
idx = json_object_get_int(jvalue);
|
|
|
|
json_object_object_get_ex(jtemp, "key", &jvalue);
|
|
if (!jvalue) {
|
|
if (!mesh_get_random_bytes(key, 16))
|
|
goto done;
|
|
add_key(jtemp, "key", key);
|
|
refresh = true;
|
|
} else {
|
|
value_str = (char *)json_object_get_string(jvalue);
|
|
if (!str2hex(value_str, strlen(value_str), key, 16)) {
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if (!keys_net_key_add(idx, key, false))
|
|
goto done;
|
|
|
|
json_object_object_get_ex(jtemp, "keyRefresh", &jvalue);
|
|
if (!jvalue)
|
|
goto done;
|
|
|
|
keys_set_kr_phase(idx, (uint8_t) json_object_get_int(jvalue));
|
|
}
|
|
|
|
/* App keys */
|
|
json_object_object_get_ex(jmain, "appKeys", &jarray);
|
|
if (jarray) {
|
|
len = json_object_array_length(jarray);
|
|
bt_shell_printf("# appkeys = %d\n", len);
|
|
|
|
for (i = 0; i < len; ++i) {
|
|
int app_idx;
|
|
int net_idx;
|
|
|
|
jtemp = json_object_array_get_idx(jarray, i);
|
|
json_object_object_get_ex(jtemp, "index",
|
|
&jvalue);
|
|
if (!jvalue)
|
|
goto done;
|
|
|
|
app_idx = json_object_get_int(jvalue);
|
|
if (!CHECK_KEY_IDX_RANGE(app_idx))
|
|
goto done;
|
|
|
|
json_object_object_get_ex(jtemp, "key", &jvalue);
|
|
if (!jvalue) {
|
|
if (!mesh_get_random_bytes(key, 16))
|
|
goto done;
|
|
add_key(jtemp, "key", key);
|
|
refresh = true;
|
|
} else {
|
|
value_str =
|
|
(char *)json_object_get_string(jvalue);
|
|
str2hex(value_str, strlen(value_str), key, 16);
|
|
}
|
|
|
|
json_object_object_get_ex(jtemp, "boundNetKey",
|
|
&jvalue);
|
|
if (!jvalue)
|
|
goto done;
|
|
|
|
net_idx = json_object_get_int(jvalue);
|
|
if (!CHECK_KEY_IDX_RANGE(net_idx))
|
|
goto done;
|
|
|
|
keys_app_key_add(net_idx, app_idx, key, false);
|
|
}
|
|
}
|
|
|
|
/* Provisioner info */
|
|
json_object_object_get_ex(jmain, "provisioners", &jarray);
|
|
if (!jarray)
|
|
goto done;
|
|
|
|
len = json_object_array_length(jarray);
|
|
bt_shell_printf("# provisioners = %d\n", len);
|
|
|
|
for (i = 0; i < len; ++i) {
|
|
|
|
jprov = json_object_array_get_idx(jarray, i);
|
|
|
|
/* Allocated unicast range */
|
|
json_object_object_get_ex(jprov, "allocatedUnicastRange",
|
|
&jtemp);
|
|
if (!jtemp) {
|
|
goto done;
|
|
}
|
|
|
|
if (!parse_unicast_range(jtemp)) {
|
|
bt_shell_printf("Doneed to parse unicast range\n");
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
json_object_object_get_ex(jmain, "nodes", &jarray);
|
|
if (!jarray) {
|
|
res = true;
|
|
goto done;
|
|
}
|
|
|
|
len = json_object_array_length(jarray);
|
|
|
|
bt_shell_printf("# provisioned nodes = %d\n", len);
|
|
for (i = 0; i < len; ++i) {
|
|
json_object *jnode;
|
|
jnode = json_object_array_get_idx(jarray, i);
|
|
|
|
if (!jnode || !parse_node(jnode, false))
|
|
goto done;
|
|
}
|
|
|
|
res = true;
|
|
done:
|
|
|
|
g_free(str);
|
|
|
|
if (res && refresh)
|
|
prov_file_write(jmain, false);
|
|
|
|
if (jmain)
|
|
json_object_put(jmain);
|
|
|
|
return res;
|
|
}
|
|
|
|
bool prov_db_read(const char *filename)
|
|
{
|
|
prov_filename = filename;
|
|
return read_json_db(filename, true, false);
|
|
}
|
|
|
|
bool prov_db_read_local_node(const char *filename, bool provisioner)
|
|
{
|
|
local_filename = filename;
|
|
return read_json_db(filename, provisioner, true);
|
|
}
|