Major rewrite for Multi-Node and DBus
Subsystems (2)
v2 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.
Brian Gix (12):
mesh: Staging for Mesh DBus API rewrite
mesh: Delete obsolete files
mesh: Rewite Network layer for multiple nodes
mesh: Direction agnostic PB-Adv implimentation
mesh: Acceptor side provisioning implimentation
mesh: Initiator side provisioning implimentation
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
mesh: Enable building Mesh Daemon
Inga Stotland (18):
mesh: Utilities for DBus support
mesh: Internal errors
mesh: Re-write storage for Multiple Nodes
mesh: Rewrite Node handling for multiple nodes
mesh: centralize generic utilities
mesh: Re-architect for DBus API
mesh: Make config model handle multiple nodes
mesh: Multi node Config Server model
mesh: Restrusture 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: Add structural changes to for mesh
mesh: Sample Provisioning Agent
mesh: Sample On/Off Client and Server
mesh: Sample Mesh Joiner (provision acceptor)
Makefile.mesh | 27 +-
configure.ac | 5 +
mesh/agent.c | 665 ++++++++++++++++----
mesh/agent.h | 71 ++-
mesh/appkey.c | 17 +-
mesh/cfgmod-server.c | 173 +++---
mesh/cfgmod.h | 2 +-
mesh/config/composition.json | 44 --
mesh/dbus.c | 181 ++++++
mesh/dbus.h | 40 ++
mesh/display.c | 64 --
mesh/error.h | 35 ++
mesh/friend.c | 76 +--
mesh/main.c | 73 ++-
mesh/mesh-db.c | 454 +++++++++-----
mesh/mesh-db.h | 6 +-
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 | 625 ++++++++++++++-----
mesh/mesh.h | 27 +-
mesh/model.c | 811 +++++++++++++++++-------
mesh/model.h | 66 +-
mesh/net.c | 293 +++------
mesh/net.h | 31 +-
mesh/node.c | 1338 +++++++++++++++++++++++++++++++++-------
mesh/node.h | 42 +-
mesh/pb-adv.c | 444 +++++++++++++
mesh/{display.h => pb-adv.h} | 13 +-
mesh/prov-acceptor.c | 711 +++++++++++++++++++++
mesh/prov-initiator.c | 650 +++++++++++++++++++
mesh/prov.c | 722 ----------------------
mesh/prov.h | 14 +-
mesh/provision.c | 1162 ----------------------------------
mesh/provision.h | 112 +++-
mesh/storage.c | 570 ++++++++---------
mesh/storage.h | 39 +-
mesh/test/agent.py | 40 ++
mesh/test/example-onoff-client | 288 +++++++++
mesh/test/example-onoff-server | 365 +++++++++++
mesh/test/test-join | 408 ++++++++++++
mesh/util.c | 26 +
mesh/util.h | 1 +
44 files changed, 7188 insertions(+), 3700 deletions(-)
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 mesh/test/agent.py
create mode 100644 mesh/test/example-onoff-client
create mode 100644 mesh/test/example-onoff-server
create mode 100644 mesh/test/test-joinSignature · 1 line
2.14.5
PATCH v2 1/30 mesh: Staging for Mesh DBus API rewrite
--- Makefile.am | 1 - 1 file changed, 1 deletion(-)
Makefile.am +0 -1
@@ -303,7 +303,6 @@ unit_tests = include Makefile.tools include Makefile.obexd include android/Makefile.am -include Makefile.mesh if HID2HCI rulesdir = $(UDEV_DIR)/rules.d
Signature · 1 line
2.14.5
PATCH v2 2/30 mesh: Delete obsolete files
In reply to Brian Gix--- mesh/config/composition.json | 44 -- mesh/display.c | 64 --- mesh/display.h | 28 - mesh/prov.c | 722 -------------------------- mesh/provision.c | 1162 ------------------------------------------ 5 files changed, 2020 deletions(-) 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
mesh/config/composition.json deleted +0 -44
@@ -1,44 +0,0 @@ -{ - "$schema":"file:\/\/\/BlueZ\/MeshD\/local_schema\/mesh.jsonschema", - "meshName":"BT Mesh sample node", - "UUID":"E0ED0F0200000000203C100200000000", - "cid":"0002", - "pid":"0010", - "vid":"0001", - "crpl":"000a", - "proxy":"unsupported", - "friend":"disabled", - "lowPower":"disabled", - "relay":{ - "mode":"enabled" - }, - "elements":[ - { - "elementIndex":0, - "location":"0001", - "models":[ - { - "modelId":"0000" - }, - { - "modelId":"1001" - } - ] - } - ], - "provision": { - "privateKey": "729aa0670d72cd6497502ed473502b037e8803b5c60829a5a3caa219505530ba", - "algorithms": [ 0 ], - "inputOOB": { - "size": 8, - "actions": [ 2, 3] - }, - "outputOOB": { - "size": 8, - "actions": [ 3, 4] - }, - "publicType": false, - "staticType": false - }, - } -}
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 v2 3/30 mesh: Utilities for DBus support
In reply to Brian GixFrom: Inga Stotland <[email protected]>
--- mesh/dbus.c | 181 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ mesh/dbus.h | 40 ++++++++++++++ 2 files changed, 221 insertions(+) create mode 100644 mesh/dbus.c create mode 100644 mesh/dbus.h
mesh/dbus.c new file +181 -0
@@ -0,0 +1,181 @@ +/* +* +* 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 "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" + +struct l_dbus *dbus; + +struct error_entry { +const char *dbus_err; +const char *default_desc; +}; + +/* +* Important: The entries in this table are ordered to enum +* values in mesh_error_t (error.h) +*/ +static struct error_entry 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; +} + +uint32_t dbus_get_byte_array (struct l_dbus_message_iter *array,uint8_t *buf, +uint32_t max_len) +{ +uint32_t i; + +for (i =0 ; i < max_len; i++) { +if (!l_dbus_message_iter_next_entry (array, buf + i)) +break ; + } + +return i; +} + +uint32_t dbus_disconnect_watch_add (struct l_dbus *dbus,const char *name, +l_dbus_watch_func_t callback, +void *user_data) +{ +return l_dbus_add_signal_watch (dbus,"org.freedesktop.DBus" , +"/org/freedesktop/DBus" , +L_DBUS_INTERFACE_DBUS ,"NameOwnerChanged" , +L_DBUS_MATCH_ARGUMENT (0 ), name, +L_DBUS_MATCH_NONE , + callback, user_data); +} + +bool dbus_disconnect_watch_remove (struct l_dbus *dbus,uint32_t id) +{ +return l_dbus_remove_signal_watch (dbus, id); +} + +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 +40 -0
@@ -0,0 +1,40 @@ +/* +* +* 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 ); +uint32_t dbus_disconnect_watch_add (struct l_dbus *dbus,const char *name, +l_dbus_watch_func_t callback, +void *user_data); +bool dbus_disconnect_watch_remove (struct l_dbus *dbus,uint32_t id); +uint32_t dbus_get_byte_array (struct l_dbus_message_iter *array,uint8_t *buf, +uint32_t max_len); +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 v2 4/30 mesh: Internal errors
In reply to Brian GixFrom: Inga Stotland <[email protected]>
--- mesh/error.h | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 mesh/error.h
mesh/error.h new file +35 -0
@@ -0,0 +1,35 @@ +/* +* +* 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 +*/ +typedef enum { +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 , +}mesh_error_t ;
Signature · 1 line
2.14.5
PATCH v2 5/30 mesh: Re-write storage for Multiple Nodes
In reply to Brian GixFrom: Inga Stotland <[email protected]>
--- mesh/storage.c | 570 +++++++++++++++++++++++++-------------------------------- mesh/storage.h | 39 ++-- 2 files changed, 269 insertions(+), 340 deletions(-)
mesh/storage.c +249 -321
@@ -27,6 +27,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 +44,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 bool read_local_node_cb (struct mesh_db_node *db_node,void *user_data) +static const char *storage_dir; +static struct l_queue *node_ids; + +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 +109,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 +139,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 +155,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)) -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; - -if (!net) -return false; - - node =node_create_from_storage (net, db_node, true); - -if (!node) +if (!mesh_db_read_device_key (jnode, key_buf))return false; -mesh_net_local_node_set (net, node, db_node->provisioner); - crpl =node_get_crpl (node); -mesh_net_set_crpl (net, crpl); +node_set_device_key (node, key_buf); - 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 +200,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 +208,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 +229,70 @@ done:return result; } -bool storage_parse_config (struct mesh_net *net,const char *config_name) -{ -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) +bool storage_set_ttl (json_object *jnode,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 +300,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 +365,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 +380,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 +398,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 +20 -19
@@ -18,34 +18,35 @@* */ +#include <json-c/json.h> +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 v2 6/30 mesh: Rewrite Node handling for multiple nodes
In reply to Brian GixFrom: Inga Stotland <[email protected]>
--- mesh/node.c | 1338 +++++++++++++++++++++++++++++++++++++++++++++++++---------- mesh/node.h | 42 +- 2 files changed, 1158 insertions(+), 222 deletions(-)
mesh/node.c +1129 -209
@@ -22,21 +22,40 @@#include <config.h> #endif +#include <stdio.h> #include <sys/time.h> #include <ell/ell.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) { + +/* Preserve the last sequence number */ +storage_write_sequence_number (net,mesh_net_get_seq_num (net)); -l_queue_destroy (nodes, free_node_resources); +if (storage_save_config (node, true,NULL ,NULL )) +l_info ("Saved final config to %s" , node->cfg_file); + } + +if (node->disc_watch) +dbus_disconnect_watch_remove (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 =dbus_disconnect_watch_add (bus, node->owner, + app_disc_cb, node); + 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; + + len =dbus_get_byte_array (&iter_data, data,L_ARRAY_SIZE (data)); +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; + + len =dbus_get_byte_array (&iter_data, data,L_ARRAY_SIZE (data)); +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; + + len =dbus_get_byte_array (&iter_data, data,L_ARRAY_SIZE (data)); +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 -13
80 lines not on this page · raw message
Signature · 1 line
2.14.5
PATCH v2 7/30 mesh: Rewite Network layer for multiple nodes
In reply to Brian Gix--- mesh/net.c | 293 ++++++++++++++++--------------------------------------------- mesh/net.h | 31 ++----- 2 files changed, 83 insertions(+), 241 deletions(-)
mesh/net.c +76 -217
@@ -30,7 +30,6 @@#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 +111,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 +125,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 +134,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 +247,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 +495,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 +643,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 +683,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 +757,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 +954,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 +974,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 +1004,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 +1187,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 +1788,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 +2486,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 +2646,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 +2668,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 +2681,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 +2908,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 +2948,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 +2971,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 +3237,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 +3280,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 +3330,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 +3745,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 +3770,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 +3830,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 -24
@@ -259,9 +259,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 +300,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 +361,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 +371,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 v2 8/30 mesh: Direction agnostic PB-Adv implimentation
In reply to Brian Gix--- 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 v2 9/30 mesh: Acceptor side provisioning implimentation
In reply to Brian Gix--- mesh/prov-acceptor.c | 711 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 711 insertions(+) create mode 100644 mesh/prov-acceptor.c
mesh/prov-acceptor.c new file +711 -0
@@ -0,0 +1,711 @@ +/* +* +* 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); +#if defined(GATT_ENABLED ) +/* TODO: Cleanup GATT bearer if exists */ + else if (prov->transport == PB_GATT) + pb_gatt_unreg(prov->trans_data); +#endif + } + +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 ) { +#if defined(GATT_ENABLED ) +/* TODO: Disable PB-GATT */ +#endif + } + +#if defined(GATT_ENABLED ) + else if (transport == PB_GATT) { +/* TODO: Disable PB-ADV */ +pb_adv_unreg (prov); + } +#endif + + else + 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,mesh_error_t 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,mesh_error_t 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,mesh_error_t 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 defined(GATT_ENABLED ) +/* If we support PB-GATT, that means we need to set up a GATT +* service, and need the existence of bluetoothd, with it's +* own LE capable controller. That is a battle for another day. +* We will *always* support PB-ADV. +*/ +#endif +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 v2 10/30 mesh: Initiator side provisioning implimentation
In reply to Brian Gix--- mesh/prov-initiator.c | 650 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 650 insertions(+) create mode 100644 mesh/prov-initiator.c
mesh/prov-initiator.c new file +650 -0
@@ -0,0 +1,650 @@ +/* +* +* 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,mesh_error_t 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,mesh_error_t 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,mesh_error_t 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 defined(GATT_ENABLED ) +/* If we support PB-GATT, that means we need to set up a GATT +* service, and need the existence of bluetoothd, with it's +* own LE capable controller. That is a battle for another day. +* We will *always* support PB-ADV. +*/ +#endif +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 v2 11/30 mesh: Rewrite Controler interface for full init
In reply to Brian Gix--- 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 v2 12/30 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 v2 13/30 mesh: centralize generic utilities
In reply to Brian GixFrom: Inga Stotland <[email protected]>
--- mesh/util.c | 26 ++++++++++++++++++++++++++ mesh/util.h | 1 + 2 files changed, 27 insertions(+)
mesh/util.c +26 -0
@@ -26,10 +26,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 -0
@@ -22,3 +22,4 @@ 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 v2 14/30 mesh: re-arrange provisioning for DBus API
In reply to Brian Gix--- 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 v2 15/30 mesh: Re-architect for DBus API
In reply to Brian GixFrom: Inga Stotland <[email protected]>
--- mesh/mesh.c | 625 ++++++++++++++++++++++++++++++++++++++++++++++-------------- mesh/mesh.h | 27 ++- 2 files changed, 505 insertions(+), 147 deletions(-)
mesh/mesh.c +487 -138
@@ -36,9 +36,24 @@#include "mesh/node.h" #include "mesh/net.h" #include "mesh/storage.h" -#include "mesh/cfgmod.h" +#include "mesh/prov.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" + +#define MESH_COMP_MAX_LEN 378 + +/* +* 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 +61,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 +113,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 +186,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 +219,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 +227,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 +287,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) +dbus_disconnect_watch_remove (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 +409,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) +dbus_disconnect_watch_remove (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); + + n =dbus_get_byte_array (&iter_uuid, join_pending->uuid,16 ); + +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 =dbus_disconnect_watch_add (dbus, sender, + prov_disc_cb,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 -9
@@ -18,15 +18,24 @@* */ -struct bt_mesh ; -struct mesh_net ; +#define BLUEZ_MESH_NAME "org.bluez.mesh" -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); +#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" + +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 v2 16/30 mesh: Make config model handle multiple nodes
In reply to Brian GixFrom: Inga Stotland <[email protected]>
--- mesh/cfgmod.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
mesh/cfgmod.h +1 -1
@@ -95,4 +95,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 v2 17/30 mesh: Multi node Config Server model
In reply to Brian GixFrom: Inga Stotland <[email protected]>
--- mesh/cfgmod-server.c | 173 ++++++++++++++++++++++++++------------------------- 1 file changed, 88 insertions(+), 85 deletions(-)
mesh/cfgmod-server.c +88 -85
@@ -40,7 +40,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 +60,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 +70,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 +83,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 +133,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 +152,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 +183,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 +212,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 +221,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 +252,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 +271,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 +279,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 +301,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 +324,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 +344,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 +392,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 +429,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 +446,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 +474,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 +489,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 +537,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 +643,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 +653,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 +668,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 +679,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 +695,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 +715,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 +725,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 +733,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 +762,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 +781,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 +790,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 +801,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 +815,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 +850,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 +864,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 +879,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 +913,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 +926,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 +947,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 +982,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 +997,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 +1019,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 +1104,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 +1124,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 +1162,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 +1173,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 +1190,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); }
Signature · 1 line
2.14.5
PATCH v2 18/30 mesh: restructure I/O for multiple nodes
In reply to Brian Gix--- 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 v2 19/30 mesh: Restrusture DB to support multiple nodes
In reply to Brian GixFrom: Inga Stotland <[email protected]>
--- mesh/mesh-db.c | 454 +++++++++++++++++++++++++++++++++++++-------------------- mesh/mesh-db.h | 6 +- 2 files changed, 296 insertions(+), 164 deletions(-)
mesh/mesh-db.c +293 -161
@@ -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 -3
@@ -103,9 +103,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 +122,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 v2 21/30 mesh: DBUS interface for Provisioning Agent
In reply to Brian GixFrom: Inga Stotland <[email protected]>
--- mesh/agent.c | 665 ++++++++++++++++++++++++++++++++++++++++++++++++----------- mesh/agent.h | 71 +++++-- 2 files changed, 593 insertions(+), 143 deletions(-)
mesh/agent.c +542 -123
@@ -22,208 +22,627 @@#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; +}; + +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 } +}; -return true; +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; +mesh_error_t 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 ; -if (!str2hex (input,strlen (input), buf, pending_request.len)) { -bt_shell_printf ("Incorrect input: expecting %d hex octets\n" , - pending_request.len); -try_again (); +agent_free (agent); +l_queue_remove (agents, agent); +} + +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); + } } -if (pending_request.cb) - pending_request.cb (HEXADECIMAL , buf, pending_request.len, - pending_request.user_data); + 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); -reset_input_request (); + req->type = type; + req->cb = cb; + req->user_data = data; + +return req; } -static void response_decimal (const char *input,void *user_data) +static mesh_error_t get_reply_error (struct l_dbus_message *reply) { -uint8_t buf[DECIMAL_OOB_LEN ]; +const char *name, *desc; + +if (l_dbus_message_is_error (reply)) { -if (strlen (input) > pending_request.len) { -bt_shell_printf ("Bad input: expected no more than %d digits\n" , - pending_request.len); -try_again (); +l_dbus_message_get_error (reply, &name, &desc); +l_error ("Agent failed output action (%s), %s" , name, desc); +return MESH_ERROR_FAILED ; + } + +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; +mesh_error_t err; + +if (!l_queue_find (agents, simple_match, agent) || !agent->req)return ; + + req = agent->req; + + err =get_reply_error (reply); + +l_dbus_message_unref (req->msg); + +if (req->cb) { + cb = req->cb; +cb (req->user_data, err); } -l_put_be32 (atoi (input), buf); +l_free (req); + agent->req =NULL ; +} + +static void numeric_reply (struct l_dbus_message *reply,void *user_data) +{ +struct mesh_agent *agent = user_data; +struct agent_request *req; +mesh_agent_number_cb_t cb; +uint32_t count; +mesh_error_t err; + +if (!l_queue_find (agents, simple_match, agent) || !agent->req) +return ; -if (pending_request.cb) - pending_request.cb (DECIMAL , buf,DECIMAL_OOB_LEN , - pending_request.user_data); + req = agent->req; -reset_input_request (); + 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 response_ascii (const char *input,void *user_data) +static void key_reply (struct l_dbus_message *reply,void *user_data) { -if (pending_request.cb) - pending_request.cb (ASCII , (uint8_t *) input,strlen (input), - pending_request.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 ]; +mesh_error_t 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; + } + +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 (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 bool request_hexadecimal (uint16_t len) +static mesh_error_t output_request (struct mesh_agent *agent,const char *action, +agent_request_type_t type,uint32_t cnt, +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; + +if (!l_queue_find (agents, simple_match, agent)) +return MESH_ERROR_DOES_NOT_EXIST ; + +if (agent->req) +return MESH_ERROR_BUSY ; -bt_shell_printf ("Request hexadecimal key (hex %d octets)\n" , len); -bt_shell_prompt_input ("mesh" ,"Enter key (hex number):" , - response_hexadecimal,NULL ); + 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 ); -return true; + agent->req->msg =l_dbus_message_ref (msg); + +return MESH_ERROR_NONE ; } -static uint32_t power_ten (uint8_t power) +static mesh_error_t prompt_input (struct mesh_agent *agent,const char *action, +agent_request_type_t type,bool numeric, +void *cb,void *user_data) { -uint32_t ret =1 ; +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 ; + +if (agent->req) +return MESH_ERROR_BUSY ; + + 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); -while (power--) - ret *=10 ; + reply_cb = numeric ? numeric_reply : key_reply; -return ret; +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 bool request_decimal (uint16_t len) +static mesh_error_t request_key (struct mesh_agent *agent, +agent_request_type_t type, +void *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; +const char *method_name; + +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 (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 ; +} + +mesh_error_t mesh_agent_display_string (struct mesh_agent *agent, +const char *str,mesh_agent_cb_t cb, +void *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 ; + +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) +mesh_error_t 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) +mesh_error_t 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; +mesh_error_t 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) +mesh_error_t 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) +mesh_error_t 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 ) +mesh_error_t 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 +51 -20
83 lines not on this page · raw message
Signature · 1 line
2.14.5
PATCH v2 22/30 mesh: restructure App Key storage
In reply to Brian GixFrom: Inga Stotland <[email protected]>
--- mesh/appkey.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-)
mesh/appkey.c +9 -8
@@ -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 ;
Signature · 1 line
2.14.5
PATCH v2 23/30 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 v2 24/30 mesh: Update for DBus API and multi-node support
In reply to Brian GixFrom: Inga Stotland <[email protected]>
--- mesh/main.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 7 deletions(-)
mesh/main.c +66 -7
@@ -33,11 +33,14 @@#include <sys/stat.h> #include <ell/ell.h> +#include <dbus/dbus.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 v2 25/30 mesh: Add default location for Mesh Node storage
In reply to Brian GixFrom: Inga Stotland <[email protected]>
--- configure.ac | 5 +++++ 1 file changed, 5 insertions(+)
configure.ac +5 -0
@@ -364,6 +364,11 @@ AC_DEFINE_UNQUOTED(CONFIGDIR, "${configdir}", [Directory for the configuration files]) AC_SUBST(CONFIGDIR, "${configdir}") +if (test "${enable_mesh}" = "yes"); then + AC_DEFINE_UNQUOTED(MESH_STORAGEDIR, "${storagedir}/mesh", + [Directory for the storage files]) +fi + AC_ARG_ENABLE(android, AC_HELP_STRING([--enable-android], [enable BlueZ for Android]), [enable_android=${enableval}])
Signature · 1 line
2.14.5
PATCH v2 26/30 mesh: Add structural changes to for mesh
In reply to Brian GixFrom: Inga Stotland <[email protected]>
--- Makefile.mesh | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-)
Makefile.mesh +17 -10
@@ -3,35 +3,42 @@ 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/mesh-defs.h + mesh/dbus.h mesh/dbus.c \ + mesh/agent.h mesh/agent.c \ + mesh/prov-acceptor.c mesh/prov-initiator.c \ + 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) -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) +# +# noinst_PROGRAMS += mesh/btmesh +# +# mesh_btmesh_SOURCES = $(mesh_sources) \ +# mesh/btmesh.c +# +#mesh_btmesh_LDADD = src/shared/ecc.lo src/shared/queue.lo src/shared/io-ell.lo \ +# src/shared/util.lo src/shared/hci.lo src/shared/mgmt.lo \ +# src/libshared-mainloop.la \ +# -lreadline @ELL_LIBS@ -ljson-c + endif
Signature · 1 line
2.14.5
PATCH v2 27/30 mesh: Sample Provisioning Agent
In reply to Brian GixFrom: Inga Stotland <[email protected]>
--- mesh/test/agent.py | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100755 mesh/test/agent.py
mesh/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 v2 28/30 mesh: Sample On/Off Client and Server
In reply to Brian GixFrom: Inga Stotland <[email protected]>
--- mesh/test/example-onoff-client | 288 ++++++++++++++++++++++++++++++++ mesh/test/example-onoff-server | 365 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 653 insertions(+) create mode 100644 mesh/test/example-onoff-client create mode 100644 mesh/test/example-onoff-server
mesh/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()
mesh/test/example-onoff-server new file +365 -0
365 lines not on this page · raw message
Signature · 1 line
2.14.5
PATCH v2 29/30 mesh: Sample Mesh Joiner (provision acceptor)
In reply to Brian GixFrom: Inga Stotland <[email protected]>
--- mesh/test/test-join | 408 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 408 insertions(+) create mode 100644 mesh/test/test-join
mesh/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
PATCH v2 30/30 mesh: Enable building Mesh Daemon
In reply to Brian Gix--- Makefile.am | 1 + 1 file changed, 1 insertion(+)
Makefile.am +1 -0
@@ -303,6 +303,7 @@ unit_tests = include Makefile.tools include Makefile.obexd include android/Makefile.am +include Makefile.mesh if HID2HCI rulesdir = $(UDEV_DIR)/rules.d
Signature · 1 line
2.14.5