Major rewrite for Multi-Node and DBus
Subsystems (2)
v6 cover Major rewrite for Multi-Node and DBus
The Mesh Daemon has been largely rewritten.
It matches the API in doc/mesh-api.txt, and is now accessible from non- privledged DBus clients. The commandline version has been temporarily removed, although it will probably be re-added in the future. The dBus privledges need to be adjusted to allow for non-privledged access to Daemon interfaces. We will shortly also be adding a Mesh Specific README and TODO file, but in the meantime, contact Brian and/or Inga with any questions.
v6 -- Address Marcel's v5 comments, including cleanup, and unstacking include files. There was also some compression of commits, where little was being actually done. Other big difference with patch set is a more verbose explanation of non-trivial commits, particularily where functionality was removed (or deleted) in favor of rewrites in other (mostly new) files. This is especially true of Provisioning which has been largely rewritten for both readability and for focus.
Tested on TIP of upstream/master as of 28-Dec-2018, on Fedora 27, 28 and 29, with both ./bootstrap-configure, and distcheck.
Brian Gix (10):
mesh: Structural changes for mesh
mesh: Rewrite Network layer for multiple nodes
mesh: Direction agnostic PB-ADV implementation
mesh: Acceptor side provisioning implementation
mesh: Initiator side provisioning implementation
mesh: Rewrite Controler interface for full init
mesh: Unchanged variables set to const
mesh: re-arrange provisioning for DBus API
mesh: restructure I/O for multiple nodes
mesh: Clean-up Comment style
Inga Stotland (16):
mesh: Utilities for DBus support
mesh: Internal errors
mesh: Rewrite storage for Multiple Nodes
mesh: Rewrite Node handling for multiple nodes
mesh: Hex-String manipulation, and debug logging
mesh: Re-architect for DBus API
mesh: Multi node Config Server model
mesh: Restructure DB to support multiple nodes
mesh: Restructure model services for multiple nodes
mesh: DBUS interface for Provisioning Agent
mesh: restructure App Key storage
mesh: Update for DBus API and multi-node support
mesh: Add default location for Mesh Node storage
mesh: Sample Provisioning Agent
mesh: Sample On/Off Client and Server
mesh: Sample Mesh Joiner (provision acceptor)
.gitignore | 1 -
Makefile.mesh | 19 +-
configure.ac | 3 +
mesh/agent.c | 665 +++++++++++++++++----
mesh/agent.h | 69 ++-
mesh/appkey.c | 19 +-
mesh/appkey.h | 1 -
mesh/btmesh.c | 181 ------
mesh/cfgmod-server.c | 179 +++---
mesh/cfgmod.h | 3 +-
mesh/config/composition.json | 44 --
mesh/dbus.c | 151 +++++
mesh/dbus.h | 33 ++
mesh/display.c | 64 --
mesh/error.h | 34 ++
mesh/friend.c | 76 +--
mesh/main.c | 75 ++-
mesh/mesh-db.c | 456 +++++++++-----
mesh/mesh-db.h | 9 +-
mesh/mesh-io-api.h | 2 +-
mesh/mesh-io-generic.c | 149 ++++-
mesh/mesh-io.c | 3 +-
mesh/mesh-io.h | 3 +-
mesh/mesh.c | 626 +++++++++++++++-----
mesh/mesh.h | 28 +-
mesh/model.c | 813 +++++++++++++++++--------
mesh/model.h | 69 ++-
mesh/net.c | 294 +++------
mesh/net.h | 34 +-
mesh/node.c | 1340 +++++++++++++++++++++++++++++++++++-------
mesh/node.h | 43 +-
mesh/pb-adv.c | 444 ++++++++++++++
mesh/{display.h => pb-adv.h} | 13 +-
mesh/prov-acceptor.c | 684 +++++++++++++++++++++
mesh/prov-initiator.c | 641 ++++++++++++++++++++
mesh/prov.c | 722 -----------------------
mesh/prov.h | 14 +-
mesh/provision.c | 1162 ------------------------------------
mesh/provision.h | 112 +++-
mesh/storage.c | 571 ++++++++----------
mesh/storage.h | 38 +-
mesh/util.c | 27 +-
mesh/util.h | 2 +-
test/agent.py | 40 ++
test/example-onoff-client | 288 +++++++++
test/example-onoff-server | 365 ++++++++++++
test/test-join | 408 +++++++++++++
47 files changed, 7103 insertions(+), 3914 deletions(-)
delete mode 100644 mesh/btmesh.c
delete mode 100644 mesh/config/composition.json
create mode 100644 mesh/dbus.c
create mode 100644 mesh/dbus.h
delete mode 100644 mesh/display.c
create mode 100644 mesh/error.h
create mode 100644 mesh/pb-adv.c
rename mesh/{display.h => pb-adv.h} (71%)
create mode 100644 mesh/prov-acceptor.c
create mode 100644 mesh/prov-initiator.c
delete mode 100644 mesh/prov.c
delete mode 100644 mesh/provision.c
create mode 100755 test/agent.py
create mode 100644 test/example-onoff-client
create mode 100644 test/example-onoff-server
create mode 100644 test/test-joinSignature · 1 line
2.14.5
PATCH v6 1/26 mesh: Structural changes for mesh
btmesh.c: (Deleted) Contains no unique functionality display.[ch]: retained functionality moved to util.c prov.c: PB-ADV functionaility retained in pb-adv.c proivision.c: Retained functionality split between
prov-acceptor.c and prov-initiator.c
--- .gitignore | 1 - Makefile.mesh | 19 +- mesh/btmesh.c | 181 ------- mesh/config/composition.json | 44 -- mesh/display.c | 64 --- mesh/display.h | 28 - mesh/prov.c | 722 -------------------------- mesh/provision.c | 1162 ------------------------------------------ 8 files changed, 6 insertions(+), 2215 deletions(-) delete mode 100644 mesh/btmesh.c delete mode 100644 mesh/config/composition.json delete mode 100644 mesh/display.c delete mode 100644 mesh/display.h delete mode 100644 mesh/prov.c delete mode 100644 mesh/provision.c
.gitignore +0 -1
@@ -130,7 +130,6 @@ emulator/hfp client/bluetoothctl tools/meshctl mesh/meshd -mesh/btmesh src/bluetoothd.8 src/bluetooth.service
Makefile.mesh +6 -13
@@ -3,35 +3,28 @@ if MESH mesh_sources = mesh/mesh.h mesh/mesh.c \ mesh/net_keys.h mesh/net_keys.c \ mesh/mesh-io.h mesh/mesh-io.c \ - mesh/mesh-io-api.h \ + mesh/error.h mesh/mesh-io-api.h \ mesh/mesh-io-generic.h \ mesh/mesh-io-generic.c \ mesh/storage.h mesh/storage.c \ mesh/net.h mesh/net.c \ - mesh/display.h mesh/display.c \ mesh/crypto.h mesh/crypto.c \ mesh/friend.h mesh/friend.c \ mesh/appkey.h mesh/appkey.c \ mesh/node.h mesh/node.c \ - mesh/prov.h mesh/prov.c \ - mesh/provision.h mesh/provision.c \ + mesh/provision.h mesh/prov.h \ mesh/model.h mesh/model.c \ mesh/cfgmod.h mesh/cfgmod-server.c \ mesh/mesh-db.h mesh/mesh-db.c \ mesh/util.h mesh/util.c \ + mesh/dbus.h mesh/dbus.c \ + mesh/agent.h mesh/agent.c \ + mesh/prov-acceptor.c mesh/prov-initiator.c \ + mesh/pb-adv.h mesh/pb-adv.c \ mesh/mesh-defs.h libexec_PROGRAMS += mesh/meshd mesh_meshd_SOURCES = $(mesh_sources) mesh/main.c mesh_meshd_LDADD = src/libshared-ell.la $(ell_ldadd) -ljson-c mesh_meshd_DEPENDENCIES = $(ell_dependencies) src/libshared-ell.la - -noinst_PROGRAMS += mesh/btmesh - -mesh_btmesh_SOURCES = $(mesh_sources) mesh/agent.h \ - mesh/agent.c \ - mesh/btmesh.c -mesh_btmesh_LDADD = src/libshared-mainloop.la $(ell_ldadd) -lreadline -ljson-c -mesh_btmesh_DEPENDENCIES = $(ell_dependencies) - endif
mesh/btmesh.c deleted +0 -181
181 lines not on this page · raw message
mesh/config/composition.json deleted +0 -44
44 lines not on this page · raw message
mesh/display.c deleted +0 -64
64 lines not on this page · raw message
mesh/display.h deleted +0 -28
@@ -1,28 +0,0 @@ -/* -* -* BlueZ - Bluetooth protocol stack for Linux -* -* Copyright (C) 2018 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. -* -*/ - -#define COLOR_OFF "\x1B[0m" -#define COLOR_RED "\x1B[0;91m" -#define COLOR_GREEN "\x1B[0;92m" -#define COLOR_YELLOW "\x1B[0;93m" -#define COLOR_BLUE "\x1B[0;94m" - -unsigned int num_columns (void ); - -void print_packet (const char *label,const void *data,uint16_t size);
mesh/prov.c deleted +0 -722
722 lines not on this page · raw message
mesh/provision.c deleted +0 -1162
1,162 lines not on this page · raw message
Signature · 1 line
2.14.5
PATCH v6 2/26 mesh: Utilities for DBus support
In reply to Brian GixFrom: Inga Stotland <[email protected]>
These files implement the BlueZ mesh DBus API as described in doc/mesh-api.txt
--- mesh/dbus.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ mesh/dbus.h | 33 +++++++++++++ 2 files changed, 184 insertions(+) create mode 100644 mesh/dbus.c create mode 100644 mesh/dbus.h
mesh/dbus.c new file +151 -0
@@ -0,0 +1,151 @@ +/* +* +* BlueZ - Bluetooth protocol stack for Linux +* +* Copyright (C) 2018 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 + +#include <time.h> +#include <ell/ell.h> +#include <json-c/json.h> + +#include "lib/bluetooth.h" +#include "lib/mgmt.h" + +#include "src/shared/mgmt.h" + +#include "mesh/mesh-defs.h" +#include "mesh/mesh-io.h" +#include "mesh/node.h" +#include "mesh/net.h" +#include "mesh/storage.h" +#include "mesh/cfgmod.h" +#include "mesh/model.h" +#include "mesh/mesh.h" +#include "mesh/error.h" +#include "mesh/dbus.h" + +static struct l_dbus *dbus; + +struct error_entry { +const char *dbus_err; +const char *default_desc; +}; + +/* +* Important: The entries in this table follow the order of +* enumerated values in mesh_error (file error.h) +*/ +static struct error_entry const error_table[] = +{ + {NULL ,NULL }, + {ERROR_INTERFACE ".Failed" ,"Operation failed" }, + {ERROR_INTERFACE ".NotAuthorized" ,"Permission denied" }, + {ERROR_INTERFACE ".NotFound" ,"Object not found" }, + {ERROR_INTERFACE ".InvalidArgs" ,"Invalid arguments" }, + {ERROR_INTERFACE ".InProgress" ,"Already in progress" }, + {ERROR_INTERFACE ".AlreadyExists" ,"Already exists" }, + {ERROR_INTERFACE ".DoesNotExist" ,"Does not exist" }, + {ERROR_INTERFACE ".Canceled" ,"Operation canceled" } +}; + +struct l_dbus_message *dbus_error (struct l_dbus_message *msg,int err, +const char *description) +{ +int array_len =L_ARRAY_SIZE (error_table); + +/* Default to ".Failed" */ +if (!err || err >= array_len) + err =MESH_ERROR_FAILED ; + +if (description) +return l_dbus_message_new_error (msg, + error_table[err].dbus_err, +"%s" , description); +else +return l_dbus_message_new_error (msg, + error_table[err].dbus_err, +"%s" , error_table[err].default_desc); +} + +struct l_dbus *dbus_get_bus (void ) +{ +return dbus; +} + +bool dbus_init (struct l_dbus *bus) +{ +/* Network interface */ +if (!mesh_dbus_init (bus)) +return false; + +/* Node interface */ +if (!node_dbus_init (bus)) +return false; + + dbus = bus; + +return true; +} + +bool dbus_match_interface (struct l_dbus_message_iter *interfaces, +const char *match) +{ +const char *interface; +struct l_dbus_message_iter properties; + +while (l_dbus_message_iter_next_entry (interfaces, &interface, + &properties)) { +if (!strcmp (match, interface)) +return true; + } + +return false; +} + +bool dbus_append_byte_array (struct l_dbus_message_builder *builder, +const uint8_t *data,int len) +{ +int i; + +if (!l_dbus_message_builder_enter_array (builder,"y" )) +return false; + +for (i =0 ; i < len; i++) +if (!l_dbus_message_builder_append_basic (builder,'y' , + data + i)) +return false; + +if (!l_dbus_message_builder_leave_array (builder)) +return false; + +return true; +} + +void dbus_append_dict_entry_basic (struct l_dbus_message_builder *builder, +const char *key,const char *signature, +const void *data) +{ +l_dbus_message_builder_enter_dict (builder,"sv" ); +l_dbus_message_builder_append_basic (builder,'s' , key); +l_dbus_message_builder_enter_variant (builder, signature); +l_dbus_message_builder_append_basic (builder, signature[0 ], data); +l_dbus_message_builder_leave_variant (builder); +l_dbus_message_builder_leave_dict (builder); +}
mesh/dbus.h new file +33 -0
@@ -0,0 +1,33 @@ +/* +* +* BlueZ - Bluetooth protocol stack for Linux +* +* Copyright (C) 2018 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. +* +*/ + +#define BLUEZ_MESH_PATH "/org/bluez/mesh" +#define BLUEZ_MESH_SERVICE "org.bluez.mesh" + +bool dbus_init (struct l_dbus *dbus); +struct l_dbus *dbus_get_bus (void ); +bool dbus_append_byte_array (struct l_dbus_message_builder *builder, +const uint8_t *data,int len); +void dbus_append_dict_entry_basic (struct l_dbus_message_builder *builder, +const char *key,const char *signature, +const void *data); +bool dbus_match_interface (struct l_dbus_message_iter *interfaces, +const char *match); +struct l_dbus_message *dbus_error (struct l_dbus_message *msg,int err, +const char *description);
Signature · 1 line
2.14.5
PATCH v6 3/26 mesh: Internal errors
In reply to Brian GixFrom: Inga Stotland <[email protected]>
Error codes that map to specific faults that may occur while using the Mesh DBus API.
--- mesh/error.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 mesh/error.h
mesh/error.h new file +34 -0
@@ -0,0 +1,34 @@ +/* +* +* BlueZ - Bluetooth protocol stack for Linux +* +* Copyright (C) 2018 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. +* +*/ + +/* +* Important: Changes in this table must be reflected in the +* the entries of error_table[] in dbus.c +*/ +enum mesh_error { +MESH_ERROR_NONE , +MESH_ERROR_FAILED , +MESH_ERROR_NOT_AUTHORIZED , +MESH_ERROR_NOT_FOUND , +MESH_ERROR_INVALID_ARGS , +MESH_ERROR_BUSY , +MESH_ERROR_ALREADY_EXISTS , +MESH_ERROR_DOES_NOT_EXIST , +MESH_ERROR_CANCELED , +};
Signature · 1 line
2.14.5
PATCH v6 4/26 mesh: Rewrite storage for Multiple Nodes
In reply to Brian GixFrom: Inga Stotland <[email protected]>
Node storage now occurs in a privileged location, in the (default:/var/lib/bluetooth/mesh) and is stored so that multiple nodes may be handled by a single instance of the daemon. The node storage files must be priviledged access only, to prevent unauthorized access to the security material entrusted to each node.
--- mesh/storage.c | 571 +++++++++++++++++++++++++-------------------------------- mesh/storage.h | 38 ++-- 2 files changed, 267 insertions(+), 342 deletions(-)
mesh/storage.c +249 -322
@@ -15,7 +15,6 @@* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * -* */ #ifdef HAVE_CONFIG_H
@@ -27,6 +26,8 @@#include <fcntl.h> #include <stdio.h> #include <unistd.h> +#include <dirent.h> +#include <libgen.h> #include <sys/types.h> #include <sys/stat.h>
@@ -42,39 +43,43 @@#include "mesh/net.h" #include "mesh/appkey.h" #include "mesh/model.h" +#include "mesh/mesh-db.h" #include "mesh/storage.h" -/* -* TODO: figure out naming convention to store alternative nodes -* Mesh storage dir wil be in configure.ac -*/ -#define DEVICE_COMPOSITION_FILE "../config/composition.json" -#define NODE_CONGIGURATION_FILE "../config/configuration.json" +struct write_info { +json_object *jnode; +const char *config_name; +void *user_data; +mesh_status_func_t cb; +}; + +static const char *storage_dir; +static struct l_queue *node_ids; -static bool read_local_node_cb (struct mesh_db_node *db_node,void *user_data) +static bool simple_match (const void *a,const void *b) { -struct mesh_net *net = user_data; -struct mesh_node *node; +return a == b; +} + +static bool read_node_cb (struct mesh_db_node *db_node,void *user_data) +{ +struct mesh_node *node = user_data; +struct mesh_net *net;uint32_t seq_number; -uint16_t crpl;uint8_t ttl, mode, cnt, num_ele;uint16_t unicast, interval;uint8_t *uuid; -if (!net) -return false; - - node =node_create_from_storage (net, db_node, true); -if (!node) +if (!node_init_from_storage (node, db_node)) { +node_free (node);return false; + } -mesh_net_local_node_set (net, node, db_node->provisioner); + net =node_get_net (node); seq_number =node_get_sequence_number (node);mesh_net_set_seq_num (net, seq_number); ttl =node_default_ttl_get (node);mesh_net_set_default_ttl (net, ttl); - crpl =node_get_crpl (node); -mesh_net_set_crpl (net, crpl); mode =node_proxy_mode_get (node);if (mode ==MESH_MODE_ENABLED || mode ==MESH_MODE_DISABLED )
@@ -103,6 +108,7 @@ static bool read_local_node_cb(struct mesh_db_node *db_node, void *user_data) uuid =node_uuid_get (node);if (uuid)mesh_net_id_uuid_set (net, uuid); +return true; }
@@ -132,13 +138,14 @@ static bool read_app_keys_cb(uint16_t net_idx, uint16_t app_idx, uint8_t *key,return appkey_key_init (net, net_idx, app_idx, key, new_key); } -static bool parse_local_node (struct mesh_net *net,json_object *jnode) +static bool parse_node (struct mesh_node *node,json_object *jnode) {bool bvalue;uint32_t iv_index;uint8_t key_buf[16 ];uint8_t cnt;uint16_t interval; +struct mesh_net *net =node_get_net (node);if (mesh_db_read_iv_index (jnode, &iv_index, &bvalue))mesh_net_set_iv_index (net, iv_index, bvalue);
@@ -147,97 +154,35 @@ static bool parse_local_node(struct mesh_net *net, json_object *jnode)mesh_net_transmit_params_set (net, cnt, interval);/* Node composition/configuration info */ -if (!mesh_db_read_node (jnode, read_local_node_cb, net)) +if (!mesh_db_read_node (jnode, read_node_cb, node))return false;if (!mesh_db_read_net_keys (jnode, read_net_keys_cb, net))return false; -/* TODO: use the actual "primary" network index for this node */ -if (mesh_db_read_device_key (jnode, key_buf) && - !node_set_device_key (mesh_net_local_node_get (net), key_buf)) +if (!mesh_db_read_device_key (jnode, key_buf))return false; -mesh_db_read_app_keys (jnode, read_app_keys_cb, net); - -return true; -} - -static bool read_unprov_device_cb (struct mesh_db_node *db_node,void *user_data) -{ -struct mesh_net *net = user_data; -struct mesh_node *node; -uint16_t crpl; -uint8_t *uuid; +node_set_device_key (node, key_buf); -if (!net) -return false; - - node =node_create_from_storage (net, db_node, true); - -if (!node) -return false; - -mesh_net_local_node_set (net, node, db_node->provisioner); - crpl =node_get_crpl (node); -mesh_net_set_crpl (net, crpl); - - uuid =node_uuid_get (node); -if (uuid) -mesh_net_id_uuid_set (net, uuid); +mesh_db_read_app_keys (jnode, read_app_keys_cb, net);return true; } -static bool parse_unprovisioned_device (struct mesh_net *net,json_object *jnode) -{ -struct mesh_db_prov prov; -struct mesh_net_prov_caps *caps; -struct mesh_node *node; - -/* Node composition/configuration info */ -if (!mesh_db_read_unprovisioned_device (jnode, - read_unprov_device_cb, net)) -return false; - -if (!mesh_db_read_prov_info (jnode, &prov)) -return false; - - caps =mesh_net_prov_caps_get (net); -if (!caps) -return false; - - node =mesh_net_local_node_get (net); -if (!node) -return false; - - caps->num_ele =node_get_num_elements (node); -l_put_le16 (prov.algorithm, &caps->algorithms); - caps->pub_type = prov.pub_type; - caps->static_type = prov.static_type; - caps->output_size = prov.output_oob.size; -l_put_le16 (prov.output_oob.actions, &caps->output_action); - caps->input_size = prov.input_oob.size; -l_put_le16 (prov.input_oob.actions, &caps->input_action); - -return mesh_net_priv_key_set (net, prov.priv_key); -} - -static bool parse_config (struct mesh_net *net,const char *config_name, -bool unprovisioned) +static bool parse_config (char *in_file,char *out_file,uint16_t node_id) {int fd;char *str; -const char *out;struct stat st;ssize_t sz;json_object *jnode =NULL ;bool result = false; +struct mesh_node *node; -if (!config_name) -return false; +l_info ("Loading configuration from %s" , in_file); - fd =open (config_name,O_RDONLY ); + fd =open (in_file,O_RDONLY );if (!fd)return false;
@@ -254,7 +199,7 @@ static bool parse_config(struct mesh_net *net, const char *config_name, sz =read (fd, str, st.st_size);if (sz != st.st_size) { -l_error ("Failed to read configuration file" ); +l_error ("Failed to read configuration file %s" , in_file); goto done; }
@@ -262,22 +207,19 @@ static bool parse_config(struct mesh_net *net, const char *config_name,if (!jnode) goto done; -mesh_net_jconfig_set (net, jnode); + node =node_new (); -if (!unprovisioned) - result =parse_local_node (net, jnode); -else - result =parse_unprovisioned_device (net, jnode); +node_jconfig_set (node, jnode); +node_cfg_file_set (node, out_file); +node_id_set (node, node_id); + + result =parse_node (node, jnode);if (!result) { -storage_release (net); - goto done; +json_object_put (jnode); +node_free (node); } -mesh_net_cfg_file_get (net, &out); -if (!out) -mesh_net_cfg_file_set (net, !unprovisioned ? - config_name :NODE_CONGIGURATION_FILE ); done:close (fd);if (str)
@@ -286,166 +228,70 @@ done:return result; } -bool storage_parse_config (struct mesh_net *net,const char *config_name) +bool storage_set_ttl (json_object *jnode,uint8_t ttl) { -bool result = false; -bool unprovisioned = !config_name; - -if (unprovisioned) { - result =parse_config (net,DEVICE_COMPOSITION_FILE , true); - goto done; - } - - result =parse_config (net, config_name, false); - -if (!result) { -size_t len =strlen (config_name) +5 ; -char *bak =l_malloc (len); - -/* Fall-back to Backup version */ -strncpy (bak, config_name, len); - bak =strncat (bak,".bak" ,5 ); - -remove (config_name); -rename (bak, config_name); - - result =parse_config (net, config_name, false); - -l_free (bak); - } - -/* If configuration read fails, try as unprovisioned device */ -if (!result) { -l_info ("Parse configuration failed, trying unprovisioned" ); - unprovisioned = true; - result =parse_config (net,DEVICE_COMPOSITION_FILE , true); - } - -done: -if (result) -mesh_net_provisioned_set (net, !unprovisioned); - -return result; -} - -bool storage_local_set_ttl (struct mesh_net *net,uint8_t ttl) -{ -json_object *jnode; - -if (!net) -return false; - - jnode =mesh_net_jconfig_get (net); -if (!jnode) -return false; -return mesh_db_write_int (jnode,"defaultTTL" , ttl); } -bool storage_local_set_relay (struct mesh_net *net,bool enable, +bool storage_set_relay (json_object *jnode,bool enable,uint8_t count,uint8_t interval) { -json_object *jnode; - -if (!net) -return false; - - jnode =mesh_net_jconfig_get (net); -if (!jnode) -return false; -return mesh_db_write_relay_mode (jnode, enable, count, interval); } -bool storage_local_set_transmit_params (struct mesh_net *net,uint8_t count, +bool storage_set_transmit_params (json_object *jnode,uint8_t count,uint8_t interval) { -json_object *jnode; - -if (!net) -return false; - - jnode =mesh_net_jconfig_get (net); -if (!jnode) -return false; -return mesh_db_write_net_transmit (jnode, count, interval); } -bool storage_local_set_mode (struct mesh_net *net,uint8_t mode, +bool storage_set_mode (json_object *jnode,uint8_t mode,const char *mode_name) { -json_object *jnode; - -if (!net || !mode_name) -return false; - - jnode =mesh_net_jconfig_get (net); -if (!jnode) -return false; -return mesh_db_write_mode (jnode, mode_name, mode); } -bool storage_model_bind (struct mesh_net *net,uint16_t addr,uint32_t mod_id, +bool storage_model_bind (struct mesh_node *node,uint16_t addr,uint32_t mod_id,uint16_t app_idx,bool unbind) {json_object *jnode; -bool is_local; +int ele_idx; +bool is_vendor = (mod_id >0xffff ); -if (!net) + ele_idx =node_get_element_idx (node, addr); +if (ele_idx <0 )return false; - is_local =mesh_net_is_local_address (net, addr); -if (is_local) { -int ele_idx; -bool is_vendor = (mod_id >0xffff ); - - ele_idx =node_get_element_idx (mesh_net_local_node_get (net), - addr); -if (ele_idx <0 ) -return false; - - jnode =mesh_net_jconfig_get (net); -if (!jnode) -return false; - -if (unbind) -return mesh_db_model_binding_del (jnode, ele_idx, - is_vendor, mod_id, app_idx); -else -return mesh_db_model_binding_add (jnode, ele_idx, - is_vendor, mod_id, app_idx); - } + jnode =node_jconfig_get (node); -/* TODO: write remote node bindings to provisioner DB */ -return false; +if (unbind) +return mesh_db_model_binding_del (jnode, ele_idx, is_vendor, + mod_id, app_idx); +else +return mesh_db_model_binding_add (jnode, ele_idx, is_vendor, + mod_id, app_idx); } -bool storage_local_app_key_add (struct mesh_net *net,uint16_t net_idx, +bool storage_app_key_add (struct mesh_net *net,uint16_t net_idx,uint16_t app_idx,const uint8_t key[16 ],bool update) {json_object *jnode; +struct mesh_node *node =mesh_net_node_get (net); -if (!net) -return false; - - jnode =mesh_net_jconfig_get (net); + jnode =node_jconfig_get (node);if (!jnode)return false;return mesh_db_app_key_add (jnode, net_idx, app_idx, key, update); } -bool storage_local_app_key_del (struct mesh_net *net,uint16_t net_idx, +bool storage_app_key_del (struct mesh_net *net,uint16_t net_idx,uint16_t app_idx) {json_object *jnode; +struct mesh_node *node =mesh_net_node_get (net); -if (!net) -return false; - - jnode =mesh_net_jconfig_get (net); + jnode =node_jconfig_get (node);if (!jnode)return false;
@@ -453,116 +299,53 @@ bool storage_local_app_key_del(struct mesh_net *net, uint16_t net_idx, } -bool storage_local_net_key_add (struct mesh_net *net,uint16_t net_idx, +bool storage_net_key_add (struct mesh_net *net,uint16_t net_idx,const uint8_t key[16 ],int phase) { -json_object *jnode; - -if (!net) -return false; - - jnode =mesh_net_jconfig_get (net); -if (!jnode) -return false; +struct mesh_node *node =mesh_net_node_get (net); +json_object *jnode =node_jconfig_get (node);return mesh_db_net_key_add (jnode, net_idx, key, phase); } -bool storage_local_net_key_del (struct mesh_net *net,uint16_t net_idx) +bool storage_net_key_del (struct mesh_net *net,uint16_t net_idx) { -json_object *jnode; - -if (!net) -return false; - - jnode =mesh_net_jconfig_get (net); -if (!jnode) -return false; +struct mesh_node *node =mesh_net_node_get (net); +json_object *jnode =node_jconfig_get (node);return mesh_db_net_key_del (jnode, net_idx); } -bool storage_local_set_iv_index (struct mesh_net *net,uint32_t iv_index, +bool storage_set_iv_index (struct mesh_net *net,uint32_t iv_index,bool update) { -json_object *jnode; - -if (!net) -return false; - - jnode =mesh_net_jconfig_get (net); -if (!jnode) -return false; +struct mesh_node *node =mesh_net_node_get (net); +json_object *jnode =node_jconfig_get (node);return mesh_db_write_iv_index (jnode, iv_index, update); } -bool storage_local_set_device_key (struct mesh_net *net,uint8_t dev_key[16 ]) -{ -json_object *jnode; - -if (!net) -return false; - - jnode =mesh_net_jconfig_get (net); -if (!jnode) -return false; - -return mesh_db_write_device_key (jnode, dev_key); -} - -bool storage_local_set_unicast (struct mesh_net *net,uint16_t unicast) -{ -json_object *jnode; - -if (!net) -return false; - - jnode =mesh_net_jconfig_get (net); -if (!jnode) -return false; - -return mesh_db_write_uint16_hex (jnode,"unicastAddress" , unicast); -} - -bool storage_local_write_sequence_number (struct mesh_net *net,uint32_t seq) +bool storage_write_sequence_number (struct mesh_net *net,uint32_t seq) { -json_object *jnode; -const char *cfg_file; +struct mesh_node *node =mesh_net_node_get (net); +json_object *jnode =node_jconfig_get (node);bool result; - -if (!net) -return false; - - jnode =mesh_net_jconfig_get (net); -if (!jnode) -return false; - +l_debug ("" ); result =mesh_db_write_int (jnode,"sequenceNumber" , seq);if (!result)return false; - result =mesh_net_cfg_file_get (net, &cfg_file); -if (result && cfg_file) - result =storage_save_config (net, cfg_file, false,NULL ,NULL ); + result =storage_save_config (node, false,NULL ,NULL );return result; } -static bool save_config (struct mesh_net *net,const char *config_name) +static bool save_config (json_object *jnode,const char *config_name) {FILE *outfile;const char *str; -json_object *jnode;bool result = false; -if (!net || !config_name) -return false; - - jnode =mesh_net_jconfig_get (net); -if (!jnode) -return false; - outfile =fopen (config_name,"w" );if (!outfile) {l_error ("Failed to save configuration to %s" , config_name);
@@ -581,13 +364,6 @@ static bool save_config(struct mesh_net *net, const char *config_name)return result; } -struct write_info { -const char *config_name; -struct mesh_net *net; -void *user_data; -mesh_status_func_t cb; -}; -static void idle_save_config (void *user_data) {struct write_info *info = user_data;
@@ -603,7 +379,7 @@ static void idle_save_config(void *user_data)remove (tmp);l_debug ("Storage-Wrote" ); - result =save_config (info->net, tmp); + result =save_config (info->jnode, tmp);if (result) {remove (bak);
@@ -621,48 +397,199 @@ static void idle_save_config(void *user_data)l_free (info); } -bool storage_save_config (struct mesh_net *net,const char *config_name, -bool no_wait,mesh_status_func_t cb,void *user_data) +bool storage_save_config (struct mesh_node *node,bool no_wait, +mesh_status_func_t cb,void *user_data) {struct write_info *info; info = l_new(struct write_info, 1);if (!info)return false; - - info->net = net; - info->config_name = config_name; +l_debug ("" ); + info->jnode =node_jconfig_get (node); + info->config_name =node_cfg_file_get (node); info->cb = cb; info->user_data = user_data;if (no_wait)idle_save_config (info); -l_idle_oneshot (idle_save_config, info,NULL ); +else +l_idle_oneshot (idle_save_config, info,NULL );return true; } -bool storage_save_new_config (struct mesh_net *net,const char *config_name, -mesh_status_func_t cb,void *user_data) +static int create_dir (const char *dirname) { -json_object *jnode; +struct stat st; +char dir[PATH_MAX +1 ], *prev, *next; +int err; - jnode =mesh_net_jconfig_get (net); -if (!jnode) + err =stat (dirname, &st); +if (!err &&S_ISREG (st.st_mode)) +return 0 ; + +memset (dir,0 ,PATH_MAX +1 ); +strcat (dir,"/" ); + + prev =strchr (dirname,'/' ); + +while (prev) { + next =strchr (prev +1 ,'/' ); +if (!next) +break ; + +if (next - prev ==1 ) { + prev = next; +continue ; + } + +strncat (dir, prev +1 , next - prev); +mkdir (dir,0755 ); + + prev = next; + } + +mkdir (dirname,0755 ); + +return 0 ; +} + +bool storage_load_nodes (const char *dir_name) +{ +DIR *dir; +struct dirent *entry; + +create_dir (dir_name); + dir =opendir (dir_name); +if (!dir) { +l_error ("Failed to open mesh node storage directory: %s" , + dir_name);return false; + } + + storage_dir = dir_name; + node_ids =l_queue_new (); + +while ((entry =readdir (dir)) !=NULL ) { +char name_buf[PATH_MAX ]; +char *filename; +uint32_t node_id; +size_t len; + +if (entry->d_type !=DT_DIR ) +continue ; + +if (sscanf (entry->d_name,"%04x" , &node_id) !=1 ) +continue ; + +snprintf (name_buf,PATH_MAX ,"%s/%s/node.json" , dir_name, + entry->d_name); + +l_queue_push_tail (node_ids,L_UINT_TO_PTR (node_id)); + + len =strlen (name_buf); + filename =l_malloc (len +1 ); -mesh_db_remove_property (jnode,"provision" ); +strncpy (filename, name_buf, len +1 ); -return storage_save_config (net, config_name, false, cb, user_data); +if (parse_config (name_buf, filename, node_id)) +continue ; + +/* Fall-back to Backup version */ +snprintf (name_buf,PATH_MAX ,"%s/%s/node.json.bak" , dir_name, + entry->d_name); + +if (parse_config (name_buf, filename, node_id)) { +remove (filename); +rename (name_buf, filename); +continue ; + } + +l_free (filename); + } + +return true; } -void storage_release (struct mesh_net *net) +bool storage_create_node_config (struct mesh_node *node,void *data) { +struct mesh_db_node *db_node = data; +uint16_t node_id; +uint8_t num_tries =0 ; +char name_buf[PATH_MAX ]; +char *filename;json_object *jnode; +size_t len; + +if (!storage_dir) +return false; + + jnode =json_object_new_object (); + +if (!mesh_db_add_node (jnode, db_node)) +return false; + +do { +l_getrandom (&node_id,2 ); +if (!l_queue_find (node_ids, simple_match, +L_UINT_TO_PTR (node_id))) +break ; + }while (++num_tries <10 ); + +if (num_tries ==10 ) +l_error ("Failed to generate unique node ID" ); + +snprintf (name_buf,PATH_MAX ,"%s/%04x" , storage_dir, node_id); + +/* Create a new directory and node.json file */ +if (mkdir (name_buf,0755 ) !=0 ) + goto fail; - jnode =mesh_net_jconfig_get (net); + len =strlen (name_buf) +strlen ("/node.json" ) +1 ; + filename =l_malloc (len); + +snprintf (filename, len,"%s/node.json" , name_buf); +l_debug ("New node config %s" , filename); + +if (!save_config (jnode, filename)) { +l_free (filename); + goto fail; + } + +node_jconfig_set (node, jnode); +node_cfg_file_set (node, filename); + +return true; +fail: +json_object_put (jnode); +return false; +} + +/* Permanently remove node configuration */ +void storage_remove_node_config (struct mesh_node *node) +{ +char *cfgname; +struct json_object *jnode; +const char *dir_name; + + jnode =node_jconfig_get (node);if (jnode)json_object_put (jnode); +node_jconfig_set (node,NULL ); + + cfgname = (char *)node_cfg_file_get (node); +if (!cfgname) +return ; + +l_debug ("Delete node config file %s" , cfgname); +remove (cfgname); + + dir_name =dirname (cfgname); + +l_debug ("Delete directory %s" , dir_name); +rmdir (dir_name); -mesh_net_jconfig_set (net,NULL ); +l_free (cfgname); +node_cfg_file_set (node,NULL ); }
mesh/storage.h +18 -20
@@ -15,37 +15,35 @@* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * -* */ struct mesh_net ; +struct mesh_node ; -bool storage_parse_config (struct mesh_net *net,const char *config_name); -bool storage_save_config (struct mesh_net *net,const char *config_name, -bool no_wait,mesh_status_func_t cb,void *user_data); -bool storage_save_new_config (struct mesh_net *net,const char *config_name, +bool storage_load_nodes (const char *dir); +bool storage_create_node_config (struct mesh_node *node,void *db_node); +void storage_remove_node_config (struct mesh_node *node); +bool storage_save_config (struct mesh_node *node,bool no_wait,mesh_status_func_t cb,void *user_data); -void storage_release (struct mesh_net *net); - -bool storage_model_bind (struct mesh_net *net,uint16_t addr,uint32_t id, +bool storage_model_bind (struct mesh_node *node,uint16_t addr,uint32_t id,uint16_t app_idx,bool unbind); -bool storage_local_set_ttl (struct mesh_net *net,uint8_t ttl); -bool storage_local_set_relay (struct mesh_net *net,bool enable,uint8_t count, +bool storage_set_ttl (json_object *jnode,uint8_t ttl); +bool storage_set_relay (json_object *jnode,bool enable,uint8_t count,uint8_t interval); -bool storage_local_set_transmit_params (struct mesh_net *net,uint8_t count, +bool storage_set_transmit_params (json_object *jnode,uint8_t count,uint8_t interval); -bool storage_local_set_mode (struct mesh_net *net,uint8_t mode, +bool storage_set_mode (json_object *jnode,uint8_t mode,const char *mode_name); -bool storage_local_net_key_add (struct mesh_net *net,uint16_t net_idx, +bool storage_net_key_add (struct mesh_net *net,uint16_t net_idx,const uint8_t key[16 ],int phase); -bool storage_local_net_key_del (struct mesh_net *net,uint16_t net_idx); -bool storage_local_app_key_add (struct mesh_net *net,uint16_t net_idx, +bool storage_net_key_del (struct mesh_net *net,uint16_t net_idx); +bool storage_app_key_add (struct mesh_net *net,uint16_t net_idx,uint16_t app_idx,const uint8_t key[16 ],bool update); -bool storage_local_app_key_del (struct mesh_net *net,uint16_t net_idx, +bool storage_app_key_del (struct mesh_net *net,uint16_t net_idx,uint16_t app_idx); -bool storage_local_write_sequence_number (struct mesh_net *net,uint32_t seq); -bool storage_local_set_iv_index (struct mesh_net *net,uint32_t iv_index, +bool storage_write_sequence_number (struct mesh_net *net,uint32_t seq); +bool storage_set_iv_index (struct mesh_net *net,uint32_t iv_index,bool update); -bool storage_local_set_device_key (struct mesh_net *net,uint8_t dev_key[16 ]); -bool storage_local_set_unicast (struct mesh_net *net,uint16_t unicast); +bool storage_set_device_key (struct mesh_node *node,uint8_t dev_key[16 ]); +bool storage_set_unicast (struct mesh_node *node,uint16_t unicast);
Signature · 1 line
2.14.5
PATCH v6 5/26 mesh: Rewrite Node handling for multiple nodes
In reply to Brian GixFrom: Inga Stotland <[email protected]>
The Node describes an addressable entity in the Mesh. It has a composition that described the capabilities and purpose of the Node to remote Config Client nodes that are responsible for entire mesh maintenance. I also maintains runtime storage of the Encryption/Decryption keys, Subscriptions, and Publications that the remote Config Client has set up.
--- mesh/node.c | 1340 +++++++++++++++++++++++++++++++++++++++++++++++++---------- mesh/node.h | 43 +- 2 files changed, 1159 insertions(+), 224 deletions(-)
mesh/node.c +1130 -210
@@ -15,28 +15,47 @@* 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 +#include <stdio.h> #include <sys/time.h> #include <ell/ell.h> +#include <json-c/json.h> #include "mesh/mesh-defs.h" #include "mesh/mesh.h" +#include "mesh/mesh-io.h" #include "mesh/net.h" -#include "mesh/node.h" +#include "mesh/mesh-db.h" +#include "mesh/provision.h" #include "mesh/storage.h" #include "mesh/appkey.h" #include "mesh/model.h" +#include "mesh/cfgmod.h" +#include "mesh/util.h" +#include "mesh/error.h" +#include "mesh/dbus.h" +#include "mesh/agent.h" +#include "mesh/node.h" #define MIN_COMP_SIZE 14 +#define MESH_NODE_PATH_PREFIX "/node" +#define MESH_ELEMENT_PATH_PREFIX "/ele" + +/* Default element location: unknown */ +#define DEFAULT_LOCATION 0x0000 + +#define DEFAULT_CRPL 10 +#define DEFAULT_SEQUENCE_NUMBER 0 +struct node_element { +char *path;struct l_queue *models;uint16_t location;uint8_t idx;
@@ -51,30 +70,45 @@ struct node_composition {struct mesh_node {struct mesh_net *net; -struct l_queue *net_keys; -struct l_queue *app_keys;struct l_queue *elements; +char *app_path; +char *owner; +char *path; +void *jconfig; +char *cfg_file; +uint32_t disc_watch;time_t upd_sec;uint32_t seq_number;uint32_t seq_min_cache; -uint16_t primary; -uint16_t num_ele; -uint8_t dev_uuid[16 ]; -uint8_t dev_key[16 ]; -uint8_t ttl; +uint16_t id;bool provisioner; +uint16_t primary;struct node_composition *comp;struct {uint16_t interval;uint8_t cnt;uint8_t mode; } relay; +uint8_t dev_uuid[16 ]; +uint8_t dev_key[16 ]; +uint8_t num_ele; +uint8_t ttl;uint8_t lpn;uint8_t proxy;uint8_t friend;uint8_t beacon; }; +struct attach_obj_request { +node_attach_ready_func_t cb; +struct mesh_node *node; +}; + +struct join_obj_request { +node_join_ready_func_t cb; +const uint8_t *uuid; +}; +static struct l_queue *nodes;static bool match_node_unicast (const void *a,const void *b)
@@ -94,6 +128,14 @@ static bool match_device_uuid(const void *a, const void *b)return (memcmp (node->dev_uuid, uuid,16 ) ==0 ); } +static bool match_token (const void *a,const void *b) +{ +const struct mesh_node *node = a; +const uint64_t *token = b; +const uint64_t tmp =l_get_u64 (node->dev_key); +return *token == tmp; +} +static bool match_element_idx (const void *a,const void *b) {const struct node_element *element = a;
@@ -102,17 +144,15 @@ static bool match_element_idx(const void *a, const void *b)return (element->idx == index); } -static bool match_key_idx (const void *a,const void *b) +static bool match_element_path (const void *a,const void *b) { -return (L_PTR_TO_UINT (a) ==L_PTR_TO_UINT (b)); -} +const struct node_element *element = a; +const char *path = b; -static bool match_model_id (const void *a,const void *b) -{ -const struct mesh_model *model = a; -uint32_t id =L_PTR_TO_UINT (b); +if (!element->path) +return false; -return (mesh_model_get_model_id (model) == id); +return (!strcmp (element->path, path)); }struct mesh_node *node_find_by_addr (uint16_t addr)
@@ -140,20 +180,30 @@ struct mesh_node *node_new(void)struct mesh_node *node; node = l_new(struct mesh_node, 1); + node->net =mesh_net_new (node); -if (!node) -return NULL ; +if (!nodes) + nodes =l_queue_new ();l_queue_push_tail (nodes, node);return node; } +static void free_element_path (void *a,void *b) +{ +struct node_element *element = a; + +l_free (element->path); + element->path =NULL ; +} +static void element_free (void *data) {struct node_element *element = data;l_queue_destroy (element->models, mesh_model_free); +l_free (element->path);l_free (element); }
@@ -161,13 +211,20 @@ static void free_node_resources(void *data) {struct mesh_node *node = data; -l_queue_destroy (node->net_keys,NULL ); -l_queue_destroy (node->app_keys,NULL ); +/* Unregister io callbacks */ +if (node->net) +mesh_net_detach (node->net); +mesh_net_free (node->net); +l_queue_destroy (node->elements, element_free);l_free (node->comp); +l_free (node->app_path); +l_free (node->owner); -if (node->net) -mesh_net_unref (node->net); +if (node->path) +l_dbus_object_remove_interface (dbus_get_bus (), node->path, +MESH_NODE_INTERFACE ); +l_free (node->path);l_free (node); }
@@ -176,19 +233,18 @@ void node_free(struct mesh_node *node) {if (!node)return ; +l_queue_remove (nodes, node);free_node_resources (node); } -static bool add_models (struct mesh_net *net,struct node_element *ele, +static bool add_models (struct mesh_node *node,struct node_element *ele,struct mesh_db_element *db_ele) {const struct l_queue_entry *entry;if (!ele->models) ele->models =l_queue_new (); -if (!ele->models) -return false; entry =l_queue_get_entries (db_ele->models);for (; entry; entry = entry->next) {
@@ -196,7 +252,7 @@ static bool add_models(struct mesh_net *net, struct node_element *ele,struct mesh_db_model *db_mod; db_mod = entry->data; - mod =mesh_model_init (net, ele->idx, db_mod); + mod =mesh_model_setup (node, ele->idx, db_mod);if (!mod)return false;
@@ -206,6 +262,32 @@ static bool add_models(struct mesh_net *net, struct node_element *ele,return true; } +static void add_internal_model (struct mesh_node *node,uint32_t mod_id, +uint8_t ele_idx) +{ +struct node_element *ele; +struct mesh_model *mod; +struct mesh_db_model db_mod; + + ele =l_queue_find (node->elements, match_element_idx, +L_UINT_TO_PTR (ele_idx)); + +if (!ele) +return ; + +memset (&db_mod,0 ,sizeof (db_mod)); + db_mod.id = mod_id; + + mod =mesh_model_setup (node, ele_idx, &db_mod); +if (!mod) +return ; + +if (!ele->models) + ele->models =l_queue_new (); + +l_queue_push_tail (ele->models, mod); +} +static bool add_element (struct mesh_node *node,struct mesh_db_element *db_ele) {struct node_element *ele;
@@ -217,7 +299,7 @@ static bool add_element(struct mesh_node *node, struct mesh_db_element *db_ele) ele->idx = db_ele->index; ele->location = db_ele->location; -if (!db_ele->models || !add_models (node->net, ele, db_ele)) +if (!db_ele->models || !add_models (node, ele, db_ele))return false;l_queue_push_tail (node->elements, ele);
@@ -231,9 +313,6 @@ static bool add_elements(struct mesh_node *node, struct mesh_db_node *db_node)if (!node->elements) node->elements =l_queue_new (); -if (!node->elements) -return false; - entry =l_queue_get_entries (db_node->elements);for (; entry; entry = entry->next)if (!add_element (node, entry->data))
@@ -242,26 +321,12 @@ static bool add_elements(struct mesh_node *node, struct mesh_db_node *db_node)return true; } -struct mesh_node *node_create_from_storage (struct mesh_net *net, -struct mesh_db_node *db_node, -bool local) +bool node_init_from_storage (struct mesh_node *node,void *data) { -struct mesh_node *node; +struct mesh_db_node *db_node = data;unsigned int num_ele; -if (local && !net) -return NULL ; - - node =node_new (); -if (!node) -return NULL ; - node->comp = l_new(struct node_composition, 1); -if (!node->comp) { -node_free (node); -return NULL ; - } - node->comp->cid = db_node->cid; node->comp->pid = db_node->pid; node->comp->vid = db_node->vid;
@@ -276,107 +341,77 @@ struct mesh_node *node_create_from_storage(struct mesh_net *net, node->relay.interval = db_node->modes.relay.interval; node->beacon = db_node->modes.beacon; -l_info ("relay %2.2x, proxy %2.2x, lpn %2.2x, friend %2.2x" , - node->relay.mode, node->proxy, node->friend, node->lpn); +l_debug ("relay %2.2x, proxy %2.2x, lpn %2.2x, friend %2.2x" , + node->relay.mode, node->proxy, node->friend, node->lpn); node->ttl = db_node->ttl; node->seq_number = db_node->seq_number; num_ele =l_queue_length (db_node->elements); -if (num_ele >0xff ) { -node_free (node); -return NULL ; - } +if (num_ele >0xff ) +return false; node->num_ele = num_ele; -if (num_ele !=0 && !add_elements (node, db_node)) { -node_free (node); -return NULL ; - } +if (num_ele !=0 && !add_elements (node, db_node)) +return false; node->primary = db_node->unicast;memcpy (node->dev_uuid, db_node->uuid,16 ); -if (local) - node->net =mesh_net_ref (net); +/* Initialize configuration server model */ +mesh_config_srv_init (node,PRIMARY_ELE_IDX ); -return node; +return true; } -void node_cleanup (struct mesh_net *net) +void node_cleanup (void *data) { -struct mesh_node *node; +struct mesh_node *node = data; +struct mesh_net *net = node->net; -if (!net) -return ; - node =mesh_net_local_node_get (net); -if (node) -node_free (node); +/* Save local node configuration */ +if (node->cfg_file) { -l_queue_destroy (nodes, free_node_resources); +/* Preserve the last sequence number */ +storage_write_sequence_number (net,mesh_net_get_seq_num (net)); +if (storage_save_config (node, true,NULL ,NULL )) +l_info ("Saved final config to %s" , node->cfg_file); + } + +if (node->disc_watch) +l_dbus_remove_watch (dbus_get_bus (), node->disc_watch); + +free_node_resources (node); } -bool node_is_provisioned (struct mesh_node *node) +void node_cleanup_all (void ) { -return (!IS_UNASSIGNED (node->primary)); +l_queue_destroy (nodes, node_cleanup); +l_dbus_unregister_interface (dbus_get_bus (),MESH_NODE_INTERFACE ); } -bool node_net_key_delete (struct mesh_node *node,uint16_t idx) +bool node_is_provisioned (struct mesh_node *node) { -if (!node) -return false; - -if (!l_queue_find (node->net_keys, match_key_idx,L_UINT_TO_PTR (idx))) -return false; - -l_queue_remove (node->net_keys,L_UINT_TO_PTR (idx)); -/* TODO: remove all associated app keys and bindings */ -return true; +return (!IS_UNASSIGNED (node->primary)); }bool node_app_key_delete (struct mesh_net *net,uint16_t addr,uint16_t net_idx,uint16_t app_idx) {struct mesh_node *node; -uint32_t index;const struct l_queue_entry *entry; node =node_find_by_addr (addr);if (!node)return false; - index = (net_idx <<16 ) + app_idx; - -if (!l_queue_find (node->app_keys, match_key_idx,L_UINT_TO_PTR (index))) -return false; - -l_queue_remove (node->app_keys,L_UINT_TO_PTR (index)); - -storage_local_app_key_del (net, net_idx, app_idx); - entry =l_queue_get_entries (node->elements);for (; entry; entry = entry->next) {struct node_element *ele = entry->data; -mesh_model_app_key_delete (net, ele->models, app_idx); +mesh_model_app_key_delete (node, ele->models, app_idx); } - -return true; -} - -bool node_set_primary (struct mesh_node *node,uint16_t unicast) -{ -if (!node) -return false; - - node->primary = unicast; - -/* If local node, save to storage */ -if (node->net) -return storage_local_set_unicast (node->net, unicast); - -/* TODO: for provisioner, store remote node info */ return true; }
@@ -388,20 +423,9 @@ uint16_t node_get_primary(struct mesh_node *node)return node->primary; } -bool node_set_device_key (struct mesh_node *node,uint8_t key[16 ]) - +void node_set_device_key (struct mesh_node *node,uint8_t key[16 ]) { -if (!node || !key) -return false; -memcpy (node->dev_key, key,16 ); - -/* If local node, save to storage */ -if (node->net) -return storage_local_set_device_key (node->net, key); - -/* TODO: for provisioner, store remote node info */ -return true; }const uint8_t *node_get_device_key (struct mesh_node *node)
@@ -417,22 +441,6 @@ uint8_t node_get_num_elements(struct mesh_node *node)return node->num_ele; } -struct l_queue *node_get_net_keys (struct mesh_node *node) -{ -if (!node) -return NULL ; -else -return node->net_keys; -} - -struct l_queue *node_get_app_keys (struct mesh_node *node) -{ -if (!node) -return NULL ; -else -return node->app_keys; -} -struct l_queue *node_get_element_models (struct mesh_node *node,uint8_t ele_idx,int *status) {
@@ -458,31 +466,6 @@ struct l_queue *node_get_element_models(struct mesh_node *node,return ele->models; } -struct mesh_model *node_get_model (struct mesh_node *node,uint8_t ele_idx, -uint32_t id,int *status) -{ -struct l_queue *models; -struct mesh_model *model; - -if (!node) { -if (status) - *status =MESH_STATUS_INVALID_ADDRESS ; -return NULL ; - } - - models =node_get_element_models (node, ele_idx, status); -if (!models) -return NULL ; - - model =l_queue_find (models, match_model_id,L_UINT_TO_PTR (id)); - -if (status) - *status = (model) ?MESH_STATUS_SUCCESS : -MESH_STATUS_INVALID_MODEL ; - -return model; -} -uint8_t node_default_ttl_get (struct mesh_node *node) {if (!node)
@@ -492,20 +475,16 @@ uint8_t node_default_ttl_get(struct mesh_node *node)bool node_default_ttl_set (struct mesh_node *node,uint8_t ttl) { -bool res, is_local; +bool res;if (!node)return false; - is_local = (node->net &&mesh_net_local_node_get (node->net) == node) ? - true : false; - - res =storage_local_set_ttl (node->net, ttl); + res =storage_set_ttl (node->jconfig, ttl);if (res) { node->ttl = ttl; -if (is_local) -mesh_net_set_default_ttl (node->net, ttl); +mesh_net_set_default_ttl (node->net, ttl); }return res;
@@ -513,21 +492,13 @@ bool node_default_ttl_set(struct mesh_node *node, uint8_t ttl)bool node_set_sequence_number (struct mesh_node *node,uint32_t seq) { -bool is_local;struct timeval write_time; -if (!node)return false; node->seq_number = seq; - is_local = (node->net &&mesh_net_local_node_get (node->net) == node) ? - true : false; - -if (!is_local) -return true; -/* * Holistically determine worst case 5 minute sequence consumption * so that we typically (once we reach a steady state) rewrite the
@@ -541,7 +512,7 @@ bool node_set_sequence_number(struct mesh_node *node, uint32_t seq)if (elapsed <MIN_SEQ_CACHE_TIME ) {uint32_t ideal = node->seq_min_cache; -l_info ("Old Seq Cache: %d" , node->seq_min_cache); +l_debug ("Old Seq Cache: %d" , node->seq_min_cache); ideal *= (MIN_SEQ_CACHE_TIME / elapsed);
@@ -550,14 +521,13 @@ bool node_set_sequence_number(struct mesh_node *node, uint32_t seq)else node->seq_min_cache +=MIN_SEQ_CACHE ; -l_info ("New Seq Cache: %d" , node->seq_min_cache); +l_debug ("New Seq Cache: %d" , node->seq_min_cache); } } node->upd_sec = write_time.tv_sec; -l_info ("Storage-Write" ); -return storage_local_write_sequence_number (node->net, seq); +return storage_write_sequence_number (node->net, seq); }uint32_t node_get_sequence_number (struct mesh_node *node)
@@ -629,24 +599,19 @@ 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) { -bool res, is_local; +bool res;if (!node || node->relay.mode ==MESH_MODE_UNSUPPORTED )return false; - is_local = (node->net &&mesh_net_local_node_get (node->net) == node) ? - true : false; - - res =storage_local_set_relay (node->net, enable, cnt, interval); + res =storage_set_relay (node->jconfig, enable, cnt, interval);if (res) { node->relay.mode = enable ?MESH_MODE_ENABLED :MESH_MODE_DISABLED ; node->relay.cnt = cnt; node->relay.interval = interval; -if (is_local) -mesh_net_set_relay_mode (node->net, enable, cnt, - interval); +mesh_net_set_relay_mode (node->net, enable, cnt, interval); }return res;
@@ -654,22 +619,18 @@ bool node_relay_mode_set(struct mesh_node *node, bool enable, uint8_t cnt,bool node_proxy_mode_set (struct mesh_node *node,bool enable) { -bool res, is_local; +bool res;uint8_t proxy;if (!node || node->proxy ==MESH_MODE_UNSUPPORTED )return false; - is_local = (node->net &&mesh_net_local_node_get (node->net) == node) ? - true : false; - proxy = enable ?MESH_MODE_ENABLED :MESH_MODE_DISABLED ; - res =storage_local_set_mode (node->net, proxy,"proxy" ); + res =storage_set_mode (node->jconfig, proxy,"proxy" );if (res) { node->proxy = proxy; -if (is_local) -mesh_net_set_proxy_mode (node->net, enable); +mesh_net_set_proxy_mode (node->net, enable); }return res;
@@ -685,22 +646,18 @@ uint8_t node_proxy_mode_get(struct mesh_node *node)bool node_beacon_mode_set (struct mesh_node *node,bool enable) { -bool res, is_local; +bool res;uint8_t beacon;if (!node)return false; - is_local = (node->net &&mesh_net_local_node_get (node->net) == node) ? - true : false; - beacon = enable ?MESH_MODE_ENABLED :MESH_MODE_DISABLED ; - res =storage_local_set_mode (node->net, beacon,"beacon" ); + res =storage_set_mode (node->jconfig, beacon,"beacon" );if (res) { node->beacon = beacon; -if (is_local) -mesh_net_set_beacon_mode (node->net, enable); +mesh_net_set_beacon_mode (node->net, enable); }return res;
@@ -716,22 +673,18 @@ uint8_t node_beacon_mode_get(struct mesh_node *node)bool node_friend_mode_set (struct mesh_node *node,bool enable) { -bool res, is_local; +bool res;uint8_t friend;if (!node || node->friend ==MESH_MODE_UNSUPPORTED )return false; - is_local = (node->net &&mesh_net_local_node_get (node->net) == node) ? - true : false; - friend = enable ?MESH_MODE_ENABLED :MESH_MODE_DISABLED ; - res =storage_local_set_mode (node->net, friend,"friend" ); + res =storage_set_mode (node->jconfig, friend,"friend" );if (res) { node->friend = friend; -if (is_local) -mesh_net_set_friend_mode (node->net, enable); +mesh_net_set_friend_mode (node->net, enable); }return res;
@@ -788,7 +741,7 @@ uint16_t node_generate_comp(struct mesh_node *node, uint8_t *buf, uint16_t sz)/* At least fit location and zeros for number of models */ if ((n +4 ) > sz)return n; -l_info ("ele->location %d" , ele->location); +l_put_le16 (ele->location, buf + n); n +=2 ;
@@ -805,7 +758,7 @@ uint16_t node_generate_comp(struct mesh_node *node, uint8_t *buf, uint16_t sz) mod_id =mesh_model_get_model_id ( (const struct mesh_model *) mod); -if ((mod_id >>16 ) ==0xffff ) { +if ((mod_id &VENDOR_ID_MASK ) ==VENDOR_ID_MASK ) {if (n +2 > sz) goto element_done;
@@ -849,3 +802,970 @@ element_done:return n; } + + +#define MIN_COMPOSITION_LEN 16 + +bool node_parse_composition (struct mesh_node *node,uint8_t *data, +uint16_t len) +{ +struct node_composition *comp; +uint16_t features; +uint8_t num_ele; +bool mode; + +if (!len) +return false; + +/* Skip page -- We only support Page Zero */ + data++; + len--; + +if (len <MIN_COMPOSITION_LEN ) +return false; + + comp = l_new(struct node_composition, 1); +if (!comp) +return false; + + node->elements =l_queue_new (); +if (!node->elements) { +l_free (comp); +return false; + } + + node->comp = l_new(struct node_composition, 1); + comp->cid =l_get_le16 (&data[0 ]); + comp->pid =l_get_le16 (&data[2 ]); + comp->vid =l_get_le16 (&data[4 ]); + comp->crpl =l_get_le16 (&data[6 ]); + features =l_get_le16 (&data[8 ]); + data +=10 ; + len -=10 ; + + mode = !!(features &FEATURE_PROXY ); + node->proxy = mode ?MESH_MODE_DISABLED :MESH_MODE_UNSUPPORTED ; + + mode = !!(features &FEATURE_LPN ); + node->lpn = mode ?MESH_MODE_DISABLED :MESH_MODE_UNSUPPORTED ; + + mode = !!(features &FEATURE_FRIEND ); + node->friend = mode ?MESH_MODE_DISABLED :MESH_MODE_UNSUPPORTED ; + + mode = !!(features &FEATURE_RELAY ); + node->relay.mode = mode ?MESH_MODE_DISABLED :MESH_MODE_UNSUPPORTED ; + + num_ele =0 ; + +do { +uint8_t m, v; +uint16_t mod_id; +uint16_t vendor_id; +struct node_element *ele; +struct mesh_model *mod; + + ele = l_new(struct node_element, 1); +if (!ele) +return false; + + ele->idx = num_ele; + ele->location =l_get_le16 (data); + len -=2 ; + data +=2 ; + + m = *data++; + v = *data++; + len -=2 ; + +/* Parse SIG models */ +while (len >=2 && m--) { + mod_id =l_get_le16 (data); + mod =mesh_model_new (ele->idx, mod_id); +if (!mod) { +element_free (ele); + goto fail; + } + +l_queue_push_tail (ele->models, mod); + data +=2 ; + len -=2 ; + } + +if (v && len <4 ) { +element_free (ele); + goto fail; + } + +/* Parse vendor models */ +while (len >=4 && v--) { + mod_id =l_get_le16 (data +2 ); + vendor_id =l_get_le16 (data); + mod_id |= (vendor_id <<16 ); + mod =mesh_model_vendor_new (ele->idx, vendor_id, + mod_id); +if (!mod) { +element_free (ele); + goto fail; + } + +l_queue_push_tail (ele->models, mod); + data +=4 ; + len -=4 ; + } + + num_ele++; +l_queue_push_tail (node->elements, ele); + + }while (len >=6 ); + +/* Check the consistency for the remote node */ +if (node->num_ele > num_ele) + goto fail; + + node->comp = comp; + node->num_ele = num_ele; + +return true; + +fail: +l_queue_destroy (node->elements, element_free); +l_free (comp); + +return false; +} + +void node_id_set (struct mesh_node *node,uint16_t id) +{ +if (node) + node->id = id; +} + +static void attach_io (void *a,void *b) +{ +struct mesh_node *node = a; +struct mesh_io *io = b; + +if (node->net) +mesh_net_attach (node->net, io); +} + +/* Register callbacks for io */ +void node_attach_io (struct mesh_io *io) +{ +l_queue_foreach (nodes, attach_io, io); +} + +static bool register_node_object (struct mesh_node *node) +{ + node->path =l_malloc (strlen (MESH_NODE_PATH_PREFIX ) +5 ); + +snprintf (node->path,10 ,MESH_NODE_PATH_PREFIX "%4.4x" , node->id); + +if (!l_dbus_object_add_interface (dbus_get_bus (), node->path, +MESH_NODE_INTERFACE , node)) +return false; + +return true; +} + +static void app_disc_cb (struct l_dbus *bus,void *user_data) +{ +struct mesh_node *node = user_data; + +l_info ("App %s disconnected (%u)" , node->owner, node->disc_watch); + + node->disc_watch =0 ; + +l_queue_foreach (node->elements, free_element_path,NULL ); + +l_free (node->owner); + node->owner =NULL ; + +l_free (node->app_path); + node->app_path =NULL ; +} + +static bool validate_element_properties (struct mesh_node *node, +const char *path, +struct l_dbus_message_iter *properties) +{ +uint8_t ele_idx; +struct node_element *ele; +const char *key; +struct l_dbus_message_iter variant; +bool have_index = false; + +l_debug ("path %s" , path); + +while (l_dbus_message_iter_next_entry (properties, &key, &variant)) { +if (!strcmp (key,"Index" )) { + have_index = true; +break ; + } + } + +if (!have_index) { +l_debug ("Mandatory property \"Index\" not found" ); +return false; + } + +if (!l_dbus_message_iter_get_variant (&variant,"y" , &ele_idx)) +return false; + + ele =l_queue_find (node->elements, match_element_idx, +L_UINT_TO_PTR (ele_idx)); + +if (!ele) { +l_debug ("Element with index %u not found" , ele_idx); +return false; + } + +/* TODO: validate models */ + + ele->path =l_strdup (path); + +return true; +} + +static void get_managed_objects_attach_cb (struct l_dbus_message *msg, +void *user_data) +{ +struct l_dbus_message_iter objects, interfaces; +struct attach_obj_request *req = user_data; +struct mesh_node *node = req->node; +const char *path; +uint64_t token =l_get_u64 (node->dev_key); +uint8_t num_ele; + +if (l_dbus_message_is_error (msg)) { +l_error ("Failed to get app's dbus objects" ); + goto fail; + } + +if (!l_dbus_message_get_arguments (msg,"a{oa{sa{sv}}}" , &objects)) { +l_error ("Failed to parse app's dbus objects" ); + goto fail; + } + + num_ele =0 ; + +while (l_dbus_message_iter_next_entry (&objects, &path, &interfaces)) { +struct l_dbus_message_iter properties; +const char *interface; + +while (l_dbus_message_iter_next_entry (&interfaces, &interface, + &properties)) { +if (strcmp (MESH_ELEMENT_INTERFACE , interface)) +continue ; + +if (!validate_element_properties (node, path, + &properties)) + goto fail; + + num_ele++; + } + } + +/* +* Check that the number of element objects matches the expected number +* of elements on the node +*/ +if (num_ele != node->num_ele) + goto fail; + +/* Register node object with D-Bus */ +register_node_object (node); + +if (node->path) { +struct l_dbus *bus =dbus_get_bus (); + + node->disc_watch =l_dbus_add_disconnect_watch (bus, node->owner, + app_disc_cb, node,NULL ); + req->cb (MESH_ERROR_NONE , node->path, token); + +return ; + } +fail: + req->cb (MESH_ERROR_FAILED ,NULL , token); + +l_queue_foreach (node->elements, free_element_path,NULL ); +l_free (node->app_path); + node->app_path =NULL ; + +l_free (node->owner); + node->owner =NULL ; +} + +/* Establish relationship between application and mesh node */ +int node_attach (const char *app_path,const char *sender,uint64_t token, +node_attach_ready_func_t cb) +{ +struct attach_obj_request *req; +struct mesh_node *node; + +l_debug ("" ); + + node =l_queue_find (nodes, match_token, &token); +if (!node) +return MESH_ERROR_NOT_FOUND ; + +/* TODO: decide what to do if previous node->app_path is not NULL */ + node->app_path =l_strdup (app_path); + + node->owner =l_strdup (sender); + + req = l_new(struct attach_obj_request, 1); + req->node = node; + req->cb = cb; + +l_dbus_method_call (dbus_get_bus (), sender, app_path, +L_DBUS_INTERFACE_OBJECT_MANAGER , +"GetManagedObjects" ,NULL , + get_managed_objects_attach_cb, + req, l_free); +return MESH_ERROR_NONE ; + +} + +static void add_model_from_properties (struct node_element *ele, +struct l_dbus_message_iter *property) +{ +struct l_dbus_message_iter ids; +uint16_t model_id; +int i =0 ; + +if (!ele->models) + ele->models =l_queue_new (); + +if (!l_dbus_message_iter_get_variant (property,"aq" , &ids)) +return ; + +while (l_dbus_message_iter_next_entry (&ids, &model_id)) { +struct mesh_model *mod; +l_debug ("model_id %4.4x" , model_id); + mod =mesh_model_new (ele->idx, model_id); +l_queue_push_tail (ele->models, mod); + i++; +if (i >3 ) +break ; + } +} + +static void add_vendor_model_from_properties (struct node_element *ele, +struct l_dbus_message_iter *property) +{ +struct { +uint16_t v; +uint16_t m; + } id_pair; + +if (!ele->models) + ele->models =l_queue_new (); + +while (l_dbus_message_iter_next_entry (property, &id_pair)) { +struct mesh_model *mod; + mod =mesh_model_vendor_new (ele->idx, id_pair.v, id_pair.m); +l_queue_push_tail (ele->models, mod); + } +} + +static bool get_element_properties (struct mesh_node *node,const char *path, +struct l_dbus_message_iter *properties) +{ +struct node_element *ele; +const char *key; +struct l_dbus_message_iter variant; +bool have_index = false; + +l_debug ("path %s" , path); + + ele = l_new(struct node_element, 1); + ele->location =DEFAULT_LOCATION ; + +while (l_dbus_message_iter_next_entry (properties, &key, &variant)) { +if (!strcmp (key,"Index" )) { +if (!l_dbus_message_iter_get_variant (&variant,"y" , + &ele->idx)) +return false; + have_index = true; + }else if (!strcmp (key,"Location" )) { +l_dbus_message_iter_get_variant (&variant,"q" , + &ele->location); + }else if (!strcmp (key,"Models" )) { +add_model_from_properties (ele, &variant); + }else if (!strcmp (key,"VendorModels" )) { +add_vendor_model_from_properties (ele, &variant); + } + } + +if (!have_index) { +l_debug ("Mandatory property \"Index\" not found" ); +return false; + } + +l_queue_push_tail (node->elements, ele); + +return true; +} + +static bool get_app_properties (struct mesh_node *node,const char *path, +struct l_dbus_message_iter *properties) +{ +const char *key; +struct l_dbus_message_iter variant; + +l_debug ("path %s" , path); + +if (!node->comp) + node->comp = l_new(struct node_composition, 1); + +while (l_dbus_message_iter_next_entry (properties, &key, &variant)) { + +if (!strcmp (key,"CompanyID" )) { +if (!l_dbus_message_iter_get_variant (&variant,"q" , + &node->comp->cid)) +return false; + }else if (!strcmp (key,"ProductID" )) { +if (!l_dbus_message_iter_get_variant (&variant,"q" , + &node->comp->pid)) +return false; + }else if (!strcmp (key,"VersionID" )) { +if (!l_dbus_message_iter_get_variant (&variant,"q" , + &node->comp->vid)) +return false; + } + } + +return true; +} + +static void convert_node_to_storage (struct mesh_node *node, +struct mesh_db_node *db_node) +{ +const struct l_queue_entry *entry; + + db_node->cid = node->comp->cid; + db_node->pid = node->comp->pid; + db_node->vid = node->comp->vid; + db_node->crpl = node->comp->crpl; + db_node->modes.lpn = node->lpn; + db_node->modes.proxy = node->proxy; + +memcpy (db_node->uuid, node->dev_uuid,16 ); + + node->friend = db_node->modes.friend; + db_node->modes.relay.state = node->relay.mode; + db_node->modes.relay.cnt = node->relay.cnt; + db_node->modes.relay.interval = node->relay.interval; + db_node->modes.beacon = node->beacon; + + db_node->ttl = node->ttl; + db_node->seq_number = node->seq_number; + + db_node->elements =l_queue_new (); + + entry =l_queue_get_entries (node->elements); + +for (; entry; entry = entry->next) { +struct node_element *ele = entry->data; +struct mesh_db_element *db_ele; +const struct l_queue_entry *mod_entry; + + db_ele = l_new(struct mesh_db_element, 1); + + db_ele->index = ele->idx; + db_ele->location = ele->location; + db_ele->models =l_queue_new (); + + mod_entry =l_queue_get_entries (ele->models); + +for (; mod_entry; mod_entry = mod_entry->next) { +struct mesh_model *mod = mod_entry->data; +struct mesh_db_model *db_mod; +uint32_t mod_id =mesh_model_get_model_id (mod); + + db_mod = l_new(struct mesh_db_model, 1); + db_mod->id = mod_id; + db_mod->vendor = ((mod_id &VENDOR_ID_MASK ) + !=VENDOR_ID_MASK ); + +l_queue_push_tail (db_ele->models, db_mod); + } +l_queue_push_tail (db_node->elements, db_ele); + } + +} + +static bool create_node_config (struct mesh_node *node) +{ +struct mesh_db_node db_node; +const struct l_queue_entry *entry; +bool res; + +convert_node_to_storage (node, &db_node); + res =storage_create_node_config (node, &db_node); + +/* Free temporarily allocated resources */ + entry =l_queue_get_entries (db_node.elements); +for (; entry; entry = entry->next) { +struct mesh_db_element *db_ele = entry->data; + +l_queue_destroy (db_ele->models, l_free); + } + +l_queue_destroy (db_node.elements, l_free); + +return res; +} + +static void set_defaults (struct mesh_node *node) +{ +/* TODO: these values should come from mesh.conf */ +if (!node->comp) + node->comp = l_new(struct node_composition, 1); + + node->comp->crpl =DEFAULT_CRPL ; + node->lpn =MESH_MODE_UNSUPPORTED ; + node->proxy =MESH_MODE_UNSUPPORTED ; + node->friend =MESH_MODE_UNSUPPORTED ; + node->beacon =MESH_MODE_DISABLED ; + node->relay.mode =MESH_MODE_DISABLED ; + node->ttl =DEFAULT_TTL ; + node->seq_number =DEFAULT_SEQUENCE_NUMBER ; + +/* Add configuration server model on primary element */ +add_internal_model (node,CONFIG_SRV_MODEL ,PRIMARY_ELE_IDX ); +} + +static void get_managed_objects_join_cb (struct l_dbus_message *msg, +void *user_data) +{ +struct l_dbus_message_iter objects, interfaces; +struct join_obj_request *req = user_data; +const char *path; +struct mesh_node *node =NULL ; +void *agent =NULL ; + +if (l_dbus_message_is_error (msg)) { +l_error ("Failed to get app's dbus objects" ); + goto fail; + } + +if (!l_dbus_message_get_arguments (msg,"a{oa{sa{sv}}}" , &objects)) { +l_error ("Failed to parse app's dbus objects" ); + goto fail; + } + + node = l_new(struct mesh_node, 1); + node->elements =l_queue_new (); + +while (l_dbus_message_iter_next_entry (&objects, &path, &interfaces)) { +struct l_dbus_message_iter properties; +const char *interface; + +while (l_dbus_message_iter_next_entry (&interfaces, &interface, + &properties)) { +bool res; + +if (!strcmp (MESH_ELEMENT_INTERFACE , interface)) { + res =get_element_properties (node, path, + &properties); +if (!res) + goto fail; + + node->num_ele++; +continue ; + + } + +if (!strcmp (MESH_APPLICATION_INTERFACE , interface)) { + res =get_app_properties (node, path, + &properties); +if (!res) + goto fail; + +continue ; + } + +if (!strcmp (MESH_PROVISION_AGENT_INTERFACE , + interface)) { +const char *sender; + + sender =l_dbus_message_get_sender (msg); + agent =mesh_agent_create (path, sender, + &properties); +if (!agent) + goto fail; + } + } + } + +if (!node->comp){ +l_error ("Interface %s not found" ,MESH_APPLICATION_INTERFACE ); + goto fail; + } + +if (!agent) { +l_error ("Interface %s not found" , +MESH_PROVISION_AGENT_INTERFACE ); + goto fail; + } + +if (!node->num_ele) { +l_error ("Interface %s not found" ,MESH_ELEMENT_INTERFACE ); + goto fail; + } + +if (!l_queue_find (node->elements, match_element_idx, +L_UINT_TO_PTR (PRIMARY_ELE_IDX ))) { + +l_debug ("Primary element not detected" ); + goto fail; + } + +set_defaults (node); +memcpy (node->dev_uuid, req->uuid,16 ); + +if (!create_node_config (node)) + goto fail; + + req->cb (node, agent); + +return ; +fail: +if (agent) +free_node_resources (node); + +if (node) +mesh_agent_remove (agent); + + req->cb (NULL ,NULL ); +} + +/* Create a temporary pre-provisioned node */ +void node_join (const char *app_path,const char *sender,const uint8_t *uuid, +node_join_ready_func_t cb) +{ +struct join_obj_request *req; + +l_debug ("" ); + + req = l_new(struct join_obj_request, 1); + req->uuid = uuid; + req->cb = cb; + +l_dbus_method_call (dbus_get_bus (), sender, app_path, +L_DBUS_INTERFACE_OBJECT_MANAGER , +"GetManagedObjects" ,NULL , + get_managed_objects_join_cb, + req, l_free); +} + +static void build_element_config (void *a,void *b) +{ +struct node_element *ele = a; +struct l_dbus_message_builder *builder = b; + +l_debug ("Element %u" , ele->idx); + +l_dbus_message_builder_enter_struct (builder,"ya(qa{sv})" ); + +/* Element index */ +l_dbus_message_builder_append_basic (builder,'y' , &ele->idx); + +l_dbus_message_builder_enter_array (builder,"(qa{sv})" ); + +/* Iterate over models */ +l_queue_foreach (ele->models, model_build_config, builder); + +l_dbus_message_builder_leave_array (builder); + +l_dbus_message_builder_leave_struct (builder); +} + +void node_build_attach_reply (struct l_dbus_message *reply,uint64_t token) +{ +struct mesh_node *node; +struct l_dbus_message_builder *builder; + + node =l_queue_find (nodes, match_token, &token); +if (!node) +return ; + + builder =l_dbus_message_builder_new (reply); + +/* Node object path */ +l_dbus_message_builder_append_basic (builder,'o' , node->path); + +/* Array of element configurations "a*/ +l_dbus_message_builder_enter_array (builder,"(ya(qa{sv}))" ); +l_queue_foreach (node->elements, build_element_config, builder); +l_dbus_message_builder_leave_array (builder); +l_dbus_message_builder_finalize (builder); +l_dbus_message_builder_destroy (builder); +} + +static struct l_dbus_message *send_call (struct l_dbus *dbus, +struct l_dbus_message *msg, +void *user_data) +{ +struct mesh_node *node = user_data; +const char *sender, *ele_path; +struct l_dbus_message_iter iter_data; +struct node_element *ele; +uint16_t dst, app_idx, src; +uint8_t data[MESH_MAX_ACCESS_PAYLOAD ]; +uint32_t len; +struct l_dbus_message *reply; + +l_debug ("Send" ); + + sender =l_dbus_message_get_sender (msg); + +if (strcmp (sender, node->owner)) +return dbus_error (msg,MESH_ERROR_NOT_AUTHORIZED ,NULL ); + +if (!l_dbus_message_get_arguments (msg,"oqqay" , &ele_path, &dst, + &app_idx, &iter_data)) +return dbus_error (msg,MESH_ERROR_INVALID_ARGS ,NULL ); + + ele =l_queue_find (node->elements, match_element_path, ele_path); +if (!ele) +return dbus_error (msg,MESH_ERROR_NOT_FOUND , +"Element not found" ); + + src =node_get_primary (node) + ele->idx; + +l_dbus_message_iter_get_fixed_array (&iter_data, data, &len); +if (!len) +return dbus_error (msg,MESH_ERROR_INVALID_ARGS , +"Mesh message is empty" ); + +if (!mesh_model_send (node, src, dst, app_idx, +mesh_net_get_default_ttl (node->net), data, len)) +return dbus_error (msg,MESH_ERROR_FAILED ,NULL ); + + reply =l_dbus_message_new_method_return (msg); +l_dbus_message_set_arguments (reply,"" ); + +return reply; +} + +static struct l_dbus_message *publish_call (struct l_dbus *dbus, +struct l_dbus_message *msg, +void *user_data) +{ +struct mesh_node *node = user_data; +const char *sender, *ele_path; +struct l_dbus_message_iter iter_data; +uint16_t mod_id, src; +struct node_element *ele; +uint8_t data[MESH_MAX_ACCESS_PAYLOAD ]; +uint32_t len; +struct l_dbus_message *reply; +int result; + +l_debug ("Publish" ); + + sender =l_dbus_message_get_sender (msg); + +if (strcmp (sender, node->owner)) +return dbus_error (msg,MESH_ERROR_NOT_AUTHORIZED ,NULL ); + +if (!l_dbus_message_get_arguments (msg,"oqay" , &ele_path, &mod_id, + &iter_data)) +return dbus_error (msg,MESH_ERROR_INVALID_ARGS ,NULL ); + + ele =l_queue_find (node->elements, match_element_path, ele_path); +if (!ele) +return dbus_error (msg,MESH_ERROR_NOT_FOUND , +"Element not found" ); + + src =node_get_primary (node) + ele->idx; + +l_dbus_message_iter_get_fixed_array (&iter_data, data, &len); +if (!len) +return dbus_error (msg,MESH_ERROR_INVALID_ARGS , +"Mesh message is empty" ); + + result =mesh_model_publish (node,VENDOR_ID_MASK | mod_id, src, +mesh_net_get_default_ttl (node->net), data, len); + +if (result !=MESH_ERROR_NONE ) +return dbus_error (msg, result,NULL ); + + reply =l_dbus_message_new_method_return (msg); +l_dbus_message_set_arguments (reply,"" ); + +return reply; +} + +static struct l_dbus_message *vendor_publish_call (struct l_dbus *dbus, +struct l_dbus_message *msg, +void *user_data) +{ +struct mesh_node *node = user_data; +const char *sender, *ele_path; +struct l_dbus_message_iter iter_data; +uint16_t src; +uint16_t model_id, vendor; +uint32_t vendor_mod_id; +struct node_element *ele; +uint8_t data[MESH_MAX_ACCESS_PAYLOAD ]; +uint32_t len; +struct l_dbus_message *reply; +int result; + +l_debug ("Publish" ); + + sender =l_dbus_message_get_sender (msg); + +if (strcmp (sender, node->owner)) +return dbus_error (msg,MESH_ERROR_NOT_AUTHORIZED ,NULL ); + +if (!l_dbus_message_get_arguments (msg,"oqqay" , &ele_path, &vendor, + &model_id, &iter_data)) +return dbus_error (msg,MESH_ERROR_INVALID_ARGS ,NULL ); + + ele =l_queue_find (node->elements, match_element_path, ele_path); +if (!ele) +return dbus_error (msg,MESH_ERROR_NOT_FOUND , +"Element not found" ); + + src =node_get_primary (node) + ele->idx; + +l_dbus_message_iter_get_fixed_array (&iter_data, data, &len); +if (!len) +return dbus_error (msg,MESH_ERROR_INVALID_ARGS , +"Mesh message is empty" ); + + vendor_mod_id = (vendor <<16 ) | model_id; + result =mesh_model_publish (node, vendor_mod_id, src, +mesh_net_get_default_ttl (node->net), data, len); + +if (result !=MESH_ERROR_NONE ) +return dbus_error (msg, result,NULL ); + + reply =l_dbus_message_new_method_return (msg); +l_dbus_message_set_arguments (reply,"" ); + +return reply; +} + +static void setup_node_interface (struct l_dbus_interface *iface) +{ +l_dbus_interface_method (iface,"Send" ,0 , send_call,"" ,"oqqay" , +"element_path" ,"destination" , +"key" ,"data" ); +l_dbus_interface_method (iface,"Publish" ,0 , publish_call,"" ,"oqay" , +"element_path" ,"model_id" ,"data" ); +l_dbus_interface_method (iface,"VendorPublish" ,0 , vendor_publish_call, +"" ,"oqqay" ,"element_path" , +"vendor" ,"model_id" ,"data" ); + +/*TODO: Properties */ +} + +bool node_dbus_init (struct l_dbus *bus) +{ +if (!l_dbus_register_interface (bus,MESH_NODE_INTERFACE , + setup_node_interface, +NULL , false)) { +l_info ("Unable to register %s interface" ,MESH_NODE_INTERFACE ); +return false; + } + +return true; +} + +const char *node_get_owner (struct mesh_node *node) +{ +return node->owner; +} + +const char *node_get_element_path (struct mesh_node *node,uint8_t ele_idx) +{ +struct node_element *ele; + + ele =l_queue_find (node->elements, match_element_idx, +L_UINT_TO_PTR (ele_idx)); + +if (!ele) +return NULL ; + +return ele->path; +} + +bool node_add_pending_local (struct mesh_node *node,void *prov_node_info, +struct mesh_io *io) +{ +struct mesh_prov_node_info *info = prov_node_info; +bool kr = !!(info->flags &PROV_FLAG_KR ); +bool ivu = !!(info->flags &PROV_FLAG_IVU ); + + node->net =mesh_net_new (node); + +if (!nodes) + nodes =l_queue_new (); + +l_queue_push_tail (nodes, node); + +if (!storage_set_iv_index (node->net, info->iv_index, ivu)) +return false; + +mesh_net_set_iv_index (node->net, info->iv_index, ivu); + +if (!mesh_db_write_uint16_hex (node->jconfig,"unicastAddress" , + info->unicast)) +return false; + + node->primary = info->unicast; +mesh_net_register_unicast (node->net, info->unicast, node->num_ele); + +memcpy (node->dev_key, info->device_key,16 ); +if (!mesh_db_write_device_key (node->jconfig, info->device_key)) +return false; + +if (mesh_net_add_key (node->net, kr, info->net_index, + info->net_key) !=MESH_STATUS_SUCCESS ) +return false; + +if (!storage_net_key_add (node->net, info->net_index, info->net_key, + kr ?KEY_REFRESH_PHASE_TWO :KEY_REFRESH_PHASE_NONE )) +return false; + +if (!storage_save_config (node, true,NULL ,NULL )) +return false; + +/* Initialize configuration server model */ +mesh_config_srv_init (node,PRIMARY_ELE_IDX ); + +mesh_net_attach (node->net, io); + +return true; +} + +void node_jconfig_set (struct mesh_node *node,void *jconfig) +{ + node->jconfig = jconfig; +} + +void *node_jconfig_get (struct mesh_node *node) +{ +return node->jconfig; +} + +void node_cfg_file_set (struct mesh_node *node,char *cfg) +{ + node->cfg_file = cfg; +} + +char *node_cfg_file_get (struct mesh_node *node) +{ +return node->cfg_file; +} + +struct mesh_net *node_get_net (struct mesh_node *node) +{ +return node->net; +}
mesh/node.h +29 -14
83 lines not on this page · raw message
Signature · 1 line
2.14.5
PATCH v6 6/26 mesh: Rewrite Network layer for multiple nodes
In reply to Brian GixThe Network layer of the Mesh Daemon has access to all network keys that have been entrusted to Nodes on the local device, and acts as a MUX by forwarding incoming messages to some, all or none of the local Nodes, based on addressing and keys.
It also is reponsible for for applying Network layer encryption to outgoing messages, and for relaying messages based on TTL.
--- mesh/net.c | 294 ++++++++++++++++--------------------------------------------- mesh/net.h | 34 ++----- 2 files changed, 84 insertions(+), 244 deletions(-)
mesh/net.c +77 -217
@@ -26,11 +26,11 @@#include <stdio.h> #include <sys/time.h> #include <ell/ell.h> +#include <json-c/json.h> #include "mesh/mesh-defs.h" #include "mesh/util.h" -#include "mesh/display.h" #include "mesh/crypto.h" #include "mesh/net_keys.h" #include "mesh/mesh.h"
@@ -112,12 +112,9 @@ struct mesh_subnet { };struct mesh_net { -int ref_count;struct mesh_io *io; -struct mesh_node *local_node; +struct mesh_node *node;struct mesh_prov *prov; -void *jconfig_local; -const char *cfg_file;struct l_queue *app_keys;unsigned int pkt_id;unsigned int bea_id;
@@ -129,7 +126,6 @@ struct mesh_net {bool beacon_enable;bool proxy_enable;bool provisioner; -bool provisioned;bool friend_seq;struct l_timeout *iv_update_timeout;enum _iv_upd_state iv_upd_state;
@@ -139,7 +135,6 @@ struct mesh_net {uint32_t iv_index;uint32_t seq_num;uint32_t cached_seq_num; -uint16_t crpl;uint16_t src_addr;uint16_t last_addr;uint16_t friend_addr;
@@ -253,6 +248,8 @@ struct net_decode {bool proxy; }; +static struct l_queue *nets; +static inline struct mesh_subnet *get_primary_subnet (struct mesh_net *net) {return l_queue_peek_head (net->subnets);
@@ -499,8 +496,8 @@ uint32_t mesh_net_next_seq_num(struct mesh_net *net)/* Periodically store advanced sequence number */ if (net->seq_num +MIN_SEQ_TRIGGER >= net->cached_seq_num) { net->cached_seq_num = net->seq_num + -node_seq_cache (net->local_node); -node_set_sequence_number (net->local_node, net->cached_seq_num); +node_seq_cache (net->node); +node_set_sequence_number (net->node, net->cached_seq_num); }return seq;
@@ -647,15 +644,13 @@ static void start_network_beacon(void *a, void *b) network_beacon_timeout, subnet, NULL); } -struct mesh_net *mesh_net_new (uint16_t index) +struct mesh_net *mesh_net_new (struct mesh_node *node) {struct mesh_net *net; net = l_new(struct mesh_net, 1); -if (!net) -return NULL ; - + net->node = node; net->pkt_id =0 ; net->bea_id =0 ; net->key_id_next =0 ;
@@ -689,27 +684,17 @@ struct mesh_net *mesh_net_new(uint16_t index)memset (&net->heartbeat,0 ,sizeof (net->heartbeat)); -return mesh_net_ref (net); -} - -struct mesh_net *mesh_net_ref (struct mesh_net *net) -{ -if (!net) -return NULL ; - -__sync_fetch_and_add (&net->ref_count,1 ); +if (!nets) + nets =l_queue_new ();return net; } -void mesh_net_unref (struct mesh_net *net) +void mesh_net_free (struct mesh_net *net) {if (!net)return ; -if (__sync_sub_and_fetch (&net->ref_count,1 )) -return ; -l_queue_destroy (net->subnets, subnet_free);l_queue_destroy (net->fast_cache, mesh_msg_free);l_queue_destroy (net->msg_cache, mesh_msg_free);
@@ -773,7 +758,6 @@ bool mesh_net_register_unicast(struct mesh_net *net,if (!net || !IS_UNICAST (address) || !num_ele)return false; -l_info ("mesh_net_set_address: 0x%x" , address); net->src_addr = address; net->last_addr = address + num_ele -1 ;if (net->last_addr < net->src_addr)
@@ -971,7 +955,7 @@ int mesh_net_del_key(struct mesh_net *net, uint16_t idx)l_queue_remove (net->subnets, subnet);subnet_free (subnet); -if (!storage_local_net_key_del (net, idx)) +if (!storage_net_key_del (net, idx))return MESH_STATUS_STORAGE_FAIL ;return MESH_STATUS_SUCCESS ;
@@ -991,7 +975,7 @@ int mesh_net_add_key(struct mesh_net *net, bool update, uint16_t idx,l_info ("Start key refresh" ); status =mesh_net_kr_phase_one (net, idx, value);if (status ==MESH_STATUS_SUCCESS && - !storage_local_net_key_add (net, idx, + !storage_net_key_add (net, idx, value,KEY_REFRESH_PHASE_ONE ))return MESH_STATUS_STORAGE_FAIL ; }else
@@ -1021,7 +1005,7 @@ int mesh_net_add_key(struct mesh_net *net, bool update, uint16_t idx,return MESH_STATUS_INSUFF_RESOURCES ; } -if (!storage_local_net_key_add (net, idx, value, +if (!storage_net_key_add (net, idx, value,KEY_REFRESH_PHASE_NONE )) {l_queue_remove (net->subnets, subnet);subnet_free (subnet);
@@ -1204,14 +1188,6 @@ static bool match_msg_timeout(const void *a, const void *b)return sar->msg_timeout == msg_timeout; } -static bool match_sar_id (const void *a,const void *b) -{ -const struct mesh_sar *sar = a; -unsigned int id =L_PTR_TO_UINT (b); - -return sar->id == id; -} -static bool match_seg_timeout (const void *a,const void *b) {const struct mesh_sar *sar = a;
@@ -1813,7 +1789,7 @@ static bool msg_rxed(struct mesh_net *net, bool frnd, } not_for_friend: -return mesh_model_rx (net, szmic, seqAuth, seq, iv_index, +return mesh_model_rx (net->node, szmic, seqAuth, seq, iv_index, ttl, src, dst, key_id, data, size); }
@@ -2511,22 +2487,40 @@ static void packet_received(void *user_data, const void *data, uint8_t size,send_relay_pkt (net, packet, size +1 ); } +struct net_queue_data { +struct mesh_io_recv_info *info; +const uint8_t *data; +uint16_t len; +}; + +static void net_rx (void *net_ptr,void *user_data) +{ +struct net_queue_data *data = user_data; +struct mesh_net *net = net_ptr; +int8_t rssi =0 ; + +if (data->info) { + net->instant = data->info->instant; + net->chan = data->info->chan; + rssi = data->info->rssi; + } + +packet_received (net, data->data, data->len, rssi); +} +static void net_msg_recv (void *user_data,struct mesh_io_recv_info *info,const uint8_t *data,uint16_t len) { -struct mesh_net *net = user_data; -int8_t rssi =0 ; +struct net_queue_data net_data = { + .info = info, + .data = data +1 , + .len = len -1 , + }; -if (len <=2 || !net) +if (len <=2 )return ; -if (info) { - net->instant = info->instant; - net->chan = info->chan; - rssi = info->rssi; - } - -packet_received (user_data, data +1 , len -1 , rssi); +l_queue_foreach (nets, net_rx, &net_data); }static void set_network_beacon (void *a,void *b)
@@ -2653,7 +2647,7 @@ static void update_iv_kr_state(struct mesh_subnet *subnet, uint32_t iv_index, net->iv_upd_state =IV_UPD_NORMAL ; } -storage_local_set_iv_index (net, iv_index, net->iv_upd_state); +storage_set_iv_index (net, iv_index, net->iv_upd_state);/* Figure out the key refresh phase */ if (kr_transition) {
@@ -2675,7 +2669,7 @@ static void update_iv_kr_state(struct mesh_subnet *subnet, uint32_t iv_index, net->iv_upd_state =IV_UPD_UPDATING ; net->iv_update_timeout =l_timeout_create (IV_IDX_UPD_MIN , iv_upd_to, net,NULL ); -storage_local_set_iv_index (net, iv_index, net->iv_upd_state); +storage_set_iv_index (net, iv_index, net->iv_upd_state); }else if (iv_update && iv_index != net->iv_index) {l_error ("Update attempted too soon (iv idx already updated)" );return ;
@@ -2688,7 +2682,7 @@ static void update_iv_kr_state(struct mesh_subnet *subnet, uint32_t iv_index,if (iv_index > net->iv_index) {l_queue_clear (net->msg_cache, mesh_msg_free); net->iv_index = iv_index; -storage_local_set_iv_index (net, iv_index, net->iv_upd_state); +storage_set_iv_index (net, iv_index, net->iv_upd_state); }/* Figure out the key refresh phase */
@@ -2915,34 +2909,37 @@ bool mesh_net_set_beacon_mode(struct mesh_net *net, bool enable)return true; } +static bool is_this_net (const void *a,const void *b) +{ +return a == b; +} +bool mesh_net_attach (struct mesh_net *net,struct mesh_io *io) { +bool first; +if (!net)return false; - net->io = io; -if (net->provisioned) { + first =l_queue_isempty (nets); +if (first) { +if (!nets) + nets =l_queue_new (); +l_info ("Register io cb" );mesh_io_register_recv_cb (io,MESH_IO_FILTER_BEACON , beacon_recv, net);mesh_io_register_recv_cb (io,MESH_IO_FILTER_NET , - net_msg_recv, net); + net_msg_recv,NULL );l_queue_foreach (net->subnets, start_network_beacon, net); + } - }else { -uint8_t *uuid =node_uuid_get (net->local_node); - -if (!uuid) -return false; +if (l_queue_find (nets, is_this_net, net)) +return false; -mesh_io_deregister_recv_cb (io,MESH_IO_FILTER_BEACON ); -mesh_io_deregister_recv_cb (io,MESH_IO_FILTER_NET ); +l_queue_push_head (nets, net); -mesh_prov_listen (net, uuid, (uint8_t *) &net->prov_caps, - acceptor_prov_open, - acceptor_prov_close, - acceptor_prov_receive, net); - } + net->io = io;return true; }
@@ -2952,10 +2949,10 @@ struct mesh_io *mesh_net_detach(struct mesh_net *net)struct mesh_io *io;uint8_t type =0 ; -if (!net) +if (!net || !net->io)return NULL ; - io = net->io; + io = net->io;mesh_io_send_cancel (net->io, &type,1 );mesh_io_deregister_recv_cb (io,MESH_IO_FILTER_BEACON );
@@ -2975,7 +2972,7 @@ bool mesh_net_iv_index_update(struct mesh_net *net)mesh_net_flush_msg_queues (net); net->iv_upd_state =IV_UPD_UPDATING ; net->iv_index++; -if (!storage_local_set_iv_index (net, net->iv_index,IV_UPD_UPDATING )) +if (!storage_set_iv_index (net, net->iv_index,IV_UPD_UPDATING ))return false;l_queue_foreach (net->subnets, set_network_beacon, net);
@@ -3241,28 +3238,25 @@ void mesh_net_send_seg(struct mesh_net *net, uint32_t net_key_id,l_free (str); } -unsigned int mesh_net_app_send (struct mesh_net *net,bool frnd_cred, -uint16_t src,uint16_t dst, -uint8_t key_id,uint8_t ttl, -uint32_t seq,uint32_t iv_index, -bool szmic, +bool mesh_net_app_send (struct mesh_net *net,bool frnd_cred,uint16_t src, +uint16_t dst,uint8_t key_id,uint8_t ttl, +uint32_t seq,uint32_t iv_index,bool szmic,const void *msg,uint16_t msg_len,mesh_net_status_func_t status_func,void *user_data) {struct mesh_sar *payload =NULL ;uint8_t seg, seg_max; -unsigned int ret =0 ;bool result;if (!net || msg_len >384 ) -return 0 ; +return false;if (!src) src = net->src_addr;if (!src || !dst) -return 0 ; +return false;if (ttl ==0xff ) ttl = net->default_ttl;
@@ -3287,7 +3281,7 @@ unsigned int mesh_net_app_send(struct mesh_net *net, bool frnd_cred,/* Adjust our seq_num for "virtual" delivery */ net->seq_num += seg_max;mesh_net_next_seq_num (net); -return 0 ; +return true; }/* If Segmented, Cancel any OB segmented message to same DST */
@@ -3337,29 +3331,13 @@ unsigned int mesh_net_app_send(struct mesh_net *net, bool frnd_cred,l_timeout_create (MSG_TO , outmsg_to, net,NULL ); payload->status_func = status_func; payload->user_data = user_data; - ret = payload->id = ++net->sar_id_next; + payload->id = ++net->sar_id_next; }else mesh_sar_free (payload); -return ret; -} - -void mesh_net_app_send_cancel (struct mesh_net *net,unsigned int id) -{ -struct mesh_sar *sar =l_queue_remove_if (net->sar_out, match_sar_id, -L_UINT_TO_PTR (id)); - -if (sar) { -l_info ("Canceling OB %d" , id); -if (sar->status_func) - sar->status_func (sar->remote,2 , - sar->buf, sar->len -4 , - sar->user_data); - } -mesh_sar_free (sar); +return result; } -/* TODO: add net key index */ void mesh_net_ack_send(struct mesh_net *net, uint32_t key_id, uint32_t iv_index, uint8_t ttl,
@@ -3768,40 +3746,9 @@ uint32_t mesh_net_friend_timeout(struct mesh_net *net, uint16_t addr)return frnd->poll_timeout; } -bool mesh_net_local_node_set (struct mesh_net *net,struct mesh_node *node, -bool provisioner) +struct mesh_node *mesh_net_node_get (struct mesh_net *net) { -if (net->local_node) { -l_info ("Local node already registered" ); -return false; - } - - net->local_node = node; - net->provisioner = provisioner; - -return true; -} - -struct mesh_node *mesh_net_local_node_get (struct mesh_net *net) -{ -return net->local_node; -} - -bool mesh_net_set_crpl (struct mesh_net *net,uint16_t crpl) -{ -if (!net) -return false; - - net->crpl = crpl; -return true; -} - -uint16_t mesh_net_get_crpl (struct mesh_net *net) -{ -if (!net) -return 0 ; - -return net->crpl; +return net->node; }struct l_queue *mesh_net_get_app_keys (struct mesh_net *net)
@@ -3824,41 +3771,6 @@ bool mesh_net_have_key(struct mesh_net *net, uint16_t idx) L_UINT_TO_PTR(idx)) != NULL); } -bool mesh_net_jconfig_set (struct mesh_net *net,void *jconfig) -{ -if (!net) -return false; - - net->jconfig_local = jconfig; -return true; -} - -void *mesh_net_jconfig_get (struct mesh_net *net) -{ -if (!net) -return NULL ; - -return net->jconfig_local; -} - -bool mesh_net_cfg_file_set (struct mesh_net *net,const char *cfg) -{ -if (!net) -return false; - - net->cfg_file = cfg; -return true; -} - -bool mesh_net_cfg_file_get (struct mesh_net *net,const char **cfg) -{ -if (!net) -return false; - - *cfg = net->cfg_file; -return true; -} -bool mesh_net_is_local_address (struct mesh_net *net,uint16_t addr) {if (!net)
@@ -3919,55 +3831,3 @@ void mesh_net_set_prov(struct mesh_net *net, struct mesh_prov *prov) net->prov = prov; } -bool mesh_net_provisioned_new (struct mesh_net *net,uint8_t device_key[16 ], -uint16_t net_idx,uint8_t net_key[16 ], -uint16_t unicast,uint16_t snb_flags, -uint32_t iv_index,mesh_status_func_t cb, -void *user_data) -{ -if (net->provisioned || !net->local_node) -return false; - -if (!node_set_primary (net->local_node, unicast) || - !(mesh_net_register_unicast (net, unicast, -mesh_net_get_num_ele (net)))) -return false; - -if (!node_set_device_key (net->local_node, device_key)) -return false; - - net->iv_index = iv_index; - net->iv_update = ((snb_flags &0x02 ) !=0 ); -if (!storage_local_set_iv_index (net, iv_index, net->iv_update)) -return false; - -if (mesh_net_add_key (net, false, net_idx, net_key) != -MESH_STATUS_SUCCESS ) -return false; - -if ((snb_flags &0x01 ) && - (mesh_net_add_key (net, true, net_idx, net_key) != -MESH_STATUS_SUCCESS )) { -l_queue_clear (net->subnets, l_free); -return false; - } - -return storage_save_new_config (net, net->cfg_file, cb, user_data); - -} - -void mesh_net_provisioned_set (struct mesh_net *net,bool provisioned) -{ -if (!net) -return ; - - net->provisioned = provisioned; -} - -bool mesh_net_provisioned_get (struct mesh_net *net) -{ -if (!net) -return false; - -return net->provisioned; -}
mesh/net.h +7 -27
@@ -17,9 +17,6 @@* */ -#include <stdbool.h> -#include <stdint.h> -#ifndef __packed#define __packed __attribute__((packed))#endif
@@ -259,9 +256,8 @@ typedef void (*mesh_net_status_func_t)(uint16_t remote, uint8_t status, void *data, uint16_t size, void *user_data); -struct mesh_net *mesh_net_new (uint16_t index); -struct mesh_net *mesh_net_ref (struct mesh_net *net); -void mesh_net_unref (struct mesh_net *net); +struct mesh_net *mesh_net_new (struct mesh_node *node); +void mesh_net_free (struct mesh_net *net);void mesh_net_flush_msg_queues (struct mesh_net *net);void mesh_net_set_iv_index (struct mesh_net *net,uint32_t index,bool update);bool mesh_net_iv_index_update (struct mesh_net *net);
@@ -301,13 +297,12 @@ void mesh_net_transport_send(struct mesh_net *net, uint32_t key_id, uint32_t seq, uint16_t src, uint16_t dst, const uint8_t *msg, uint16_t msg_len); -unsigned int mesh_net_app_send (struct mesh_net *net,bool frnd_cred, -uint16_t src,uint16_t dst,uint8_t key_id, -uint8_t ttl,uint32_t seq,uint32_t iv_index, -bool szmic,const void *msg,uint16_t msg_len, +bool mesh_net_app_send (struct mesh_net *net,bool frnd_cred,uint16_t src, +uint16_t dst,uint8_t key_id,uint8_t ttl, +uint32_t seq,uint32_t iv_index,bool szmic, +const void *msg,uint16_t msg_len,mesh_net_status_func_t status_func,void *user_data); -void mesh_net_app_send_cancel (struct mesh_net *net,unsigned int id); void mesh_net_ack_send(struct mesh_net *net, uint32_t key_id, uint32_t iv_index, uint8_t ttl, uint32_t seq, uint16_t src, uint16_t dst, bool rly,
@@ -363,16 +358,8 @@ void mesh_net_sub_list_add(struct mesh_net *net, uint16_t addr);void mesh_net_sub_list_del (struct mesh_net *net,uint16_t addr);uint32_t mesh_net_friend_timeout (struct mesh_net *net,uint16_t addr);struct mesh_io *mesh_net_get_io (struct mesh_net *net); -bool mesh_net_local_node_set (struct mesh_net *net,struct mesh_node *node, -bool provisioner); -struct mesh_node *mesh_net_local_node_get (struct mesh_net *net); -bool mesh_net_set_crpl (struct mesh_net *net,uint16_t crpl); -uint16_t mesh_net_get_crpl (struct mesh_net *net); +struct mesh_node *mesh_net_node_get (struct mesh_net *net);bool mesh_net_have_key (struct mesh_net *net,uint16_t net_idx); -bool mesh_net_jconfig_set (struct mesh_net *net,void *jconfig); -void *mesh_net_jconfig_get (struct mesh_net *net); -bool mesh_net_cfg_file_set (struct mesh_net *net,const char *cfg); -bool mesh_net_cfg_file_get (struct mesh_net *net,const char **cfg);bool mesh_net_is_local_address (struct mesh_net *net,uint16_t addr);void mesh_net_set_window_accuracy (struct mesh_net *net,uint8_t accuracy); void mesh_net_transmit_params_set(struct mesh_net *net, uint8_t count,
@@ -381,10 +368,3 @@ void mesh_net_transmit_params_get(struct mesh_net *net, uint8_t *count, uint16_t *interval);struct mesh_prov *mesh_net_get_prov (struct mesh_net *net);void mesh_net_set_prov (struct mesh_net *net,struct mesh_prov *prov); -void mesh_net_provisioned_set (struct mesh_net *net,bool provisioned); -bool mesh_net_provisioned_get (struct mesh_net *net); -bool mesh_net_provisioned_new (struct mesh_net *net,uint8_t device_key[16 ], -uint16_t net_idx,uint8_t net_key[16 ], -uint16_t unicast,uint16_t snb_flags, -uint32_t iv_index,mesh_status_func_t cb, -void *user_data);
Signature · 1 line
2.14.5
PATCH v6 7/26 mesh: Direction agnostic PB-ADV implementation
In reply to Brian GixOriginally found in prov.c, this file implements the PB-ADV provisioning transport. It may be used by either the Acceptor or the Initiator side of the Provisioning procedure, but only one session may be active at once.
--- mesh/pb-adv.c | 444 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ mesh/pb-adv.h | 23 +++ 2 files changed, 467 insertions(+) create mode 100644 mesh/pb-adv.c create mode 100644 mesh/pb-adv.h
mesh/pb-adv.c new file +444 -0
@@ -0,0 +1,444 @@ +/* +* +* BlueZ - Bluetooth protocol stack for Linux +* +* Copyright (C) 2018 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 + +#include <sys/select.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> +#include <termios.h> + +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <getopt.h> +#include <time.h> +#include <ell/ell.h> + +#include "mesh/mesh-defs.h" +#include "src/shared/ecc.h" + +#include "mesh/util.h" +#include "mesh/net_keys.h" +#include "mesh/crypto.h" +#include "mesh/net.h" +#include "mesh/mesh-io.h" +#include "mesh/mesh.h" +#include "mesh/prov.h" +#include "mesh/provision.h" +#include "mesh/pb-adv.h" + + +struct pb_adv_session { +mesh_prov_open_func_t open_cb; +mesh_prov_close_func_t close_cb; +mesh_prov_receive_func_t rx_cb; +mesh_prov_ack_func_t ack_cb; +struct l_timeout *tx_timeout; +uint32_t conn_id; +uint16_t exp_len; +uint8_t exp_fcs; +uint8_t exp_segs; +uint8_t got_segs; +uint8_t msg_num; +uint8_t local_acked; +uint8_t local_msg_num; +uint8_t peer_msg_num; +uint8_t last_peer_msg_num; +uint8_t sar[80 ]; +uint8_t uuid[16 ]; +bool initiator; +bool opened; +void *user_data; +}; + +#define PB_ADV_ACK 0x01 +#define PB_ADV_OPEN_REQ 0x03 +#define PB_ADV_OPEN_CFM 0x07 +#define PB_ADV_CLOSE 0x0B + +#define PB_ADV_MTU 24 + +static struct pb_adv_session *pb_session =NULL ; + +static void send_adv_segs (struct pb_adv_session *session,const uint8_t *data, +uint16_t size) +{ +uint16_t init_size; +uint8_t buf[PB_ADV_MTU +6 ] = {MESH_AD_TYPE_PROVISION }; +uint8_t max_seg; +uint8_t consumed; +int i; + +if (!size) +return ; + +mesh_send_cancel (buf,1 ); + +l_put_be32 (session->conn_id, buf +1 ); + buf[1 +4 ] = ++session->local_msg_num; + +if (size >PB_ADV_MTU -4 ) { + max_seg =1 + + (((size - (PB_ADV_MTU -4 )) -1 ) / (PB_ADV_MTU -1 )); + init_size =PB_ADV_MTU -4 ; + }else { + max_seg =0 ; + init_size = size; + } + +/* print_packet("FULL-TX", data, size); */ + +l_debug ("Sending %u fragments for %u octets" , max_seg +1 , size); + + buf[6 ] = max_seg <<2 ; +l_put_be16 (size, buf +7 ); + buf[9 ] =mesh_crypto_compute_fcs (data, size); +memcpy (buf +10 , data, init_size); + +l_debug ("max_seg: %2.2x" , max_seg); +l_debug ("size: %2.2x, CRC: %2.2x" , size, buf[9 ]); +/* print_packet("PB-TX", buf + 1, init_size + 9); */ +mesh_send_pkt (MESH_IO_TX_COUNT_UNLIMITED ,50 , buf, init_size +10 ); + + consumed = init_size; + +for (i =1 ; i <= max_seg; i++) { +uint8_t seg_size;/* Amount of payload data being sent */ + +if (size - consumed >PB_ADV_MTU -1 ) + seg_size =PB_ADV_MTU -1 ; +else + seg_size = size - consumed; + + buf[6 ] = (i <<2 ) |0x02 ; +memcpy (buf +7 , data + consumed, seg_size); + +/* print_packet("PB-TX", buf + 1, seg_size + 6); */ + +mesh_send_pkt (MESH_IO_TX_COUNT_UNLIMITED ,50 , + buf, seg_size +7 ); + + consumed += seg_size; + } +} + +static void tx_timeout (struct l_timeout *timeout,void *user_data) +{ +struct pb_adv_session *session = user_data; +uint8_t cancel[] = {MESH_AD_TYPE_PROVISION }; +mesh_prov_close_func_t cb; + +if (!session || pb_session != session) +return ; + +l_timeout_remove (session->tx_timeout); + session->tx_timeout =NULL ; + +mesh_send_cancel (cancel,sizeof (cancel)); + +l_info ("TX timeout" ); + cb = pb_session->close_cb; + user_data = pb_session->user_data; +l_free (pb_session); + pb_session =NULL ; +cb (user_data,1 ); +} + +static void pb_adv_tx (void *user_data,uint8_t *data,uint16_t len) +{ +struct pb_adv_session *session = user_data; + +if (!session || pb_session != session) +return ; + +l_timeout_remove (session->tx_timeout); + session->tx_timeout =l_timeout_create (30 , tx_timeout, session,NULL ); + +send_adv_segs (session, data, len); +} + +static void send_open_cfm (struct pb_adv_session *session) +{ +uint8_t open_cfm[7 ] = {MESH_AD_TYPE_PROVISION }; + +l_put_be32 (session->conn_id, open_cfm +1 ); + open_cfm[1 +4 ] =0 ; + open_cfm[1 +4 +1 ] =0x07 ;/* OPEN_CFM */ + +/* print_packet("PB-TX", open_cfm + 1, sizeof(open_cfm) - 1); */ + +mesh_send_cancel (open_cfm,1 ); +mesh_send_pkt (5 ,100 , open_cfm,sizeof (open_cfm)); +} + +static void send_ack (struct pb_adv_session *session,uint8_t msg_num) +{ +uint8_t ack[7 ] = {MESH_AD_TYPE_PROVISION }; + +l_put_be32 (session->conn_id, ack +1 ); + ack[1 +4 ] = msg_num; + ack[1 +4 +1 ] =0x01 ;/* ACK */ + +/* print_packet("ADV-ACK", ack + 1, sizeof(ack) - 1); */ +mesh_send_pkt (1 ,100 , ack,sizeof (ack)); +} + +static void send_close_ind (struct pb_adv_session *session,uint8_t reason) +{ +uint8_t close_ind[8 ] = {MESH_AD_TYPE_PROVISION }; + +if (!pb_session || pb_session->user_data != session) +return ; + +l_put_be32 (session->conn_id, close_ind +1 ); + close_ind[5 ] =0 ; + close_ind[6 ] =PB_ADV_CLOSE ;/* CLOSE_IND */ + close_ind[7 ] = reason; + +mesh_send_cancel (close_ind,1 ); +mesh_send_pkt (5 ,100 , close_ind,sizeof (close_ind)); +} + +static void pb_adv_packet (void *user_data,const uint8_t *pkt,uint16_t len) +{ +struct pb_adv_session *session = user_data; +uint32_t conn_id; +size_t offset; +uint8_t msg_num; +uint8_t type; +bool first; + +if (!session || pb_session != session) +return ; + + conn_id =l_get_be32 (pkt +1 ); + type =l_get_u8 (pkt +6 ); + +/* Validate new or existing Connection ID */ +if (session->conn_id) { +if (session->conn_id != conn_id) +return ; + }else if (type !=0x03 ) +return ; +else if (!conn_id) +return ; + + msg_num =l_get_u8 (pkt +5 ); + pkt +=7 ; + len -=7 ; + +switch (type) { +case PB_ADV_OPEN_CFM : +/* +* Ignore if: +* 1. We are acceptor +* 2. We are already provisioning on different conn_id +*/ + +if (!session->initiator) +return ; + + first = !session->opened; + session->opened = true; + +/* Only call Open callback once */ +if (first) { +l_debug ("PB-ADV open confirmed" ); + session->open_cb (session->user_data, pb_adv_tx, + session,PB_ADV ); + } +return ; + +case PB_ADV_OPEN_REQ : +/* +* Ignore if: +* 1. We are initiator +* 2. Open request not addressed to us +* 3. We are already provisioning on different conn_id +*/ + +if (session->initiator) +return ; + +if (memcmp (pkt, session->uuid,16 )) +return ; + + first = !session->conn_id; + session->conn_id = conn_id; + session->last_peer_msg_num =0xFF ; + session->local_acked =0xFF ; + session->peer_msg_num =0x00 ; + session->local_msg_num =0x7F ; + session->opened = true; + +/* Only call Open callback once */ +if (first) { +l_debug ("PB-ADV open requested" ); + session->open_cb (session->user_data, pb_adv_tx, + session,PB_ADV ); + } + +/* Send CFM once per received request */ +send_open_cfm (session); +break ; + +case PB_ADV_CLOSE : +l_timeout_remove (session->tx_timeout); +l_debug ("Link closed notification: %2.2x" , pkt[0 ]); +/* Wrap callback for pre-cleaning */ +if (true) { +mesh_prov_close_func_t cb = session->close_cb; +void *user_data = session->user_data; + +l_free (session); + pb_session =NULL ; +cb (user_data, pkt[0 ]); + } +break ; + +case PB_ADV_ACK : +if (!session->opened) +return ; + +if (msg_num != session->local_msg_num) +return ; + +if (session->local_acked > msg_num) +return ; + +l_debug ("Got ACK %d" , msg_num); + session->local_acked = msg_num; + session->ack_cb (session->user_data, msg_num); +break ; + +default :/* DATA SEGMENT */ +if (!session->opened) +return ; + +if (msg_num == session->last_peer_msg_num) { +send_ack (session, msg_num); +return ; + } + +switch (type &0x03 ) { +case 0x00 : + session->peer_msg_num = msg_num; + session->exp_len =l_get_be16 (pkt); + +l_debug ("PB-ADV start with %u fragments, %d octets" , + type >>2 , session->exp_len); + +if (session->exp_len >sizeof (session->sar)) { +l_debug ("Incoming length exceeded: %d" , + session->exp_len); +return ; + } + + session->exp_fcs =l_get_u8 (pkt +2 ); + session->exp_segs =0xff >> (7 - (type >>2 )); + +/* Save first segment */ +memcpy (session->sar, pkt +3 , len -3 ); + session->got_segs |=1 ; +break ; + +case 0x02 : + session->peer_msg_num = msg_num; + offset =20 + (((type >>2 ) -1 ) *23 ); + +if (offset + len -3 >sizeof (session->sar)) { +l_debug ("Length exceeded: %d" , + session->exp_len); +return ; + } + +l_debug ("Processing fragment %u" , type >>2 ); +memcpy (session->sar + offset, pkt, len); + session->got_segs |=1 << (type >>2 ); +break ; + +default : +/* Malformed or unrecognized */ +return ; + } + +if (session->got_segs != session->exp_segs) +return ; + +/* Validate RXed packet and pass up to Provisioning */ +if (!mesh_crypto_check_fcs (session->sar, + session->exp_len, + session->exp_fcs)) { + +/* This can be a false negative if first +* segment missed, and can almost always +* be ignored. +*/ + +l_debug ("Invalid FCS" ); +return ; + } + +if (session->last_peer_msg_num != session->peer_msg_num) { + session->got_segs =0 ; + session->rx_cb (session->user_data, session->sar, + session->exp_len); + } + + session->last_peer_msg_num = session->peer_msg_num; +send_ack (session, session->last_peer_msg_num); + } +} + +bool pb_adv_reg (mesh_prov_open_func_t open_cb,mesh_prov_close_func_t close_cb, +mesh_prov_receive_func_t rx_cb,mesh_prov_ack_func_t ack_cb, +uint8_t uuid[16 ],void *user_data) +{ +if (pb_session) +return false; + + pb_session = l_new(struct pb_adv_session, 1); + pb_session->open_cb = open_cb; + pb_session->close_cb = close_cb; + pb_session->rx_cb = rx_cb; + pb_session->ack_cb = ack_cb; + pb_session->user_data = user_data; +memcpy (pb_session->uuid, uuid,16 ); + +/* TODO: register PB AD type and Start Beaconing ? */ +mesh_reg_prov_rx (pb_adv_packet, pb_session); + +return true; +} + +void pb_adv_unreg (void *user_data) +{ +if (!pb_session || pb_session->user_data != user_data) +return ; + +l_timeout_remove (pb_session->tx_timeout); +send_close_ind (pb_session,0 ); +l_free (pb_session); + pb_session =NULL ; +}
mesh/pb-adv.h new file +23 -0
@@ -0,0 +1,23 @@ +/* +* +* BlueZ - Bluetooth protocol stack for Linux +* +* Copyright (C) 2018 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. +* +*/ + +bool pb_adv_reg (mesh_prov_open_func_t open_cb,mesh_prov_close_func_t close_cb, +mesh_prov_receive_func_t rx_cb,mesh_prov_ack_func_t ack_cb, +uint8_t uuid[16 ],void *user_data); +void pb_adv_unreg (void *user_data);
Signature · 1 line
2.14.5
PATCH v6 8/26 mesh: Acceptor side provisioning implementation
In reply to Brian GixThis functionaility (originally found in provision.c) was rewritten as the Acceptor side only of the provisioning procedure. This is the more common procedure of the unprovisioned device that is brought into an existing mesh network by a remote (master) Provisioner.
--- mesh/prov-acceptor.c | 684 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 684 insertions(+) create mode 100644 mesh/prov-acceptor.c
mesh/prov-acceptor.c new file +684 -0
@@ -0,0 +1,684 @@ +/* +* +* BlueZ - Bluetooth protocol stack for Linux +* +* Copyright (C) 2018 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 + +#include <sys/select.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> +#include <termios.h> + +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <getopt.h> +#include <time.h> +#include <ell/ell.h> + +#include "mesh/mesh-defs.h" +#include "src/shared/ecc.h" + +#include "mesh/util.h" +#include "mesh/net_keys.h" +#include "mesh/crypto.h" +#include "mesh/net.h" +#include "mesh/error.h" +#include "mesh/prov.h" +#include "mesh/provision.h" +#include "mesh/pb-adv.h" +#include "mesh/mesh.h" +#include "mesh/agent.h" + +/* Quick size sanity check */ +static const uint16_t expected_pdu_size[] = { +2 ,/* PROV_INVITE */ +12 ,/* PROV_CAPS */ +6 ,/* PROV_START */ +65 ,/* PROV_PUB_KEY */ +1 ,/* PROV_INP_CMPLT */ +17 ,/* PROV_CONFIRM */ +17 ,/* PROV_RANDOM */ +34 ,/* PROV_DATA */ +1 ,/* PROV_COMPLETE */ +2 ,/* PROV_FAILED */ +}; + +#define BEACON_TYPE_UNPROVISIONED 0x00 + +static const uint8_t pkt_filter =MESH_AD_TYPE_PROVISION ; +static const uint8_t bec_filter[] = {MESH_AD_TYPE_BEACON , +BEACON_TYPE_UNPROVISIONED }; + +enum acp_state { +ACP_PROV_IDLE =0 , +ACP_PROV_CAPS_SENT , +ACP_PROV_CAPS_ACKED , +ACP_PROV_KEY_SENT , +ACP_PROV_KEY_ACKED , +ACP_PROV_INP_CMPLT_SENT , +ACP_PROV_INP_CMPLT_ACKED , +ACP_PROV_CONF_SENT , +ACP_PROV_CONF_ACKED , +ACP_PROV_RAND_SENT , +ACP_PROV_RAND_ACKED , +ACP_PROV_CMPLT_SENT , +ACP_PROV_FAIL_SENT , +}; + +#define MAT_REMOTE_PUBLIC 0x01 +#define MAT_LOCAL_PRIVATE 0x02 +#define MAT_RAND_AUTH 0x04 +#define MAT_SECRET (MAT_REMOTE_PUBLIC | MAT_LOCAL_PRIVATE) + +struct mesh_prov_acceptor { +mesh_prov_acceptor_complete_func_t cmplt; +prov_trans_tx_t trans_tx; +void *agent; +void *caller_data; +void *trans_data; +struct l_timeout *timeout; +uint32_t to_secs; +enum acp_state state; +uint8_t transport; +uint8_t material; +uint8_t expected; +int8_t previous; +struct conf_input conf_inputs; +uint8_t calc_key[16 ]; +uint8_t salt[16 ]; +uint8_t confirm[16 ]; +uint8_t s_key[16 ]; +uint8_t s_nonce[13 ]; +uint8_t private_key[32 ]; +uint8_t secret[32 ]; +uint8_t rand_auth_workspace[48 ]; +}; + +static struct mesh_prov_acceptor *prov =NULL ; + +static void acceptor_free (void ) +{ + +if (prov) +l_timeout_remove (prov->timeout); + +mesh_send_cancel (bec_filter,sizeof (bec_filter)); +mesh_send_cancel (&pkt_filter,sizeof (pkt_filter)); + +if (prov->trans_tx) { +if (prov->transport ==PB_ADV ) +pb_adv_unreg (prov->trans_data); + } + +l_free (prov); + prov =NULL ; +} + +static void acp_prov_close (void *user_data,uint8_t reason) +{ +/* TODO: Handle Close */ +} + +static void prov_to (struct l_timeout *timeout,void *user_data) +{ +struct mesh_prov_acceptor *rx_prov = user_data; +uint8_t fail_code[2 ] = {PROV_FAILED ,PROV_ERR_UNEXPECTED_ERR }; + +if (rx_prov != prov) +return ; + + prov->timeout =NULL ; + +if (prov->cmplt && prov->trans_tx) { + prov->cmplt (prov->caller_data,PROV_ERR_TIMEOUT ,NULL ); + prov->cmplt =NULL ; + prov->trans_tx (prov->trans_data, fail_code,2 ); + prov->timeout =l_timeout_create (1 , prov_to, prov,NULL ); +return ; + } + +acceptor_free (); +} + +static void acp_prov_open (void *user_data,prov_trans_tx_t trans_tx, +void *trans_data,uint8_t transport) +{ +struct mesh_prov_acceptor *rx_prov = user_data; + +/* Only one provisioning session may be open at a time */ +if (rx_prov != prov) +return ; + +/* Only one provisioning session may be open at a time */ +if (prov->trans_tx && prov->trans_tx != trans_tx && + prov->transport != transport) +return ; + +if (transport !=PB_ADV ) +return ; + + prov->trans_tx = trans_tx; + prov->transport = transport; + prov->trans_data = trans_data; + prov->timeout =l_timeout_create (prov->to_secs, prov_to, prov,NULL ); +} + +static void swap_u256_bytes (uint8_t *u256) +{ +int i; + +/* End-to-End byte reflection of 32 octet buffer */ +for (i =0 ; i <16 ; i++) { + u256[i] ^= u256[31 - i]; + u256[31 - i] ^= u256[i]; + u256[i] ^= u256[31 - i]; + } +} + +static void prov_calc_secret (const uint8_t *pub,const uint8_t *priv, +uint8_t *secret) +{ +uint8_t tmp[64 ]; + +/* Convert to ECC byte order */ +memcpy (tmp, pub,64 ); +swap_u256_bytes (tmp); +swap_u256_bytes (tmp +32 ); + +ecdh_shared_secret (tmp, priv, secret); + +/* Convert to Mesh byte order */ +swap_u256_bytes (secret); +} + +static void acp_credentials (struct mesh_prov_acceptor *prov) +{ +prov_calc_secret (prov->conf_inputs.prv_pub_key, + prov->private_key, prov->secret); + +mesh_crypto_s1 (&prov->conf_inputs, +sizeof (prov->conf_inputs), prov->salt); + +mesh_crypto_prov_conf_key (prov->secret, prov->salt, + prov->calc_key); + +l_getrandom (prov->rand_auth_workspace,16 ); + +print_packet ("PublicKeyProv" , prov->conf_inputs.prv_pub_key,64 ); +print_packet ("PublicKeyDev" , prov->conf_inputs.dev_pub_key,64 ); +print_packet ("PrivateKeyLocal" , prov->private_key,32 ); +print_packet ("ConfirmationInputs" , &prov->conf_inputs, +sizeof (prov->conf_inputs)); +print_packet ("ECDHSecret" , prov->secret,32 ); +print_packet ("LocalRandom" , prov->rand_auth_workspace,16 ); +print_packet ("ConfirmationSalt" , prov->salt,16 ); +print_packet ("ConfirmationKey" , prov->calc_key,16 ); +} + +static uint32_t digit_mod (uint8_t power) +{ +uint32_t ret =1 ; + +while (power--) + ret *=10 ; + +return ret; +} + +static void number_cb (void *user_data,int err,uint32_t number) +{ +struct mesh_prov_acceptor *rx_prov = user_data; +uint8_t out[2 ]; + +if (prov != rx_prov) +return ; + +if (err) { + out[0 ] =PROV_FAILED ; + out[1 ] =PROV_ERR_UNEXPECTED_ERR ; + prov->trans_tx (prov->trans_data, out,2 ); +return ; + } + +/* Save two copies, to generate two confirmation values */ +l_put_be32 (number, prov->rand_auth_workspace +28 ); +l_put_be32 (number, prov->rand_auth_workspace +44 ); + prov->material |=MAT_RAND_AUTH ; + out[0 ] =PROV_INP_CMPLT ; + prov->trans_tx (prov->trans_data, out,1 ); +} + +static void static_cb (void *user_data,int err,uint8_t *key,uint32_t len) +{ +struct mesh_prov_acceptor *rx_prov = user_data; +uint8_t out[2 ]; + +if (prov != rx_prov) +return ; + +if (err || !key || len !=16 ) { + out[0 ] =PROV_FAILED ; + out[1 ] =PROV_ERR_UNEXPECTED_ERR ; + prov->trans_tx (prov->trans_data, out,2 ); +return ; + } + +/* Save two copies, to generate two confirmation values */ +memcpy (prov->rand_auth_workspace +16 , key,16 ); +memcpy (prov->rand_auth_workspace +32 , key,16 ); + prov->material |=MAT_RAND_AUTH ; +} + +static void priv_key_cb (void *user_data,int err,uint8_t *key,uint32_t len) +{ +struct mesh_prov_acceptor *rx_prov = user_data; +uint8_t out[2 ]; + +if (prov != rx_prov) +return ; + +if (err || !key || len !=32 ) { + out[0 ] =PROV_FAILED ; + out[1 ] =PROV_ERR_UNEXPECTED_ERR ; + prov->trans_tx (prov->trans_data, out,2 ); +return ; + } + +memcpy (prov->private_key, key,32 ); +ecc_make_public_key (prov->private_key, + prov->conf_inputs.dev_pub_key); + +/* Convert to Mesh byte order */ +swap_u256_bytes (prov->conf_inputs.dev_pub_key); +swap_u256_bytes (prov->conf_inputs.dev_pub_key +32 ); + + prov->material |=MAT_LOCAL_PRIVATE ; +if ((prov->material &MAT_SECRET ) ==MAT_SECRET ) +acp_credentials (prov); +} + +static void acp_prov_rx (void *user_data,const uint8_t *data,uint16_t len) +{ +struct mesh_prov_acceptor *rx_prov = user_data; +struct mesh_prov_node_info *info; +uint8_t *out; +uint8_t type = *data++; +uint8_t fail_code[2 ]; +uint32_t oob_key; +uint64_t decode_mic; +bool result; + +if (rx_prov != prov || !prov->trans_tx) +return ; + +l_debug ("Provisioning packet received type: %2.2x (%u octets)" , + type, len); + +if (type == prov->previous) { +l_error ("Ignore repeated %2.2x packet" , type); +return ; + }else if (type > prov->expected || type < prov->previous) { +l_error ("Expected %2.2x, Got:%2.2x" , prov->expected, type); + fail_code[1 ] =PROV_ERR_UNEXPECTED_PDU ; + goto failure; + } + +if (type >=L_ARRAY_SIZE (expected_pdu_size) || + len != expected_pdu_size[type]) { +l_error ("Expected PDU size %d, Got %d (type: %2.2x)" , + len, expected_pdu_size[type], type); + fail_code[1 ] =PROV_ERR_INVALID_FORMAT ; + goto failure; + } + +switch (type){ +case PROV_INVITE :/* Prov Invite */ +/* Prov Capabilities */ + out =l_malloc (1 +sizeof (struct mesh_net_prov_caps )); + out[0 ] =PROV_CAPS ; +memcpy (out +1 , &prov->conf_inputs.caps, +sizeof (prov->conf_inputs.caps)); + + prov->conf_inputs.invite.attention = data[0 ]; + + prov->state =ACP_PROV_CAPS_SENT ; + prov->expected =PROV_START ; + prov->trans_tx (prov->trans_data, + out,sizeof (prov->conf_inputs.caps) +1 ); +l_free (out); +break ; + +case PROV_START :/* Prov Start */ +memcpy (&prov->conf_inputs.start, data, +sizeof (prov->conf_inputs.start)); + +if (prov->conf_inputs.start.algorithm || + prov->conf_inputs.start.pub_key >1 || + prov->conf_inputs.start.auth_method >3 ) { + fail_code[1 ] =PROV_ERR_INVALID_FORMAT ; + goto failure; + } + +if (prov->conf_inputs.start.pub_key) { +if (prov->conf_inputs.caps.pub_type) { +/* Prompt Agent for Private Key of OOB */ +mesh_agent_request_private_key (prov->agent, + priv_key_cb, prov); + }else { + fail_code[1 ] =PROV_ERR_INVALID_PDU ; + goto failure; + } + }else { +/* Ephemeral Public Key requested */ +ecc_make_key (prov->conf_inputs.dev_pub_key, + prov->private_key); +swap_u256_bytes (prov->conf_inputs.dev_pub_key); +swap_u256_bytes (prov->conf_inputs.dev_pub_key +32 ); + prov->material |=MAT_LOCAL_PRIVATE ; + } + + prov->expected =PROV_PUB_KEY ; +break ; + +case PROV_PUB_KEY :/* Public Key */ +/* Save Key */ +memcpy (prov->conf_inputs.prv_pub_key, data,64 ); + prov->material |=MAT_REMOTE_PUBLIC ; + prov->expected =PROV_CONFIRM ; + +if ((prov->material &MAT_SECRET ) !=MAT_SECRET ) +return ; + +acp_credentials (prov); + +if (!prov->conf_inputs.start.pub_key) { + out =l_malloc (65 ); + out[0 ] =PROV_PUB_KEY ; +memcpy (out +1 , prov->conf_inputs.dev_pub_key,64 ); + prov->trans_tx (prov->trans_data, out,65 ); +l_free (out); + } + +/* Start Step 3 */ +switch (prov->conf_inputs.start.auth_method) { +default : +case 0 : +/* Auth Type 3c - No OOB */ +break ; + +case 1 : +/* Auth Type 3c - Static OOB */ +/* Prompt Agent for Static OOB */ + fail_code[1 ] =mesh_agent_request_static (prov->agent, + static_cb, prov); + +if (fail_code[1 ]) + goto failure; + +break ; + +case 2 : +/* Auth Type 3a - Output OOB */ +l_getrandom (&oob_key,sizeof (oob_key)); + oob_key %=digit_mod (prov->conf_inputs.start.auth_size); + +/* Save two copies, for two confirmation values */ +l_put_be32 (oob_key, prov->rand_auth_workspace +28 ); +l_put_be32 (oob_key, prov->rand_auth_workspace +44 ); + prov->material |=MAT_RAND_AUTH ; + +if (prov->conf_inputs.start.auth_action == +PROV_ACTION_OUT_ALPHA ) { +/* TODO: Construst NUL-term string to pass */ + fail_code[1 ] =mesh_agent_display_string ( + prov->agent,NULL ,NULL , prov); + }else { +/* Ask Agent to Display U32 */ + fail_code[1 ] =mesh_agent_display_number ( + prov->agent, false, + prov->conf_inputs.start.auth_action, + oob_key,NULL , prov); + } + +if (fail_code[1 ]) + goto failure; + +break ; + +case 3 : +/* Auth Type 3b - input OOB */ +/* Prompt Agent for Input OOB */ +if (prov->conf_inputs.start.auth_action == +PROV_ACTION_IN_ALPHA ) { + fail_code[1 ] =mesh_agent_prompt_alpha ( + prov->agent, + static_cb, prov); + }else { + fail_code[1 ] =mesh_agent_prompt_number ( + prov->agent, false, + prov->conf_inputs.start.auth_action, + number_cb, prov); + } + +if (fail_code[1 ]) + goto failure; + +break ; + } + + prov->expected =PROV_CONFIRM ; +break ; + +case PROV_CONFIRM :/* Confirmation */ + out =l_malloc (17 ); + out[0 ] =PROV_CONFIRM ; + +/* Calculate and Send our Confirmation */ +mesh_crypto_aes_cmac (prov->calc_key, prov->rand_auth_workspace, +32 , out +1 ); + prov->trans_tx (prov->trans_data, out,17 ); +l_free (out); + +/* Save Provisioners confirmation for later compare */ +memcpy (prov->confirm, data,16 ); + prov->expected =PROV_RANDOM ; +break ; + +case PROV_RANDOM :/* Random Value */ + out =l_malloc (17 ); +/* Calculate Session key (needed later) while data is fresh */ +mesh_crypto_prov_prov_salt (prov->salt, data, + prov->rand_auth_workspace, + prov->salt); +mesh_crypto_session_key (prov->secret, prov->salt, prov->s_key); +mesh_crypto_nonce (prov->secret, prov->salt, prov->s_nonce); + +/* Calculate expected Provisioner Confirm */ +memcpy (prov->rand_auth_workspace +16 , data,16 ); +mesh_crypto_aes_cmac (prov->calc_key, + prov->rand_auth_workspace +16 ,32 , out); + +/* Compare our calculation with Provisioners */ +if (memcmp (out, prov->confirm,16 )) { + fail_code[1 ] =PROV_ERR_CONFIRM_FAILED ; +l_free (out); + goto failure; + } + +/* Send Random value we used */ + out[0 ] =PROV_RANDOM ; +memcpy (out +1 , prov->rand_auth_workspace,16 ); + prov->trans_tx (prov->trans_data, out,17 ); +l_free (out); + prov->expected =PROV_DATA ; +break ; + +case PROV_DATA :/* Provisioning Data */ + +/* Calculate our device key */ +mesh_crypto_device_key (prov->secret, + prov->salt, + prov->calc_key); + +/* Decrypt new node data into workspace */ +mesh_crypto_aes_ccm_decrypt (prov->s_nonce, prov->s_key, +NULL ,0 , + data, len -1 , prov->rand_auth_workspace, + &decode_mic,sizeof (decode_mic)); + +/* Validate that the data hasn't been messed with in transit */ +if (l_get_be64 (data +25 ) != decode_mic) { +l_error ("Provisioning Failed-MIC compare" ); + fail_code[1 ] =PROV_ERR_DECRYPT_FAILED ; + goto failure; + } + + info =l_malloc (sizeof (struct mesh_prov_node_info )); + +memcpy (info->device_key, prov->calc_key,16 ); +memcpy (info->net_key, prov->rand_auth_workspace,16 ); + info->net_index =l_get_be16 (prov->rand_auth_workspace +16 ); + info->flags = prov->rand_auth_workspace[18 ]; + info->iv_index =l_get_be32 (prov->rand_auth_workspace +19 ); + info->unicast =l_get_be16 (prov->rand_auth_workspace +23 ); + + result = prov->cmplt (prov->caller_data,PROV_ERR_SUCCESS , info); + prov->cmplt =NULL ; +l_free (info); + +if (result) { + prov->rand_auth_workspace[0 ] =PROV_COMPLETE ; + prov->trans_tx (prov->trans_data, + prov->rand_auth_workspace,1 ); + goto cleanup; + }else { + fail_code[1 ] =PROV_ERR_UNEXPECTED_ERR ; + goto failure; + } +break ; + +case PROV_FAILED :/* Provisioning Error -- abort */ +/* TODO: Call Complete Callback (Fail)*/ + prov->cmplt (prov->caller_data, + data[0 ] ? data[0 ] :PROV_ERR_UNEXPECTED_ERR , +NULL ); + prov->cmplt =NULL ; + goto cleanup; + } + + prov->previous = type; +return ; + +failure: + fail_code[0 ] =PROV_FAILED ; + prov->trans_tx (prov->trans_data, fail_code,2 ); +if (prov->cmplt) + prov->cmplt (prov->caller_data, fail_code[1 ],NULL ); + prov->cmplt =NULL ; + +cleanup: +l_timeout_remove (prov->timeout); + +/* Give PB Link 5 seconds to end session */ + prov->timeout =l_timeout_create (5 , prov_to, prov,NULL ); +} + +static void acp_prov_ack (void *user_data,uint8_t msg_num) +{ +/* TODO: Handle PB-ADV Ack */ +} + + +/* This starts unprovisioned device beacon */ +bool acceptor_start (uint8_t num_ele,uint8_t uuid[16 ], +uint16_t algorithms,uint32_t timeout, +struct mesh_agent *agent, +mesh_prov_acceptor_complete_func_t complete_cb, +void *caller_data) +{ +struct mesh_agent_prov_caps *caps; +uint8_t beacon[24 ] = {MESH_AD_TYPE_BEACON , +BEACON_TYPE_UNPROVISIONED }; +uint8_t len =sizeof (beacon) -sizeof (uint32_t ); +bool result; + +/* Invoked from Join() method in mesh-api.txt, to join a +* remote mesh network. +*/ + +if (prov) +return false; + + prov = l_new(struct mesh_prov_acceptor, 1); + prov->to_secs = timeout; + prov->agent = agent; + prov->cmplt = complete_cb; + prov->previous =-1 ; + prov->caller_data = caller_data; + + caps =mesh_agent_get_caps (agent); + +/* TODO: Should we sanity check values here or elsewhere? */ + prov->conf_inputs.caps.num_ele = num_ele; + prov->conf_inputs.caps.pub_type = caps->pub_type; + prov->conf_inputs.caps.static_type = caps->static_type; + prov->conf_inputs.caps.output_size = caps->output_size; + prov->conf_inputs.caps.input_size = caps->input_size; + +/* Store UINT16 values in Over-the-Air order, in packed structure +* for crypto inputs +*/ +l_put_be16 (algorithms, &prov->conf_inputs.caps.algorithms); +l_put_be16 (caps->output_action, &prov->conf_inputs.caps.output_action); +l_put_be16 (caps->input_action, &prov->conf_inputs.caps.input_action); + +/* Compose Unprovisioned Beacon */ +memcpy (beacon +2 , uuid,16 ); +l_put_be16 (caps->oob_info, beacon +18 ); +if (caps->oob_info &OOB_INFO_URI_HASH ){ +l_put_be32 (caps->uri_hash, beacon +20 ); + len +=sizeof (uint32_t ); + } + +/* Infinitely Beacon until Canceled, or Provisioning Starts */ + result =mesh_send_pkt (0 ,500 , beacon, len); + +if (!result) + goto error_fail; + +/* Always register for PB-ADV */ + result =pb_adv_reg (acp_prov_open, acp_prov_close, acp_prov_rx, + acp_prov_ack, uuid, prov); + +if (result) +return true; + +error_fail: +acceptor_free (); +return false; +} + +void acceptor_cancel (void *user_data) +{ +acceptor_free (); +}
Signature · 1 line
2.14.5
PATCH v6 9/26 mesh: Initiator side provisioning implementation
In reply to Brian GixThis functionaility (originally found in provision.c) was rewritten as the Initiator side only of the provisioning procedure. If the local device owns and controls access to a mesh network, this is the side of the provisioning procedure that it must use to bring new unprovisioned devices into the network as Nodes.
--- mesh/prov-initiator.c | 641 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 641 insertions(+) create mode 100644 mesh/prov-initiator.c
mesh/prov-initiator.c new file +641 -0
@@ -0,0 +1,641 @@ +/* +* +* BlueZ - Bluetooth protocol stack for Linux +* +* Copyright (C) 2018 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 + +#include <sys/select.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> +#include <termios.h> + +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <getopt.h> +#include <time.h> +#include <ell/ell.h> + +#include "mesh/mesh-defs.h" +#include "src/shared/ecc.h" + +#include "mesh/util.h" +#include "mesh/net_keys.h" +#include "mesh/crypto.h" +#include "mesh/net.h" +#include "mesh/error.h" +#include "mesh/prov.h" +#include "mesh/provision.h" +#include "mesh/pb-adv.h" +#include "mesh/mesh.h" +#include "mesh/agent.h" + +/* Quick size sanity check */ +static const uint16_t expected_pdu_size[] = { +2 ,/* PROV_INVITE */ +12 ,/* PROV_CAPS */ +6 ,/* PROV_START */ +65 ,/* PROV_PUB_KEY */ +1 ,/* PROV_INP_CMPLT */ +17 ,/* PROV_CONFIRM */ +17 ,/* PROV_RANDOM */ +34 ,/* PROV_DATA */ +1 ,/* PROV_COMPLETE */ +2 ,/* PROV_FAILED */ +}; + +#define BEACON_TYPE_UNPROVISIONED 0x00 + +static const uint8_t pkt_filter =MESH_AD_TYPE_PROVISION ; + +enum int_state { +INT_PROV_IDLE =0 , +INT_PROV_INVITE_SENT , +INT_PROV_INVITE_ACKED , +INT_PROV_START_SENT , +INT_PROV_START_ACKED , +INT_PROV_KEY_SENT , +INT_PROV_KEY_ACKED , +INT_PROV_CONF_SENT , +INT_PROV_CONF_ACKED , +INT_PROV_RAND_SENT , +INT_PROV_RAND_ACKED , +INT_PROV_DATA_SENT , +INT_PROV_DATA_ACKED , +}; + +#define MAT_REMOTE_PUBLIC 0x01 +#define MAT_LOCAL_PRIVATE 0x02 +#define MAT_RAND_AUTH 0x04 +#define MAT_SECRET (MAT_REMOTE_PUBLIC | MAT_LOCAL_PRIVATE) + +struct mesh_prov_initiator { +mesh_prov_initiator_complete_func_t cmplt; +prov_trans_tx_t trans_tx; +void *agent; +void *caller_data; +void *trans_data; +struct l_timeout *timeout; +uint32_t to_secs; +enum int_state state; +enum trans_type transport; +uint8_t material; +uint8_t expected; +int8_t previous; +struct conf_input conf_inputs; +uint8_t calc_key[16 ]; +uint8_t salt[16 ]; +uint8_t confirm[16 ]; +uint8_t s_key[16 ]; +uint8_t s_nonce[13 ]; +uint8_t private_key[32 ]; +uint8_t secret[32 ]; +uint8_t rand_auth_workspace[48 ]; +}; + +static struct mesh_prov_initiator *prov =NULL ; + +static void initiator_free (void ) +{ + +if (prov) +l_timeout_remove (prov->timeout); + +mesh_send_cancel (&pkt_filter,sizeof (pkt_filter)); + +l_free (prov); + prov =NULL ; +} + +static void int_prov_close (void *user_data,uint8_t reason) +{ +/* TODO: Handle Close */ +} + +static void int_prov_open (void *user_data,prov_trans_tx_t trans_tx, +void *trans_data,uint8_t transport) +{ +struct mesh_prov_initiator *rx_prov = user_data; +uint8_t invite[] = {PROV_INVITE ,30 }; + +/* Only one provisioning session may be open at a time */ +if (rx_prov != prov) +return ; + +/* Only one provisioning session may be open at a time */ +if (prov->trans_tx && prov->trans_tx != trans_tx && + prov->transport != transport) +return ; + +/* We only care here if transport does *not* match */ +if (transport != prov->transport) +return ; + +/* Always use an ephemeral key when Initiator */ +ecc_make_key (prov->conf_inputs.prv_pub_key, prov->private_key); + prov->material |=MAT_LOCAL_PRIVATE ; + + prov->trans_tx = trans_tx; + prov->trans_data = trans_data; + prov->state =INT_PROV_INVITE_SENT ; + prov->expected =PROV_CAPS ; + + prov->conf_inputs.invite.attention = invite[1 ]; + prov->trans_tx (prov->trans_data, invite,sizeof (invite)); +return ; +} + +static void swap_u256_bytes (uint8_t *u256) +{ +int i; + +/* End-to-End byte reflection of 32 octet buffer */ +for (i =0 ; i <16 ; i++) { + u256[i] ^= u256[31 - i]; + u256[31 - i] ^= u256[i]; + u256[i] ^= u256[31 - i]; + } +} + +static void prov_calc_secret (const uint8_t *pub,const uint8_t *priv, +uint8_t *secret) +{ +uint8_t tmp[64 ]; + +/* Convert to ECC byte order */ +memcpy (tmp, pub,64 ); +swap_u256_bytes (tmp); +swap_u256_bytes (tmp +32 ); + +ecdh_shared_secret (tmp, priv, secret); + +/* Convert to Mesh byte order */ +swap_u256_bytes (secret); +} + +static void int_credentials (struct mesh_prov_initiator *prov) +{ +prov_calc_secret (prov->conf_inputs.dev_pub_key, + prov->private_key, prov->secret); + +mesh_crypto_s1 (&prov->conf_inputs, +sizeof (prov->conf_inputs), prov->salt); + +mesh_crypto_prov_conf_key (prov->secret, prov->salt, + prov->calc_key); + +l_getrandom (prov->rand_auth_workspace,16 ); + +print_packet ("PublicKeyProv" , prov->conf_inputs.prv_pub_key,64 ); +print_packet ("PublicKeyDev" , prov->conf_inputs.dev_pub_key,64 ); +print_packet ("PrivateKeyLocal" , prov->private_key,32 ); +print_packet ("ConfirmationInputs" , &prov->conf_inputs, +sizeof (prov->conf_inputs)); +print_packet ("ECDHSecret" , prov->secret,32 ); +print_packet ("LocalRandom" , prov->rand_auth_workspace,16 ); +print_packet ("ConfirmationSalt" , prov->salt,16 ); +print_packet ("ConfirmationKey" , prov->calc_key,16 ); +} + +static uint8_t u16_high_bit (uint16_t mask) +{ +uint8_t cnt =0 ; + +if (!mask) +return 0xff ; + +while (mask &0xfffe ) { + cnt++; + mask >>=1 ; + } + +return cnt; +} + +static uint32_t digit_mod (uint8_t power) +{ +uint32_t ret =1 ; + +while (power--) + ret *=10 ; + +return ret; +} + +static void calc_local_material (const uint8_t *random) +{ +/* Calculate SessionKey while the data is fresh */ +mesh_crypto_prov_prov_salt (prov->salt, + prov->rand_auth_workspace, random, + prov->salt); +mesh_crypto_session_key (prov->secret, prov->salt, + prov->s_key); +mesh_crypto_nonce (prov->secret, prov->salt, prov->s_nonce); + +print_packet ("SessionKey" , prov->s_key,sizeof (prov->s_key)); +print_packet ("Nonce" , prov->s_nonce,sizeof (prov->s_nonce)); +print_packet ("RandomDevice" , prov->rand_auth_workspace,16 ); +} + +static void number_cb (void *user_data,int err,uint32_t number) +{ +struct mesh_prov_initiator *rx_prov = user_data; +uint8_t out[2 ]; + +if (prov != rx_prov) +return ; + +if (err) { + out[0 ] =PROV_FAILED ; + out[1 ] =PROV_ERR_UNEXPECTED_ERR ; + prov->trans_tx (prov->trans_data, out,2 ); +return ; + } + +/* Save two copies, to generate two confirmation values */ +l_put_be32 (number, prov->rand_auth_workspace +28 ); +l_put_be32 (number, prov->rand_auth_workspace +44 ); + prov->material |=MAT_RAND_AUTH ; +} + +static void static_cb (void *user_data,int err,uint8_t *key,uint32_t len) +{ +struct mesh_prov_initiator *rx_prov = user_data; +uint8_t out[2 ]; + +if (prov != rx_prov) +return ; + +if (err || !key || len !=16 ) { + out[0 ] =PROV_FAILED ; + out[1 ] =PROV_ERR_UNEXPECTED_ERR ; + prov->trans_tx (prov->trans_data, out,2 ); +return ; + } + +memcpy (prov->rand_auth_workspace +16 , key,16 ); +memcpy (prov->rand_auth_workspace +32 , key,16 ); + prov->material |=MAT_RAND_AUTH ; +} + +static void pub_key_cb (void *user_data,int err,uint8_t *key,uint32_t len) +{ +struct mesh_prov_initiator *rx_prov = user_data; +uint8_t out[2 ]; + +if (prov != rx_prov) +return ; + +if (err || !key || len !=64 ) { + out[0 ] =PROV_FAILED ; + out[1 ] =PROV_ERR_UNEXPECTED_ERR ; + prov->trans_tx (prov->trans_data, out,2 ); +return ; + } + +memcpy (prov->conf_inputs.dev_pub_key, key,64 ); + prov->material |=MAT_REMOTE_PUBLIC ; + +if ((prov->material &MAT_SECRET ) ==MAT_SECRET ) +int_credentials (prov); +} + +static void int_prov_rx (void *user_data,const uint8_t *data,uint16_t len) +{ +struct mesh_prov_initiator *rx_prov = user_data; +uint8_t *out; +uint8_t type = *data++; +uint8_t fail_code[2 ]; +uint32_t oob_key; +uint64_t mic; + +if (rx_prov != prov || !prov->trans_tx) +return ; + +l_debug ("Provisioning packet received type: %2.2x (%u octets)" , + type, len); + +if (type == prov->previous) { +l_error ("Ignore repeated %2.2x packet" , type); +return ; + }else if (type > prov->expected || type < prov->previous) { +l_error ("Expected %2.2x, Got:%2.2x" , prov->expected, type); + fail_code[1 ] =PROV_ERR_UNEXPECTED_PDU ; + goto failure; + } + +if (type >=L_ARRAY_SIZE (expected_pdu_size) || + len != expected_pdu_size[type]) { +l_error ("Expected PDU size %d, Got %d (type: %2.2x)" , + len, expected_pdu_size[type], type); + fail_code[1 ] =PROV_ERR_INVALID_FORMAT ; + goto failure; + } + +switch (type) { +case PROV_CAPS :/* Capabilities */ + prov->state =INT_PROV_INVITE_ACKED ; +memcpy (&prov->conf_inputs.caps, data, +sizeof (prov->conf_inputs.caps)); + +l_debug ("Got Num Ele %d" , data[0 ]); +l_debug ("Got alg %4.4x" ,l_get_be16 (data +1 )); +l_debug ("Got pub_type %d" , data[3 ]); +l_debug ("Got static_type %d" , data[4 ]); +l_debug ("Got output_size %d" , data[5 ]); +l_debug ("Got output_action %d" ,l_get_be16 (data +6 )); +l_debug ("Got input_size %d" , data[8 ]); +l_debug ("Got input_action %d" ,l_get_be16 (data +9 )); + +if (!(l_get_be16 (data +1 ) &0x0001 )) { +l_error ("Unsupported Algorithm" ); + fail_code[1 ] =PROV_ERR_INVALID_FORMAT ; + goto failure; + } + +/* If Public Key available Out of Band, use it */ +if (prov->conf_inputs.caps.pub_type) { + prov->conf_inputs.start.pub_key =0x01 ; + prov->expected =PROV_CONFIRM ; +/* Prompt Agent for remote Public Key */ +mesh_agent_request_public_key (prov->agent, + pub_key_cb, prov); + +/* Nothing else for us to do now */ + }else + prov->expected =PROV_PUB_KEY ; + +/* Parse OOB Options, prefer static, then out, then in */ +if (prov->conf_inputs.caps.static_type) { + + prov->conf_inputs.start.auth_method =0x01 ; + + }else if (prov->conf_inputs.caps.output_size && + prov->conf_inputs.caps.output_action) { + + prov->conf_inputs.start.auth_method =0x02 ; + prov->conf_inputs.start.auth_action = +u16_high_bit (l_get_be16 (data +6 )); + prov->conf_inputs.start.auth_size = + (data[5 ] >8 ?8 : data[5 ]); + + }else if (prov->conf_inputs.caps.input_size && + prov->conf_inputs.caps.input_action) { + + prov->conf_inputs.start.auth_method =0x03 ; + prov->conf_inputs.start.auth_action = +u16_high_bit (l_get_be16 (data +9 )); + prov->conf_inputs.start.auth_size = + (data[8 ] >8 ?8 : data[8 ]); + + } + + out =l_malloc (1 +sizeof (prov->conf_inputs.start)); + out[0 ] =PROV_START ; +memcpy (out +1 , &prov->conf_inputs.start, +sizeof (prov->conf_inputs.start)); + + prov->state =INT_PROV_START_SENT ; + prov->trans_tx (prov->trans_data, out, +sizeof (prov->conf_inputs.start) +1 ); +l_free (out); +break ; + +case PROV_PUB_KEY :/* Public Key */ +/* If we expected Pub Key Out-Of-Band, then fail */ +if (prov->conf_inputs.start.pub_key) { + fail_code[1 ] =PROV_ERR_INVALID_PDU ; + goto failure; + } + +memcpy (prov->conf_inputs.dev_pub_key, data,64 ); + prov->material |=MAT_REMOTE_PUBLIC ; + prov->expected =PROV_CONFIRM ; + +if ((prov->material &MAT_SECRET ) !=MAT_SECRET ) +return ; + +int_credentials (prov); + prov->state =INT_PROV_KEY_ACKED ; + + prov->expected =PROV_CONFIRM ; + +memset (prov->rand_auth_workspace +16 ,0 ,32 ); +switch (prov->conf_inputs.start.auth_method) { +default : +case 0 : +/* Auth Type 3c - No OOB */ + prov->material |=MAT_RAND_AUTH ; +break ; +case 1 : +/* Auth Type 3c - Static OOB */ +/* Prompt Agent for Static OOB */ + fail_code[1 ] =mesh_agent_request_static (prov->agent, + static_cb, prov); + +if (fail_code[1 ]) + goto failure; + +break ; +case 2 : +/* Auth Type 3a - Output OOB */ +/* Prompt Agent for Output OOB */ +if (prov->conf_inputs.start.auth_action == +PROV_ACTION_OUT_ALPHA ) { + fail_code[1 ] =mesh_agent_prompt_alpha ( + prov->agent, + static_cb, prov); + }else { + fail_code[1 ] =mesh_agent_prompt_number ( + prov->agent, true, + prov->conf_inputs.start.auth_action, + number_cb, prov); + } + +if (fail_code[1 ]) + goto failure; + +break ; + + +case 3 : +/* Auth Type 3b - input OOB */ +l_getrandom (&oob_key,sizeof (oob_key)); + oob_key %=digit_mod (prov->conf_inputs.start.auth_size); + +/* Save two copies, for two confirmation values */ +l_put_be32 (oob_key, prov->rand_auth_workspace +28 ); +l_put_be32 (oob_key, prov->rand_auth_workspace +44 ); + prov->material |=MAT_RAND_AUTH ; +/* Ask Agent to Display U32 */ +if (prov->conf_inputs.start.auth_action == +PROV_ACTION_IN_ALPHA ) { +/* TODO: Construst NUL-term string to pass */ + fail_code[1 ] =mesh_agent_display_string ( + prov->agent,NULL ,NULL , prov); + }else { + fail_code[1 ] =mesh_agent_display_number ( + prov->agent, false, + prov->conf_inputs.start.auth_action, + oob_key,NULL , prov); + } + +if (fail_code[1 ]) + goto failure; + +break ; + + + } +break ; + +case PROV_INP_CMPLT :/* Provisioning Input Complete */ +/* TODO: Cancel Agent prompt */ + prov->expected =PROV_CONFIRM ; + out =l_malloc (17 ); + out[0 ] =PROV_CONFIRM ; +mesh_crypto_aes_cmac (prov->calc_key, prov->rand_auth_workspace, +32 , out +1 ); + prov->trans_tx (prov->trans_data, out,17 ); +l_free (out); +break ; + +case PROV_CONFIRM :/* Confirmation */ + prov->state =INT_PROV_CONF_ACKED ; +/* RXed Device Confirmation */ +memcpy (prov->confirm, data,16 ); +print_packet ("ConfirmationDevice" , prov->confirm,16 ); + prov->expected =PROV_RANDOM ; + out =l_malloc (17 ); + out[0 ] =PROV_RANDOM ; +memcpy (out +1 , prov->rand_auth_workspace,16 ); + prov->trans_tx (prov->trans_data, out,17 ); +l_free (out); +break ; + +case PROV_RANDOM :/* Random */ + prov->state =INT_PROV_RAND_ACKED ; + +/* RXed Device Confirmation */ +memcpy (prov->rand_auth_workspace +16 , data,16 ); +print_packet ("RandomDevice" , data,16 ); +calc_local_material (data); + +mesh_crypto_aes_cmac (prov->calc_key, + prov->rand_auth_workspace +16 , +32 , prov->rand_auth_workspace); + +if (memcmp (prov->rand_auth_workspace, prov->confirm,16 )) { +l_error ("Provisioning Failed-Confirm compare)" ); + fail_code[1 ] =PROV_ERR_CONFIRM_FAILED ; + goto failure; + } + +if (prov->state ==INT_PROV_RAND_ACKED ) { + prov->expected =PROV_COMPLETE ; + out =l_malloc (34 ); + out[0 ] =PROV_DATA ; +/* TODO: Fill Prov Data Structure */ +/* Encrypt Prov Data */ +mesh_crypto_aes_ccm_encrypt (prov->s_nonce, prov->s_key, +NULL ,0 , + out +1 , +25 , + out +1 , + &mic,sizeof (mic)); + prov->trans_tx (prov->trans_data, out,34 ); +l_free (out); + } +break ; + +case PROV_COMPLETE :/* Complete */ +l_info ("Provisioning Complete" ); + prov->state =INT_PROV_IDLE ; +//mesh_prov_close(prov, 0); +break ; + +case PROV_FAILED :/* Failed */ +l_error ("Provisioning Failed (reason: %d)" , data[0 ]); +//mesh_prov_close(prov, data[0]); +break ; + +default : +l_error ("Unknown Pkt %2.2x" , type); + fail_code[1 ] =PROV_ERR_UNEXPECTED_PDU ; + goto failure; + } + + prov->previous = type; +return ; + +failure: + fail_code[0 ] =PROV_FAILED ; + prov->trans_tx (prov->trans_data, fail_code,2 ); +/* TODO: Call Complete Callback (Fail)*/ +} + +static void int_prov_ack (void *user_data,uint8_t msg_num) +{ +/* TODO: Handle PB-ADV Ack */ +} + + +bool initiator_start (enum trans_type transport, +uint8_t uuid[16 ], +uint16_t max_ele, +uint16_t server,/* Only valid for PB-Remote */ +uint32_t timeout,/* in seconds from mesh.conf */ +struct mesh_agent *agent, +mesh_prov_initiator_complete_func_t complete_cb, +void *caller_data) +{ +bool result; + +/* Invoked from Add() method in mesh-api.txt, to add a +* remote unprovisioned device network. +*/ + +if (prov) +return false; + + prov = l_new(struct mesh_prov_initiator, 1); + prov->to_secs = timeout; + prov->agent = agent; + prov->cmplt = complete_cb; + prov->caller_data = caller_data; + prov->previous =-1 ; + +/* Always register for PB-ADV */ + result =pb_adv_reg (int_prov_open, int_prov_close, int_prov_rx, + int_prov_ack, uuid, prov); + +if (result) +return true; + +initiator_free (); +return false; +} + +void initiator_cancel (void *user_data) +{ +initiator_free (); +}
Signature · 1 line
2.14.5
PATCH v6 10/26 mesh: Rewrite Controler interface for full init
In reply to Brian GixFunctionaility has been added to allow a BT 4.0 or later controller to be used for Advertising based Mesh usage, regardless of how it was previously initialized.
--- mesh/mesh-io-generic.c | 149 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 138 insertions(+), 11 deletions(-)
mesh/mesh-io-generic.c +138 -11
@@ -30,7 +30,6 @@#include "monitor/bt.h" #include "src/shared/hci.h" -#include "mesh/display.h" #include "mesh/mesh-io.h" #include "mesh/mesh-io-api.h"
@@ -177,6 +176,116 @@ static void event_callback(const void *buf, uint8_t size, void *user_data) } } +static void local_commands_callback (const void *data,uint8_t size, +void *user_data) +{ +const struct bt_hci_rsp_read_local_commands *rsp = data; + +if (rsp->status) +l_error ("Failed to read local commands" ); +} + +static void local_features_callback (const void *data,uint8_t size, +void *user_data) +{ +const struct bt_hci_rsp_read_local_features *rsp = data; + +if (rsp->status) +l_error ("Failed to read local features" ); +} + +static void hci_generic_callback (const void *data,uint8_t size, +void *user_data) +{ +uint8_t status =l_get_u8 (data); + +if (status) +l_error ("Failed to initialize HCI" ); +} + +static void configure_hci (struct mesh_io_private *io) +{ +struct bt_hci_cmd_le_set_scan_parameters cmd; +struct bt_hci_cmd_set_event_mask cmd_sem; +struct bt_hci_cmd_le_set_event_mask cmd_slem; + +/* Set scan parameters */ + cmd.type =0x00 ;/* Passive Scanning. No scanning PDUs shall be sent */ + cmd.interval =0x0030 ;/* Scan Interval = N * 0.625ms */ + cmd.window =0x0030 ;/* Scan Window = N * 0.625ms */ + cmd.own_addr_type =0x00 ;/* Public Device Address */ +/* Accept all advertising packets except directed advertising packets +* not addressed to this device (default). +*/ + cmd.filter_policy =0x00 ; + +/* Set event mask +* +* Mask: 0x2000800002008890 +* Disconnection Complete +* Encryption Change +* Read Remote Version Information Complete +* Hardware Error +* Data Buffer Overflow +* Encryption Key Refresh Complete +* LE Meta +*/ + cmd_sem.mask[0 ] =0x90 ; + cmd_sem.mask[1 ] =0x88 ; + cmd_sem.mask[2 ] =0x00 ; + cmd_sem.mask[3 ] =0x02 ; + cmd_sem.mask[4 ] =0x00 ; + cmd_sem.mask[5 ] =0x80 ; + cmd_sem.mask[6 ] =0x00 ; + cmd_sem.mask[7 ] =0x20 ; + +/* Set LE event mask +* +* Mask: 0x000000000000087f +* LE Connection Complete +* LE Advertising Report +* LE Connection Update Complete +* LE Read Remote Used Features Complete +* LE Long Term Key Request +* LE Remote Connection Parameter Request +* LE Data Length Change +* LE PHY Update Complete +*/ + cmd_slem.mask[0 ] =0x7f ; + cmd_slem.mask[1 ] =0x08 ; + cmd_slem.mask[2 ] =0x00 ; + cmd_slem.mask[3 ] =0x00 ; + cmd_slem.mask[4 ] =0x00 ; + cmd_slem.mask[5 ] =0x00 ; + cmd_slem.mask[6 ] =0x00 ; + cmd_slem.mask[7 ] =0x00 ; + +/* TODO: Move to suitable place. Set suitable masks */ +/* Reset Command */ +bt_hci_send (io->hci,BT_HCI_CMD_RESET ,NULL ,0 , hci_generic_callback, +NULL ,NULL ); + +/* Read local supported commands */ +bt_hci_send (io->hci,BT_HCI_CMD_READ_LOCAL_COMMANDS ,NULL ,0 , + local_commands_callback,NULL ,NULL ); + +/* Read local supported features */ +bt_hci_send (io->hci,BT_HCI_CMD_READ_LOCAL_FEATURES ,NULL ,0 , + local_features_callback,NULL ,NULL ); + +/* Set event mask */ +bt_hci_send (io->hci,BT_HCI_CMD_SET_EVENT_MASK , &cmd_sem, +sizeof (cmd_sem), hci_generic_callback,NULL ,NULL ); + +/* Set LE event mask */ +bt_hci_send (io->hci,BT_HCI_CMD_LE_SET_EVENT_MASK , &cmd_slem, +sizeof (cmd_slem), hci_generic_callback,NULL ,NULL ); + +/* Scan Params */ +bt_hci_send (io->hci,BT_HCI_CMD_LE_SET_SCAN_PARAMETERS , &cmd, +sizeof (cmd), hci_generic_callback,NULL ,NULL ); +} +static bool dev_init (uint16_t index,struct mesh_io *io) {struct mesh_io_private *tmp;
@@ -198,6 +307,8 @@ static bool dev_init(uint16_t index, struct mesh_io *io)if (!tmp->hci) goto fail; +configure_hci (tmp); +bt_hci_register (tmp->hci,BT_HCI_EVT_LE_META_EVENT , event_callback, io,NULL );
@@ -480,7 +591,6 @@ static bool send_tx(struct mesh_io *io, struct mesh_io_send_info *info,if (!info || !data || !len || len >sizeof (tx->pkt))return false; - tx = l_new(struct tx_pkt, 1);if (!tx)return false;
@@ -524,7 +634,7 @@ static bool find_by_pattern(const void *a, const void *b)return (!memcmp (tx->pkt, pattern->data, pattern->len)); } -static bool tx_cancel (struct mesh_io *io,uint8_t *data,uint8_t len) +static bool tx_cancel (struct mesh_io *io,const uint8_t *data,uint8_t len) {struct mesh_io_private *pvt = io->pvt;struct tx_pkt *tx;
@@ -568,13 +678,25 @@ static bool find_by_filter_id(const void *a, const void *b)return rx_reg->filter_id == filter_id; } +static void set_recv_scan_enable (const void *buf,uint8_t size, +void *user_data) +{ +struct mesh_io_private *pvt = user_data; +struct bt_hci_cmd_le_set_scan_enable cmd; + + cmd.enable =0x01 ;/* Enable scanning */ + cmd.filter_dup =0x00 ;/* Report duplicates */ +bt_hci_send (pvt->hci,BT_HCI_CMD_LE_SET_SCAN_ENABLE , + &cmd,sizeof (cmd),NULL ,NULL ,NULL ); +} +static bool recv_register (struct mesh_io *io,uint8_t filter_id,mesh_io_recv_func_t cb,void *user_data) { -struct bt_hci_cmd_le_set_scan_enable cmd; +struct bt_hci_cmd_le_set_scan_parameters cmd;struct mesh_io_private *pvt = io->pvt;struct pvt_rx_reg *rx_reg; -bool scanning; +bool already_scanning;l_info ("%s %d" , __func__, filter_id);if (!cb || !filter_id || filter_id >sizeof (pvt->filters))
@@ -593,15 +715,20 @@ static bool recv_register(struct mesh_io *io, uint8_t filter_id, rx_reg->cb = cb; rx_reg->user_data = user_data; - scanning = !l_queue_isempty (pvt->rx_regs); + already_scanning = !l_queue_isempty (pvt->rx_regs);l_queue_push_head (pvt->rx_regs, rx_reg); -if (!scanning) { - cmd.enable =0x01 ;/* Enable scanning */ - cmd.filter_dup =0x00 ;/* Report duplicates */ -bt_hci_send (pvt->hci,BT_HCI_CMD_LE_SET_SCAN_ENABLE , - &cmd,sizeof (cmd),NULL ,NULL ,NULL ); +if (!already_scanning) { + cmd.type =0x00 ;/* Passive scanning */ + cmd.interval =L_CPU_TO_LE16 (0x0010 );/* 10 ms */ + cmd.window =L_CPU_TO_LE16 (0x0010 );/* 10 ms */ + cmd.own_addr_type =0x01 ;/* ADDR_TYPE_RANDOM */ + cmd.filter_policy =0x00 ;/* Accept all */ + +bt_hci_send (pvt->hci,BT_HCI_CMD_LE_SET_SCAN_PARAMETERS , + &cmd,sizeof (cmd), + set_recv_scan_enable, pvt,NULL ); }return true;
Signature · 1 line
2.14.5
PATCH v6 11/26 mesh: Unchanged variables set to const
In reply to Brian Gix--- mesh/mesh-io-api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
mesh/mesh-io-api.h +1 -1
@@ -31,7 +31,7 @@ typedef bool (*mesh_io_deregister_t)(struct mesh_io *io, uint8_t filter_id);typedef bool (*mesh_io_filter_set_t )(struct mesh_io *io,uint8_t filter_id,const uint8_t *data,uint8_t len,mesh_io_status_func_t callback,void *user_data); -typedef bool (*mesh_io_tx_cancel_t )(struct mesh_io *io,uint8_t *pattern, +typedef bool (*mesh_io_tx_cancel_t )(struct mesh_io *io,const uint8_t *pattern,uint8_t len);struct mesh_io_api {
Signature · 1 line
2.14.5
PATCH v6 12/26 mesh: Hex-String manipulation, and debug logging
In reply to Brian GixFrom: Inga Stotland <[email protected]>
Centralized some frequently used functionaility for logging and save/retrieve of long (128+ bit) hexidecimal data.
--- mesh/util.c | 27 ++++++++++++++++++++++++++- mesh/util.h | 2 +- 2 files changed, 27 insertions(+), 2 deletions(-)
mesh/util.c +26 -1
@@ -15,7 +15,6 @@* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * -* */ #ifdef HAVE_CONFIG_H
@@ -26,10 +25,36 @@#include <stdbool.h> #include <stdint.h> #include <stdio.h> +#include <unistd.h> +#include <termios.h> #include <time.h> +#include <sys/ioctl.h> +#include <sys/time.h> + +#include <ell/ell.h> #include "mesh/util.h" +void print_packet (const char *label,const void *data,uint16_t size) +{ +struct timeval pkt_time; + +gettimeofday (&pkt_time,NULL ); + +if (size >0 ) { +char *str; + + str =l_util_hexstring (data, size); +l_debug ("%05d.%03d %s: %s" , + (uint32_t ) pkt_time.tv_sec %100000 , + (uint32_t ) pkt_time.tv_usec/1000 , label, str); +l_free (str); + }else +l_debug ("%05d.%03d %s: empty" , + (uint32_t ) pkt_time.tv_sec %100000 , + (uint32_t ) pkt_time.tv_usec/1000 , label); +} +uint32_t get_timestamp_secs (void ) {struct timespec ts;
mesh/util.h +1 -1
@@ -15,10 +15,10 @@* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * -* */ uint32_t get_timestamp_secs (void );bool str2hex (const char *str,uint16_t in_len,uint8_t *out,uint16_t out_len);size_t hex2str (uint8_t *in,size_t in_len,char *out,size_t out_len); +void print_packet (const char *label,const void *data,uint16_t size);
Signature · 1 line
2.14.5
PATCH v6 13/26 mesh: re-arrange provisioning for DBus API
In reply to Brian GixProvisioning restructured so that it is a service of a high level (DBus based) API, and may be used on potentially multiple provisioning transports.
--- mesh/prov.h | 14 +++++-- mesh/provision.h | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 112 insertions(+), 14 deletions(-)
mesh/prov.h +10 -4
@@ -47,11 +47,17 @@ enum mesh_prov_mode { };struct mesh_prov ; -typedef void (*mesh_prov_open_func_t )(struct mesh_prov *prov); -typedef void (*mesh_prov_close_func_t )(struct mesh_prov *prov,uint8_t reason); + +typedef void (*prov_trans_tx_t )(void *trans_data,uint8_t *data,uint16_t len); +typedef void (*mesh_prov_open_func_t )(void *user_data,prov_trans_tx_t trans_tx, +void *trans_data,uint8_t trans_type); + +typedef void (*mesh_prov_close_func_t )(void *user_data,uint8_t reason);typedef void (*mesh_prov_send_func_t )(bool success,struct mesh_prov *prov); -typedef void (*mesh_prov_receive_func_t )(const void *data,uint16_t size, -struct mesh_prov *prov); +typedef void (*mesh_prov_ack_func_t )(void *user_data,uint8_t msg_num); +typedef void (*mesh_prov_receive_func_t )(void *user_data,const uint8_t *data, +uint16_t size); +struct prov_invite {uint8_t attention;
mesh/provision.h +102 -10
116 lines not on this page · raw message
Signature · 1 line
2.14.5
PATCH v6 14/26 mesh: Re-architect for DBus API
In reply to Brian GixFrom: Inga Stotland <[email protected]>
The mesh code controls how the main functionalities of the daemon (Provisioning and Mesh Network Messaging) interact with the bluetooth controllers that are available. Restructured so that multiple nodes, on multiple networks, can share the same controllers.
--- mesh/mesh.c | 626 ++++++++++++++++++++++++++++++++++++++++++++++-------------- mesh/mesh.h | 28 ++- 2 files changed, 503 insertions(+), 151 deletions(-)
mesh/mesh.c +485 -141
@@ -15,7 +15,6 @@* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * -* */ #ifdef HAVE_CONFIG_H
@@ -23,22 +22,33 @@#endif #define _GNU_SOURCE -#include <time.h> #include <ell/ell.h> +#include <json-c/json.h> #include "lib/bluetooth.h" #include "lib/mgmt.h" #include "src/shared/mgmt.h" -#include "mesh/mesh-defs.h" #include "mesh/mesh-io.h" #include "mesh/node.h" #include "mesh/net.h" #include "mesh/storage.h" -#include "mesh/cfgmod.h" +#include "mesh/provision.h" #include "mesh/model.h" +#include "mesh/dbus.h" +#include "mesh/error.h" #include "mesh/mesh.h" +#include "mesh/agent.h" + +/* +* The default values for mesh configuration. Can be +* overwritten by values from mesh.conf +*/ +#define DEFAULT_PROV_TIMEOUT 60 +#define DEFAULT_ALGORITHMS 0x0001 + +/* TODO: add more default values */ struct scan_filter {uint8_t id;
@@ -46,42 +56,49 @@ struct scan_filter { };struct bt_mesh { -struct mesh_net *net;struct mesh_io *io;struct l_queue *filters; -int ref_count; -uint16_t index; +prov_rx_cb_t prov_rx; +void *prov_data; +uint32_t prov_timeout; +uint16_t algorithms;uint16_t req_index;uint8_t max_filters; }; +struct join_data { +struct l_dbus_message *msg; +struct mesh_agent *agent; +const char *sender; +const char *app_path; +struct mesh_node *node; +uint32_t disc_watch; +uint8_t uuid[16 ]; +}; + +struct attach_data { +uint64_t token; +struct l_dbus_message *msg; +const char *app; +}; + +static struct bt_mesh mesh;static struct l_queue *controllers; -static struct l_queue *mesh_list;static struct mgmt *mgmt_mesh;static bool initialized; -static struct bt_mesh *current; + +/* We allow only one outstanding Join request */ +static struct join_data *join_pending; + +/* Pending Attach requests */ +static struct l_queue *attach_queue;static bool simple_match (const void *a,const void *b) {return a == b; } -static void save_exit_config (struct bt_mesh *mesh) -{ -const char *cfg_filename; - -if (!mesh_net_cfg_file_get (mesh->net, &cfg_filename) || !cfg_filename) -return ; - -/* Preserve the last sequence number before saving configuration */ -storage_local_write_sequence_number (mesh->net, -mesh_net_get_seq_num (mesh->net)); - -if (storage_save_config (mesh->net, cfg_filename, true,NULL ,NULL )) -l_info ("Saved final configuration to %s" , cfg_filename); -} - -static void start_io (struct bt_mesh *mesh,uint16_t index) +static void start_io (uint16_t index) {struct mesh_io *io;struct mesh_io_caps caps;
@@ -91,21 +108,70 @@ static void start_io(struct bt_mesh *mesh, uint16_t index) io =mesh_io_new (index,MESH_IO_TYPE_GENERIC );if (!io) {l_error ("Failed to start mesh io (hci %u)" , index); - current =NULL ;return ; }mesh_io_get_caps (io, &caps); - mesh->max_filters = caps.max_num_filters; + mesh.max_filters = caps.max_num_filters; + + mesh.io = io; + +l_debug ("Started mesh (io %p) on hci %u" , mesh.io, index); + +node_attach_io (io); +} + +/* Used for any outbound traffic that doesn't have Friendship Constraints */ +/* This includes Beacons, Provisioning and unrestricted Network Traffic */ +bool mesh_send_pkt (uint8_t count,uint16_t interval, +uint8_t *data,uint16_t len) +{ +struct mesh_io_send_info info = { + .type =MESH_IO_TIMING_TYPE_GENERAL , + .u.gen.cnt = count, + .u.gen.interval = interval, + .u.gen.max_delay =0 , + .u.gen.min_delay =0 , + }; + +return mesh_io_send (mesh.io, &info, data, len); +} + +bool mesh_send_cancel (const uint8_t *filter,uint8_t len) +{ +return mesh_io_send_cancel (mesh.io, filter, len); +} -mesh_net_attach (mesh->net, io); -mesh_net_set_window_accuracy (mesh->net, caps.window_accuracy); - mesh->io = io; - mesh->index = index; +static void prov_rx (void *user_data,struct mesh_io_recv_info *info, +const uint8_t *data,uint16_t len) +{ +if (user_data != &mesh) +return ; + +if (mesh.prov_rx) + mesh.prov_rx (mesh.prov_data, data, len); +} + +bool mesh_reg_prov_rx (prov_rx_cb_t cb,void *user_data) +{ +if (mesh.prov_rx && mesh.prov_rx != cb) +return false; - current =NULL ; + mesh.prov_rx = cb; + mesh.prov_data = user_data; -l_debug ("Started mesh (io %p) on hci %u" , mesh->io, index); +return mesh_io_register_recv_cb (mesh.io,MESH_IO_FILTER_PROV , + prov_rx, &mesh); +} + +void mesh_unreg_prov_rx (prov_rx_cb_t cb) +{ +if (mesh.prov_rx != cb) +return ; + + mesh.prov_rx =NULL ; + mesh.prov_data =NULL ; +mesh_io_deregister_recv_cb (mesh.io,MESH_IO_FILTER_PROV ); } static void read_info_cb(uint8_t status, uint16_t length,
@@ -115,7 +181,7 @@ static void read_info_cb(uint8_t status, uint16_t length,const struct mgmt_rp_read_info *rp = param;uint32_t current_settings, supported_settings; -if (!current) +if (mesh.io)/* Already initialized */ return ;
@@ -148,7 +214,7 @@ static void read_info_cb(uint8_t status, uint16_t length,return ; } -start_io (current, index); +start_io (index); } static void index_added(uint16_t index, uint16_t length, const void *param,
@@ -156,11 +222,8 @@ static void index_added(uint16_t index, uint16_t length, const void *param, {l_debug ("hci device %u" , index); -if (!current) -return ; - -if (current->req_index !=MGMT_INDEX_NONE && - index != current->req_index) { +if (mesh.req_index !=MGMT_INDEX_NONE && + index != mesh.req_index) {l_debug ("Ignore index %d" , index);return ; }
@@ -219,145 +282,100 @@ static void read_index_list_cb(uint8_t status, uint16_t length, } } -static bool load_config (struct bt_mesh *mesh,const char *in_config_name) +static bool init_mgmt (void ) { -if (!mesh->net) -return false; - -if (!storage_parse_config (mesh->net, in_config_name)) + mgmt_mesh =mgmt_new_default (); +if (!mgmt_mesh)return false; -/* Register foundational models */ -mesh_config_srv_init (mesh->net,PRIMARY_ELE_IDX ); - -return true; -} - -static bool init_mesh (void ) -{ -if (initialized) -return true; - controllers =l_queue_new ();if (!controllers)return false; - mesh_list =l_queue_new (); -if (!mesh_list) -return false; - - mgmt_mesh =mgmt_new_default (); -if (!mgmt_mesh) - goto fail; -mgmt_register (mgmt_mesh,MGMT_EV_INDEX_ADDED ,MGMT_INDEX_NONE , index_added,NULL ,NULL );mgmt_register (mgmt_mesh,MGMT_EV_INDEX_REMOVED ,MGMT_INDEX_NONE , index_removed,NULL ,NULL ); - - initialized = true;return true; - -fail: -l_error ("Failed to initialize mesh management" ); - -l_queue_destroy (controllers,NULL ); - -return false; } -struct bt_mesh *mesh_new (uint16_t index,const char *config_file) +bool mesh_init (uint16_t index,const char *config_dir) { -struct bt_mesh *mesh; +if (initialized) +return true; + +if (!init_mgmt ()) { +l_error ("Failed to initialize mesh management" ); +return false; + } -if (!init_mesh ()) -return NULL ; + mesh.req_index = index; - mesh = l_new(struct bt_mesh, 1); -if (!mesh) -return NULL ; +mesh_model_init (); +mesh_agent_init (); - mesh->req_index = index; - mesh->index =MGMT_INDEX_NONE ; +/* TODO: read mesh.conf */ + mesh.prov_timeout =DEFAULT_PROV_TIMEOUT ; + mesh.algorithms =DEFAULT_ALGORITHMS ; - mesh->net =mesh_net_new (index); -if (!mesh->net) { -l_free (mesh); -return NULL ; - } +if (!config_dir) + config_dir =MESH_STORAGEDIR ; -if (!load_config (mesh, config_file)) { -l_error ("Failed to load mesh configuration: %s" , config_file); -l_free (mesh); -return NULL ; - } +l_info ("Loading node configuration from %s" , config_dir); + +if (!storage_load_nodes (config_dir)) +return false; -/* -* TODO: Check if another mesh is searching for io. -* If so, add to pending list and return. -*/ l_debug ("send read index_list" );if (mgmt_send (mgmt_mesh,MGMT_OP_READ_INDEX_LIST ,MGMT_INDEX_NONE ,0 ,NULL , - read_index_list_cb, mesh,NULL ) >0 ) { - current = mesh; -l_queue_push_tail (mesh_list, mesh); -return mesh_ref (mesh); - } - -l_free (mesh); + read_index_list_cb,NULL ,NULL ) <=0 ) +return false; -return NULL ; +return true; } -struct bt_mesh *mesh_ref (struct bt_mesh *mesh) +static void attach_exit (void *data) { -if (!mesh) -return NULL ; - -__sync_fetch_and_add (&mesh->ref_count,1 ); +struct l_dbus_message *reply; +struct attach_data *pending = data; -return mesh; + reply =dbus_error (pending->msg,MESH_ERROR_FAILED ,"Failed. Exiting" ); +l_dbus_send (dbus_get_bus (), reply); +l_free (pending); } -void mesh_unref (struct bt_mesh *mesh) +void mesh_cleanup (void ) { -struct mesh_io *io; +struct l_dbus_message *reply; -if (!mesh) -return ; +mesh_io_destroy (mesh.io); +mgmt_unref (mgmt_mesh); -if (__sync_sub_and_fetch (&mesh->ref_count,1 )) -return ; +if (join_pending) { + reply =dbus_error (join_pending->msg,MESH_ERROR_FAILED , +"Failed. Exiting" ); +l_dbus_send (dbus_get_bus (), reply); -if (mesh_net_provisioned_get (mesh->net)) -save_exit_config (mesh); +if (join_pending->disc_watch) +l_dbus_remove_watch (dbus_get_bus (), + join_pending->disc_watch); -node_cleanup (mesh->net); +if (join_pending->node) +node_free (join_pending->node); -storage_release (mesh->net); - io =mesh_net_detach (mesh->net); -if (io) -mesh_io_destroy (io); +l_free (join_pending); + join_pending =NULL ; + } -mesh_net_unref (mesh->net); -l_queue_remove (mesh_list, mesh); -l_free (mesh); -} +l_queue_destroy (attach_queue, attach_exit); +node_cleanup_all (); +mesh_model_cleanup (); -void mesh_cleanup (void ) -{l_queue_destroy (controllers,NULL ); -l_queue_destroy (mesh_list,NULL ); -mgmt_unref (mgmt_mesh); -} - -bool mesh_set_output (struct bt_mesh *mesh,const char *config_name) -{ -if (!config_name) -return false; - -return mesh_net_cfg_file_set (mesh->net, config_name); +l_dbus_object_remove_interface (dbus_get_bus (),BLUEZ_MESH_PATH , +MESH_NETWORK_INTERFACE ); +l_dbus_unregister_interface (dbus_get_bus (),MESH_NETWORK_INTERFACE ); }const char *mesh_status_str (uint8_t err)
@@ -386,7 +404,333 @@ const char *mesh_status_str(uint8_t err) } } -struct mesh_net *mesh_get_net (struct bt_mesh *mesh) +static void free_pending_join_call (bool failed) +{ +if (!join_pending) +return ; + +if (join_pending->disc_watch) +l_dbus_remove_watch (dbus_get_bus (), + join_pending->disc_watch); + +mesh_agent_remove (join_pending->agent); + +if (failed) { +storage_remove_node_config (join_pending->node); +mesh_agent_remove (join_pending->agent); + } + +l_free (join_pending); + join_pending =NULL ; +} + +/* This is being called if the app exits unexpectedly */ +static void prov_disc_cb (struct l_dbus *bus,void *user_data) +{ +if (!join_pending) +return ; + +if (join_pending->msg) +l_dbus_message_unref (join_pending->msg); + +acceptor_cancel (&mesh); + + join_pending->disc_watch =0 ; + +free_pending_join_call (true); +} + +static const char *prov_status_str (uint8_t status) +{ +switch (status) { +case PROV_ERR_SUCCESS : +return "success" ; +case PROV_ERR_INVALID_PDU : +case PROV_ERR_INVALID_FORMAT : +case PROV_ERR_UNEXPECTED_PDU : +return "bad-pdu" ; +case PROV_ERR_CONFIRM_FAILED : +return "confirmation-failed" ; +case PROV_ERR_INSUF_RESOURCE : +return "out-of-resources" ; +case PROV_ERR_DECRYPT_FAILED : +return "decryption-error" ; +case PROV_ERR_CANT_ASSIGN_ADDR : +return "cannot-assign-addresses" ; +case PROV_ERR_TIMEOUT : +return "timeout" ; +case PROV_ERR_UNEXPECTED_ERR : +default : +return "unexpected-error" ; + } +} + +static void send_join_failed (const char *owner,const char *path, +uint8_t status) +{ +struct l_dbus_message *msg; +struct l_dbus *dbus =dbus_get_bus (); + + msg =l_dbus_message_new_method_call (dbus, owner, path, +MESH_APPLICATION_INTERFACE , +"JoinFailed" ); + +l_dbus_message_set_arguments (msg,"s" ,prov_status_str (status)); +l_dbus_send (dbus_get_bus (), msg); + +free_pending_join_call (true); +} + +static bool prov_complete_cb (void *user_data,uint8_t status, +struct mesh_prov_node_info *info) +{ +struct l_dbus *dbus =dbus_get_bus (); +struct l_dbus_message *msg; +const char *owner; +const char *path; +const uint8_t *dev_key; + +l_debug ("Provisioning complete %s" ,prov_status_str (status)); + +if (!join_pending) +return false; + + owner = join_pending->sender; + path = join_pending->app_path; + +if (status ==PROV_ERR_SUCCESS && + !node_add_pending_local (join_pending->node, info, mesh.io)) + status =PROV_ERR_UNEXPECTED_ERR ; + +if (status !=PROV_ERR_SUCCESS ) { +send_join_failed (owner, path, status); +return false; + } + + dev_key =node_get_device_key (join_pending->node); + + msg =l_dbus_message_new_method_call (dbus, owner, path, +MESH_APPLICATION_INTERFACE , +"JoinComplete" ); + +l_dbus_message_set_arguments (msg,"t" ,l_get_u64 (dev_key)); + +l_dbus_send (dbus_get_bus (), msg); + +free_pending_join_call (false); + +return true; +} + +static void node_init_cb (struct mesh_node *node,struct mesh_agent *agent) +{ +struct l_dbus_message *reply; +uint8_t num_ele; + +if (!node) { + reply =dbus_error (join_pending->msg,MESH_ERROR_FAILED , +"Failed to create node from application" ); + goto fail; + } + + join_pending->node = node; + num_ele =node_get_num_elements (node); + +if (!acceptor_start (num_ele, join_pending->uuid, mesh.algorithms, + mesh.prov_timeout, agent, prov_complete_cb, + &mesh)) + { + reply =dbus_error (join_pending->msg,MESH_ERROR_FAILED , +"Failed to start provisioning acceptor" ); + goto fail; + } + + reply =l_dbus_message_new_method_return (join_pending->msg); +l_dbus_send (dbus_get_bus (), reply); + join_pending->msg =NULL ; + +return ; + +fail: +l_dbus_send (dbus_get_bus (), reply); +mesh_agent_remove (join_pending->agent); +l_free (join_pending); + join_pending =NULL ; +} + +static struct l_dbus_message *join_network_call (struct l_dbus *dbus, +struct l_dbus_message *msg, +void *user_data) { -return mesh->net; +const char *app_path, *sender; +struct l_dbus_message_iter iter_uuid; +uint32_t n; + +l_debug ("Join network request" ); + +if (join_pending) +return dbus_error (msg,MESH_ERROR_BUSY , +"Provisioning in progress" ); + +if (!l_dbus_message_get_arguments (msg,"oay" , &app_path, + &iter_uuid)) +return dbus_error (msg,MESH_ERROR_INVALID_ARGS ,NULL ); + + join_pending = l_new(struct join_data, 1); + +l_dbus_message_iter_get_fixed_array (&iter_uuid, join_pending->uuid, &n); + +if (n !=16 ) { +l_free (join_pending); + join_pending =NULL ; +return dbus_error (msg,MESH_ERROR_INVALID_ARGS , +"Bad device UUID" ); + } + + sender =l_dbus_message_get_sender (msg); + + join_pending->sender =l_strdup (sender); + join_pending->disc_watch =l_dbus_add_disconnect_watch (dbus, sender, + prov_disc_cb,NULL ,NULL ); + join_pending->msg =l_dbus_message_ref (msg); + join_pending->app_path = app_path; + +/* Try to create a temporary node */ +node_join (app_path, sender, join_pending->uuid, node_init_cb); + +return NULL ; +} + +static struct l_dbus_message *cancel_join_call (struct l_dbus *dbus, +struct l_dbus_message *msg, +void *user_data) +{ +struct l_dbus_message *reply; + +l_debug ("Cancel Join" ); + +if (!join_pending) { + reply =dbus_error (msg,MESH_ERROR_DOES_NOT_EXIST , +"No join in progress" ); + goto done; + } + +acceptor_cancel (&mesh); + +/* Return error to the original Join call */ +if (join_pending->msg) { + reply =dbus_error (join_pending->msg,MESH_ERROR_FAILED ,NULL ); +l_dbus_send (dbus_get_bus (), reply); + } + + reply =l_dbus_message_new_method_return (msg); +l_dbus_message_set_arguments (reply,"" ); + +free_pending_join_call (true); +done: +return reply; +} + +static bool match_attach_request (const void *a,const void *b) +{ +const struct attach_data *pending = a; +const uint64_t *token = b; + +return *token == pending->token; +} + +static void attach_ready_cb (int status,char *node_path,uint64_t token) +{ +struct l_dbus_message *reply; +struct attach_data *pending; + + pending =l_queue_find (attach_queue, match_attach_request, &token); +if (!pending) +return ; + +if (status !=MESH_ERROR_NONE ) { +const char *desc = (status ==MESH_ERROR_NOT_FOUND ) ? +"Node match not found" :"Attach failed" ; + reply =dbus_error (pending->msg, status, desc); + goto done; + } + + reply =l_dbus_message_new_method_return (pending->msg); + +node_build_attach_reply (reply, token); + +done: +l_dbus_send (dbus_get_bus (), reply); +l_queue_remove (attach_queue, pending); +l_free (pending); +} + +static struct l_dbus_message *attach_call (struct l_dbus *dbus, +struct l_dbus_message *msg, +void *user_data) +{ +uint64_t token =1 ; +const char *app_path, *sender; +struct attach_data *pending; + +l_debug ("Attach" ); + +if (!l_dbus_message_get_arguments (msg,"ot" , &app_path, &token)) +return dbus_error (msg,MESH_ERROR_INVALID_ARGS ,NULL ); + + sender =l_dbus_message_get_sender (msg); + +if (node_attach (app_path, sender, token, attach_ready_cb) != +MESH_ERROR_NONE ) +return dbus_error (msg,MESH_ERROR_NOT_FOUND , +"Matching node not found" ); + + pending = l_new(struct attach_data, 1); + + pending->token = token; + pending->msg =l_dbus_message_ref (msg); + +if (!attach_queue) + attach_queue =l_queue_new (); + +l_queue_push_tail (attach_queue, pending); + +return NULL ; +} + +static void setup_network_interface (struct l_dbus_interface *iface) +{ +l_dbus_interface_method (iface,"Join" ,0 , join_network_call,"" , +"oay" ,"app" ,"uuid" ); + +l_dbus_interface_method (iface,"Cancel" ,0 , cancel_join_call,"" ,"" ); + +l_dbus_interface_method (iface,"Attach" ,0 , attach_call, +"oa(ya(qa{sv}))" ,"ot" ,"node" ,"configuration" , +"app" ,"token" ); + +/* TODO: Implement Leave method */ +} + +bool mesh_dbus_init (struct l_dbus *dbus) +{ +if (!l_dbus_register_interface (dbus,MESH_NETWORK_INTERFACE , + setup_network_interface, +NULL , false)) { +l_info ("Unable to register %s interface" , +MESH_NETWORK_INTERFACE ); +return false; + } + +if (!l_dbus_object_add_interface (dbus,BLUEZ_MESH_PATH , +MESH_NETWORK_INTERFACE ,NULL )) { +l_info ("Unable to register the mesh object on '%s'" , +MESH_NETWORK_INTERFACE ); +l_dbus_unregister_interface (dbus,MESH_NETWORK_INTERFACE ); +return false; + } + +l_info ("Added Network Interface on %s" ,BLUEZ_MESH_PATH ); + +return true; }
mesh/mesh.h +18 -10
@@ -15,18 +15,26 @@* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * -* */ -struct bt_mesh ; -struct mesh_net ; +#define BLUEZ_MESH_NAME "org.bluez.mesh" + +#define MESH_NETWORK_INTERFACE "org.bluez.mesh.Network1" +#define MESH_NODE_INTERFACE "org.bluez.mesh.Node1" +#define MESH_ELEMENT_INTERFACE "org.bluez.mesh.Element1" +#define MESH_APPLICATION_INTERFACE "org.bluez.mesh.Application1" +#define MESH_PROVISION_AGENT_INTERFACE "org.bluez.mesh.ProvisionAgent1" +#define ERROR_INTERFACE "org.bluez.mesh.Error" -struct bt_mesh *mesh_new (uint16_t index,const char *in_config_name); -struct bt_mesh *mesh_ref (struct bt_mesh *mesh); -void mesh_unref (struct bt_mesh *mesh); -bool mesh_set_output (struct bt_mesh *mesh,const char *out_config_name); +typedef void (*prov_rx_cb_t )(void *user_data,const uint8_t *data, +uint16_t len); +bool mesh_init (uint16_t index,const char *in_config_name);void mesh_cleanup (void ); -const char *mesh_status_str (uint8_t err); +bool mesh_dbus_init (struct l_dbus *dbus); -/* Command line testing */ -struct mesh_net *mesh_get_net (struct bt_mesh *mesh); +const char *mesh_status_str (uint8_t err); +bool mesh_send_pkt (uint8_t count,uint16_t interval,uint8_t *data, +uint16_t len); +bool mesh_send_cancel (const uint8_t *filter,uint8_t len); +bool mesh_reg_prov_rx (prov_rx_cb_t cb,void *user_data); +void mesh_unreg_prov_rx (prov_rx_cb_t cb);
Signature · 1 line
2.14.5
PATCH v6 15/26 mesh: Multi node Config Server model
In reply to Brian GixFrom: Inga Stotland <[email protected]>
The Config Server model is an internal service that allows priviledged remote Config Client nodes to manipulate and configure local keys, subscription lists, and publications of models on specific local nodes. It has been rewritten to allow control of multiple nodes on the local device.
--- mesh/cfgmod-server.c | 179 ++++++++++++++++++++++++++------------------------- mesh/cfgmod.h | 3 +- 2 files changed, 93 insertions(+), 89 deletions(-)
mesh/cfgmod-server.c +92 -87
@@ -15,7 +15,6 @@* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * -* */ #ifdef HAVE_CONFIG_H
@@ -24,11 +23,14 @@#include <unistd.h> #include <stdio.h> +#include <stdint.h> #include <sys/time.h> #include <ell/ell.h> +#include <ell/ell.h> -#include "mesh/mesh-defs.h" +#include "json-c/json.h" +#include "mesh/mesh-defs.h" #include "mesh/mesh.h" #include "mesh/node.h" #include "mesh/net.h"
@@ -40,7 +42,7 @@#define CFG_MAX_MSG_LEN 380 -static void send_pub_status (struct mesh_net *net,uint16_t src,uint16_t dst, +static void send_pub_status (struct mesh_node *node,uint16_t src,uint16_t dst,uint8_t status,uint16_t ele_addr,uint16_t pub_addr,uint32_t mod_id,uint16_t idx,bool cred_flag,uint8_t ttl,uint8_t period,uint8_t retransmit)
@@ -60,7 +62,7 @@ static void send_pub_status(struct mesh_net *net, uint16_t src, uint16_t dst, msg[n++] = ttl; msg[n++] = period; msg[n++] = retransmit; -if (mod_id <0x10000 ) { +if (mod_id <0x10000 || mod_id >VENDOR_ID_MASK ) {l_put_le16 (mod_id, msg + n); n +=2 ; }else {
@@ -70,12 +72,11 @@ static void send_pub_status(struct mesh_net *net, uint16_t src, uint16_t dst, n +=2 ; } -mesh_model_send (net,CONFIG_SRV_MODEL , - dst, src, +mesh_model_send (node, dst, src,APP_IDX_DEV ,DEFAULT_TTL , msg, n); } -static bool config_pub_get (struct mesh_net *net,uint16_t src,uint16_t dst, +static bool config_pub_get (struct mesh_node *node,uint16_t src,uint16_t dst,const uint8_t *pkt,uint16_t size) {uint32_t mod_id;
@@ -84,33 +85,34 @@ static bool config_pub_get(struct mesh_net *net, uint16_t src, uint16_t dst,struct mesh_model_pub *pub =NULL ;int status; -if (size ==4 ) +if (size ==4 ) { mod_id =l_get_le16 (pkt +2 ); -else if (size ==6 ) { + mod_id |=VENDOR_ID_MASK ; + }else if (size ==6 ) { mod_id =l_get_le16 (pkt +2 ) <<16 ; mod_id |=l_get_le16 (pkt +4 ); }else return false; ele_addr =l_get_le16 (pkt); - ele_idx =node_get_element_idx (mesh_net_local_node_get (net), ele_addr); + ele_idx =node_get_element_idx (node, ele_addr);if (ele_idx >=0 ) - pub =mesh_model_pub_get (net, ele_idx, mod_id, &status); + pub =mesh_model_pub_get (node, ele_idx, mod_id, &status);else status =MESH_STATUS_INVALID_ADDRESS ;if (pub && status ==MESH_STATUS_SUCCESS ) -send_pub_status (net, src, dst, status, ele_addr, pub->addr, +send_pub_status (node, src, dst, status, ele_addr, pub->addr, mod_id, pub->idx, pub->credential, pub->ttl, pub->period, pub->retransmit);else -send_pub_status (net, src, dst, status, ele_addr,0 , mod_id, +send_pub_status (node, src, dst, status, ele_addr,0 , mod_id,0 ,0 ,0 ,0 ,0 );return true; } -static bool config_pub_set (struct mesh_net *net,uint16_t src,uint16_t dst, +static bool config_pub_set (struct mesh_node *node,uint16_t src,uint16_t dst,const uint8_t *pkt,uint16_t size,bool unreliable) {
@@ -133,6 +135,7 @@ static bool config_pub_set(struct mesh_net *net, uint16_t src, uint16_t dst, period = pkt[7 ]; retransmit = pkt[8 ]; mod_id =l_get_le16 (pkt +9 ); + mod_id |=VENDOR_ID_MASK ;break ;case 13 :
@@ -151,6 +154,7 @@ static bool config_pub_set(struct mesh_net *net, uint16_t src, uint16_t dst, period = pkt[21 ]; retransmit = pkt[22 ]; mod_id =l_get_le16 (pkt +23 ); + mod_id |=VENDOR_ID_MASK ;break ;case 27 :
@@ -181,24 +185,24 @@ static bool config_pub_set(struct mesh_net *net, uint16_t src, uint16_t dst,if (!b_virt && test_addr >0x7fff && test_addr <0xc000 )return false; - status =mesh_model_pub_set (net, ele_addr, mod_id, pub_addr, idx, + status =mesh_model_pub_set (node, ele_addr, mod_id, pub_addr, idx, cred_flag, ttl, period, retransmit, b_virt, &ota); -l_info ("pub_set: status %d, ea %4.4x, ota: %4.4x, mod: %x, idx: %3.3x" , +l_debug ("pub_set: status %d, ea %4.4x, ota: %4.4x, mod: %x, idx: %3.3x" , status, ele_addr, ota, mod_id, idx);if (IS_UNASSIGNED (ota) && !b_virt) ttl = period = idx =0 ;if (status >=0 && !unreliable) -send_pub_status (net, src, dst, status, ele_addr, ota, +send_pub_status (node, src, dst, status, ele_addr, ota, mod_id, idx, cred_flag, ttl, period, retransmit);return true; } -static void send_sub_status (struct mesh_net *net,uint16_t src,uint16_t dst, +static void send_sub_status (struct mesh_node *node,uint16_t src,uint16_t dst,uint8_t status,uint16_t ele_addr,uint16_t addr,uint32_t mod) {
@@ -210,7 +214,7 @@ static void send_sub_status(struct mesh_net *net, uint16_t src, uint16_t dst, n +=2 ;l_put_le16 (addr, msg + n); n +=2 ; -if (mod >=0x10000 ) { +if (mod >=0x10000 && mod <VENDOR_ID_MASK ) {l_put_le16 (mod >>16 , msg + n);l_put_le16 (mod, msg + n +2 ); n +=4 ;
@@ -219,11 +223,10 @@ static void send_sub_status(struct mesh_net *net, uint16_t src, uint16_t dst, n +=2 ; } -mesh_model_send (net,CONFIG_SRV_MODEL , dst, src,APP_IDX_DEV , -DEFAULT_TTL , msg, n); +mesh_model_send (node, dst, src,APP_IDX_DEV ,DEFAULT_TTL , msg, n); } -static bool config_sub_get (struct mesh_net *net,uint16_t src,uint16_t dst, +static bool config_sub_get (struct mesh_node *node,uint16_t src,uint16_t dst,const uint8_t *pkt,uint16_t size) {uint16_t ele_addr;
@@ -251,6 +254,7 @@ static bool config_sub_get(struct mesh_net *net, uint16_t src, uint16_t dst, n +=2 ;l_put_le16 (mod_id, msg + n); n +=2 ; + mod_id |=VENDOR_ID_MASK ;break ;case 6 :
@@ -269,7 +273,7 @@ static bool config_sub_get(struct mesh_net *net, uint16_t src, uint16_t dst, } buf_size =sizeof (uint16_t ) *MAX_GRP_PER_MOD ; - ret =mesh_model_sub_get (net, ele_addr, mod_id, msg + n, buf_size, + ret =mesh_model_sub_get (node, ele_addr, mod_id, msg + n, buf_size, &size);if (!ret)
@@ -277,13 +281,11 @@ static bool config_sub_get(struct mesh_net *net, uint16_t src, uint16_t dst,else if (ret >0 ) *status = ret; -mesh_model_send (net,CONFIG_SRV_MODEL , - dst, src,APP_IDX_DEV , -DEFAULT_TTL , msg, n); +mesh_model_send (node, dst, src,APP_IDX_DEV ,DEFAULT_TTL , msg, n);return true; } -static void config_sub_set (struct mesh_net *net,uint16_t src,uint16_t dst, +static void config_sub_set (struct mesh_node *node,uint16_t src,uint16_t dst,const uint8_t *pkt,uint16_t size,bool virt,uint32_t opcode) {
@@ -301,13 +303,15 @@ static void config_sub_set(struct mesh_net *net, uint16_t src, uint16_t dst,if (opcode !=OP_CONFIG_MODEL_SUB_DELETE_ALL )return ; mod_id =l_get_le16 (pkt +2 ); + mod_id |=VENDOR_ID_MASK ;break ;case 6 :if (virt)return ; -if (opcode !=OP_CONFIG_MODEL_SUB_DELETE_ALL ) +if (opcode !=OP_CONFIG_MODEL_SUB_DELETE_ALL ) { mod_id =l_get_le16 (pkt +4 ); -else { + mod_id |=VENDOR_ID_MASK ; + }else { mod_id =l_get_le16 (pkt +2 ) <<16 ; mod_id |=l_get_le16 (pkt +4 ); }
@@ -322,6 +326,7 @@ static void config_sub_set(struct mesh_net *net, uint16_t src, uint16_t dst,if (!virt)return ; mod_id =l_get_le16 (pkt +18 ); + mod_id |=VENDOR_ID_MASK ;break ;case 22 :if (!virt)
@@ -341,42 +346,42 @@ static void config_sub_set(struct mesh_net *net, uint16_t src, uint16_t dst, func = opcode & ~OP_UNRELIABLE ;switch (func) {default : -l_info ("Bad opcode: %x" , func); +l_debug ("Bad opcode: %x" , func);return ;case OP_CONFIG_MODEL_SUB_DELETE_ALL : - status =mesh_model_sub_del_all (net, ele_addr, mod_id); + status =mesh_model_sub_del_all (node, ele_addr, mod_id);break ;case OP_CONFIG_MODEL_SUB_VIRT_OVERWRITE : grp =UNASSIGNED_ADDRESS ;/* Fall Through */ case OP_CONFIG_MODEL_SUB_OVERWRITE : - status =mesh_model_sub_ovr (net, ele_addr, mod_id, + status =mesh_model_sub_ovr (node, ele_addr, mod_id, addr, virt, &grp);break ;case OP_CONFIG_MODEL_SUB_VIRT_ADD : grp =UNASSIGNED_ADDRESS ;/* Fall Through */ case OP_CONFIG_MODEL_SUB_ADD : - status =mesh_model_sub_add (net, ele_addr, mod_id, + status =mesh_model_sub_add (node, ele_addr, mod_id, addr, virt, &grp);break ;case OP_CONFIG_MODEL_SUB_VIRT_DELETE : grp =UNASSIGNED_ADDRESS ;/* Fall Through */ case OP_CONFIG_MODEL_SUB_DELETE : - status =mesh_model_sub_del (net, ele_addr, mod_id, + status =mesh_model_sub_del (node, ele_addr, mod_id, addr, virt, &grp);break ; }if (!unreliable && status >=0 ) -send_sub_status (net, src, dst, status, ele_addr, grp, mod_id); +send_sub_status (node, src, dst, status, ele_addr, grp, mod_id); } -static void send_model_app_status (struct mesh_net *net,uint16_t src, +static void send_model_app_status (struct mesh_node *node,uint16_t src,uint16_t dst,uint8_t status,uint16_t addr,uint32_t id,uint16_t idx)
@@ -389,18 +394,17 @@ static void send_model_app_status(struct mesh_net *net, uint16_t src, n +=2 ;l_put_le16 (idx, msg + n); n +=2 ; -if (id >0xffff ) { +if (id >=0x10000 && id <VENDOR_ID_MASK ) {l_put_le16 (id >>16 , msg + n); n +=2 ; }l_put_le16 (id, msg + n); n +=2 ; -mesh_model_send (net,CONFIG_SRV_MODEL , dst, src,APP_IDX_DEV , -DEFAULT_TTL , msg, n); +mesh_model_send (node, dst, src,APP_IDX_DEV ,DEFAULT_TTL , msg, n); } -static void model_app_list (struct mesh_net *net,uint16_t src,uint16_t dst, +static void model_app_list (struct mesh_node *node,uint16_t src,uint16_t dst,const uint8_t *pkt,uint16_t size) {uint16_t ele_addr;
@@ -427,6 +431,7 @@ static void model_app_list(struct mesh_net *net, uint16_t src, uint16_t dst, mod_id =l_get_le16 (pkt +2 );l_put_le16 (ele_addr, msg +1 + n);l_put_le16 (mod_id, msg +3 + n); + mod_id |=VENDOR_ID_MASK ; n +=5 ;break ;case 6 :
@@ -443,20 +448,20 @@ static void model_app_list(struct mesh_net *net, uint16_t src, uint16_t dst, } - result =mesh_model_get_bindings (net, ele_addr, mod_id, msg + n, + result =mesh_model_get_bindings (node, ele_addr, mod_id, msg + n, buf_size, &size); n += size;if (result >=0 ) { *status = result; -mesh_model_send (net,CONFIG_SRV_MODEL , dst, src,APP_IDX_DEV , -DEFAULT_TTL , msg, n); +mesh_model_send (node, dst, src,APP_IDX_DEV ,DEFAULT_TTL , + msg, n); }l_free (msg); } -static bool model_app_bind (struct mesh_net *net,uint16_t src,uint16_t dst, +static bool model_app_bind (struct mesh_node *node,uint16_t src,uint16_t dst,const uint8_t *pkt,uint16_t size,bool unbind) {
@@ -471,6 +476,7 @@ static bool model_app_bind(struct mesh_net *net, uint16_t src, uint16_t dst,case 6 : mod_id =l_get_le16 (pkt +4 ); + mod_id |=VENDOR_ID_MASK ;break ;case 8 : mod_id =l_get_le16 (pkt +4 ) <<16 ;
@@ -485,11 +491,11 @@ static bool model_app_bind(struct mesh_net *net, uint16_t src, uint16_t dst,return false;if (unbind) - result =mesh_model_binding_del (net, ele_addr, mod_id, idx); + result =mesh_model_binding_del (node, ele_addr, mod_id, idx);else - result =mesh_model_binding_add (net, ele_addr, mod_id, idx); + result =mesh_model_binding_add (node, ele_addr, mod_id, idx); -send_model_app_status (net, src, dst, result, ele_addr, mod_id, idx); +send_model_app_status (node, src, dst, result, ele_addr, mod_id, idx);return true; }
@@ -533,7 +539,7 @@ static void hb_sub_timeout_func(struct l_timeout *timeout, void *user_data)struct mesh_net *net = user_data;struct mesh_net_heartbeat *hb =mesh_net_heartbeat_get (net); -l_info ("HB Subscription Ended" ); +l_debug ("HB Subscription Ended" );l_timeout_remove (hb->sub_timer); hb->sub_timer =NULL ; hb->sub_enabled = false;
@@ -639,7 +645,7 @@ static int hb_subscription_set(struct mesh_net *net, uint16_t src,static void node_reset (struct l_timeout *timeout,void *user_data) { -l_info ("Node Reset" ); +l_debug ("Node Reset" );l_timeout_remove (timeout);l_main_quit (); }
@@ -649,7 +655,8 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst, const uint8_t *data, uint16_t size, uint8_t ttl, const void *user_data) { - struct mesh_net *net = (struct mesh_net *) user_data; + struct mesh_node *node = (struct mesh_node *) user_data; +struct mesh_net *net =node_get_net (node);const uint8_t *pkt = data;struct timeval time_now;uint32_t opcode, tmp32;
@@ -663,7 +670,6 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,bool virt = false;uint8_t count;uint16_t interval; -struct mesh_node *node;uint16_t n;if (idx !=APP_IDX_DEV )
@@ -675,10 +681,10 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst, }else return false; + net =node_get_net (node); hb =mesh_net_heartbeat_get (net);l_debug ("CONFIG-SRV-opcode 0x%x size %u idx %3.3x" , opcode, size, idx); - node =mesh_net_local_node_get (net); n =0 ;switch (opcode) {
@@ -691,8 +697,8 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,/* Only page 0 is currently supported */ if (pkt[0 ] !=0 ) { -l_info ("Unsupported page number %d" , pkt[0 ]); -l_info ("Returning page number 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);
@@ -711,7 +717,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,/* Fall Through */ case OP_CONFIG_DEFAULT_TTL_GET : -l_info ("Get/Set Default TTL" ); +l_debug ("Get/Set Default TTL" ); n =mesh_model_opcode_set (OP_CONFIG_DEFAULT_TTL_STATUS , msg); msg[n++] =node_default_ttl_get (node);
@@ -721,7 +727,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,if (size !=25 && size !=27 )return true; -config_pub_set (net, src, unicast, pkt, size, +config_pub_set (node, src, unicast, pkt, size, !!(opcode &OP_UNRELIABLE ));break ;
@@ -729,24 +735,24 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,if (size !=11 && size !=13 )return true; -config_pub_set (net, src, unicast, pkt, size, +config_pub_set (node, src, unicast, pkt, size, !!(opcode &OP_UNRELIABLE ));break ;case OP_CONFIG_MODEL_PUB_GET : -config_pub_get (net, src, unicast, pkt, size); +config_pub_get (node, src, unicast, pkt, size);break ;case OP_CONFIG_VEND_MODEL_SUB_GET :if (size !=6 )return true; -config_sub_get (net, src, unicast, pkt, size); +config_sub_get (node, src, unicast, pkt, size);break ;case OP_CONFIG_MODEL_SUB_GET :if (size !=4 )return true; -config_sub_get (net, src, unicast, pkt, size); +config_sub_get (node, src, unicast, pkt, size);break ;case OP_CONFIG_MODEL_SUB_VIRT_OVERWRITE :
@@ -758,7 +764,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,case OP_CONFIG_MODEL_SUB_DELETE :case OP_CONFIG_MODEL_SUB_ADD :case OP_CONFIG_MODEL_SUB_DELETE_ALL : -config_sub_set (net, src, unicast, pkt, size, virt, opcode); +config_sub_set (node, src, unicast, pkt, size, virt, opcode);break ;case OP_CONFIG_RELAY_SET :
@@ -777,7 +783,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst, msg[n++] =node_relay_mode_get (node, &count, &interval); msg[n++] = ((count -1 ) <<5 ) + ((interval/10 -1 ) &0x1f ); -l_info ("Get/Set Relay Config (%d)" , msg[n-1 ]); +l_debug ("Get/Set Relay Config (%d)" , msg[n-1 ]);break ;case OP_CONFIG_NETWORK_TRANSMIT_SET :
@@ -786,7 +792,8 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst, count = (pkt[0 ] >>5 ) +1 ; interval = ((pkt[0 ] &0x1f ) +1 ) *10 ; -if (storage_local_set_transmit_params (net, count, interval)) +if (storage_set_transmit_params (node_jconfig_get (node), count, + interval))mesh_net_transmit_params_set (net, count, interval);/* Fall Through */
@@ -796,7 +803,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,mesh_net_transmit_params_get (net, &count, &interval); msg[n++] = ((count -1 ) <<5 ) + ((interval/10 -1 ) &0x1f ); -l_info ("Get/Set Network Transmit Config" ); +l_debug ("Get/Set Network Transmit Config" );break ;case OP_CONFIG_PROXY_SET :
@@ -810,7 +817,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst, n =mesh_model_opcode_set (OP_CONFIG_PROXY_STATUS , msg); msg[n++] =node_proxy_mode_get (node); -l_info ("Get/Set Config Proxy (%d)" , msg[n-1 ]); +l_debug ("Get/Set Config Proxy (%d)" , msg[n-1 ]);break ;case OP_NODE_IDENTITY_SET :
@@ -845,7 +852,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst, n +=2 ; msg[n++] = state; -l_info ("Get/Set Config Identity (%d)" , state); +l_debug ("Get/Set Config Identity (%d)" , state);break ;case OP_CONFIG_BEACON_SET :
@@ -859,7 +866,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst, n =mesh_model_opcode_set (OP_CONFIG_BEACON_STATUS , msg); msg[n++] =node_beacon_mode_get (node); -l_info ("Get/Set Config Beacon (%d)" , msg[n-1 ]); +l_debug ("Get/Set Config Beacon (%d)" , msg[n-1 ]);break ;case OP_CONFIG_FRIEND_SET :
@@ -874,7 +881,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst, n =mesh_model_opcode_set (OP_CONFIG_FRIEND_STATUS , msg); msg[n++] =node_friend_mode_get (node); -l_info ("Get/Set Friend (%d)" , msg[n-1 ]); +l_debug ("Get/Set Friend (%d)" , msg[n-1 ]);break ;case OP_CONFIG_KEY_REFRESH_PHASE_SET :
@@ -908,7 +915,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst, n +=2 ; msg[n++] = phase; -l_info ("Get/Set Key Refresh State (%d)" , msg[n-1 ]); +l_debug ("Get/Set Key Refresh State (%d)" , msg[n-1 ]);break ;case OP_APPKEY_ADD :
@@ -921,7 +928,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst, b_res =appkey_key_add (net, net_idx, app_idx, pkt +3 , opcode ==OP_APPKEY_UPDATE ); -l_info ("Add/Update AppKey %s: Net_Idx %3.3x, App_Idx %3.3x" , +l_debug ("Add/Update AppKey %s: Net_Idx %3.3x, App_Idx %3.3x" , (b_res ==MESH_STATUS_SUCCESS ) ?"success" :"fail" , net_idx, app_idx);
@@ -942,9 +949,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst, net_idx =l_get_le16 (pkt) &0xfff ; app_idx =l_get_le16 (pkt +1 ) >>4 ; b_res =appkey_key_delete (net, net_idx, app_idx); -if (b_res ==MESH_STATUS_SUCCESS ) -node_app_key_delete (net, dst, net_idx, app_idx); -l_info ("Delete AppKey %s Net_Idx %3.3x to App_Idx %3.3x" , +l_debug ("Delete AppKey %s Net_Idx %3.3x to App_Idx %3.3x" , (b_res ==MESH_STATUS_SUCCESS ) ?"success" :"fail" , net_idx, app_idx);
@@ -979,7 +984,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst, b_res =mesh_net_add_key (net, opcode ==OP_NETKEY_UPDATE ,l_get_le16 (pkt), pkt +2 ); -l_info ("NetKey Add/Update %s" , +l_debug ("NetKey Add/Update %s" , (b_res ==MESH_STATUS_SUCCESS ) ?"success" :"fail" ); n =mesh_model_opcode_set (OP_NETKEY_STATUS , msg);
@@ -994,7 +999,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst, b_res =mesh_net_del_key (net,l_get_le16 (pkt)); -l_info ("NetKey delete %s" , +l_debug ("NetKey delete %s" , (b_res ==MESH_STATUS_SUCCESS ) ?"success" :"fail" ); n =mesh_model_opcode_set (OP_NETKEY_STATUS , msg);
@@ -1016,26 +1021,26 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,case OP_MODEL_APP_BIND :case OP_MODEL_APP_UNBIND : -model_app_bind (net, src, unicast, pkt, size, +model_app_bind (node, src, unicast, pkt, size, opcode !=OP_MODEL_APP_BIND );break ;case OP_VEND_MODEL_APP_GET :if (size !=6 )return true; -model_app_list (net, src, unicast, pkt, size); +model_app_list (node, src, unicast, pkt, size);break ;case OP_MODEL_APP_GET :if (size !=4 )return true; -model_app_list (net, src, unicast, pkt, size); +model_app_list (node, src, unicast, pkt, size);break ;case OP_CONFIG_HEARTBEAT_PUB_SET : -l_info ("OP_CONFIG_HEARTBEAT_PUB_SET" ); +l_debug ("OP_CONFIG_HEARTBEAT_PUB_SET" );if (size !=9 ) { -l_info ("bad size %d" , size); +l_debug ("bad size %d" , size);return true; }if (pkt[2 ] >0x11 || pkt[3 ] >0x10 || pkt[4 ] >0x7f )
@@ -1101,7 +1106,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,if (size !=5 )return true; -l_info ("Set Sub Period (Log %2.2x) %d sec" , +l_debug ("Set Sub Period (Log %2.2x) %d sec" , pkt[4 ],log_to_uint32 (pkt[4 ],1 )); b_res = hb_subscription_set(net, l_get_le16(pkt),
@@ -1121,7 +1126,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,else time_now.tv_sec = hb->sub_period - time_now.tv_sec; -l_info ("Sub Period (Log %2.2x) %d sec" , +l_debug ("Sub Period (Log %2.2x) %d sec" ,uint32_to_log (time_now.tv_sec), (int ) time_now.tv_sec);
@@ -1159,8 +1164,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,if (n) {/* print_packet("App Tx", long_msg ? long_msg : msg, n); */ -mesh_model_send (net,CONFIG_SRV_MODEL , - unicast, src, +mesh_model_send (node, unicast, src,APP_IDX_DEV ,DEFAULT_TTL , long_msg ? long_msg : msg, n); }
@@ -1171,7 +1175,8 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,static void cfgmod_srv_unregister (void *user_data) { -struct mesh_net *net = user_data; +struct mesh_node *node = user_data; +struct mesh_net *net =node_get_net (node);struct mesh_net_heartbeat *hb =mesh_net_heartbeat_get (net);l_timeout_remove (hb->pub_timer);
@@ -1187,8 +1192,8 @@ static const struct mesh_model_ops ops = { .pub = NULL }; -void mesh_config_srv_init (struct mesh_net *net,uint8_t ele_idx) +void mesh_config_srv_init (struct mesh_node *node,uint8_t ele_idx) {l_debug ("%2.2x" , ele_idx); -mesh_model_register (net, ele_idx,CONFIG_SRV_MODEL , &ops, net); +mesh_model_register (node, ele_idx,CONFIG_SRV_MODEL , &ops, node); }
mesh/cfgmod.h +1 -2
@@ -15,7 +15,6 @@* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * -* */ #define CONFIG_SRV_MODEL (VENDOR_ID_MASK | 0x0000)
@@ -95,4 +94,4 @@#define OP_VEND_MODEL_APP_GET 0x804C#define OP_VEND_MODEL_APP_LIST 0x804E -void mesh_config_srv_init (struct mesh_net *net,uint8_t ele_idx); +void mesh_config_srv_init (struct mesh_node *node,uint8_t ele_idx);
Signature · 1 line
2.14.5
PATCH v6 16/26 mesh: restructure I/O for multiple nodes
In reply to Brian GixRestructured access to Bluetooth Controllers to allow the usage of Multiple controllers, and potentially functionality tailored to Mesh specific features.
--- mesh/mesh-io.c | 3 ++- mesh/mesh-io.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-)
mesh/mesh-io.c +2 -1
@@ -177,7 +177,8 @@ bool mesh_io_send(struct mesh_io *io, struct mesh_io_send_info *info,return false; } -bool mesh_io_send_cancel (struct mesh_io *io,uint8_t *pattern,uint8_t len) +bool mesh_io_send_cancel (struct mesh_io *io,const uint8_t *pattern, +uint8_t len) { io =l_queue_find (io_list, match_by_io, io);
mesh/mesh-io.h +2 -1
@@ -96,4 +96,5 @@ bool mesh_set_filter(struct mesh_io *io, uint8_t filter_id,bool mesh_io_send (struct mesh_io *io,struct mesh_io_send_info *info,const uint8_t *data,uint16_t len); -bool mesh_io_send_cancel (struct mesh_io *io,uint8_t *pattern,uint8_t len); +bool mesh_io_send_cancel (struct mesh_io *io,const uint8_t *pattern, +uint8_t len);
Signature · 1 line
2.14.5
PATCH v6 17/26 mesh: Restructure DB to support multiple nodes
In reply to Brian GixFrom: Inga Stotland <[email protected]>
Added needed functionality to support the storage of multiple subnets, subscription lists, and publications per node.
--- mesh/mesh-db.c | 456 +++++++++++++++++++++++++++++++++++++-------------------- mesh/mesh-db.h | 9 +- 2 files changed, 297 insertions(+), 168 deletions(-)
mesh/mesh-db.c +294 -162
@@ -15,7 +15,6 @@* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * -* */ #ifdef HAVE_CONFIG_H
@@ -29,6 +28,7 @@#include <string.h> #include <ell/ell.h> +#include <json-c/json.h> #include "mesh/mesh-defs.h" #include "mesh/util.h"
@@ -162,6 +162,7 @@ static json_object *jarray_string_del(json_object *jarray, char *str,if (str_entry && !strncmp (str, str_entry, len))continue ; +json_object_get (jentry);json_object_array_add (jarray_new, jentry); }
@@ -193,9 +194,6 @@ static json_object *jarray_key_del(json_object *jarray, int16_t idx) {json_object *jarray_new;int i, sz =json_object_array_length (jarray); -char idx_str[5 ]; - -snprintf (idx_str,5 ,"%4.4x" , idx); jarray_new =json_object_new_array ();if (!jarray_new)
@@ -203,16 +201,17 @@ static json_object *jarray_key_del(json_object *jarray, int16_t idx)for (i =0 ; i < sz; ++i) {json_object *jentry, *jvalue; -char *str; jentry =json_object_array_get_idx (jarray, i);if (json_object_object_get_ex (jentry,"index" , &jvalue)) { - str = (char *)json_object_get_string (jvalue); -if (str && !strncmp (str, idx_str,4 )) +int tmp =json_object_get_int (jvalue); + +if (tmp == idx)continue ; } +json_object_get (jentry);json_object_array_add (jarray_new, jentry); }
@@ -389,19 +388,10 @@ bool mesh_db_net_key_add(json_object *jobj, uint16_t idx,char buf[5 ];json_object_object_get_ex (jobj,"netKeys" , &jarray); -if (!jarray && (phase !=KEY_REFRESH_PHASE_NONE )) -return false;if (jarray) jentry =get_key_object (jarray, idx); -/* -* The key entry should exist if the key is updated -* (i.e., Key Refresh is underway) -*/ -if (!jentry && (phase !=KEY_REFRESH_PHASE_NONE )) -return false; -if (jentry) {uint8_t buf[16 ];json_object *jvalue;
@@ -422,7 +412,7 @@ bool mesh_db_net_key_add(json_object *jobj, uint16_t idx,return false; } -if (phase ==KEY_REFRESH_PHASE_NONE ) { +if (!jentry) { jentry =json_object_new_object ();if (!jentry) goto fail;
@@ -442,6 +432,19 @@ bool mesh_db_net_key_add(json_object *jobj, uint16_t idx,if (!add_key (jentry,"key" , key)) goto fail; +/* If Key Refresh underway, add placeholder for "Old Key" */ +if (phase !=KEY_REFRESH_PHASE_NONE ) { +uint8_t buf[16 ]; +uint8_t i; + +/* Flip Bits to differentiate */ +for (i =0 ; i <sizeof (buf); i++) + buf[i] = key[i] ^0xff ; + +if (!add_key (jentry,"oldKey" , buf)) + goto fail; + } +if (!jarray) { jarray =json_object_new_array ();if (!jarray)
@@ -733,7 +736,7 @@ static bool parse_bindings(json_object *jbindings, struct mesh_db_model *mod)if (cnt >0xffff )return false; - mod->num_subs = cnt; + mod->num_bindings = cnt;/* Allow empty bindings list */ if (!cnt)
@@ -761,6 +764,130 @@ static bool parse_bindings(json_object *jbindings, struct mesh_db_model *mod)return true; } +static bool get_key_index (json_object *jobj,const char *keyword, +uint16_t *index) +{ +int idx; + +if (!get_int (jobj, keyword, &idx)) +return false; + +if (!CHECK_KEY_IDX_RANGE (idx)) +return false; + + *index = (uint16_t ) idx; +return true; +} + +static struct mesh_db_pub *parse_model_publication (json_object *jpub) +{ +json_object *jvalue; +struct mesh_db_pub *pub; +int len, value; +char *str; + + pub = l_new(struct mesh_db_pub, 1); +if (!pub) +return NULL ; + +json_object_object_get_ex (jpub,"address" , &jvalue); + str = (char *)json_object_get_string (jvalue); + len =strlen (str); + +switch (len) { +case 4 : +if (sscanf (str,"%04hx" , &pub->addr) !=1 ) + goto fail; +break ; +case 32 : +if (!str2hex (str, len, pub->virt_addr,16 )) + goto fail; + pub->virt = true; +break ; +default : + goto fail; + } + +if (!get_key_index (jpub,"index" , &pub->idx)) + goto fail; + +if (!get_int (jpub,"ttl" , &value)) + goto fail; + pub->ttl = (uint8_t ) value; + +if (!get_int (jpub,"period" , &value)) + goto fail; + pub->period = (uint8_t ) value; + +if (!get_int (jpub,"credentials" , &value)) + goto fail; + pub->credential = (uint8_t ) value; + +if (!get_int (jpub,"retransmit" , &value)) + goto fail; + + pub->retransmit = (uint8_t ) value; +return pub; + +fail: +l_free (pub); +return NULL ; +} + +static bool parse_model_subscriptions (json_object *jsubs, +struct mesh_db_model *mod) +{ +struct mesh_db_sub *subs; +int i, cnt; + +if (json_object_get_type (jsubs) != json_type_array) +return NULL ; + + cnt =json_object_array_length (jsubs); +/* Allow empty array */ +if (!cnt) +return true; + + subs = l_new(struct mesh_db_sub, cnt); +if (!subs) +return false; + +for (i =0 ; i < cnt; ++i) { +char *str; +int len; +json_object *jvalue; + + jvalue =json_object_array_get_idx (jsubs, i); +if (!jvalue) +return false; + + str = (char *)json_object_get_string (jvalue); + len =strlen (str); + +switch (len) { +case 4 : +if (sscanf (str,"%04hx" , &subs[i].src.addr) !=1 ) + goto fail; +break ; +case 32 : +if (!str2hex (str, len, subs[i].src.virt_addr,16 )) + goto fail; + subs[i].virt = true; +break ; +default : + goto fail; + } + } + + mod->num_subs = cnt; + mod->subs = subs; + +return true; +fail: +l_free (subs); +return false; +} +static bool parse_models (json_object *jmodels,struct mesh_db_element *ele) {int i, num_models;
@@ -810,11 +937,22 @@ static bool parse_models(json_object *jmodels, struct mesh_db_element *ele)json_object_object_get_ex (jmodel,"bind" , &jarray); -if (jarray && (json_object_get_type (jmodels) != json_type_array +if (jarray && (json_object_get_type (jarray) != json_type_array || !parse_bindings (jarray, mod))) goto fail; -/* TODO add pub/sub */ +json_object_object_get_ex (jmodel,"publish" , &jvalue); +if (jvalue) { + mod->pub =parse_model_publication (jvalue); +if (!mod->pub) + goto fail; + } + +json_object_object_get_ex (jmodel,"subscribe" , &jarray); + +if (jarray && !parse_model_subscriptions (jarray, mod)) + goto fail; +l_queue_push_tail (ele->models, mod); }
@@ -1012,33 +1150,6 @@ static bool parse_composition(json_object *jcomp, struct mesh_db_node *node)return true; } -static uint16_t get_prov_flags (json_object *jarray,uint16_t max_value) -{ -int i, cnt; -uint16_t result =0 ; - - cnt =json_object_array_length (jarray); -if (!cnt) -return 0 ; - -for (i =0 ; i < cnt; ++i) { -json_object *jvalue; -int value; - - jvalue =json_object_array_get_idx (jarray, i); - value =json_object_get_int (jvalue); -if (value >16 ) -continue ; - -if ((1 << value) > max_value) -continue ; - - result |= (1 << value); - } - -return result; -} -bool mesh_db_read_node (json_object *jnode,mesh_db_node_cb cb,void *user_data) {struct mesh_db_node node;
@@ -1091,117 +1202,28 @@ bool mesh_db_read_node(json_object *jnode, mesh_db_node_cb cb, void *user_data)return cb (&node, user_data); } -bool mesh_db_read_unprovisioned_device (json_object *jnode,mesh_db_node_cb cb, -void *user_data) -{ -struct mesh_db_node node; -json_object *jvalue; -char *str; - -if (!cb) { -l_info ("Device read callback is required" ); -return false; - } - -memset (&node,0 ,sizeof (node)); - -if (!parse_composition (jnode, &node)) { -l_info ("Failed to parse local device composition" ); -return false; - } - -parse_features (jnode, &node); - -json_object_object_get_ex (jnode,"elements" , &jvalue); -if (jvalue &&json_object_get_type (jvalue) == json_type_array) { -if (!parse_elements (jvalue, &node)) -return false; - } - -json_object_object_get_ex (jnode,"UUID" , &jvalue); -if (!jvalue) -return false; - - str = (char *)json_object_get_string (jvalue); -if (!str2hex (str,strlen (str), node.uuid,16 )) -return false; - -return cb (&node, user_data); -} - -bool mesh_db_read_prov_info (json_object *jnode,struct mesh_db_prov *prov) +bool mesh_db_write_uint16_hex (json_object *jobj,const char *desc, +uint16_t value) { -json_object *jprov, *jarray, *jvalue, *jobj; -int value; -char *str; - -if (!prov) -return false; - -json_object_object_get_ex (jnode,"provision" , &jprov); -if (!jprov) -return false; - -json_object_object_get_ex (jprov,"algorithms" , &jarray); -if (!jarray ||json_object_get_type (jarray) != json_type_array) -return false; - - prov->algorithm =get_prov_flags (jarray,ALG_FIPS_256_ECC ); -if (!prov->algorithm) { -l_info ("At least one algorithm must be indicated" ); -return false; - } - -json_object_object_get_ex (jprov,"outputOOB" , &jobj); -json_object_object_get_ex (jobj,"size" , &jvalue); - value =json_object_get_int (jvalue); -if (value >8 ) -return false; - - prov->output_oob.size = (uint8_t ) value; -json_object_object_get_ex (jobj,"actions" , &jarray); -if (!jarray ||json_object_get_type (jarray) != json_type_array) -return false; - - prov->output_oob.actions =get_prov_flags (jarray,OOB_OUT_ALPHA ); - -json_object_object_get_ex (jprov,"inputOOB" , &jobj); -json_object_object_get_ex (jobj,"size" , &jvalue); - value =json_object_get_int (jvalue); -if (value >8 ) -return false; - - prov->input_oob.size = (uint8_t ) value; -json_object_object_get_ex (jobj,"actions" , &jarray); -if (!jarray ||json_object_get_type (jarray) != json_type_array) -return false; - - prov->input_oob.actions =get_prov_flags (jarray,OOB_IN_ALPHA ); - -json_object_object_get_ex (jprov,"publicType" , &jvalue); - prov->pub_type = (json_object_get_boolean (jvalue)) ?1 :0 ; - -json_object_object_get_ex (jprov,"staticType" , &jvalue); - prov->static_type = (json_object_get_boolean (jvalue)) ?1 :0 ; - -json_object_object_get_ex (jprov,"privateKey" , &jvalue); -if (!jvalue) -return false; +json_object *jstring; +char buf[5 ]; - str = (char *)json_object_get_string (jvalue); -if (!str2hex (str,strlen (str), prov->priv_key,32 )) +snprintf (buf,5 ,"%4.4x" , value); + jstring =json_object_new_string (buf); +if (!jstring)return false; +json_object_object_add (jobj, desc, jstring);return true; } -bool mesh_db_write_uint16_hex (json_object *jobj,const char *desc, -uint16_t value) +bool mesh_db_write_uint32_hex (json_object *jobj,const char *desc, +uint32_t value) {json_object *jstring; -char buf[5 ]; +char buf[9 ]; -snprintf (buf,5 ,"%4.4x" , value); +snprintf (buf,9 ,"%8.8x" , value); jstring =json_object_new_string (buf);if (!jstring)return false;
@@ -1238,23 +1260,23 @@ bool mesh_db_write_bool(json_object *jobj, const char *keyword, bool value)return true; } -bool mesh_db_write_mode (json_object *jobj,const char *keyword,int value) +static const char *mode_to_string (int mode) { -json_object *jstring; - -switch (value) { +switch (mode) {case MESH_MODE_DISABLED : - jstring =json_object_new_string ("disabled" ); -break ; +return "disabled" ;case MESH_MODE_ENABLED : - jstring =json_object_new_string ("enabled" ); -break ; -case MESH_MODE_UNSUPPORTED : - jstring =json_object_new_string ("unsupported" ); -break ; +return "enabled" ;default : -return false; - }; +return "unsupported" ; + } +} + +bool mesh_db_write_mode (json_object *jobj,const char *keyword,int value) +{ +json_object *jstring; + + jstring =json_object_new_string (mode_to_string (value));if (!jstring)return false;
@@ -1272,7 +1294,7 @@ bool mesh_db_write_relay_mode(json_object *jnode, uint8_t mode, uint8_t count,json_object_object_del (jnode,"relay" ); jrelay =json_object_new_object (); -if (jrelay) +if (!jrelay)return false;if (!mesh_db_write_mode (jrelay,"mode" , mode))
@@ -1359,3 +1381,113 @@ void mesh_db_remove_property(json_object *jobj, const char *desc) {json_object_object_del (jobj, desc); } + +static void add_model (void *a,void *b) +{ +struct mesh_db_model *mod = a; +json_object *jmodels = b, *jmodel; + + jmodel =json_object_new_object (); +if (!jmodel) +return ; + +if (!mod->vendor) +mesh_db_write_uint16_hex (jmodel,"modelId" , + (uint16_t ) mod->id); +else +mesh_db_write_uint32_hex (jmodel,"modelId" , mod->id); + +json_object_array_add (jmodels, jmodel); +} + +/* Add unprovisioned node (local) */ +bool mesh_db_add_node (json_object *jnode,struct mesh_db_node *node) { + +struct mesh_db_modes *modes = &node->modes; +const struct l_queue_entry *entry; +json_object *jelements; + +/* CID, PID, VID, crpl */ +if (!mesh_db_write_uint16_hex (jnode,"cid" , node->cid)) +return false; + +if (!mesh_db_write_uint16_hex (jnode,"pid" , node->pid)) +return false; + +if (!mesh_db_write_uint16_hex (jnode,"vid" , node->vid)) +return false; + +if (!mesh_db_write_uint16_hex (jnode,"crpl" , node->crpl)) +return false; + +/* Device UUID */ +if (!add_key (jnode,"UUID" , node->uuid)) +return false; + +/* Features: relay, LPN, friend, proxy*/ +if (!mesh_db_write_relay_mode (jnode, modes->relay.state, + modes->relay.cnt, + modes->relay.interval)) +return false; + +if (!mesh_db_write_mode (jnode,"lowPower" , modes->lpn)) +return false; + +if (!mesh_db_write_mode (jnode,"friend" , modes->friend)) +return false; + +if (!mesh_db_write_mode (jnode,"proxy" , modes->proxy)) +return false; + +/* Beaconing state */ +if (!mesh_db_write_mode (jnode,"beacon" , modes->beacon)) +return false; + +/* Sequence number */ +json_object_object_add (jnode,"sequenceNumber" , +json_object_new_int (node->seq_number)); + +/* Default TTL */ +json_object_object_add (jnode,"defaultTTL" , +json_object_new_int (node->ttl)); + +/* Elements */ + jelements =json_object_new_array (); +if (!jelements) +return false; + + entry =l_queue_get_entries (node->elements); + +for (; entry; entry = entry->next) { +struct mesh_db_element *ele = entry->data; +json_object *jelement, *jmodels; + + jelement =json_object_new_object (); + +if (!jelement) { +json_object_put (jelements); +return false; + } + +mesh_db_write_int (jelement,"elementIndex" , ele->index); +mesh_db_write_uint16_hex (jelement,"location" , ele->location); +json_object_array_add (jelements, jelement); + +/* Models */ +if (l_queue_isempty (ele->models)) +continue ; + + jmodels =json_object_new_array (); +if (!jmodels) { +json_object_put (jelements); +return false; + } + +json_object_object_add (jelement,"models" , jmodels); +l_queue_foreach (ele->models, add_model, jmodels); + } + +json_object_object_add (jnode,"elements" , jelements); + +return true; +}
mesh/mesh-db.h +3 -6
@@ -15,11 +15,8 @@* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * -* */ -#include <json-c/json.h> -struct mesh_db_sub {bool virt;union {
@@ -103,9 +100,7 @@ typedef bool (*mesh_db_app_key_cb)(uint16_t idx, uint16_t net_idx,typedef bool (*mesh_db_node_cb )(struct mesh_db_node *node,void *user_data);bool mesh_db_read_node (json_object *jobj,mesh_db_node_cb cb,void *user_data); -bool mesh_db_read_unprovisioned_device (json_object *jnode,mesh_db_node_cb cb, -void *user_data); -bool mesh_db_read_prov_info (json_object *jnode,struct mesh_db_prov *prov); +bool mesh_db_add_node (json_object *jnode,struct mesh_db_node *node);bool mesh_db_read_iv_index (json_object *jobj,uint32_t *idx,bool *update);bool mesh_db_read_device_key (json_object *jobj,uint8_t key_buf[16 ]); bool mesh_db_read_net_transmit(json_object *jobj, uint8_t *cnt,
@@ -124,6 +119,8 @@ bool mesh_db_write_app_key(json_object *jobj, uint16_t net_idx,bool mesh_db_write_int (json_object *jobj,const char *keyword,int value);bool mesh_db_write_uint16_hex (json_object *jobj,const char *desc,uint16_t value); +bool mesh_db_write_uint32_hex (json_object *jobj,const char *desc, +uint32_t value);bool mesh_db_write_bool (json_object *jobj,const char *keyword,bool value);bool mesh_db_write_relay_mode (json_object *jnode,uint8_t mode,uint8_t count,uint16_t interval);
Signature · 1 line
2.14.5
PATCH v6 18/26 mesh: Restructure model services for multiple nodes
In reply to Brian GixFrom: Inga Stotland <[email protected]>
Handles checking that incoming Mesh messages obey all authentication rules regarding subscriptions and encryption key bindings on a per node basis, before forwarding via D-Bus to external applications that are authorized to handle them.
--- mesh/model.c | 813 ++++++++++++++++++++++++++++++++++++++++++----------------- mesh/model.h | 69 +++-- 2 files changed, 613 insertions(+), 269 deletions(-)
mesh/model.c +579 -234
@@ -15,7 +15,6 @@* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * -* */ #ifdef HAVE_CONFIG_H
@@ -24,18 +23,22 @@#include <sys/time.h> #include <ell/ell.h> +#include <json-c/json.h> #include "mesh/mesh-defs.h" #include "mesh/mesh.h" #include "mesh/crypto.h" #include "mesh/node.h" +#include "mesh/mesh-db.h" #include "mesh/net.h" #include "mesh/appkey.h" -#include "mesh/model.h" -#include "mesh/display.h" #include "mesh/cfgmod.h" #include "mesh/storage.h" +#include "mesh/error.h" +#include "mesh/dbus.h" +#include "mesh/util.h" +#include "mesh/model.h" struct mesh_model {const struct mesh_model_ops *cbs;
@@ -67,6 +70,7 @@ struct mod_forward {uint8_t ttl;int8_t rssi;bool szmict; +bool has_dst;bool done; };
@@ -75,6 +79,14 @@ static struct l_queue *mesh_virtuals;static uint32_t virt_id_next =VIRTUAL_BASE ;static struct timeval tx_start; +static bool is_internal (uint32_t id) +{ +if (id ==CONFIG_SRV_MODEL || id ==CONFIG_CLI_MODEL ) +return true; + +return false; +} +static void unref_virt (void *data) {struct mesh_virtual *virt = data;
@@ -94,6 +106,17 @@ static bool simple_match(const void *a, const void *b)return a == b; } +static bool has_binding (struct l_queue *bindings,uint16_t idx) +{ +const struct l_queue_entry *l; + +for (l =l_queue_get_entries (bindings); l; l = l->next) { +if (L_PTR_TO_UINT (l->data) == idx) +return true; + } +return false; +} +static bool find_virt_by_id (const void *a,const void *b) {const struct mesh_virtual *virt = a;
@@ -110,13 +133,39 @@ static bool find_virt_by_addr(const void *a, const void *b)return memcmp (virt->addr, addr,16 ) ==0 ; } -static struct mesh_model *find_model (struct mesh_net *net,uint16_t addr, +static bool match_model_id (const void *a,const void *b) +{ +const struct mesh_model *model = a; +uint32_t id =L_PTR_TO_UINT (b); + +return (mesh_model_get_model_id (model) == id); +} + +static struct mesh_model *get_model (struct mesh_node *node,uint8_t ele_idx, +uint32_t id,int *status) +{ +struct l_queue *models; +struct mesh_model *model; + + models =node_get_element_models (node, ele_idx, status); +if (!models) { + *status =MESH_STATUS_INVALID_ADDRESS ; +return NULL ; + } + + model =l_queue_find (models, match_model_id,L_UINT_TO_PTR (id)); + +if (status) + *status = (model) ?MESH_STATUS_SUCCESS : +MESH_STATUS_INVALID_MODEL ; + +return model; +} + +static struct mesh_model *find_model (struct mesh_node *node,uint16_t addr,uint32_t mod_id,int *fail) {int ele_idx; -struct mesh_node *node; - - node =mesh_net_local_node_get (net); ele_idx =node_get_element_idx (node, addr);
@@ -126,7 +175,126 @@ static struct mesh_model *find_model(struct mesh_net *net, uint16_t addr,return NULL ; } -return node_get_model (node, (uint8_t ) ele_idx, mod_id, fail); +return get_model (node, (uint8_t ) ele_idx, mod_id, fail); +} + +static uint32_t convert_pub_period_to_ms (uint8_t pub_period) +{ +int n; + + n = (pub_period &0x3f ); + +switch (pub_period >>6 ) { +default : +return n *100 ; +case 2 : + n *=10 ; +/* Fall Through */ +case 1 : +return n *1000 ; +case 3 : +return n *10 *60 *1000 ; + } +} + +static struct l_dbus_message *create_config_update_msg (struct mesh_node *node, +uint8_t ele_idx,uint32_t id, +struct l_dbus_message_builder **builder) +{ +struct l_dbus *dbus =dbus_get_bus (); +struct l_dbus_message *msg; +const char *owner; +const char *path; +uint16_t model_id; + + owner =node_get_owner (node); + path =node_get_element_path (node, ele_idx); +if (!path || !owner) +return NULL ; + +l_debug ("Send \"UpdateModelConfiguration\"" ); + msg =l_dbus_message_new_method_call (dbus, owner, path, +MESH_ELEMENT_INTERFACE , +"UpdateModelConfiguration" ); + + *builder =l_dbus_message_builder_new (msg); + + model_id = (uint16_t ) id; + +l_dbus_message_builder_append_basic (*builder,'q' , &model_id); + +l_dbus_message_builder_enter_array (*builder,"{sv}" ); + +if ((id &VENDOR_ID_MASK ) !=VENDOR_ID_MASK ) { +uint16_t vendor = id >>16 ; +dbus_append_dict_entry_basic (*builder,"Vendor" ,"q" , &vendor); + } + +return msg; +} + +static void config_update_model_pub_period (struct mesh_node *node, +uint8_t ele_idx,uint32_t model_id, +uint32_t period) +{ +struct l_dbus *dbus =dbus_get_bus (); +struct l_dbus_message *msg; +struct l_dbus_message_builder *builder; + + msg =create_config_update_msg (node, ele_idx, model_id, &builder); +if (!msg) +return ; + +dbus_append_dict_entry_basic (builder,"PublicationPeriod" ,"u" , + &period); + +l_dbus_message_builder_leave_array (builder); +if (l_dbus_message_builder_finalize (builder)) +l_dbus_send (dbus, msg); + +l_dbus_message_builder_destroy (builder); +} + +static void append_dict_uint16_array (struct l_dbus_message_builder *builder, +struct l_queue *q,const char *key) +{ +const struct l_queue_entry *entry; + +l_dbus_message_builder_enter_dict (builder,"sv" ); +l_dbus_message_builder_append_basic (builder,'s' , key); +l_dbus_message_builder_enter_variant (builder,"aq" ); +l_dbus_message_builder_enter_array (builder,"q" ); + +for (entry =l_queue_get_entries (q); entry; entry = entry->next) { +uint16_t value = (uint16_t )L_PTR_TO_UINT (entry->data); + +l_dbus_message_builder_append_basic (builder,'q' , &value); + } + +l_dbus_message_builder_leave_array (builder); +l_dbus_message_builder_leave_variant (builder); +l_dbus_message_builder_leave_dict (builder); +} + +static void config_update_model_bindings (struct mesh_node *node, +struct mesh_model *mod) +{ +struct l_dbus *dbus =dbus_get_bus (); +struct l_dbus_message *msg; +struct l_dbus_message_builder *builder; + + msg =create_config_update_msg (node, mod->ele_idx, mod->id, + &builder); +if (!msg) +return ; + +append_dict_uint16_array (builder, mod->bindings,"Bindings" ); + +l_dbus_message_builder_leave_array (builder); +if (l_dbus_message_builder_finalize (builder)) +l_dbus_send (dbus, msg); + +l_dbus_message_builder_destroy (builder); }static void forward_model (void *a,void *b)
@@ -135,22 +303,22 @@ static void forward_model(void *a, void *b)struct mod_forward *fwd = b;struct mesh_virtual *virt;uint32_t dst; -bool has_dst = false; - -if (!mod->cbs || !mod->cbs->recv) -return ; +bool result;l_debug ("model %8.8x with idx %3.3x" , mod->id, fwd->idx); -if (fwd->idx !=APP_IDX_DEV && - !l_queue_find (mod->bindings, simple_match, -L_UINT_TO_PTR (fwd->idx))) +if (fwd->idx !=APP_IDX_DEV && !has_binding (mod->bindings, fwd->idx))return ; dst = fwd->dst;if (dst == fwd->unicast ||IS_ALL_NODES (dst)) - has_dst = true; + fwd->has_dst = true;else if (fwd->virt) { virt =l_queue_find (mod->virtuals, simple_match, fwd->virt); + +/* Check that this is not own publication */ +if (mod->pub && (virt && virt->id == mod->pub->addr)) +return ; +if (virt) {/* * Map Virtual addresses to a usable namespace that
@@ -158,42 +326,38 @@ static void forward_model(void *a, void *b)* (multiple Virtual Addresses that map to the same * u16 OTA addr) */ - has_dst = true; + fwd->has_dst = true; dst = virt->id; } }else {if (l_queue_find (mod->subs, simple_match,L_UINT_TO_PTR (dst))) - has_dst = true; + fwd->has_dst = true; } +if (!fwd->has_dst) +return ; -if (!has_dst) +/* Return, if this is not a internal model */ +if (!mod->cbs)return ; -/* -* TODO: models shall be registered with a list of supported opcodes and -* element address. Iterate through the list of opcodes to see if the -* model is an addressee. -* If this is an internal registered model, check for a "bind" callback. -* For an external ("user") model, send D-Bus method (signal?) (TBD) -*/ + result = false; +if (mod->cbs->recv) - mod->cbs->recv (fwd->src, dst, fwd->unicast, fwd->idx, + result = mod->cbs->recv (fwd->src, dst, fwd->unicast, fwd->idx, fwd->data, fwd->size, fwd->ttl, mod->user_data); -if (dst == fwd->unicast) +if (dst == fwd->unicast && result) fwd->done = true; } -static int dev_packet_decrypt (struct mesh_net *net,const uint8_t *data, +static int dev_packet_decrypt (struct mesh_node *node,const uint8_t *data,uint16_t size,bool szmict,uint16_t src,uint16_t dst,uint8_t key_id,uint32_t seq,uint32_t iv_idx,uint8_t *out) { -struct mesh_node *node;const uint8_t *dev_key; - node =mesh_net_local_node_get (net); dev_key =node_get_device_key (node);if (!dev_key)return false;
@@ -241,32 +405,32 @@ static void cmplt(uint16_t remote, uint8_t status,struct timeval tx_end;if (status) -l_info ("Tx-->%4.4x (%d octets) Failed (%d)" , +l_debug ("Tx-->%4.4x (%d octets) Failed (%d)" , remote, size, status);else -l_info ("Tx-->%4.4x (%d octets) Succeeded" , remote, size); +l_debug ("Tx-->%4.4x (%d octets) Succeeded" , remote, size);/* print_packet("Sent Data", data, size); */ gettimeofday (&tx_end,NULL );if (tx_end.tv_sec == tx_start.tv_sec) { -l_info ("Duration 0.%zu seconds" , +l_debug ("Duration 0.%zu seconds" , tx_end.tv_usec - tx_start.tv_usec); }else {if (tx_start.tv_usec > tx_end.tv_usec) -l_info ("Duration %zu.%zu seconds" , +l_debug ("Duration %zu.%zu seconds" , tx_end.tv_sec - tx_start.tv_sec -1 , tx_end.tv_usec +1000000 - tx_start.tv_usec);else -l_info ("Duration %zu.%zu seconds" , +l_debug ("Duration %zu.%zu seconds" , tx_end.tv_sec - tx_start.tv_sec, tx_end.tv_usec - tx_start.tv_usec); } } -static bool pub_frnd_cred (struct mesh_net *net,uint16_t src,uint32_t mod_id) +static bool pub_frnd_cred (struct mesh_node *node,uint16_t src,uint32_t mod_id) { -struct mesh_model *mod =find_model (net, src, mod_id,NULL ); +struct mesh_model *mod =find_model (node, src, mod_id,NULL );if (!mod || !mod->pub)return false;
@@ -274,17 +438,16 @@ static bool pub_frnd_cred(struct mesh_net *net, uint16_t src, uint32_t mod_id)return (mod->pub->credential !=0 ); } -static unsigned int msg_send (struct mesh_net *net,uint32_t mod_id, -uint16_t src,uint32_t dst, -uint8_t key_id,const uint8_t *key, -uint8_t *aad,uint8_t ttl, -const void *msg,uint16_t msg_len) +static bool msg_send (struct mesh_node *node,bool credential,uint16_t src, +uint32_t dst,uint8_t key_id,const uint8_t *key, +uint8_t *aad,uint8_t ttl,const void *msg,uint16_t msg_len) { -unsigned int ret =0 ; +bool ret = false;uint32_t iv_index, seq_num;uint8_t *out;bool szmic = false;uint16_t out_len = msg_len +sizeof (uint32_t ); +struct mesh_net *net =node_get_net (node);/* Use large MIC if it doesn't affect segmentation */ if (msg_len >11 && msg_len <=376 ) {
@@ -309,7 +472,7 @@ static unsigned int msg_send(struct mesh_net *net, uint32_t mod_id,/* print_packet("Encrypted with", key, 16); */ - ret = mesh_net_app_send(net, pub_frnd_cred(net, src, mod_id), + ret = mesh_net_app_send(net, credential, src, dst, key_id, ttl, seq_num, iv_index, szmic,
@@ -320,79 +483,100 @@ done:return ret; } -static void model_unbind_idx (void *a,void *b) +static void remove_pub (struct mesh_node *node,struct mesh_model *mod) { -struct mesh_model *mod = a; -uint16_t idx =L_PTR_TO_UINT (b); +l_free (mod->pub); + mod->pub =NULL ; -if (idx == mod->pub->idx) { - mod->pub->addr =UNASSIGNED_ADDRESS ; -/* -* TODO: callback for internal model or -* D-Bus signal/method "model publication changed" (TBD) -*/ - } +/* TODO: remove from storage */ + +if (!mod->cbs) +/* External models */ +config_update_model_pub_period (node, mod->ele_idx, mod->id,0 ); +else if (mod->cbs && mod->cbs->pub) +/* Internal models */ + mod->cbs->pub (NULL ); +} -l_queue_remove (mod->bindings, b); +static void model_unbind_idx (struct mesh_node *node,struct mesh_model *mod, +uint16_t idx) +{ +l_queue_remove (mod->bindings,L_UINT_TO_PTR (idx)); -if (mod->cbs->bind) +if (!mod->cbs) +/* External model */ +config_update_model_bindings (node, mod); +else if (mod->cbs->bind) +/* Internal model */ mod->cbs->bind (idx,ACTION_DELETE ); + +if (mod->pub && idx != mod->pub->idx) +return ; + +/* Remove model publication if the publication key is unbound */ +remove_pub (node, mod); } -static int model_bind_idx (struct mesh_model *mod,uint16_t idx) +static void model_bind_idx (struct mesh_node *node,struct mesh_model *mod, +uint16_t idx) { -if (l_queue_length (mod->bindings) >=MAX_BINDINGS ) -return MESH_STATUS_INSUFF_RESOURCES ; +l_queue_push_tail (mod->bindings,L_UINT_TO_PTR (idx)); -if (!l_queue_push_tail (mod->bindings,L_UINT_TO_PTR (idx))) -return MESH_STATUS_INSUFF_RESOURCES ; +l_debug ("Add %4.4x to model %8.8x" , idx, mod->id); -if (mod->cbs->bind) +if (!mod->cbs) +/* External model */ +config_update_model_bindings (node, mod); +else if (mod->cbs->bind) +/* Internal model */ mod->cbs->bind (idx,ACTION_ADD ); - -return MESH_STATUS_SUCCESS ; - } -static int update_binding (struct mesh_net *net,uint16_t addr,uint32_t id, +static int update_binding (struct mesh_node *node,uint16_t addr,uint32_t id,uint16_t app_idx,bool unbind) {int fail;struct mesh_model *mod; -int status; +bool is_present; - mod =find_model (net, addr, id, &fail); + mod =find_model (node, addr, id, &fail);if (!mod) { -l_info ("model not found" ); +l_debug ("Model not found" );return fail; } + id = (id >=VENDOR_ID_MASK ) ? (id &0xffff ) : id; +if (id ==CONFIG_SRV_MODEL || id ==CONFIG_CLI_MODEL )return MESH_STATUS_INVALID_MODEL ; -if (!l_queue_find (mod->bindings, simple_match,L_UINT_TO_PTR (app_idx))) -return MESH_STATUS_CANNOT_BIND ; - -if (!appkey_have_key (net, app_idx)) +if (!appkey_have_key (node_get_net (node), app_idx))return MESH_STATUS_INVALID_APPKEY ; + is_present =has_binding (mod->bindings, app_idx); + +if (!is_present && unbind) +return MESH_STATUS_SUCCESS ; + +if (is_present && !unbind) +return MESH_STATUS_SUCCESS ; +if (unbind) { -model_unbind_idx (mod, &app_idx); +model_unbind_idx (node, mod, app_idx); -if (!storage_model_bind (net, addr, id, app_idx, true)) +if (!storage_model_bind (node, addr, id, app_idx, true))return MESH_STATUS_STORAGE_FAIL ;return MESH_STATUS_SUCCESS ; } - status =model_bind_idx (mod, app_idx); -if (status !=MESH_STATUS_SUCCESS ) -return status; +if (l_queue_length (mod->bindings) >=MAX_BINDINGS ) +return MESH_STATUS_INSUFF_RESOURCES ; -if (!storage_model_bind (net, addr, id, app_idx, false)) { -model_unbind_idx (mod, &app_idx); +if (!storage_model_bind (node, addr, id, app_idx, false))return MESH_STATUS_STORAGE_FAIL ; - } + +model_bind_idx (node, mod, app_idx);return MESH_STATUS_SUCCESS ;
@@ -428,6 +612,7 @@ static int set_pub(struct mesh_model *mod, const uint8_t *mod_addr, } } + mod->pub = l_new(struct mesh_model_pub, 1);if (b_virt) { virt =l_queue_find (mesh_virtuals, find_virt_by_addr, mod_addr);if (!virt) {
@@ -511,14 +696,57 @@ static int add_sub(struct mesh_net *net, struct mesh_model *mod,l_queue_push_tail (mod->subs,L_UINT_TO_PTR (grp)); -l_info ("Added %4.4x" , grp); -if (net) -mesh_net_dst_reg (net, grp); +l_debug ("Added %4.4x" , grp); + +mesh_net_dst_reg (net, grp);return MESH_STATUS_SUCCESS ; } -bool mesh_model_rx (struct mesh_net *net,bool szmict,uint32_t seq0, +static void send_msg_rcvd (struct mesh_node *node,uint8_t ele_idx,bool is_sub, +uint16_t src,uint16_t key_idx, +uint16_t size,const uint8_t *data) +{ +struct l_dbus *dbus =dbus_get_bus (); +struct l_dbus_message *msg; +struct l_dbus_message_builder *builder; +const char *owner; +const char *path; + + owner =node_get_owner (node); + path =node_get_element_path (node, ele_idx); +if (!path || !owner) +return ; + +l_debug ("Send \"MessageReceived\"" ); + + msg =l_dbus_message_new_method_call (dbus, owner, path, +MESH_ELEMENT_INTERFACE ,"MessageReceived" ); + + builder =l_dbus_message_builder_new (msg); + +if (!l_dbus_message_builder_append_basic (builder,'q' , &src)) + goto error; + +if (!l_dbus_message_builder_append_basic (builder,'q' , &key_idx)) + goto error; + +if (!l_dbus_message_builder_append_basic (builder,'b' , &is_sub)) + goto error; + +if (!dbus_append_byte_array (builder, data, size)) + goto error; + +if (!l_dbus_message_builder_finalize (builder)) + goto error; + +l_dbus_send (dbus, msg); + +error: +l_dbus_message_builder_destroy (builder); +} + +bool mesh_model_rx (struct mesh_node *node,bool szmict,uint32_t seq0,uint32_t seq,uint32_t iv_index,uint8_t ttl,uint16_t src,uint16_t dst,uint8_t key_id,const uint8_t *data,uint16_t size)
@@ -531,30 +759,25 @@ bool mesh_model_rx(struct mesh_net *net, bool szmict, uint32_t seq0, .size = size - (szmict ? 8 : 4), .ttl = ttl, .virt = NULL, - .done = false, }; - -struct mesh_node *node; +struct mesh_net *net =node_get_net (node);uint8_t num_ele;int decrypt_idx, i, ele_idx;uint16_t addr;struct mesh_virtual *decrypt_virt =NULL ; +bool result = false; +bool is_subscription;l_debug ("iv_index %8.8x key_id = %2.2x" , iv_index, key_id);if (!dst)return false; - node =mesh_net_local_node_get (net); -if (!node) -return false; - ele_idx =node_get_element_idx (node, dst);if (dst <0x8000 && ele_idx <0 )/* Unicast and not addressed to us */ return false; - clear_text =l_malloc (size);if (!clear_text)return false;
@@ -566,7 +789,7 @@ bool mesh_model_rx(struct mesh_net *net, bool szmict, uint32_t seq0,* is hinted by key_id, but is not necessarily definitive */ if (key_id ==APP_ID_DEV ||mesh_net_provisioner_mode_get (net)) - decrypt_idx =dev_packet_decrypt (net, data, size, szmict, src, + decrypt_idx =dev_packet_decrypt (node, data, size, szmict, src, dst, key_id, seq0, iv_index, clear_text);else if ((dst &0xc000 ) ==0x8000 )
@@ -582,18 +805,18 @@ bool mesh_model_rx(struct mesh_net *net, bool szmict, uint32_t seq0,if (decrypt_idx <0 ) {l_error ("model.c - Failed to decrypt application payload" ); - forward.done = false; + result = false; goto done; }/* print_packet("Clr Rx (pre-cache-check)", clear_text, size - 4); */ if (key_id !=APP_ID_DEV ) { -uint16_t crpl =mesh_net_get_crpl (net); +uint16_t crpl =node_get_crpl (node);if (appkey_msg_in_replay_cache (net, (uint16_t ) decrypt_idx, src, crpl, seq, iv_index)) { - forward.done = true; + result = true; goto done; } }
@@ -608,59 +831,86 @@ bool mesh_model_rx(struct mesh_net *net, bool szmict, uint32_t seq0,if (!num_ele ||IS_UNASSIGNED (addr)) goto done; + is_subscription = !(IS_UNICAST (dst)); +for (i =0 ; i < num_ele; i++) {struct l_queue *models; -if (dst <0x8000 && ele_idx != i) +if (!is_subscription && ele_idx != i)continue ; forward.unicast = addr + i; + forward.has_dst = false; + models =node_get_element_models (node, i,NULL ); + +/* Internal models */ l_queue_foreach (models, forward_model, &forward); -if (dst <0x8000 && ele_idx == i) +/* +* Cycle through external models if the message has not been +* handled by internal models +*/ +if (forward.has_dst && !forward.done) +send_msg_rcvd (node, i, is_subscription, src, + forward.idx, forward.size, + forward.data); + +/* +* Either the message has been processed internally or +* has been passed on to an external model. +*/ + result = forward.has_dst | forward.done; + +/* If the message was to unicast address, we are done */ +if (!is_subscription && ele_idx == i)break ; } + done:l_free (clear_text); -return forward.done; +return result; } -unsigned int mesh_model_send (struct mesh_net *net,uint32_t mod_id, -uint16_t src,uint32_t target, -uint16_t app_idx,uint8_t ttl, +int mesh_model_publish (struct mesh_node *node,uint32_t mod_id, +uint16_t src,uint8_t ttl,const void *msg,uint16_t msg_len) { +struct mesh_net *net =node_get_net (node);struct mesh_model *mod; +uint32_t target;uint8_t *aad =NULL ;uint16_t dst;uint8_t key_id;const uint8_t *key; +bool result;/* print_packet("Mod Tx", msg, msg_len); */ if (!net || msg_len >380 ) -return 0 ; +return MESH_ERROR_INVALID_ARGS ;/* If SRC is 0, use the Primary Element */ if (src ==0 ) src =mesh_net_get_address (net); - mod =find_model (net, src, mod_id,NULL ); + mod =find_model (node, src, mod_id,NULL );if (!mod) { -l_info ("model %x not found" , mod_id); -return 0 ; +l_debug ("model %x not found" , mod_id); +return MESH_ERROR_NOT_FOUND ; + } + +if (!mod->pub) { +l_debug ("publication doesn't exist (model %x)" , mod_id); +return MESH_ERROR_DOES_NOT_EXIST ; }gettimeofday (&tx_start,NULL ); -if (target ==USE_PUB_VALUE ) { - target = mod->pub->addr; - app_idx = mod->pub->idx; - } + target = mod->pub->addr;if (IS_UNASSIGNED (target)) -return 0 ; +return false;if (target >=VIRTUAL_BASE ) { struct mesh_virtual *virt = l_queue_find(mesh_virtuals,
@@ -668,101 +918,139 @@ unsigned int mesh_model_send(struct mesh_net *net, uint32_t mod_id, L_UINT_TO_PTR(target));if (!virt) -return 0 ; +return false; aad = virt->addr; dst = virt->ota; - }else + }else { dst = target; + } + +l_debug ("publish dst=%x" , dst); + + key =appkey_get_key (net, mod->pub->idx, &key_id); +if (!key) { +l_debug ("no app key for (%x)" , mod->pub->idx); +return false; + } + +l_debug ("(%x) %p" , mod->pub->idx, key); +l_debug ("key_id %x" , key_id); + + result =msg_send (node,pub_frnd_cred (node, src, mod_id), src, + dst, key_id, key, aad, ttl, msg, msg_len); + +return result ?MESH_ERROR_NONE :MESH_ERROR_FAILED ; + +} + +bool mesh_model_send (struct mesh_node *node,uint16_t src,uint16_t target, +uint16_t app_idx,uint8_t ttl, +const void *msg,uint16_t msg_len) +{ +uint8_t key_id; +const uint8_t *key; + +/* print_packet("Mod Tx", msg, msg_len); */ + +/* If SRC is 0, use the Primary Element */ +if (src ==0 ) + src =node_get_primary (node); + +gettimeofday (&tx_start,NULL ); -l_debug ("dst=%x" , dst); -if (app_idx ==APP_IDX_DEV &&mesh_net_provisioner_mode_get (net)) { - key =node_get_device_key (mesh_net_local_node_get (net)); - }else if (app_idx ==APP_IDX_DEV ) { - key =node_get_device_key (mesh_net_local_node_get (net)); +if (IS_UNASSIGNED (target)) +return false; + +if (app_idx ==APP_IDX_DEV ) { + key =node_get_device_key (node);if (!key) -return 0 ; +return false;l_debug ("(%x)" , app_idx); key_id =APP_ID_DEV ; }else { - key =appkey_get_key (net, app_idx, &key_id); + key =appkey_get_key (node_get_net (node), app_idx, &key_id);if (!key) {l_debug ("no app key for (%x)" , app_idx); -return 0 ; +return false; }l_debug ("(%x) %p" , app_idx, key);l_debug ("key_id %x" , key_id); } -return msg_send (net, mod_id, src, dst, key_id, key, aad, ttl, +return msg_send (node, false, src, target, key_id, key,NULL , ttl, msg, msg_len); - } -int mesh_model_pub_set (struct mesh_net *net,uint16_t addr,uint32_t id, +int mesh_model_pub_set (struct mesh_node *node,uint16_t addr,uint32_t id,const uint8_t *mod_addr,uint16_t idx,bool cred_flag,uint8_t ttl,uint8_t period,uint8_t retransmit,bool b_virt,uint16_t *dst) {int fail =MESH_STATUS_SUCCESS ; -int ele_idx =-1 ; +int ele_idx;struct mesh_model *mod; -struct mesh_node *node; +int result; - node =mesh_net_local_node_get (net); -if (node) - ele_idx =node_get_element_idx (node, addr); + ele_idx =node_get_element_idx (node, addr); -if (!node || ele_idx <0 ) { +if (ele_idx <0 ) { fail =MESH_STATUS_INVALID_ADDRESS ;return false; } - mod =node_get_model (node, (uint8_t ) ele_idx, id, &fail); + mod =get_model (node, (uint8_t ) ele_idx, id, &fail);if (!mod)return fail;if (id ==CONFIG_SRV_MODEL || id ==CONFIG_CLI_MODEL )return MESH_STATUS_INVALID_PUB_PARAM ; -if (!appkey_have_key (net, idx)) +if (!appkey_have_key (node_get_net (node), idx))return MESH_STATUS_INVALID_APPKEY ; -return set_pub (mod, mod_addr, idx, cred_flag, ttl, period, retransmit, + result =set_pub (mod, mod_addr, idx, cred_flag, ttl, period, retransmit, b_virt, dst); + +if (result !=MESH_STATUS_SUCCESS ) +return result; + +/* TODO: save to storage */ +/* -* TODO: Add standardized Publication Change notification to model -* definition +* If the publication address is set to unassigned address value, +* remove publication */ +if (IS_UNASSIGNED (*dst)) +remove_pub (node, mod); + +/* Internal model, call registered callbacks */ +if (mod->cbs && mod->cbs->pub) { + mod->cbs->pub (mod->pub); +return MESH_STATUS_SUCCESS ; + } + +/* External model */ +config_update_model_pub_period (node, ele_idx, id, +convert_pub_period_to_ms (period)); + +return MESH_STATUS_SUCCESS ; } -struct mesh_model_pub *mesh_model_pub_get (struct mesh_net *net,uint8_t ele_idx, -uint32_t mod_id,int *status) +struct mesh_model_pub *mesh_model_pub_get (struct mesh_node *node, +uint8_t ele_idx,uint32_t mod_id,int *status) {struct mesh_model *mod; -struct mesh_node *node =mesh_net_local_node_get (net); - -if (!node) { - *status =MESH_STATUS_INVALID_ADDRESS ; -return NULL ; - } - mod =node_get_model (node, ele_idx, mod_id, status); + mod =get_model (node, ele_idx, mod_id, status);if (!mod)return NULL ;return mod->pub; } -uint32_t mesh_model_get_model_id (const struct mesh_model *model) -{ -if (!model) -return 0xffffffff ;/* TODO: use define */ -return model->id; -} -void mesh_model_free (void *data) {struct mesh_model *mod = data;
@@ -774,33 +1062,39 @@ void mesh_model_free(void *data)l_free (mod); } -struct mesh_model *mesh_model_new (uint8_t ele_idx,uint32_t id,bool vendor) +static struct mesh_model *model_new (uint8_t ele_idx,uint32_t id) { struct mesh_model *mod = l_new(struct mesh_model, 1); -if (!mod) -return NULL ; - -if (vendor) - id |=VENDOR_ID_MASK ; - mod->id = id; mod->ele_idx = ele_idx; mod->virtuals =l_queue_new (); -if (!mod->virtuals) { -l_free (mod); -return NULL ; - }return mod; } -static void restore_model_state (void *data) +struct mesh_model *mesh_model_new (uint8_t ele_idx,uint16_t id) { -struct mesh_model *mod = data; +return model_new (ele_idx, id |VENDOR_ID_MASK ); +} + +struct mesh_model *mesh_model_vendor_new (uint8_t ele_idx,uint16_t vendor_id, +uint16_t mod_id) +{ +uint32_t id = mod_id | (vendor_id <<16 ); + +return model_new (ele_idx, id); +} + +/* Internal models only */ +static void restore_model_state (struct mesh_model *mod) +{ +const struct mesh_model_ops *cbs;const struct l_queue_entry *b; cbs = mod->cbs; +if (!cbs) +return ;if (l_queue_isempty (mod->bindings) || !mod->cbs->bind) {for (b =l_queue_get_entries (mod->bindings); b; b = b->next) {
@@ -812,63 +1106,64 @@ static void restore_model_state(void *data)if (mod->pub && cbs->pub) cbs->pub (mod->pub); + } -bool mesh_model_vendor_register (struct mesh_net *net,uint8_t ele_idx, +uint32_t mesh_model_get_model_id (const struct mesh_model *model) +{ +return model->id; +} + +/* This registers an internal model, i.e. implemented within meshd */ +bool mesh_model_register (struct mesh_node *node,uint8_t ele_idx,uint32_t mod_id,const struct mesh_model_ops *cbs,void *user_data) {struct mesh_model *mod; -struct mesh_node *node; - node =mesh_net_local_node_get (net); -if (!node) -return false; +/* Internal models are always SIG models */ + mod_id =VENDOR_ID_MASK | mod_id; - mod =node_get_model (node, ele_idx, mod_id,NULL ); + mod =get_model (node, ele_idx, mod_id,NULL );if (!mod)return false; mod->cbs = cbs; mod->user_data = user_data; -l_idle_oneshot (restore_model_state, mod,NULL ); +restore_model_state (mod);return true; } -bool mesh_model_register (struct mesh_net *net,uint8_t ele_idx, -uint32_t mod_id, -const struct mesh_model_ops *cbs, -void *user_data) +void mesh_model_app_key_delete (struct mesh_node *node,struct l_queue *models, +uint16_t app_idx) { -uint32_t id =VENDOR_ID_MASK | mod_id; +const struct l_queue_entry *entry =l_queue_get_entries (models); -return mesh_model_vendor_register (net, ele_idx, id, cbs, user_data); -} +for (; entry; entry = entry->next) { +struct mesh_model *model = entry->data; -void mesh_model_app_key_delete (struct mesh_net *net,struct l_queue *models, -uint16_t app_idx) -{ -l_queue_foreach (models, model_unbind_idx,L_UINT_TO_PTR (app_idx)); +model_unbind_idx (node, model, app_idx); + } } -int mesh_model_binding_del (struct mesh_net *net,uint16_t addr,uint32_t id, +int mesh_model_binding_del (struct mesh_node *node,uint16_t addr,uint32_t id,uint16_t app_idx) {l_debug ("0x%x, 0x%x, %d" , addr, id, app_idx); -return update_binding (net, addr, id, app_idx, true); +return update_binding (node, addr, id, app_idx, true); } -int mesh_model_binding_add (struct mesh_net *net,uint16_t addr,uint32_t id, +int mesh_model_binding_add (struct mesh_node *node,uint16_t addr,uint32_t id,uint16_t app_idx) {l_debug ("0x%x, 0x%x, %d" , addr, id, app_idx); -return update_binding (net, addr, id, app_idx, false); +return update_binding (node, addr, id, app_idx, false); } -int mesh_model_get_bindings (struct mesh_net *net,uint16_t addr,uint32_t id, +int mesh_model_get_bindings (struct mesh_node *node,uint16_t addr,uint32_t id,uint8_t *buf,uint16_t buf_size,uint16_t *size) {int fail;
@@ -878,7 +1173,7 @@ int mesh_model_get_bindings(struct mesh_net *net, uint16_t addr, uint32_t id,uint32_t idx_pair;int i; - mod =find_model (net, addr, id, &fail); + mod =find_model (node, addr, id, &fail);if (!mod) { *size =0 ;
@@ -922,7 +1217,7 @@ done:return MESH_STATUS_SUCCESS ; } -int mesh_model_sub_get (struct mesh_net *net,uint16_t addr,uint32_t id, +int mesh_model_sub_get (struct mesh_node *node,uint16_t addr,uint32_t id,uint8_t *buf,uint16_t buf_size,uint16_t *size) {int fail =MESH_STATUS_SUCCESS ;
@@ -930,7 +1225,7 @@ int mesh_model_sub_get(struct mesh_net *net, uint16_t addr, uint32_t id,struct mesh_model *mod;const struct l_queue_entry *entry; - mod =find_model (net, addr, id, &fail); + mod =find_model (node, addr, id, &fail);if (!mod)return fail;
@@ -951,32 +1246,29 @@ int mesh_model_sub_get(struct mesh_net *net, uint16_t addr, uint32_t id,return MESH_STATUS_SUCCESS ; } -int mesh_model_sub_add (struct mesh_net *net,uint16_t addr,uint32_t id, +int mesh_model_sub_add (struct mesh_node *node,uint16_t addr,uint32_t id,const uint8_t *group,bool b_virt,uint16_t *dst) {int fail =MESH_STATUS_SUCCESS ;int ele_idx =-1 ;struct mesh_model *mod; -struct mesh_node *node; - node =mesh_net_local_node_get (net); -if (node) - ele_idx =node_get_element_idx (node, addr); + ele_idx =node_get_element_idx (node, addr);if (!node || ele_idx <0 ) { fail =MESH_STATUS_INVALID_ADDRESS ;return false; } - mod =node_get_model (node, (uint8_t ) ele_idx, id, &fail); + mod =get_model (node, (uint8_t ) ele_idx, id, &fail);if (!mod)return fail; -return add_sub (net, mod, group, b_virt, dst); +return add_sub (node_get_net (node), mod, group, b_virt, dst);/* TODO: communicate to registered models that sub has changed */ } -int mesh_model_sub_ovr (struct mesh_net *net,uint16_t addr,uint32_t id, +int mesh_model_sub_ovr (struct mesh_node *node,uint16_t addr,uint32_t id,const uint8_t *group,bool b_virt,uint16_t *dst) {int fail =MESH_STATUS_SUCCESS ;
@@ -984,7 +1276,7 @@ int mesh_model_sub_ovr(struct mesh_net *net, uint16_t addr, uint32_t id,struct mesh_virtual *virt;struct mesh_model *mod; - mod =find_model (net, addr, id, &fail); + mod =find_model (node, addr, id, &fail);if (!mod)return fail;
@@ -1009,7 +1301,7 @@ int mesh_model_sub_ovr(struct mesh_net *net, uint16_t addr, uint32_t id, } } - fail =mesh_model_sub_add (net, addr, id, group, b_virt, dst); + fail =mesh_model_sub_add (node, addr, id, group, b_virt, dst);if (fail) {/* Adding new group failed, so revert to old list */
@@ -1019,6 +1311,7 @@ int mesh_model_sub_ovr(struct mesh_net *net, uint16_t addr, uint32_t id, mod->virtuals = virtuals; }else {const struct l_queue_entry *entry; +struct mesh_net *net =node_get_net (node); entry =l_queue_get_entries (subs);for (; entry; entry = entry->next)
@@ -1032,14 +1325,14 @@ int mesh_model_sub_ovr(struct mesh_net *net, uint16_t addr, uint32_t id,return fail; } -int mesh_model_sub_del (struct mesh_net *net,uint16_t addr,uint32_t id, +int mesh_model_sub_del (struct mesh_node *node,uint16_t addr,uint32_t id,const uint8_t *group,bool b_virt,uint16_t *dst) {int fail =MESH_STATUS_SUCCESS ;uint16_t grp;struct mesh_model *mod; - mod =find_model (net, addr, id, &fail); + mod =find_model (node, addr, id, &fail);if (!mod)return fail;
@@ -1062,18 +1355,19 @@ int mesh_model_sub_del(struct mesh_net *net, uint16_t addr, uint32_t id, *dst = grp;if (l_queue_remove (mod->subs,L_UINT_TO_PTR (grp))) -mesh_net_dst_unreg (net, grp); +mesh_net_dst_unreg (node_get_net (node), grp);return MESH_STATUS_SUCCESS ; } -int mesh_model_sub_del_all (struct mesh_net *net,uint16_t addr,uint32_t id) +int mesh_model_sub_del_all (struct mesh_node *node,uint16_t addr,uint32_t id) {int fail =MESH_STATUS_SUCCESS ;struct mesh_model *mod;const struct l_queue_entry *entry; +struct mesh_net *net =node_get_net (node); - mod =find_model (net, addr, id, &fail); + mod =find_model (node, addr, id, &fail);if (!mod)return fail;
@@ -1088,15 +1382,22 @@ int mesh_model_sub_del_all(struct mesh_net *net, uint16_t addr, uint32_t id)return fail; } -struct mesh_model *mesh_model_init (struct mesh_net *net,uint8_t ele_idx, -struct mesh_db_model *db_mod) +struct mesh_model *mesh_model_setup (struct mesh_node *node,uint8_t ele_idx, +void *data) { +struct mesh_db_model *db_mod = data;struct mesh_model *mod; +struct mesh_net *net;uint32_t i; - mod =mesh_model_new (ele_idx, db_mod->id, db_mod->vendor); -if (!mod) +if (db_mod->num_bindings >MAX_BINDINGS ) { +l_warn ("Binding list too long %u (max %u)" , + db_mod->num_bindings,MAX_BINDINGS );return NULL ; + } + + mod =model_new (ele_idx, db_mod->vendor ? db_mod->id : + db_mod->id |VENDOR_ID_MASK );/* Implicitly bind config server model to device key */ if (db_mod->id ==CONFIG_SRV_MODEL ) {
@@ -1113,35 +1414,27 @@ struct mesh_model *mesh_model_init(struct mesh_net *net, uint8_t ele_idx,return mod; } + net =node_get_net (node); +/* Add application key bindings if present */ if (db_mod->bindings) { mod->bindings =l_queue_new (); - -if (!mod->bindings) { -mesh_model_free (mod); -return NULL ; - } - -for (i =0 ; i < db_mod->num_bindings; i++) { -if (!model_bind_idx (mod, db_mod->bindings[i])) { -mesh_model_free (mod); -return NULL ; - } - } +for (i =0 ; i < db_mod->num_bindings; i++) +model_bind_idx (node, mod, db_mod->bindings[i]); }/* Add publication if present */ if (db_mod->pub) { -uint16_t mod_addr; -uint8_t *dst; +struct mesh_db_pub *pub = db_mod->pub; +uint8_t mod_addr[2 ]; +uint8_t *pub_addr; -l_put_le16 (db_mod->pub->addr, &mod_addr); - dst = db_mod->pub->virt ? db_mod->pub->virt_addr : - (uint8_t *) &mod_addr; +/* Add publication */ +l_put_le16 (pub->addr, &mod_addr); + pub_addr = pub->virt ? pub->virt_addr : (uint8_t *) &mod_addr; -if (set_pub (mod, dst, db_mod->pub->idx, db_mod->pub->credential, - db_mod->pub->ttl, db_mod->pub->period, - db_mod->pub->retransmit, db_mod->pub->virt,NULL ) != +if (set_pub (mod, pub_addr, pub->idx, pub->credential, pub->ttl, + pub->period, pub->retransmit, pub->virt,NULL ) !=MESH_STATUS_SUCCESS ) {mesh_model_free (mod);return NULL ;
@@ -1192,7 +1485,7 @@ uint16_t mesh_model_opcode_set(uint32_t opcode, uint8_t *buf)return 3 ; } -l_info ("Illegal Opcode %x" , opcode); +l_debug ("Illegal Opcode %x" , opcode);return 0 ; }
@@ -1238,7 +1531,7 @@ bool mesh_model_opcode_get(const uint8_t *buf, uint16_t size,return true; } -void mesh_model_add_virtual (struct mesh_net *net,const uint8_t *v) +void mesh_model_add_virtual (struct mesh_node *node,const uint8_t *v) {struct mesh_virtual *virt =l_queue_find (mesh_virtuals, find_virt_by_addr, v);
@@ -1263,7 +1556,7 @@ void mesh_model_add_virtual(struct mesh_net *net, const uint8_t *v)l_queue_push_head (mesh_virtuals, virt); } -void mesh_model_del_virtual (struct mesh_net *net,uint32_t va24) +void mesh_model_del_virtual (struct mesh_node *node,uint32_t va24) { struct mesh_virtual *virt = l_queue_remove_if(mesh_virtuals, find_virt_by_id,
@@ -1272,3 +1565,55 @@ void mesh_model_del_virtual(struct mesh_net *net, uint32_t va24)if (virt)unref_virt (virt); } + +void model_build_config (void *model,void *msg_builder) +{ +struct l_dbus_message_builder *builder = msg_builder; +struct mesh_model *mod = model; +uint16_t id; + +if (is_internal (mod->id)) +return ; + +if (!l_queue_length (mod->subs) && !l_queue_length (mod->virtuals) && + !mod->pub && !l_queue_length (mod->bindings)) +return ; + +l_dbus_message_builder_enter_struct (builder,"qa{sv}" ); + +/* Model id */ + id = mod->id &0xffff ; +l_dbus_message_builder_append_basic (builder,'q' , &id); + +l_dbus_message_builder_enter_array (builder,"{sv}" ); + +/* For vendor models, add vendor id */ +if ((mod->id &VENDOR_ID_MASK ) !=VENDOR_ID_MASK ) { +uint16_t vendor = mod->id >>16 ; +dbus_append_dict_entry_basic (builder,"Vendor" ,"q" , &vendor); + } + +/* Model bindings, if present */ +if (l_queue_length (mod->bindings)) +append_dict_uint16_array (builder, mod->bindings,"Bindings" ); + +/* Model periodic publication interval, if present */ +if (mod->pub) { +uint32_t period =convert_pub_period_to_ms (mod->pub->period); +dbus_append_dict_entry_basic (builder,"PublicationPeriod" ,"u" , + &period); + } + +l_dbus_message_builder_leave_array (builder); +l_dbus_message_builder_leave_struct (builder); +} + +void mesh_model_init (void ) +{ + mesh_virtuals =l_queue_new (); +} + +void mesh_model_cleanup (void ) +{ +l_queue_destroy (mesh_virtuals, l_free); +}
mesh/model.h +34 -35
107 lines not on this page · raw message
Signature · 1 line
2.14.5
PATCH v6 19/26 mesh: DBUS interface for Provisioning Agent
In reply to Brian GixFrom: Inga Stotland <[email protected]>
Implements the time limited and user interaction D-Bus API as required for Out-Of-Band authentication during provisioning, and as described in doc/mesh-api.txt.
--- mesh/agent.c | 665 ++++++++++++++++++++++++++++++++++++++++++++++++----------- mesh/agent.h | 69 +++++-- 2 files changed, 589 insertions(+), 145 deletions(-)
mesh/agent.c +541 -124
@@ -15,215 +15,632 @@* 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 -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <string.h> -#include <inttypes.h> -#include <ell/ell.h> -#include "src/shared/shell.h" - -#include "mesh/util.h" +#include "mesh/mesh.h" +#include "mesh/provision.h" +#include "mesh/error.h" +#include "mesh/dbus.h" #include "mesh/agent.h" -struct input_request { -enum oob_type type; -uint16_t len; -agent_input_cb cb; +typedef enum { +MESH_AGENT_REQUEST_BLINK , +MESH_AGENT_REQUEST_BEEP , +MESH_AGENT_REQUEST_VIBRATE , +MESH_AGENT_REQUEST_OUT_NUMERIC , +MESH_AGENT_REQUEST_OUT_ALPHA , +MESH_AGENT_REQUEST_PUSH , +MESH_AGENT_REQUEST_TWIST , +MESH_AGENT_REQUEST_IN_NUMERIC , +MESH_AGENT_REQUEST_IN_ALPHA , +MESH_AGENT_REQUEST_STATIC_OOB , +MESH_AGENT_REQUEST_PRIVATE_KEY , +MESH_AGENT_REQUEST_PUBLIC_KEY +}agent_request_type_t ; + +struct agent_request { +agent_request_type_t type; +struct l_dbus_message *msg; +void *cb;void *user_data; }; -static struct input_request pending_request = {NONE ,0 ,NULL ,NULL }; +struct mesh_agent { +char *path; +char *owner; +struct mesh_agent_prov_caps caps; +struct agent_request *req; +}; -bool agent_completion (void ) -{ -if (pending_request.type ==NONE ) -return false; +struct prov_action { +const char *action; +uint16_t output; +uint16_t input; +uint8_t size; +}; + +struct oob_info { +const char *oob; +uint16_t mask; +}; -return true; +static struct prov_action cap_table[] = { + {"blink" ,0x0001 ,0x0000 ,1 }, + {"beep" ,0x0002 ,0x0000 ,1 }, + {"vibrate" ,0x0004 ,0x0000 ,1 }, + {"out-numeric" ,0x0008 ,0x0000 ,8 }, + {"out-alpha" ,0x0010 ,0x0000 ,8 }, + {"push" ,0x0000 ,0x0001 ,1 }, + {"twist" ,0x0000 ,0x0002 ,1 }, + {"in-numeric" ,0x0000 ,0x0004 ,8 }, + {"in-alpha" ,0x0000 ,0x0008 ,8 } +}; + +static struct oob_info oob_table[] = { + {"other" ,0x0001 }, + {"uri" ,0x0002 }, + {"machine-code-2d" ,0x0004 }, + {"barcode" ,0x0008 }, + {"nfc" ,0x0010 }, + {"number" ,0x0020 }, + {"string" ,0x0040 }, + {"on-box" ,0x0800 }, + {"in-box" ,0x1000 }, + {"on-paper" ,0x2000 }, + {"in-manual" ,0x4000 }, + {"on-device" ,0x8000 } +}; + +static struct l_queue *agents; + +static bool simple_match (const void *a,const void *b) +{ +return a == b; } -static void reset_input_request (void ) +static void parse_prov_caps (struct mesh_agent_prov_caps *caps, +struct l_dbus_message_iter *property) { - pending_request.type =NONE ; - pending_request.len =0 ; - pending_request.cb =NULL ; - pending_request.user_data =NULL ; +struct l_dbus_message_iter iter_caps; +const char *str; +uint32_t i; + +if (!l_dbus_message_iter_get_variant (property,"as" , &iter_caps)) +return ; + +while (l_dbus_message_iter_next_entry (&iter_caps, &str)) { +for (i =0 ; i <L_ARRAY_SIZE (cap_table); i++) { +if (strcmp (str, cap_table[i].action)) +continue ; + + caps->output_action |= cap_table[i].output; +if (cap_table[i].output && + caps->output_size < cap_table[i].size) + caps->output_size = cap_table[i].size; + + caps->input_action |= cap_table[i].input; +if (cap_table[i].input && + caps->input_size < cap_table[i].size) + caps->input_size = cap_table[i].size; + +break ; + } + +if (!strcmp (str,"PublicOOB" )) + caps->pub_type =1 ; +else if (!strcmp (str,"StaticOOB" )) + caps->static_type =1 ; + } + } -static void try_again (void ) +static void parse_oob_info (struct mesh_agent_prov_caps *caps, +struct l_dbus_message_iter *property) { -static int try_count; -enum oob_type type = pending_request.type; +struct l_dbus_message_iter iter_oob; +uint32_t i; +const char *str; -if (try_count ==2 ) { -reset_input_request (); - try_count =0 ; +if (!l_dbus_message_iter_get_variant (property,"as" , &iter_oob))return ; + +while (l_dbus_message_iter_next_entry (&iter_oob, &str)) { +for (i =0 ; i <L_ARRAY_SIZE (oob_table); i++) { +if (strcmp (str, oob_table[i].oob)) +continue ; + caps->oob_info |= oob_table[i].mask; + } } +} - pending_request.type =NONE ; -agent_input_request (type, pending_request.len, pending_request.cb, - pending_request.user_data); +static void agent_free (void *agent_data) +{ +struct mesh_agent *agent = agent_data; +int err; +mesh_agent_cb_t simple_cb; +mesh_agent_key_cb_t key_cb; +mesh_agent_number_cb_t number_cb; - try_count++; +if (!l_queue_find (agents, simple_match, agent)) +return ; + + err =MESH_ERROR_DOES_NOT_EXIST ; + +if (agent->req && agent->req->cb) { +struct agent_request *req = agent->req; + +switch (req->type) { +case MESH_AGENT_REQUEST_PUSH : +case MESH_AGENT_REQUEST_TWIST : +case MESH_AGENT_REQUEST_IN_NUMERIC : + number_cb = req->cb; +number_cb (req->user_data, err,0 ); +break ; +case MESH_AGENT_REQUEST_IN_ALPHA : +case MESH_AGENT_REQUEST_STATIC_OOB : +case MESH_AGENT_REQUEST_PRIVATE_KEY : +case MESH_AGENT_REQUEST_PUBLIC_KEY : + key_cb = req->cb; +key_cb (req->user_data, err,NULL ,0 ); +break ; +case MESH_AGENT_REQUEST_BLINK : +case MESH_AGENT_REQUEST_BEEP : +case MESH_AGENT_REQUEST_VIBRATE : +case MESH_AGENT_REQUEST_OUT_NUMERIC : +case MESH_AGENT_REQUEST_OUT_ALPHA : + simple_cb = agent->req->cb; +simple_cb (req->user_data, err); +default : +break ; + } + +l_dbus_message_unref (req->msg); +l_free (req); + } + +l_free (agent->path); +l_free (agent->owner); } -static void response_hexadecimal (const char *input,void *user_data) +void mesh_agent_remove (struct mesh_agent *agent) { -uint8_t buf[MAX_HEXADECIMAL_OOB_LEN ]; +if (!l_queue_find (agents, simple_match, agent)) +return ; + +agent_free (agent); +l_queue_remove (agents, agent); +} -if (!str2hex (input,strlen (input), buf, pending_request.len)) { -bt_shell_printf ("Incorrect input: expecting %d hex octets\n" , - pending_request.len); -try_again (); +void mesh_agent_cleanup (void ) +{ +if (!agents)return ; + +l_queue_destroy (agents, agent_free); + +} + +void mesh_agent_init (void ) +{ +if (!agents) + agents =l_queue_new (); +} + +struct mesh_agent *mesh_agent_create (const char *path,const char *owner, +struct l_dbus_message_iter *properties) +{ +struct mesh_agent *agent; +const char *key, *uri_string; +struct l_dbus_message_iter variant; + + agent = l_new(struct mesh_agent, 1); + +while (l_dbus_message_iter_next_entry (properties, &key, &variant)) { +if (!strcmp (key,"Capabilities" )) { +parse_prov_caps (&agent->caps, &variant); + }else if (!strcmp (key,"URI" )) { +l_dbus_message_iter_get_variant (&variant,"s" , + &uri_string); +/* TODO: compute hash */ + }else if (!strcmp (key,"OutOfBandInfo" )) { +parse_oob_info (&agent->caps, &variant); + } + } + + agent->owner =l_strdup (owner); + agent->path =l_strdup (path); + +l_queue_push_tail (agents, agent); + +return agent; +} + +struct mesh_agent_prov_caps *mesh_agent_get_caps (struct mesh_agent *agent) +{ +if (!agent || !l_queue_find (agents, simple_match, agent)) +return NULL ; + +return &agent->caps; +} + +static struct agent_request *create_request (agent_request_type_t type, +void *cb,void *data) +{ +struct agent_request *req; + + req = l_new(struct agent_request, 1); + + req->type = type; + req->cb = cb; + req->user_data = data; + +return req; +} + +static int get_reply_error (struct l_dbus_message *reply) +{ +const char *name, *desc; + +if (l_dbus_message_is_error (reply)) { + +l_dbus_message_get_error (reply, &name, &desc); +l_error ("Agent failed output action (%s), %s" , name, desc); +return MESH_ERROR_FAILED ; } -if (pending_request.cb) - pending_request.cb (HEXADECIMAL , buf, pending_request.len, - pending_request.user_data); +return MESH_ERROR_NONE ; +} + +static void simple_reply (struct l_dbus_message *reply,void *user_data) +{ +struct mesh_agent *agent = user_data; +struct agent_request *req; +mesh_agent_cb_t cb; +int err; + +if (!l_queue_find (agents, simple_match, agent) || !agent->req) +return ; + + req = agent->req; + + err =get_reply_error (reply); -reset_input_request (); +l_dbus_message_unref (req->msg); + +if (req->cb) { + cb = req->cb; +cb (req->user_data, err); + } + +l_free (req); + agent->req =NULL ; } -static void response_decimal (const char *input,void *user_data) +static void numeric_reply (struct l_dbus_message *reply,void *user_data) { -uint8_t buf[DECIMAL_OOB_LEN ]; +struct mesh_agent *agent = user_data; +struct agent_request *req; +mesh_agent_number_cb_t cb; +uint32_t count; +int err; -if (strlen (input) > pending_request.len) { -bt_shell_printf ("Bad input: expected no more than %d digits\n" , - pending_request.len); -try_again (); +if (!l_queue_find (agents, simple_match, agent) || !agent->req)return ; + + req = agent->req; + + err =get_reply_error (reply); + + count =0 ; + +if (err ==MESH_ERROR_NONE ) { +if (!l_dbus_message_get_arguments (reply,"u" , &count)) { +l_error ("Failed to retrieve numeric input" ); + err =MESH_ERROR_FAILED ; + } + } + +l_dbus_message_unref (req->msg); + +if (req->cb) { + cb = req->cb; +cb (req->user_data, err, count); + } + +l_free (req); + agent->req =NULL ; +} + +static void key_reply (struct l_dbus_message *reply,void *user_data) +{ +struct mesh_agent *agent = user_data; +struct agent_request *req; +mesh_agent_key_cb_t cb; +struct l_dbus_message_iter iter_array; +uint32_t n =0 , expected_len =0 ; +uint8_t buf[64 ]; +int err; + +if (!l_queue_find (agents, simple_match, agent) || !agent->req) +return ; + + req = agent->req; + + err =get_reply_error (reply); + +if (err !=MESH_ERROR_NONE ) + goto done; + +if (!l_dbus_message_get_arguments (reply,"au" , &iter_array)) { +l_error ("Failed to retrieve key input" ); + err =MESH_ERROR_FAILED ; + goto done; } -l_put_be32 (atoi (input), buf); +if (!l_dbus_message_iter_get_fixed_array (&iter_array, buf, &n)) { +l_error ("Failed to retrieve key input" ); + err =MESH_ERROR_FAILED ; + goto done; + } -if (pending_request.cb) - pending_request.cb (DECIMAL , buf,DECIMAL_OOB_LEN , - pending_request.user_data); +if (req->type ==MESH_AGENT_REQUEST_PRIVATE_KEY ) + expected_len =32 ; +else if (MESH_AGENT_REQUEST_PUBLIC_KEY ) + expected_len =64 ; +else + expected_len =16 ; + +if (n != expected_len) { +l_error ("Bad response length: %u (need %u)" , n, expected_len); + err =MESH_ERROR_FAILED ; + n =0 ; + } -reset_input_request (); +done: +l_dbus_message_unref (req->msg); + +if (req->cb) { + cb = req->cb; +cb (req->user_data, err, buf, n); + } + +l_free (req); + agent->req =NULL ; } -static void response_ascii (const char *input,void *user_data) +static int output_request (struct mesh_agent *agent,const char *action, +agent_request_type_t type,uint32_t cnt, +void *cb,void *user_data) { -if (pending_request.cb) - pending_request.cb (ASCII , (uint8_t *) input,strlen (input), - pending_request.user_data); +struct l_dbus *dbus =dbus_get_bus (); +struct l_dbus_message *msg; +struct l_dbus_message_builder *builder; + +if (!l_queue_find (agents, simple_match, agent)) +return MESH_ERROR_DOES_NOT_EXIST ; -reset_input_request (); +if (agent->req) +return MESH_ERROR_BUSY ; + + agent->req =create_request (type, cb, user_data); + msg =l_dbus_message_new_method_call (dbus, agent->owner, agent->path, +MESH_PROVISION_AGENT_INTERFACE , +"DisplayNumeric" ); + + builder =l_dbus_message_builder_new (msg); +l_dbus_message_builder_append_basic (builder,'s' , action); +l_dbus_message_builder_append_basic (builder,'u' , &cnt); +l_dbus_message_builder_finalize (builder); +l_dbus_message_builder_destroy (builder); + +l_debug ("Send DisplayNumeric request to %s %s" , + agent->owner, agent->path); + +l_dbus_send_with_reply (dbus_get_bus (), msg, simple_reply, agent, +NULL ); + + agent->req->msg =l_dbus_message_ref (msg); + +return MESH_ERROR_NONE ; } -static bool request_hexadecimal (uint16_t len) +static int prompt_input (struct mesh_agent *agent,const char *action, +agent_request_type_t type,bool numeric, +void *cb,void *user_data) { -if (len >MAX_HEXADECIMAL_OOB_LEN ) -return false; +struct l_dbus *dbus =dbus_get_bus (); +struct l_dbus_message *msg; +struct l_dbus_message_builder *builder; +const char *method_name; +l_dbus_message_func_t reply_cb; + +if (!l_queue_find (agents, simple_match, agent)) +return MESH_ERROR_DOES_NOT_EXIST ; -bt_shell_printf ("Request hexadecimal key (hex %d octets)\n" , len); -bt_shell_prompt_input ("mesh" ,"Enter key (hex number):" , - response_hexadecimal,NULL ); +if (agent->req) +return MESH_ERROR_BUSY ; -return true; + agent->req =create_request (type, cb, user_data); + + method_name = numeric ?"PromptNumeric" :"PromptStatic" ; + + msg =l_dbus_message_new_method_call (dbus, agent->owner, + agent->path, +MESH_PROVISION_AGENT_INTERFACE , + method_name); + + builder =l_dbus_message_builder_new (msg); +l_dbus_message_builder_append_basic (builder,'s' , action); +l_dbus_message_builder_finalize (builder); +l_dbus_message_builder_destroy (builder); + +l_debug ("Send \"%s\" input request to %s %s" , action, + agent->owner, agent->path); + + reply_cb = numeric ? numeric_reply : key_reply; + +l_dbus_send_with_reply (dbus_get_bus (), msg, reply_cb, agent,NULL ); + + agent->req->msg =l_dbus_message_ref (msg); + +return MESH_ERROR_NONE ; } -static uint32_t power_ten (uint8_t power) +static int request_key (struct mesh_agent *agent, +agent_request_type_t type, +void *cb,void *user_data) { -uint32_t ret =1 ; +struct l_dbus *dbus =dbus_get_bus (); +struct l_dbus_message *msg; +const char *method_name; + +if (!l_queue_find (agents, simple_match, agent)) +return MESH_ERROR_DOES_NOT_EXIST ; -while (power--) - ret *=10 ; +if (agent->req) +return MESH_ERROR_BUSY ; -return ret; + agent->req =create_request (type, cb, user_data); + + method_name = (type ==MESH_AGENT_REQUEST_PRIVATE_KEY ) ? +"PrivateKey" :"PublicKey" ; + + msg =l_dbus_message_new_method_call (dbus, agent->owner, + agent->path, +MESH_PROVISION_AGENT_INTERFACE , + method_name); + +l_debug ("Send key request to %s %s" , agent->owner, agent->path); + +l_dbus_send_with_reply (dbus_get_bus (), msg, key_reply, agent,NULL ); + + agent->req->msg =l_dbus_message_ref (msg); + +return MESH_ERROR_NONE ; } -static bool request_decimal (uint16_t len) +int mesh_agent_display_string (struct mesh_agent *agent,const char *str, +mesh_agent_cb_t cb,void *user_data) { -bt_shell_printf ("Request decimal key (0 - %d)\n" ,power_ten (len) -1 ); -bt_shell_prompt_input ("mesh" ,"Enter Numeric key:" , response_decimal, +struct l_dbus *dbus =dbus_get_bus (); +struct l_dbus_message *msg; +struct l_dbus_message_builder *builder; + +if (!l_queue_find (agents, simple_match, agent)) +return MESH_ERROR_DOES_NOT_EXIST ; + +if (agent->req) +return MESH_ERROR_BUSY ; + + agent->req =create_request (MESH_AGENT_REQUEST_OUT_ALPHA , + cb, user_data); + msg =l_dbus_message_new_method_call (dbus, agent->owner, agent->path, +MESH_PROVISION_AGENT_INTERFACE , +"DisplayString" ); + + builder =l_dbus_message_builder_new (msg); +l_dbus_message_builder_append_basic (builder,'s' , str); +l_dbus_message_builder_finalize (builder); +l_dbus_message_builder_destroy (builder); + +l_debug ("Send DisplayString request to %s %s" , + agent->owner, agent->path); + +l_dbus_send_with_reply (dbus_get_bus (), msg, simple_reply, agent,NULL ); -return true; + agent->req->msg =l_dbus_message_ref (msg); + +return MESH_ERROR_NONE ; + } -static bool request_ascii (uint16_t len) +int mesh_agent_display_number (struct mesh_agent *agent,bool initiator, +uint8_t action,uint32_t count, +mesh_agent_cb_t cb,void *user_data) { -if (len >MAX_ASCII_OOB_LEN ) -return false; +const char *str_type; +agent_request_type_t type; + + type = action; + +if (initiator) + type = action +MESH_AGENT_REQUEST_PUSH ; + +if (type >=L_ARRAY_SIZE (cap_table)) +return MESH_ERROR_INVALID_ARGS ; -bt_shell_printf ("Request ASCII key (max characters %d)\n" , len); -bt_shell_prompt_input ("mesh" ,"Enter key (ascii string):" , - response_ascii,NULL ); + str_type = cap_table[type].action; -return true; +return output_request (agent, str_type, type, count, cb, user_data); } -bool agent_input_request (enum oob_type type,uint16_t max_len, -agent_input_cb cb,void *user_data) +int mesh_agent_prompt_number (struct mesh_agent *agent,bool initiator, +uint8_t action, +mesh_agent_number_cb_t cb, +void *user_data) { -bool result; +const char *str_type; +agent_request_type_t type; -if (pending_request.type !=NONE ) -return false; + type = action; -switch (type) { -case HEXADECIMAL : - result =request_hexadecimal (max_len); -break ; -case DECIMAL : - result =request_decimal (max_len); -break ; -case ASCII : - result =request_ascii (max_len); -break ; -case NONE : -case OUTPUT : -default : -return false; - }; +if (!initiator) + type = action +MESH_AGENT_REQUEST_PUSH ; -if (result) { - pending_request.type = type; - pending_request.len = max_len; - pending_request.cb = cb; - pending_request.user_data = user_data; +if (type >=L_ARRAY_SIZE (cap_table)) +return MESH_ERROR_INVALID_ARGS ; -return true; - } + str_type = cap_table[type].action; + +return prompt_input (agent, str_type, type, true, cb, user_data); +} -return false; +int mesh_agent_prompt_alpha (struct mesh_agent *agent,mesh_agent_key_cb_t cb, +void *user_data) +{ +return prompt_input (agent,"in-alpha" ,MESH_AGENT_REQUEST_IN_ALPHA , + false, cb, user_data); } -static void response_output (const char *input,void *user_data) +int mesh_agent_request_static (struct mesh_agent *agent,mesh_agent_key_cb_t cb, +void *user_data) { -reset_input_request (); +return prompt_input (agent,"static-oob" ,MESH_AGENT_REQUEST_STATIC_OOB , + false, cb, user_data); } -bool agent_output_request (const char *str) +int mesh_agent_request_private_key (struct mesh_agent *agent, +mesh_agent_key_cb_t cb,void *user_data) { -if (pending_request.type !=NONE ) -return false; +return request_key (agent,MESH_AGENT_REQUEST_PRIVATE_KEY , cb, + user_data); - pending_request.type =OUTPUT ; -bt_shell_prompt_input ("mesh" , str, response_output,NULL ); -return true; } -void agent_output_request_cancel (void ) +int mesh_agent_request_public_key (struct mesh_agent *agent, +mesh_agent_key_cb_t cb,void *user_data) { -if (pending_request.type !=OUTPUT ) +return request_key (agent,MESH_AGENT_REQUEST_PUBLIC_KEY , cb, + user_data); +} + +void mesh_agent_cancel (struct mesh_agent *agent) +{ +struct l_dbus *dbus =dbus_get_bus (); +struct l_dbus_message *msg; + +if (!l_queue_find (agents, simple_match, agent))return ; - pending_request.type =NONE ; -bt_shell_release_prompt ("" ); + msg =l_dbus_message_new_method_call (dbus, agent->owner, agent->path, +MESH_PROVISION_AGENT_INTERFACE , +"Cancel" ); +l_dbus_send (dbus, msg); }
mesh/agent.h +48 -21
83 lines not on this page · raw message
Signature · 1 line
2.14.5
PATCH v6 20/26 mesh: restructure App Key storage
In reply to Brian GixFrom: Inga Stotland <[email protected]>
Implements App key specific processing including Replay Protection and Key Updating.
--- mesh/appkey.c | 19 ++++++++++--------- mesh/appkey.h | 1 - 2 files changed, 10 insertions(+), 10 deletions(-)
mesh/appkey.c +10 -9
@@ -15,7 +15,6 @@* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * -* */ #ifdef HAVE_CONFIG_H
@@ -24,6 +23,7 @@#define _GNU_SOURCE#include <ell/ell.h> +#include <json-c/json.h> #include "mesh/mesh-defs.h"
@@ -31,7 +31,7 @@#include "mesh/node.h" #include "mesh/net.h" #include "mesh/crypto.h" -#include "mesh/display.h" +#include "mesh/util.h" #include "mesh/model.h" #include "mesh/storage.h" #include "mesh/appkey.h"
@@ -206,12 +206,12 @@ bool appkey_msg_in_replay_cache(struct mesh_net *net, uint16_t idx, }if (seq < msg->seq) { -l_info ("Ignoring packet with lower sequence number" ); +l_debug ("Ignoring packet with lower sequence number" );return true; }if (seq == msg->seq) { -l_info ("Message already processed (duplicate)" ); +l_debug ("Message already processed (duplicate)" );return true; }
@@ -302,6 +302,7 @@ bool appkey_key_init(struct mesh_net *net, uint16_t net_idx, uint16_t app_idx,return false; key->net_idx = net_idx; + key->app_idx = app_idx;if (key_value && !set_key (key, app_idx, key_value, false))return false;
@@ -392,14 +393,14 @@ int appkey_key_add(struct mesh_net *net, uint16_t net_idx, uint16_t app_idx,return MESH_STATUS_SUCCESS ;if (!update) { -l_info ("Failed to add key: index already stored %x" , +l_debug ("Failed to add key: index already stored %x" , (net_idx <<16 ) | app_idx);return MESH_STATUS_IDX_ALREADY_STORED ; } }if (!key) { -if (l_queue_length (app_keys) <=MAX_APP_KEYS ) +if (!(l_queue_length (app_keys) <MAX_APP_KEYS ))return MESH_STATUS_INSUFF_RESOURCES ; key =app_key_new ();
@@ -411,7 +412,7 @@ int appkey_key_add(struct mesh_net *net, uint16_t net_idx, uint16_t app_idx,return MESH_STATUS_INSUFF_RESOURCES ; } -if (!storage_local_app_key_add (net, net_idx, app_idx, new_key, +if (!storage_app_key_add (net, net_idx, app_idx, new_key, false)) {appkey_key_free (key);return MESH_STATUS_STORAGE_FAIL ;
@@ -424,7 +425,7 @@ int appkey_key_add(struct mesh_net *net, uint16_t net_idx, uint16_t app_idx,if (!set_key (key, app_idx, new_key, true))return MESH_STATUS_INSUFF_RESOURCES ; -if (!storage_local_app_key_add (net, net_idx, app_idx, new_key, +if (!storage_app_key_add (net, net_idx, app_idx, new_key, true))return MESH_STATUS_STORAGE_FAIL ; }
@@ -457,7 +458,7 @@ int appkey_key_delete(struct mesh_net *net, uint16_t net_idx,l_queue_remove (app_keys, key);appkey_key_free (key); -if (!storage_local_app_key_del (net, net_idx, app_idx)) +if (!storage_app_key_del (net, net_idx, app_idx))return MESH_STATUS_STORAGE_FAIL ;return MESH_STATUS_SUCCESS ;
mesh/appkey.h +0 -1
@@ -15,7 +15,6 @@* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * -* */ /* TODO: get this number from configuration */
Signature · 1 line
2.14.5
PATCH v6 21/26 mesh: Clean-up Comment style
In reply to Brian Gix--- mesh/friend.c | 76 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 38 insertions(+), 38 deletions(-)
mesh/friend.c +38 -38
@@ -34,7 +34,7 @@#include "mesh/net.h" #include "mesh/crypto.h" #include "mesh/model.h" -#include "mesh/display.h" +#include "mesh/util.h" #include "mesh/friend.h"
@@ -78,7 +78,7 @@ static void response_timeout(struct l_timeout *timeout, void *user_data)struct frnd_negotiation *neg = user_data;/* LPN did not choose us */ -l_info ("Did not win negotiation for %4.4x" , neg->low_power_node); +l_debug ("Did not win negotiation for %4.4x" , neg->low_power_node);net_key_unref (neg->key_id);l_queue_remove (frnd_negotiations, neg);
@@ -177,13 +177,13 @@ void friend_request(struct mesh_net *net, uint16_t src,uint8_t minCache = (minReq >>0 ) &7 ;int32_t rsp_delay; -l_info ("RSSI of Request: %d dbm" , rssi); -l_info ("Delay: %d ms" , delay); -l_info ("Poll Timeout of Request: %d ms" , timeout *100 ); -l_info ("Previous Friend: %4.4x" , prev); -l_info ("Num Elem: %2.2x" , num_ele); -l_info ("Cache Requested: %d" ,cache_size (minCache)); -l_info ("Cache to offer: %d" , frnd_cache_size); +l_debug ("RSSI of Request: %d dbm" , rssi); +l_debug ("Delay: %d ms" , delay); +l_debug ("Poll Timeout of Request: %d ms" , timeout *100 ); +l_debug ("Previous Friend: %4.4x" , prev); +l_debug ("Num Elem: %2.2x" , num_ele); +l_debug ("Cache Requested: %d" ,cache_size (minCache)); +l_debug ("Cache to offer: %d" , frnd_cache_size);/* Determine our own suitability before * deciding to participate in negotiation
@@ -224,7 +224,7 @@ void friend_request(struct mesh_net *net, uint16_t src,* of 1, bit zero and additional 0.5 */ rsp_delay = -(rssi * scaling[rssiScale]); -l_info ("RSSI Factor: %d ms" , rsp_delay /10 ); +l_debug ("RSSI Factor: %d ms" , rsp_delay /10 );/* Relay Window (Positive Factor, larger values == more time) * Scaling factor 0-3 == multiplier of 1.0 - 2.5
@@ -232,7 +232,7 @@ void friend_request(struct mesh_net *net, uint16_t src,* of 1, bit zero and additional 0.5 */ rsp_delay += frnd_relay_window * scaling[winScale]; -l_info ("Win Size Factor: %d ms" , +l_debug ("Win Size Factor: %d ms" , (frnd_relay_window * scaling[winScale]) /10 );/* Normalize to ms */
@@ -244,7 +244,7 @@ void friend_request(struct mesh_net *net, uint16_t src,else if (rsp_delay >MAX_RESP_DELAY ) rsp_delay =MAX_RESP_DELAY ; -l_info ("Total Response Delay: %d ms" , rsp_delay); +l_debug ("Total Response Delay: %d ms" , rsp_delay);/* Add in 100ms delay before start of "Offer Period" */ rsp_delay +=RESPONSE_DELAY ;
@@ -261,7 +261,7 @@ void friend_clear_confirm(struct mesh_net *net, uint16_t src,struct frnd_negotiation *neg =l_queue_remove_if (frnd_negotiations, match_by_lpn,L_UINT_TO_PTR (lpn)); -l_info ("Friend Clear confirmed %4.4x (cnt %4.4x)" , lpn, lpnCounter); +l_debug ("Friend Clear confirmed %4.4x (cnt %4.4x)" , lpn, lpnCounter);if (!neg)return ;
@@ -276,7 +276,7 @@ static void friend_poll_timeout(struct l_timeout *timeout, void *user_data)struct mesh_friend *frnd = user_data;if (mesh_friend_clear (frnd->net, frnd)) -l_info ("Friend Poll Timeout %4.4x" , frnd->dst); +l_debug ("Friend Poll Timeout %4.4x" , frnd->dst);l_timeout_remove (frnd->timeout); frnd->timeout =NULL ;
@@ -343,7 +343,7 @@ void friend_clear(struct mesh_net *net, uint16_t src, uint16_t lpn,return ; } -l_info ("Friend Cleared %4.4x (%4.4x)" , lpn, lpnCounter); +l_debug ("Friend Cleared %4.4x (%4.4x)" , lpn, lpnCounter);l_put_be16 (lpn, msg +1 );l_put_be16 (lpnCounter, msg +3 );
@@ -369,11 +369,11 @@ static void clear_retry(struct l_timeout *timeout, void *user_data)if (secs && ((secs <<1 ) < neg->poll_timeout/10 )) { neg->receive_delay++; -l_info ("Try FRND_CLR again in %d seconds (total timeout %d)" , +l_debug ("Try FRND_CLR again in %d seconds (total timeout %d)" , secs, neg->poll_timeout/10 );l_timeout_modify (neg->timeout, secs); }else { -l_info ("FRND_CLR timed out %d" , secs); +l_debug ("FRND_CLR timed out %d" , secs);l_timeout_remove (timeout);l_queue_remove (frnd_negotiations, neg);l_free (neg);
@@ -407,7 +407,7 @@ static void friend_delay_rsp(struct l_timeout *timeout, void *user_data) seqZero &=SEQ_ZERO_MASK ; -l_info ("Fwd ACK pkt %6.6x-%8.8x" , +l_debug ("Fwd ACK pkt %6.6x-%8.8x" , pkt->u.one[0 ].seq, pkt->iv_index);
@@ -420,7 +420,7 @@ static void friend_delay_rsp(struct l_timeout *timeout, void *user_data) }else { -l_info ("Fwd CTL pkt %6.6x-%8.8x" , +l_debug ("Fwd CTL pkt %6.6x-%8.8x" , pkt->u.one[0 ].seq, pkt->iv_index);
@@ -442,7 +442,7 @@ static void friend_delay_rsp(struct l_timeout *timeout, void *user_data)else len = pkt->last_len; -l_info ("Fwd FRND pkt %6.6x" , +l_debug ("Fwd FRND pkt %6.6x" , pkt->u.s12[pkt->cnt_out].seq);print_packet ("Frnd-Msg" , pkt->u.s12[pkt->cnt_out].data, len);
@@ -462,7 +462,7 @@ static void friend_delay_rsp(struct l_timeout *timeout, void *user_data) update:/* No More Data -- send Update message with md = false */ net_seq =mesh_net_get_seq_num (net); -l_info ("Fwd FRND UPDATE %6.6x with MD == 0" , net_seq); +l_debug ("Fwd FRND UPDATE %6.6x with MD == 0" , net_seq); frnd->last = frnd->seq;mesh_net_get_snb_state (net, upd +1 , &iv_index);
@@ -488,7 +488,7 @@ void friend_poll(struct mesh_net *net, uint16_t src, bool seq,if (neg && !neg->clearing) {uint8_t msg[5 ] = {NET_OP_FRND_CLEAR }; -l_info ("Won negotiation for %4.4x" , neg->low_power_node); +l_debug ("Won negotiation for %4.4x" , neg->low_power_node);/* This call will clean-up and replace if already friends */ frnd = mesh_friend_new(net, src, neg->num_ele,
@@ -695,7 +695,7 @@ void frnd_offer(struct mesh_net *net, uint16_t src, uint8_t window, {struct frnd_offers *offer; -l_info ("RSSI of Offer: %d dbm" , l_rssi); +l_debug ("RSSI of Offer: %d dbm" , l_rssi);/* Ignore RFU window value 0 */ if (window ==0 )
@@ -735,7 +735,7 @@ static void frnd_negotiated_to(struct l_timeout *timeout, void *user_data) {struct mesh_net *net = user_data; -l_info ("frnd_negotiated_to" ); +l_debug ("frnd_negotiated_to" );if (!mesh_net_get_friend (net)) {l_timeout_remove (poll_period_to); poll_period_to =NULL ;
@@ -776,7 +776,7 @@ void frnd_poll(struct mesh_net *net, bool retry) seq = !seq;mesh_net_set_frnd_seq (net, seq); }else if (!(poll_cnt--)) { -l_info ("Lost Friendship with %4.4x" , old_friend); +l_debug ("Lost Friendship with %4.4x" , old_friend);l_timeout_remove (poll_period_to); poll_period_to =NULL ;frnd_poll_cancel (net);
@@ -790,7 +790,7 @@ void frnd_poll(struct mesh_net *net, bool retry)if (poll_retry_to)l_timeout_remove (poll_retry_to); -l_info ("TX-FRIEND POLL %d" , seq); +l_debug ("TX-FRIEND POLL %d" , seq); msg[1 ] = seq; net_seq =mesh_net_get_seq_num (net); mesh_net_transport_send(net, key_id, true,
@@ -858,7 +858,7 @@ static void req_timeout(struct l_timeout *timeout, void *user_data)l_free (best);return ; }else if (!best) { -l_info ("No Offers Received" ); +l_debug ("No Offers Received" );return ; }
@@ -884,7 +884,7 @@ static void req_timeout(struct l_timeout *timeout, void *user_data) old_keys_only: -l_info ("Winning offer %4.4x RSSI: %ddb Window: %dms Cache sz: %d" , +l_debug ("Winning offer %4.4x RSSI: %ddb Window: %dms Cache sz: %d" , best->src, best->local_rssi, best->window, best->cache);
@@ -930,23 +930,23 @@ void frnd_request_friend(struct mesh_net *net, uint8_t cache, offers =l_queue_new (); msg[n++] =NET_OP_FRND_REQUEST ; - msg[n] = cache &0x07 ;// MinRequirements - Cache - msg[n++] |= (offer_delay &0x0f ) <<3 ;// Offer Delay - poll_period_ms = (timeout *300 ) /4 ;// 3/4 of the time in ms -l_put_be32 (timeout, msg + n);// PollTimeout - msg[n++] = delay;// ReceiveDelay + msg[n] = cache &0x07 ;/* MinRequirements - Cache */ + msg[n++] |= (offer_delay &0x0f ) <<3 ;/* Offer Delay */ + poll_period_ms = (timeout *300 ) /4 ;/* 3/4 of the time in ms */ +l_put_be32 (timeout, msg + n);/* PollTimeout */ + msg[n++] = delay;/* ReceiveDelay */ n +=3 ; -l_put_be16 (old_friend, msg + n);// PreviousAddress +l_put_be16 (old_friend, msg + n);/* PreviousAddress */ n +=2 ; - msg[n++] =mesh_net_get_num_ele (net);// NumElements -l_put_be16 (cnt +1 , msg + n);// Next counter + msg[n++] =mesh_net_get_num_ele (net);/* NumElements */ +l_put_be16 (cnt +1 , msg + n);/* Next counter */ n +=2 ;print_packet ("Tx-NET_OP_FRND_REQUEST" , msg, n);mesh_net_transport_send (net,0 , false,mesh_net_get_iv_index (net),0 ,0 ,0 ,FRIENDS_ADDRESS , msg, n); -l_timeout_create_ms (1000 , req_timeout, net,NULL );// 1000 ms +l_timeout_create_ms (1000 , req_timeout, net,NULL );/* 1000 ms */ mesh_net_set_friend (net,0 ); cnt++; }
@@ -1036,7 +1036,7 @@ void frnd_key_refresh(struct mesh_net *net, uint8_t phase)case 0 :case 3 :if (new_lpn_id) { -l_info ("LPN Retiring KeySet %d" , lpn_key_id); +l_debug ("LPN Retiring KeySet %d" , lpn_key_id);net_key_unref (lpn_key_id); lpn_key_id = new_lpn_id; }
Signature · 1 line
2.14.5
PATCH v6 22/26 mesh: Update for DBus API and multi-node support
In reply to Brian GixFrom: Inga Stotland <[email protected]>
Main function with high level plumbing for incoming D-Bus messaging, and optional control of storage locations.
--- mesh/main.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 67 insertions(+), 8 deletions(-)
mesh/main.c +67 -8
@@ -15,7 +15,6 @@* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * -* */ #ifdef HAVE_CONFIG_H
@@ -33,11 +32,15 @@#include <sys/stat.h> #include <ell/ell.h> +#include <dbus/dbus.h> +#include <json-c/json.h> +#include "lib/bluetooth.h" #include "lib/mgmt.h" #include "mesh/mesh.h" #include "mesh/net.h" +#include "mesh/dbus.h" #include "mesh/storage.h" static const struct option main_options[] = {
@@ -56,12 +59,46 @@ static void usage(void) "\tmeshd [options]\n");l_info ("Options:\n" "\t--index <hcinum> Use specified controller\n" -"\t--config Configuration file\n" +"\t--config Configuration directory\n" "\t--nodetach Run in foreground\n" "\t--debug Enable debug output\n" "\t--help Show %s information\n" , __func__); } +static void do_debug (const char *str,void *user_data) +{ +const char *prefix = user_data; + +l_info ("%s%s" , prefix, str); +} + +static void request_name_callback (struct l_dbus *dbus,bool success, +bool queued,void *user_data) +{ +l_info ("Request name %s" , + success ?"success" :"failed" ); + +if (success) +dbus_init (dbus); +else +l_main_quit (); +} + +static void ready_callback (void *user_data) +{ +struct l_dbus *dbus = user_data; + +l_info ("D-Bus ready" ); +l_dbus_name_acquire (dbus,BLUEZ_MESH_NAME , false, false, false, + request_name_callback,NULL ); + +} + +static void disconnect_callback (void *user_data) +{ +l_main_quit (); +} +static void signal_handler (uint32_t signo,void *user_data) {static bool terminated;
@@ -78,8 +115,9 @@ int main(int argc, char *argv[]) {int status;bool detached = true; -struct bt_mesh *mesh =NULL ; -const char *config_file =NULL ; +bool dbus_debug = false; +struct l_dbus *dbus =NULL ; +const char *config_dir =NULL ;int index =MGMT_INDEX_NONE ;if (!l_main_init ())
@@ -91,7 +129,7 @@ int main(int argc, char *argv[])int opt;const char *str; - opt =getopt_long (argc, argv,"i:c:ndh" , main_options,NULL ); + opt =getopt_long (argc, argv,"i:c:ndbh" , main_options,NULL );if (opt <0 )break ;
@@ -117,7 +155,10 @@ int main(int argc, char *argv[])l_debug_enable ("*" );break ;case 'c' : - config_file = optarg; + config_dir = optarg; +break ; +case 'b' : + dbus_debug = true;break ;case 'h' :usage ();
@@ -130,7 +171,7 @@ int main(int argc, char *argv[]) } } -if (!mesh_new (index, config_file)) { +if (!mesh_init (index, config_dir)) {l_error ("Failed to initialize mesh" ); status =EXIT_FAILURE ; goto done;
@@ -138,6 +179,24 @@ int main(int argc, char *argv[])umask (0077 ); + dbus =l_dbus_new_default (L_DBUS_SYSTEM_BUS ); +if (!dbus) { +l_error ("unable to connect to D-Bus" ); + status =EXIT_FAILURE ; + goto done; + } + +if (dbus_debug) +l_dbus_set_debug (dbus, do_debug,"[DBUS] " ,NULL ); +l_dbus_set_ready_handler (dbus, ready_callback, dbus,NULL ); +l_dbus_set_disconnect_handler (dbus, disconnect_callback,NULL ,NULL ); + +if (!l_dbus_object_manager_enable (dbus)) { +l_error ("Failed to enable Object Manager" ); + status =EXIT_FAILURE ; + goto done; + } +if (detached) {if (daemon (0 ,0 )) {perror ("Failed to start meshd daemon" );
@@ -149,8 +208,8 @@ int main(int argc, char *argv[]) status =l_main_run_with_signal (signal_handler,NULL ); done: -mesh_unref (mesh);mesh_cleanup (); +l_dbus_destroy (dbus);l_main_exit ();return status;
Signature · 1 line
2.14.5
PATCH v6 23/26 mesh: Add default location for Mesh Node storage
In reply to Brian GixFrom: Inga Stotland <[email protected]>
--- configure.ac | 3 +++ 1 file changed, 3 insertions(+)
configure.ac +3 -0
@@ -364,6 +364,9 @@ AC_DEFINE_UNQUOTED(CONFIGDIR, "${configdir}", [Directory for the configuration files]) AC_SUBST(CONFIGDIR, "${configdir}") +AC_DEFINE_UNQUOTED(MESH_STORAGEDIR, "${storagedir}/mesh", + [Directory for the mesh daemon storage files]) + AC_ARG_ENABLE(android, AC_HELP_STRING([--enable-android], [enable BlueZ for Android]), [enable_android=${enableval}])
Signature · 1 line
2.14.5
PATCH v6 24/26 mesh: Sample Provisioning Agent
In reply to Brian GixFrom: Inga Stotland <[email protected]>
--- test/agent.py | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100755 test/agent.py
test/agent.py new file +40 -0
@@ -0,0 +1,40 @@ +#!/usr/bin/python + +import sys +import dbus +import dbus.service +import dbus.mainloop.glib + +AGENT_IFACE = 'org.bluez.mesh.ProvisionAgent1' +AGENT_PATH = "/mesh/test/agent" + +bus = None + +class Agent(dbus.service.Object): + def __init__(self, bus): + self.path = AGENT_PATH + self.bus = bus + dbus.service.Object.__init__(self, bus, self.path) + + def get_properties(self): + caps = [] + oob = [] + caps.append('out-numeric') + oob.append('other') + return { + AGENT_IFACE: { + 'Capabilities': dbus.Array(caps, 's'), + 'OutOfBandInfo': dbus.Array(oob, 's') + } + } + + def get_path(self): + return dbus.ObjectPath(self.path) + + @dbus.service.method(AGENT_IFACE, in_signature="", out_signature="") + def Cancel(self): + print("Cancel") + + @dbus.service.method(AGENT_IFACE, in_signature="su", out_signature="") + def DisplayNumeric(self, type, value): + print("DisplayNumeric type=", type, " number=", value)
Signature · 1 line
2.14.5
PATCH v6 25/26 mesh: Sample On/Off Client and Server
In reply to Brian GixFrom: Inga Stotland <[email protected]>
--- test/example-onoff-client | 288 ++++++++++++++++++++++++++++++++++++ test/example-onoff-server | 365 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 653 insertions(+) create mode 100644 test/example-onoff-client create mode 100644 test/example-onoff-server
test/example-onoff-client new file +288 -0
@@ -0,0 +1,288 @@ +#!/usr/bin/env python3 + +import sys +import struct +import numpy +import dbus +import dbus.service +import dbus.exceptions + +try: + from gi.repository import GObject +except ImportError: + import gobject as GObject +from dbus.mainloop.glib import DBusGMainLoop + +MESH_SERVICE_NAME = 'org.bluez.mesh' +DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties' +DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager' + +MESH_NETWORK_IFACE = 'org.bluez.mesh.Network1' +MESH_NODE_IFACE = 'org.bluez.mesh.Node1' +MESH_ELEMENT_IFACE = 'org.bluez.mesh.Element1' + +VENDOR_ID_NONE = 0xffff + +app = None +bus = None +mainloop = None +node = None +token = numpy.uint64(0x76bd4f2372477600) + +def unwrap(item): + if isinstance(item, dbus.Boolean): + return bool(item) + if isinstance(item, (dbus.UInt16, dbus.Int16, dbus.UInt32, dbus.Int32, + dbus.UInt64, dbus.Int64)): + return int(item) + if isinstance(item, dbus.Byte): + return bytes([int(item)]) + if isinstance(item, dbus.String): + return item + if isinstance(item, (dbus.Array, list, tuple)): + return [unwrap(x) for x in item] + if isinstance(item, (dbus.Dictionary, dict)): + return dict([(unwrap(x), unwrap(y)) for x, y in item.items()]) + + print('Dictionary item not handled') + print(type(item)) + return item + +def attach_app_cb(node_path, dict_array): + print('Mesh application registered ', node_path) + print(type(node_path)) + print(type(dict_array)) + print(dict_array) + + els = unwrap(dict_array) + print("Get Elements") + for el in els: + print(el) + idx = struct.unpack('b', el[0])[0] + print('Configuration for Element ', end='') + print(idx) + models = el[1] + + element = app.get_element(idx) + element.set_model_config(models) + + obj = bus.get_object(MESH_SERVICE_NAME, node_path) + global node + node = dbus.Interface(obj, MESH_NODE_IFACE) + +def error_cb(error): + print('D-Bus call failed: ' + str(error)) + +def generic_reply_cb(): + print('D-Bus call done') + +def interfaces_removed_cb(object_path, interfaces): + if not mesh_net: + return + + if object_path == mesh_net[2]: + print('Service was removed') + mainloop.quit() + +class Application(dbus.service.Object): + + def __init__(self, bus): + self.path = '/example' + self.elements = [] + dbus.service.Object.__init__(self, bus, self.path) + + def get_path(self): + return dbus.ObjectPath(self.path) + + def add_element(self, element): + self.elements.append(element) + + def get_element(self, idx): + for ele in self.elements: + if ele.get_index() == idx: + return ele + + @dbus.service.method(DBUS_OM_IFACE, out_signature='a{oa{sa{sv}}}') + def GetManagedObjects(self): + response = {} + print('GetManagedObjects') + for element in self.elements: + response[element.get_path()] = element.get_properties() + return response + +class Element(dbus.service.Object): + PATH_BASE = '/example/ele' + + def __init__(self, bus, index): + self.path = self.PATH_BASE + format(index, '02x') + print(self.path) + self.models = [] + self.bus = bus + self.index = index + dbus.service.Object.__init__(self, bus, self.path) + + def _get_sig_models(self): + ids = [] + for model in self.models: + id = model.get_id() + vendor = model.get_vendor() + if vendor == VENDOR_ID_NONE: + ids.append(id) + return ids + + def get_properties(self): + return { + MESH_ELEMENT_IFACE: { + 'Index': dbus.Byte(self.index), + 'Models': dbus.Array( + self._get_sig_models(), signature='q') + } + } + + def add_model(self, model): + model.set_path(self.path) + self.models.append(model) + + def get_index(self): + return self.index + + def set_model_config(self, config): + print('Set element models config') + + @dbus.service.method(MESH_ELEMENT_IFACE, + in_signature="qqbay", out_signature="") + def MessageReceived(self, source, key, is_sub, data): + print('Message Received on Element ', end='') + print(self.index) + for model in self.models: + model.process_message(source, key, data) + + @dbus.service.method(MESH_ELEMENT_IFACE, + in_signature="qa{sv}", out_signature="") + + def UpdateModelConfiguration(self, model_id, config): + print('UpdateModelConfig ', end='') + print(hex(model_id)) + for model in self.models: + if model_id == model.get_id(): + model.set_config(config) + return + + @dbus.service.method(MESH_ELEMENT_IFACE, + in_signature="", out_signature="") + def get_path(self): + return dbus.ObjectPath(self.path) + +class Model(): + def __init__(self, model_id): + self.cmd_ops = [] + self.model_id = model_id + self.vendor = VENDOR_ID_NONE + self.path = None + + def set_path(self, path): + self.path = path + + def get_id(self): + return self.model_id + + def get_vendor(self): + return self.vendor + + def process_message(self, source, key, data): + print('Model process message') + + def set_publication(self, period): + self.period = period + + def set_bindings(self, bindings): + self.bindings = bindings + + def set_config(self, config): + if 'Bindings' in config: + self.bindings = config.get('Bindings') + print('Bindings: ', end='') + print(self.bindings) + if 'PublicationPeriod' in config: + self.set_publication(config.get('PublicationPeriod')) + print('Model publication period ', end='') + print(self.pub_period, end='') + print(' ms') + +class OnOffClient(Model): + def __init__(self, model_id): + Model.__init__(self, model_id) + self.cmd_ops = { 0x8201, # get + 0x8202, # set + 0x8203 } # set unacknowledged + print('OnOff Client') + + def _reply_cb(state): + print('State ', end=''); + print(state) + + def _send_message(self, dest, key, data, reply_cb): + print('OnOffClient send data') + node.Send(self.path, dest, key, data, reply_handler=reply_cb, + error_handler=error_cb) + + def get_state(self, dest, key): + opcode = 0x8201 + data = struct.pack('<H', opcode) + self._send_message(dest, key, data, self._reply_cb) + + def set_state(self, dest, key, state): + opcode = 0x8202 + data = struct.pack('<HB', opcode, state) + self._send_message(dest, key, data, self._reply_cb) + + def process_message(self, source, key, data): + print('OnOffClient process message len ', end = '') + datalen = len(data) + print(datalen) + + if datalen!=3: + return + + opcode, state=struct.unpack('<HB',bytes(data)) + if opcode != 0x8202 : + print('Bad opcode ', end='') + print(hex(opcode)) + return + + print('Got state ', end = '') + print(hex(state)) + +def attach_app_error_cb(error): + print('Failed to register application: ' + str(error)) + mainloop.quit() + +def main(): + + DBusGMainLoop(set_as_default=True) + + global bus + bus = dbus.SystemBus() + global mainloop + global app + + mesh_net = dbus.Interface(bus.get_object(MESH_SERVICE_NAME, + "/org/bluez/mesh"), + MESH_NETWORK_IFACE) + mesh_net.connect_to_signal('InterfacesRemoved', interfaces_removed_cb) + + app = Application(bus) + first_ele = Element(bus, 0x00) + first_ele.add_model(OnOffClient(0x1001)) + app.add_element(first_ele) + + mainloop = GObject.MainLoop() + + print('Attach') + mesh_net.Attach(app.get_path(), token, + reply_handler=attach_app_cb, + error_handler=attach_app_error_cb) + mainloop.run() + +if __name__ == '__main__': + main()
test/example-onoff-server new file +365 -0
365 lines not on this page · raw message
Signature · 1 line
2.14.5
PATCH v6 26/26 mesh: Sample Mesh Joiner (provision acceptor)
In reply to Brian GixFrom: Inga Stotland <[email protected]>
--- test/test-join | 408 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 408 insertions(+) create mode 100644 test/test-join
test/test-join new file +408 -0
@@ -0,0 +1,408 @@ +#!/usr/bin/env python3 + +import sys +import struct +import numpy +import dbus +import dbus.service +import dbus.exceptions + +from threading import Timer +import time + +try: + from gi.repository import GObject +except ImportError: + import gobject as GObject +from dbus.mainloop.glib import DBusGMainLoop + +import agent + +MESH_SERVICE_NAME = 'org.bluez.mesh' +DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties' +DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager' + +MESH_NETWORK_IFACE = 'org.bluez.mesh.Network1' +MESH_NODE_IFACE = 'org.bluez.mesh.Node1' +MESH_APPLICATION_IFACE = 'org.bluez.mesh.Application1' +MESH_ELEMENT_IFACE = 'org.bluez.mesh.Element1' + +APP_COMPANY_ID = 0x05f1 +APP_PRODUCT_ID = 0x0001 +APP_VERSION_ID = 0x0001 + +VENDOR_ID_NONE = 0xffff + +mesh_net = None +app = None +bus = None +mainloop = None +node = None + +token = None + +def generic_error_cb(error): + print('D-Bus call failed: ' + str(error)) + +def generic_reply_cb(): + print('D-Bus call done') + +def unwrap(item): + if isinstance(item, dbus.Boolean): + return bool(item) + if isinstance(item, (dbus.UInt16, dbus.Int16, + dbus.UInt32, dbus.Int32, + dbus.UInt64, dbus.Int64)): + return int(item) + if isinstance(item, dbus.Byte): + return bytes([int(item)]) + if isinstance(item, dbus.String): + return item + if isinstance(item, (dbus.Array, list, tuple)): + return [unwrap(x) for x in item] + if isinstance(item, (dbus.Dictionary, dict)): + return dict([(unwrap(x), unwrap(y)) for x, y in item.items()]) + + print('Dictionary item not handled') + print(type(item)) + return item + +def join_cb(): + print('Join procedure started') + +def join_error_cb(reason): + print('Join procedure failed: ', reason) + +def attach_app_cb(node_path, dict_array): + print('Mesh application registered ', node_path) + + obj = bus.get_object(MESH_SERVICE_NAME, node_path) + + global node + node = dbus.Interface(obj, MESH_NODE_IFACE) + + els = unwrap(dict_array) + print("Get Elements") + + for el in els: + idx = struct.unpack('b', el[0])[0] + print('Configuration for Element ', end='') + print(idx) + + models = el[1] + element = app.get_element(idx) + element.set_model_config(models) + +def attach_app_error_cb(error): + print('Failed to register application: ' + str(error)) + mainloop.quit() + +def attach(token): + print('Attach') + mesh_net.Attach(app.get_path(), token, + reply_handler=attach_app_cb, + error_handler=attach_app_error_cb) + +def interfaces_removed_cb(object_path, interfaces): + if not mesh_net: + return + + if object_path == mesh_net[2]: + print('Service was removed') + mainloop.quit() + +def send_response(path, dest, key, data): + print('send response ', end='') + print(data) + node.Send(path, dest, key, data, reply_handler=generic_reply_cb, + error_handler=generic_error_cb) + +def send_publication(path, model_id, data): + print('send publication ', end='') + print(data) + node.Publish(path, model_id, data, reply_handler=generic_reply_cb, + error_handler=generic_error_cb) + +class PubTimer(): + def __init__(self): + self.seconds = None + self.func = None + self.thread = None + self.busy = False + + def _timeout_cb(self): + self.func() + self.busy = True + self._schedule_timer() + self.busy =False + + def _schedule_timer(self): + self.thread = Timer(self.seconds, self._timeout_cb) + self.thread.start() + + def start(self, seconds, func): + self.func = func + self.seconds = seconds + if not self.busy: + self._schedule_timer() + + def cancel(self): + print('Cancel timer') + if self.thread is not None: + print('Cancel thread') + self.thread.cancel() + self.thread = None + +class Application(dbus.service.Object): + + def __init__(self, bus): + self.path = '/example' + self.agent = None + self.elements = [] + dbus.service.Object.__init__(self, bus, self.path) + + def set_agent(self, agent): + self.agent = agent + + def get_path(self): + return dbus.ObjectPath(self.path) + + def add_element(self, element): + self.elements.append(element) + + def get_element(self, idx): + for ele in self.elements: + if ele.get_index() == idx: + return ele + + def get_properties(self): + return { + MESH_APPLICATION_IFACE: { + 'CompanyID': dbus.UInt16(APP_COMPANY_ID), + 'ProductID': dbus.UInt16(APP_PRODUCT_ID), + 'VersionID': dbus.UInt16(APP_VERSION_ID) + } + } + + @dbus.service.method(DBUS_OM_IFACE, out_signature='a{oa{sa{sv}}}') + + def GetManagedObjects(self): + response = {} + print('GetManagedObjects') + response[self.path] = self.get_properties() + response[self.agent.get_path()] = self.agent.get_properties() + for element in self.elements: + response[element.get_path()] = element.get_properties() + return response + + @dbus.service.method(MESH_APPLICATION_IFACE, + in_signature="t", out_signature="") + + def JoinComplete(self, value): + global token + print('JoinComplete ', value) + + token = value + attach(token) + + @dbus.service.method(MESH_APPLICATION_IFACE, + in_signature="s", out_signature="") + + def JoinFailed(self, value): + print('JoinFailed ', value) + token = value + +class Element(dbus.service.Object): + PATH_BASE = '/example/ele' + + def __init__(self, bus, index): + self.path = self.PATH_BASE + format(index, '02x') + print(self.path) + self.models = [] + self.bus = bus + self.index = index + dbus.service.Object.__init__(self, bus, self.path) + + def _get_sig_models(self): + ids = [] + for model in self.models: + id = model.get_id() + vendor = model.get_vendor() + if vendor == VENDOR_ID_NONE: + ids.append(id) + return ids + + def get_properties(self): + return { + MESH_ELEMENT_IFACE: { + 'Index': dbus.Byte(self.index), + 'Models': dbus.Array(self._get_sig_models(), 'q') + } + } + + def add_model(self, model): + model.set_path(self.path) + self.models.append(model) + + def get_index(self): + return self.index + + def set_model_config(self, configs): + print('Set element models config') + for config in configs: + mod_id = config[0] + self.UpdateModelConfiguration(mod_id, config[1]) + + @dbus.service.method(MESH_ELEMENT_IFACE, + in_signature="qqbay", out_signature="") + def MessageReceived(self, source, key, is_sub, data): + print('Message Received on Element ', end='') + print(self.index) + for model in self.models: + model.process_message(source, key, data) + + @dbus.service.method(MESH_ELEMENT_IFACE, + in_signature="qa{sv}", out_signature="") + + def UpdateModelConfiguration(self, model_id, config): + print('UpdateModelConfig ', end='') + print(hex(model_id)) + for model in self.models: + if model_id == model.get_id(): + model.set_config(config) + return + + @dbus.service.method(MESH_ELEMENT_IFACE, + in_signature="", out_signature="") + + def get_path(self): + return dbus.ObjectPath(self.path) + +class Model(): + def __init__(self, model_id): + self.cmd_ops = [] + self.model_id = model_id + self.vendor = VENDOR_ID_NONE + self.bindings = [] + self.pub_period = 0 + self.pub_id = 0 + self.path = None + + def set_path(self, path): + self.path = path + + def get_id(self): + return self.model_id + + def get_vendor(self): + return self.vendor + + def process_message(self, source, key, data): + print('Model process message') + + def set_publication(self, period): + self.pub_period = period + + def set_config(self, config): + if 'Bindings' in config: + self.bindings = config.get('Bindings') + print('Bindings: ', end='') + print(self.bindings) + if 'PublicationPeriod' in config: + self.set_publication(config.get('PublicationPeriod')) + print('Model publication period ', end='') + print(self.pub_period, end='') + print(' ms') + +class OnOffServer(Model): + def __init__(self, model_id): + Model.__init__(self, model_id) + self.cmd_ops = { 0x8201, # get + 0x8202, # set + 0x8203 } # set unacknowledged + + print("OnOff Server ", end="") + self.state = 0 + print('State ', end='') + self.timer = PubTimer() + + def process_message(self, source, key, data): + datalen = len(data) + print('OnOff Server process message len ', datalen) + + if datalen!=2 and datalen!=3: + return + + if datalen==2: + op_tuple=struct.unpack('<H',bytes(data)) + opcode = op_tuple[0] + if opcode != 0x8201: + print(hex(opcode)) + return + print('Get state') + elif datalen==3: + opcode,self.state=struct.unpack('<HB',bytes(data)) + if opcode != 0x8202 and opcode != 0x8203: + print(hex(opcode)) + return + print('Set state: ', end='') + print(self.state) + + rsp_data = struct.pack('<HB', 0x8204, self.state) + send_response(self.path, source, key, rsp_data) + + def publish(self): + print('Publish') + data = struct.pack('B', self.state) + send_publication(self.path, self.model_id, data) + + def set_publication(self, period): + if period == 0: + self.pub_period = 0 + self.timer.cancel() + return + + # We do not handle ms in this example + if period < 1000: + return + + self.pub_period = period + self.timer.start(period/1000, self.publish) + +def main(): + + DBusGMainLoop(set_as_default=True) + + global bus + bus = dbus.SystemBus() + global mainloop + global app + global mesh_net + + mesh_net = dbus.Interface(bus.get_object(MESH_SERVICE_NAME, + "/org/bluez/mesh"), + MESH_NETWORK_IFACE) + mesh_net.connect_to_signal('InterfacesRemoved', interfaces_removed_cb) + + app = Application(bus) + prov_agent = agent.Agent(bus) + app.set_agent(prov_agent) + first_ele = Element(bus, 0x00) + first_ele.add_model(OnOffServer(0x1000)) + app.add_element(first_ele) + + mainloop = GObject.MainLoop() + + print('Join') + caps = ["out-numeric"] + oob = ["other"] + uuid = bytearray.fromhex("0a0102030405060708090A0B0C0D0E0F") + print(uuid) + mesh_net.Join(app.get_path(), uuid, + reply_handler=join_cb, + error_handler=join_error_cb) + + mainloop.run() + +if __name__ == '__main__': + main()
Signature · 1 line
2.14.5