linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus
@ 2018-12-18 22:31 Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 01/30] mesh: Staging for Mesh DBus API rewrite Brian Gix
                   ` (30 more replies)
  0 siblings, 31 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, Brian Gix

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.

v4 -- Remove all trace of foreground btmesh app. It is obsolete, and
adds no functionality not also present in the meshd executable.

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 for mesh
  mesh: Sample Provisioning Agent
  mesh: Sample On/Off Client and Server
  mesh: Sample Mesh Joiner (provision acceptor)

 Makefile.mesh                  |   19 +-
 configure.ac                   |    5 +
 mesh/agent.c                   |  665 ++++++++++++++++----
 mesh/agent.h                   |   71 ++-
 mesh/appkey.c                  |   17 +-
 mesh/btmesh.c                  |  181 ------
 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 +
 45 files changed, 7177 insertions(+), 3884 deletions(-)
 delete mode 100644 mesh/btmesh.c
 delete mode 100644 mesh/config/composition.json
 create mode 100644 mesh/dbus.c
 create mode 100644 mesh/dbus.h
 delete mode 100644 mesh/display.c
 create mode 100644 mesh/error.h
 create mode 100644 mesh/pb-adv.c
 rename mesh/{display.h => pb-adv.h} (71%)
 create mode 100644 mesh/prov-acceptor.c
 create mode 100644 mesh/prov-initiator.c
 delete mode 100644 mesh/prov.c
 delete mode 100644 mesh/provision.c
 create mode 100755 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-join

-- 
2.14.5


^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 01/30] mesh: Staging for Mesh DBus API rewrite
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 02/30] mesh: Delete obsolete files Brian Gix
                   ` (29 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, Brian Gix

---
 Makefile.am | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Makefile.am b/Makefile.am
index f84a1faba..7e92977b7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 02/30] mesh: Delete obsolete files
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 01/30] mesh: Staging for Mesh DBus API rewrite Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 03/30] mesh: Utilities for DBus support Brian Gix
                   ` (28 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, Brian Gix

---
 mesh/btmesh.c                |  181 -------
 mesh/config/composition.json |   44 --
 mesh/display.c               |   64 ---
 mesh/display.h               |   28 -
 mesh/prov.c                  |  722 --------------------------
 mesh/provision.c             | 1162 ------------------------------------------
 6 files changed, 2201 deletions(-)
 delete mode 100644 mesh/btmesh.c
 delete mode 100644 mesh/config/composition.json
 delete mode 100644 mesh/display.c
 delete mode 100644 mesh/display.h
 delete mode 100644 mesh/prov.c
 delete mode 100644 mesh/provision.c

diff --git a/mesh/btmesh.c b/mesh/btmesh.c
deleted file mode 100644
index 5b724239c..000000000
--- a/mesh/btmesh.c
+++ /dev/null
@@ -1,181 +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.
- *
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#define _GNU_SOURCE
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <ell/ell.h>
-
-#include "src/shared/shell.h"
-#include "src/shared/mainloop.h"
-
-#include "mesh/mesh.h"
-#include "mesh/net.h"
-
-#define PROMPT COLOR_BLUE "[btmesh]" COLOR_OFF "# "
-
-static struct bt_mesh *mesh;
-
-static const struct option main_options[] = {
-	{ "index",	1,	0, 'i' },
-	{ "config",	1,	0, 'c' },
-	{ "save",	1,	0, 's' },
-	{ 0, 0, 0, 0 }
-};
-
-static const char *index_option;
-static const char *config_option;
-static const char *save_option;
-
-static const char **optargs[] = {
-	&index_option,
-	&config_option,
-	&save_option,
-};
-
-static const char *help[] = {
-	"Specify adapter index",
-	"Specify input configuration file",
-	"Specify output configuration file"
-};
-
-static const struct bt_shell_opt opt = {
-	.options = main_options,
-	.optno = sizeof(main_options) / sizeof(struct option),
-	.optstr = "i:c:s:",
-	.optarg = optargs,
-	.help = help,
-};
-
-static int get_arg_on_off(int argc, char *argv[])
-{
-	if (!strcmp(argv[1], "on") || !strcmp(argv[1], "yes"))
-		return 1;
-
-	if (!strcmp(argv[1], "off") || !strcmp(argv[1], "no"))
-		return 0;
-
-	bt_shell_printf("Invalid argument %s\n", argv[1]);
-	return -1;
-}
-
-static void cmd_beacon(int argc, char *argv[])
-{
-	bool res;
-	int enable;
-
-	enable = get_arg_on_off(argc, argv);
-	if (enable < 0)
-		return;
-
-	res = mesh_net_set_beacon_mode(mesh_get_net(mesh), enable);
-	if (res)
-		bt_shell_printf("Local beacon mode is %s\n",
-				enable > 0 ? "enabled" : "disabled");
-	else
-		bt_shell_printf("Failed to set local beacon mode to %s\n",
-				enable > 0 ? "enabled" : "disabled");
-}
-
-static const struct bt_shell_menu main_menu = {
-	.name = "main",
-	.entries = {
-	{ "beacon",   "<enable>",  cmd_beacon, "Enable/disable beaconing"},
-	{ } },
-};
-
-static int get_index(const char *arg)
-{
-	if (strlen(arg) > 3 && !strncasecmp(arg, "hci", 3))
-		return atoi(&arg[3]);
-	else
-		return atoi(arg);
-}
-
-static void ell_event(int fd, uint32_t events, void *user_data)
-{
-	int timeout = l_main_prepare();
-
-	l_main_iterate(timeout);
-}
-
-int main(int argc, char *argv[])
-{
-	int index;
-	int fd;
-	int status;
-
-	l_log_set_stderr();
-	l_debug_enable("*");
-
-	if (!l_main_init())
-		return -1;
-
-	bt_shell_init(argc, argv, &opt);
-	bt_shell_set_menu(&main_menu);
-
-	if (!index_option) {
-		l_info("Controller index is required");
-		goto fail;
-	}
-
-	if (config_option)
-		l_info("Reading local configuration from %s\n", config_option);
-
-	if (save_option)
-		l_info("Saving local configuration to %s\n", save_option);
-
-	bt_shell_set_prompt(PROMPT);
-
-	index = get_index(index_option);
-
-	l_info("Starting mesh on hci%d\n", index);
-
-	mesh = mesh_new(index, config_option);
-	if (!mesh) {
-		l_info("Failed to create mesh\n");
-		goto fail;
-	}
-
-	if (save_option)
-		mesh_set_output(mesh, save_option);
-
-	fd = l_main_get_epoll_fd();
-	mainloop_add_fd(fd, EPOLLIN, ell_event, NULL, NULL);
-
-	status = bt_shell_attach(fileno(stdin));
-	bt_shell_run();
-
-	mesh_unref(mesh);
-	mesh_cleanup();
-	l_main_exit();
-	return status;
-
-fail:
-	bt_shell_cleanup();
-	return EXIT_FAILURE;
-}
diff --git a/mesh/config/composition.json b/mesh/config/composition.json
deleted file mode 100644
index 20c0d0c3a..000000000
--- a/mesh/config/composition.json
+++ /dev/null
@@ -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
-  },
-   }
-}
diff --git a/mesh/display.c b/mesh/display.c
deleted file mode 100644
index 8238ae849..000000000
--- a/mesh/display.c
+++ /dev/null
@@ -1,64 +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.
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <termios.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
-#include <ell/ell.h>
-
-#include "display.h"
-
-static unsigned int cached_num_columns;
-
-unsigned int num_columns(void)
-{
-	struct winsize ws;
-
-	if (cached_num_columns > 0)
-		return cached_num_columns;
-
-	if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0 || ws.ws_col == 0)
-		cached_num_columns = 80;
-	else
-		cached_num_columns = ws.ws_col;
-
-	return cached_num_columns;
-}
-
-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);
-}
diff --git a/mesh/display.h b/mesh/display.h
deleted file mode 100644
index f5d1f7f79..000000000
--- a/mesh/display.h
+++ /dev/null
@@ -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);
diff --git a/mesh/prov.c b/mesh/prov.c
deleted file mode 100644
index 45ced404c..000000000
--- a/mesh/prov.c
+++ /dev/null
@@ -1,722 +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.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <sys/time.h>
-#include <ell/ell.h>
-
-#include "mesh/mesh-defs.h"
-
-#include "mesh/mesh-io.h"
-#include "mesh/display.h"
-#include "mesh/crypto.h"
-#include "mesh/net.h"
-#include "mesh/prov.h"
-
-#define PB_ADV_MTU	24
-
-#define DEFAULT_CONN_ID	0x00000000
-#define DEFAULT_PROV_MSG_NUM	0x00
-#define DEFAULT_DEV_MSG_NUM	0x80
-
-#define TX_TIMEOUT	30
-
-struct mesh_prov *mesh_prov_new(struct mesh_net *net, uint16_t remote)
-{
-	struct mesh_prov *prov;
-
-	prov = l_new(struct mesh_prov, 1);
-
-	prov->remote = remote;
-	prov->net = net;
-
-	return mesh_prov_ref(prov);
-}
-
-struct mesh_prov *mesh_prov_ref(struct mesh_prov *prov)
-{
-	if (!prov)
-		return NULL;
-
-	__sync_fetch_and_add(&prov->ref_count, 1);
-
-	return prov;
-}
-
-void mesh_prov_unref(struct mesh_prov *prov)
-{
-	struct mesh_io *io;
-	uint8_t type;
-
-	if (!prov)
-		return;
-
-	if (__sync_sub_and_fetch(&prov->ref_count, 1))
-		return;
-
-	io = mesh_net_get_io(prov->net);
-	type = MESH_AD_TYPE_BEACON;
-	mesh_io_send_cancel(io, &type, 1);
-	type = MESH_AD_TYPE_PROVISION;
-	mesh_io_send_cancel(io, &type, 1);
-	mesh_io_deregister_recv_cb(io, MESH_IO_FILTER_PROV);
-	mesh_io_deregister_recv_cb(io, MESH_IO_FILTER_BEACON);
-	l_timeout_remove(prov->tx_timeout);
-
-
-	l_info("Freed Prov Data");
-	l_free(prov);
-}
-
-static void packet_received(struct mesh_prov *prov, const void *data,
-						uint16_t size, uint8_t fcs)
-{
-	if (prov->receive_callback)
-		prov->receive_callback(data, size, prov);
-}
-
-static void send_open_req(struct mesh_prov *prov)
-{
-	struct mesh_io *io;
-	uint8_t open_req[23] = { MESH_AD_TYPE_PROVISION };
-	struct mesh_io_send_info info = {
-		.type = MESH_IO_TIMING_TYPE_GENERAL,
-		.u.gen.interval = 50,
-		.u.gen.cnt = 1,
-		.u.gen.min_delay = 0,
-		.u.gen.max_delay = 0,
-	};
-
-	if (!prov)
-		return;
-
-	io = mesh_net_get_io(prov->net);
-	if (!io)
-		return;
-
-	l_put_be32(prov->conn_id, open_req + 1);
-	open_req[1 + 4] = prov->local_msg_num = 0;
-	open_req[1 + 4 + 1] = 0x03; /* OPEN_REQ */
-	memcpy(open_req + 1 + 4 + 1 + 1, prov->uuid, 16);
-
-	/* print_packet("PB-TX", open_req + 1, sizeof(open_req) - 1); */
-	mesh_io_send_cancel(io, open_req, 1);
-	mesh_io_send(io, &info, open_req, sizeof(open_req));
-}
-
-static void send_open_cfm(struct mesh_prov *prov)
-{
-	struct mesh_io *io;
-	uint8_t open_cfm[7] = { MESH_AD_TYPE_PROVISION };
-	struct mesh_io_send_info info = {
-		.type = MESH_IO_TIMING_TYPE_GENERAL,
-		.u.gen.interval = 50,
-		.u.gen.cnt = 1,
-		.u.gen.min_delay = 0,
-		.u.gen.max_delay = 0,
-	};
-
-	if (!prov)
-		return;
-
-	io = mesh_net_get_io(prov->net);
-	if (!io)
-		return;
-
-	l_put_be32(prov->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_io_send_cancel(io, open_cfm, 1);
-	mesh_io_send(io, &info, open_cfm, sizeof(open_cfm));
-}
-
-static void send_close_ind(struct mesh_prov *prov, uint8_t reason)
-{
-	uint8_t buf[8] = { MESH_AD_TYPE_PROVISION };
-	struct mesh_io *io;
-	struct mesh_io_send_info info = {
-		.type = MESH_IO_TIMING_TYPE_GENERAL,
-		.u.gen.interval = 50,
-		.u.gen.cnt = 3,
-		.u.gen.min_delay = 0,
-		.u.gen.max_delay = 0,
-	};
-
-	if (!prov)
-		return;
-
-	if (prov->bearer == MESH_BEARER_ADV) {
-		io = mesh_net_get_io(prov->net);
-		if (!io)
-			return;
-
-		l_put_be32(prov->conn_id, buf + 1);
-		buf[5] = 0;
-		buf[6] = 0x0B; /* CLOSE_IND */
-		buf[7] = reason;
-
-		/* print_packet("PB-TX", buf + 1, sizeof(buf) - 1); */
-
-		mesh_io_send_cancel(io, buf, 1);
-		mesh_io_send(io, &info, buf, sizeof(buf));
-	}
-
-	prov->bearer = MESH_BEARER_IDLE;
-}
-
-static void tx_timeout(struct l_timeout *timeout, void *user_data)
-{
-	struct mesh_prov *prov = user_data;
-	uint8_t cancel[] = { MESH_AD_TYPE_PROVISION };
-	struct mesh_io *io;
-
-	if (!prov)
-		return;
-
-	l_timeout_remove(prov->tx_timeout);
-	prov->tx_timeout = NULL;
-
-	io = mesh_net_get_io(prov->net);
-	if (!io)
-		return;
-
-	mesh_io_send_cancel(io, cancel, sizeof(cancel));
-
-	l_info("TX timeout");
-	mesh_prov_close(prov, 1);
-}
-
-static void send_adv_segs(struct mesh_prov *prov)
-{
-	struct mesh_io *io = mesh_net_get_io(prov->net);
-	struct mesh_io_send_info info = {
-		.type = MESH_IO_TIMING_TYPE_GENERAL,
-		.u.gen.interval = 50,
-		.u.gen.cnt = MESH_IO_TX_COUNT_UNLIMITED,
-		.u.gen.min_delay = 0,
-		.u.gen.max_delay = 0,
-	};
-	const void *data = prov->packet_buf;
-	uint16_t size = prov->packet_len;
-	uint16_t init_size;
-	uint8_t buf[1 + PB_ADV_MTU + 5] = { MESH_AD_TYPE_PROVISION };
-	uint8_t max_seg;
-	uint8_t consumed;
-	int i;
-
-	if (!size)
-		return;
-
-	mesh_io_send_cancel(io, buf, 1);
-
-	l_put_be32(prov->conn_id, buf + 1);
-	buf[1 + 4] = prov->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[1 + 4 + 1] = max_seg << 2;
-	l_put_be16(size, buf + 1 + 4 + 1 + 1);
-	buf[9] = mesh_crypto_compute_fcs(data, size);
-	memcpy(buf + 1 + 4 + 1 + 1 + 2 + 1, 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_io_send(io, &info, 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_io_send(io, &info, buf, seg_size + 7);
-
-		consumed += seg_size;
-	}
-}
-
-static void send_adv_msg(struct mesh_prov *prov, const void *data,
-								uint16_t size)
-{
-	l_timeout_remove(prov->tx_timeout);
-	prov->tx_timeout = l_timeout_create(TX_TIMEOUT, tx_timeout, prov, NULL);
-
-	memcpy(prov->packet_buf, data, size);
-	prov->packet_len = size;
-
-	send_adv_segs(prov);
-}
-
-static void send_ack(struct mesh_prov *prov)
-{
-	struct mesh_io *io = mesh_net_get_io(prov->net);
-	struct mesh_io_send_info info = {
-		.type = MESH_IO_TIMING_TYPE_GENERAL,
-		.u.gen.interval = 50,
-		.u.gen.cnt = 1,
-		.u.gen.min_delay = 0,
-		.u.gen.max_delay = 0,
-	};
-	uint8_t ack[7] = { MESH_AD_TYPE_PROVISION };
-
-	l_put_be32(prov->conn_id, ack + 1);
-	ack[1 + 4] = prov->last_peer_msg_num;
-	ack[1 + 4 + 1] = 0x01; /* ACK */
-
-	/* print_packet("ADV-ACK", ack + 1, sizeof(ack) - 1); */
-	mesh_io_send(io, &info, ack, sizeof(ack));
-}
-
-static void adv_data_pkt(uint8_t type, const void *pkt, uint8_t size,
-								void *user_data)
-{
-	const uint8_t *data = pkt;
-	struct mesh_prov *prov = user_data;
-	uint16_t offset = 0;
-
-	if ((type & 0x03) == 0x00) {
-		uint8_t last_seg = type >> 2;
-
-		prov->expected_len = l_get_be16(data);
-		prov->expected_fcs = l_get_u8(data + 2);
-
-		/* print_packet("Pkt", pkt, size); */
-		data += 3;
-		size -= 3;
-
-		prov->trans = MESH_TRANS_RX;
-
-		if (prov->expected_len > sizeof(prov->peer_buf)) {
-			l_info("Incoming pkt exceeds storage %d > %ld",
-				prov->expected_len, sizeof(prov->peer_buf));
-			return;
-		} else if (last_seg == 0)
-			prov->trans = MESH_TRANS_IDLE;
-
-		prov->expected_segs = 0xff >> (7 - last_seg);
-		prov->got_segs |= 1;
-		memcpy(prov->peer_buf, data, size);
-
-	} else if ((type & 0x03) == 0x02) {
-		offset = (PB_ADV_MTU - 4) + ((type >> 2) - 1) *
-							(PB_ADV_MTU - 1);
-
-		if (offset + size > prov->expected_len) {
-			l_info("Incoming pkt exceeds agreed len %d + %d > %d",
-					offset, size, prov->expected_len);
-			return;
-		}
-
-		prov->trans = MESH_TRANS_RX;
-
-		l_debug("Processing fragment %u", type & 0x3f);
-
-		prov->got_segs |= 1 << (type >> 2);
-		memcpy(prov->peer_buf + offset, data, size);
-
-	} else if (type == 0x01) {
-		if (prov->send_callback) {
-			void *data = prov->send_data;
-			mesh_prov_send_func_t cb = prov->send_callback;
-
-			prov->trans = MESH_TRANS_IDLE;
-			prov->send_callback = NULL;
-			prov->send_data = NULL;
-
-			cb(true, data);
-		}
-		return;
-	} else
-		return;
-
-	if (prov->got_segs != prov->expected_segs)
-		return;
-
-	/* Validate RXed packet and pass up to Provisioning */
-	if (!mesh_crypto_check_fcs(prov->peer_buf,
-				prov->expected_len,
-				prov->expected_fcs)) {
-		l_debug("Invalid FCS");
-		return;
-	}
-
-	prov->last_peer_msg_num = prov->peer_msg_num;
-	send_ack(prov);
-
-	prov->trans = MESH_TRANS_IDLE;
-
-	packet_received(prov, prov->peer_buf,
-			prov->expected_len, prov->expected_fcs);
-
-	/* Reset Re-Assembly for next packet */
-	prov->expected_len = sizeof(prov->peer_buf);
-	prov->expected_fcs = 0;
-	prov->expected_segs = 0;
-	prov->got_segs = 0;
-
-}
-
-static void adv_bearer_packet(void *user_data, struct mesh_io_recv_info *info,
-					const uint8_t *pkt, uint16_t len)
-{
-	struct mesh_prov *prov = user_data;
-	uint32_t conn_id;
-	uint8_t msg_num;
-	uint8_t type;
-
-	if (len < 6) {
-		l_info("  Too short packet");
-		return;
-	}
-
-	conn_id = l_get_be32(pkt + 1);
-	msg_num = l_get_u8(pkt + 1 + 4);
-	type = l_get_u8(pkt + 1 + 4 + 1);
-
-	/*if (prov->conn_id == conn_id) print_packet("ADV-RX", pkt, len); */
-
-	if (prov->conn_id != DEFAULT_CONN_ID) {
-		if (prov->conn_id != conn_id) {
-			l_debug("rxed unknown conn_id: %8.8x != %8.8x",
-							conn_id, prov->conn_id);
-			return;
-		}
-	} else if (type != 0x03)
-		return;
-
-	/* print_packet("PB-ADV-RX", pkt, len); */
-
-	/* Normalize pkt to start of PROV pkt payload */
-	pkt += 7;
-	len -= 7;
-
-	if (type == 0x07) { /* OPEN_CFM */
-		if (conn_id != prov->conn_id)
-			return;
-
-		if (msg_num != prov->local_msg_num)
-			return;
-
-		l_info("Link open confirmed");
-
-		prov->bearer = MESH_BEARER_ADV;
-		if (prov->open_callback)
-			prov->open_callback(prov->receive_data);
-	} else if (type == 0x01) {
-		if (conn_id != prov->conn_id)
-			return;
-
-		if (msg_num != prov->local_msg_num)
-			return;
-
-		l_debug("Got ACK %d", msg_num);
-		adv_data_pkt(type, pkt, len, user_data);
-	} else if (type == 0x03) {
-		/*
-		 * Ignore if:
-		 * 1. We are already provisioning
-		 * 2. We are not advertising that we are unprovisioned
-		 * 3. Open request not addressed to us
-		 */
-		if (prov->conn_id != DEFAULT_CONN_ID &&
-				prov->conn_id != conn_id)
-			return;
-
-		if (prov->local_msg_num != (DEFAULT_DEV_MSG_NUM - 1))
-			return;
-
-		if (memcmp(pkt, prov->uuid, 16))
-			return;
-
-		l_info("Link open request");
-
-		prov->last_peer_msg_num = 0xFF;
-		prov->bearer = MESH_BEARER_ADV;
-		if (prov->open_callback && prov->conn_id == DEFAULT_CONN_ID)
-			prov->open_callback(prov->receive_data);
-
-		prov->conn_id = conn_id;
-		prov->peer_msg_num = msg_num;
-		send_open_cfm(prov);
-	} else if (type == 0x0B) {
-		if (prov->conn_id != conn_id)
-			return;
-
-		prov->conn_id = DEFAULT_CONN_ID;
-		prov->local_msg_num = 0xFF;
-		prov->peer_msg_num = 0xFF;
-		prov->last_peer_msg_num = 0xFF;
-
-		l_timeout_remove(prov->tx_timeout);
-		prov->tx_timeout = NULL;
-
-		l_info("Link closed notification: %2.2x", pkt[0]);
-
-		if (prov->close_callback)
-			prov->close_callback(prov->receive_data, pkt[0]);
-	} else if ((type & 0x03) == 0x00) {
-		if (prov->conn_id != conn_id)
-			return;
-
-		if (msg_num == prov->last_peer_msg_num) {
-			send_ack(prov);
-			return;
-		}
-
-		prov->peer_msg_num = msg_num;
-
-		l_debug("Processing Data with %u fragments,%d octets",
-						type >> 2, l_get_be16(pkt));
-		adv_data_pkt(type, pkt, len, user_data);
-
-	} else if ((type & 0x03) == 0x02) {
-		if (prov->conn_id != conn_id)
-			return;
-
-		if (msg_num == prov->last_peer_msg_num) {
-			send_ack(prov);
-			return;
-		}
-
-		prov->peer_msg_num = msg_num;
-
-		l_debug("Processing fragment %u", type >> 2);
-		adv_data_pkt(type, pkt, len, user_data);
-	}
-}
-
-static void beacon_packet(void *user_data, struct mesh_io_recv_info *info,
-					const uint8_t *pkt, uint16_t len)
-{
-	struct mesh_prov *prov = user_data;
-	struct mesh_io *io;
-
-	pkt++;
-	len--;
-
-	if (len < 19)
-		return;
-
-	if (!pkt[0])
-		print_packet("UnProv-BEACON-RX", pkt, len);
-
-	/* Ignore devices not matching UUID */
-	if (pkt[0] || memcmp(pkt + 1, prov->uuid, 16))
-		return;
-
-	io = mesh_net_get_io(prov->net);
-	mesh_io_deregister_recv_cb(io, MESH_IO_FILTER_BEACON);
-
-	if ((prov->conn_id != DEFAULT_CONN_ID) ||
-			(prov->bearer != MESH_BEARER_IDLE)) {
-		l_info("PB-ADV: Already Provisioning");
-		return;
-	}
-
-	l_getrandom(&prov->conn_id, sizeof(prov->conn_id));
-	prov->bearer = MESH_BEARER_ADV;
-	send_open_req(prov);
-}
-
-static bool mesh_prov_enable(struct mesh_prov *prov, enum mesh_prov_mode mode,
-							uint8_t uuid[16])
-{
-	const uint8_t pb_adv_data[] = { MESH_AD_TYPE_BEACON, 0 };
-	uint8_t adv_data[62];
-	uint8_t adv_len, type;
-	struct mesh_io *io;
-	struct mesh_io_send_info tx_info = {
-		.type = MESH_IO_TIMING_TYPE_GENERAL,
-		.u.gen.interval = 1000,	/* ms */
-		.u.gen.cnt = 0,		/* 0 == Infinite */
-		.u.gen.min_delay = 0,	/* no delay */
-		.u.gen.max_delay = 0,	/* no delay */
-	};
-
-	if (!prov || !prov->net)
-		return false;
-
-
-	prov->mode = mode;
-	memcpy(prov->uuid, uuid, 16);
-	prov->conn_id = DEFAULT_CONN_ID;
-	io = mesh_net_get_io(prov->net);
-
-	switch (mode) {
-	case MESH_PROV_MODE_NONE:
-		break;
-	case MESH_PROV_MODE_INITIATOR:
-		print_packet("Searching for uuid", uuid, 16);
-		prov->local_msg_num = DEFAULT_PROV_MSG_NUM;
-		prov->peer_msg_num = DEFAULT_DEV_MSG_NUM;
-		mesh_io_register_recv_cb(io, MESH_IO_FILTER_PROV,
-						adv_bearer_packet, prov);
-		mesh_io_register_recv_cb(io, MESH_IO_FILTER_BEACON,
-						beacon_packet, prov);
-		break;
-
-	case MESH_PROV_MODE_ADV_ACCEPTOR:
-		prov->local_msg_num = DEFAULT_DEV_MSG_NUM - 1;
-		prov->peer_msg_num = DEFAULT_PROV_MSG_NUM;
-
-		print_packet("Beaconing as unProvisioned uuid", uuid, 16);
-		adv_len = sizeof(pb_adv_data);
-		memcpy(adv_data, pb_adv_data, adv_len);
-		memcpy(adv_data + adv_len, uuid, 16);
-		adv_len += 16;
-		adv_len += 2;
-		mesh_io_register_recv_cb(io, MESH_IO_FILTER_PROV,
-						adv_bearer_packet, prov);
-		type = MESH_AD_TYPE_BEACON;
-		mesh_io_send_cancel(io, &type, 1);
-		mesh_io_send(io, &tx_info, adv_data, adv_len);
-		break;
-
-	case MESH_PROV_MODE_GATT_CLIENT:
-	case MESH_PROV_MODE_MESH_GATT_CLIENT:
-	case MESH_PROV_MODE_GATT_ACCEPTOR:
-	case MESH_PROV_MODE_MESH_SERVER:
-	case MESH_PROV_MODE_MESH_CLIENT:
-	default:
-		l_error("Unimplemented Prov Mode: %d", mode);
-		break;
-	}
-
-	return true;
-}
-
-bool mesh_prov_listen(struct mesh_net *net, uint8_t uuid[16], uint8_t caps[12],
-					mesh_prov_open_func_t open_callback,
-					mesh_prov_close_func_t close_callback,
-					mesh_prov_receive_func_t recv_callback,
-					void *user_data)
-{
-	struct mesh_prov *prov = mesh_net_get_prov(net);
-
-	if (!prov) {
-		prov = mesh_prov_new(net, 0);
-		if (!prov)
-			return false;
-
-		mesh_net_set_prov(net, prov);
-	}
-
-	prov->open_callback = open_callback;
-	prov->close_callback = close_callback;
-	prov->receive_callback = recv_callback;
-	prov->receive_data = prov; /* TODO: retink the callback placement */
-	memcpy(prov->caps, caps, sizeof(prov->caps));
-
-	prov->trans = MESH_TRANS_IDLE;
-
-
-	return mesh_prov_enable(prov, MESH_PROV_MODE_ADV_ACCEPTOR, uuid);
-}
-
-unsigned int mesh_prov_send(struct mesh_prov *prov,
-					const void *ptr, uint16_t size,
-					mesh_prov_send_func_t send_callback,
-					void *user_data)
-{
-	const uint8_t *data = ptr;
-
-	if (!prov)
-		return 0;
-
-	if (prov->trans != MESH_TRANS_IDLE)
-		return 0;
-
-	if (prov->remote) {
-		/* TODO -- PB-Remote */
-	} else {
-		prov->send_callback = send_callback;
-		prov->send_data = user_data;
-		prov->trans = MESH_TRANS_TX;
-		prov->local_msg_num++;
-		send_adv_msg(prov, data, size);
-	}
-
-	return 1;
-}
-
-bool mesh_prov_close(struct mesh_prov *prov, uint8_t reason)
-{
-	if (!prov)
-		return false;
-
-	prov->local_msg_num = 0;
-	send_close_ind(prov, reason);
-
-	prov->conn_id = DEFAULT_CONN_ID;
-	prov->local_msg_num = 0xFF;
-	prov->peer_msg_num = 0xFF;
-	prov->last_peer_msg_num = 0xFF;
-
-	if (prov->tx_timeout) {
-		l_timeout_remove(prov->tx_timeout);
-
-		/* If timing out, give Close indication 1 second of
-		 * provisioning timing to get final Close indication out
-		 */
-		prov->tx_timeout = l_timeout_create(1, tx_timeout, prov, NULL);
-	}
-
-	if (prov->close_callback)
-		prov->close_callback(prov->receive_data, reason);
-
-	return false;
-}
-
-void mesh_prov_set_addr(struct mesh_prov *prov, uint16_t addr)
-{
-	prov->addr = addr;
-}
-
-uint16_t mesh_prov_get_idx(struct mesh_prov *prov)
-{
-	return prov->net_idx;
-}
diff --git a/mesh/provision.c b/mesh/provision.c
deleted file mode 100644
index 17422ce0a..000000000
--- a/mesh/provision.c
+++ /dev/null
@@ -1,1162 +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.
- *
- */
-
-#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/display.h"
-#include "mesh/net_keys.h"
-#include "mesh/crypto.h"
-#include "mesh/net.h"
-#include "mesh/prov.h"
-#include "mesh/provision.h"
-#include "mesh/node.h"
-
-#define PROV_INVITE	0x00
-#define PROV_CAPS	0x01
-#define PROV_START	0x02
-#define PROV_PUB_KEY	0x03
-#define PROV_INP_CMPLT	0x04
-#define PROV_CONFIRM	0x05
-#define PROV_RANDOM	0x06
-#define PROV_DATA	0x07
-#define PROV_COMPLETE	0x08
-#define PROV_FAILED	0x09
-
-#define PROV_ERR_INVALID_PDU		0x01
-#define PROV_ERR_INVALID_FORMAT		0x02
-#define PROV_ERR_UNEXPECTED_PDU		0x03
-#define PROV_ERR_CONFIRM_FAILED		0x04
-#define PROV_ERR_INSUF_RESOURCE		0x05
-#define PROV_ERR_DECRYPT_FAILED		0x06
-#define PROV_ERR_UNEXPECTED_ERR		0x07
-#define PROV_ERR_CANT_ASSIGN_ADDR	0x08
-
-/* Expected Provisioning PDU sizes */
-static const uint16_t expected_pdu_size[] = {
-	1 + 1,					/* PROV_INVITE */
-	1 + 1 + 2 + 1 + 1 + 1 + 2 + 1 + 2,	/* PROV_CAPS */
-	1 + 1 + 1 + 1 + 1 + 1,			/* PROV_START */
-	1 + 64,					/* PROV_PUB_KEY */
-	1,					/* PROV_INP_CMPLT */
-	1 + 16,					/* PROV_CONFIRM */
-	1 + 16,					/* PROV_RANDOM */
-	1 + 16 + 2 + 1 + 4 + 2 + 8,		/* PROV_DATA */
-	1,					/* PROV_COMPLETE */
-	1 + 1,					/* PROV_FAILED */
-};
-
-static enum {
-	PUB_KEY_TYPE_ephemeral,
-	PUB_KEY_TYPE_available,
-} pub_key_type = PUB_KEY_TYPE_ephemeral;
-
-static enum {
-	AUTH_TYPE_3a,
-	AUTH_TYPE_3b,
-	AUTH_TYPE_3c,
-} prov_auth_type = AUTH_TYPE_3c;
-
-enum {
-	INT_PROV_IDLE,
-	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,
-} int_prov_state = INT_PROV_IDLE;
-
-enum {
-	ACP_PROV_IDLE,
-	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,
-} acp_prov_state = ACP_PROV_IDLE;
-
-static uint8_t prov_expected;
-static int8_t prov_last = -1;
-
-static void int_prov_send_cmplt(bool success, struct mesh_prov *prov);
-static void acp_prov_send_cmplt(bool success, struct mesh_prov *prov);
-
-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 uint8_t u16_highest_bit(uint16_t mask)
-{
-	uint8_t cnt = 0;
-
-	if (!mask)
-		return 0xff;
-
-	while (mask & 0xfffe) {
-		cnt++;
-		mask >>= 1;
-	}
-
-	return cnt;
-}
-
-static void send_prov_start(struct mesh_prov *prov)
-{
-	struct mesh_net *net = prov->net;
-	struct mesh_net_prov_caps *caps = mesh_net_prov_caps_get(net);
-	uint8_t prov_start[6] = { PROV_START };
-
-	memset(prov_start + 1, 0, 1 + 1 + 1 + 1 + 1);
-	if (!(caps->algorithms & 0x0001)) {
-		/* We only support FIPS P-256 Elliptic Curve */
-		l_error("Unrecognized Algorithm %4.4x", caps->algorithms);
-		return;
-	}
-
-	if (caps->pub_type) {
-		/* Prov Step 2b: New device exposed PublicKey OOB */
-		prov_start[2] = 0x01;
-		pub_key_type = PUB_KEY_TYPE_available;
-	} else {
-		pub_key_type = PUB_KEY_TYPE_ephemeral;
-	}
-
-	if (caps->output_size &&
-			caps->output_action) {
-		/* Prov Step 3a: Output OOB used */
-		prov_start[3] = 0x02;
-		prov_start[4] = u16_highest_bit(caps->output_action);
-		prov_start[5] = caps->output_size > 8 ?
-			8 : caps->output_size;
-
-		prov_auth_type = AUTH_TYPE_3a;
-
-	} else if (caps->input_size &&
-			caps->input_action) {
-		/* Prov Step 3b: Input OOB used */
-		prov_start[3] = 0x03;
-		prov_start[4] = u16_highest_bit(caps->input_action);
-		prov_start[5] = caps->input_size > 8 ?
-			8 : caps->input_size;
-
-		prov_auth_type = AUTH_TYPE_3b;
-
-	} else  {
-		if (caps->static_type)
-			prov_start[3] = 0x01;
-
-		/* Prov Step 3c: Static OOB used (or no OOB available) */
-		prov_auth_type = AUTH_TYPE_3c;
-	}
-
-	memcpy(&prov->conf_inputs.start, prov_start + 1,
-					sizeof(prov->conf_inputs.start));
-
-	int_prov_state = INT_PROV_START_SENT;
-	if (pub_key_type == PUB_KEY_TYPE_ephemeral)
-		prov_expected = PROV_PUB_KEY;
-	else if (prov_auth_type == AUTH_TYPE_3b)
-		prov_expected = PROV_INP_CMPLT;
-	else
-		prov_expected = PROV_CONFIRM;
-
-	mesh_prov_send(prov, prov_start, 6,
-			int_prov_send_cmplt, prov);
-
-}
-
-static void calculate_secrets(struct mesh_prov *prov, bool initiator)
-{
-	struct mesh_net *net = prov->net;
-	uint8_t *priv_key = mesh_net_priv_key_get(net);
-	bool test_mode = mesh_net_test_mode(net);
-	uint8_t tmp[64];
-
-	if (initiator) {
-		memcpy(prov->conf_inputs.prv_pub_key,
-					prov->l_public, sizeof(prov->l_public));
-		memcpy(prov->conf_inputs.dev_pub_key,
-					prov->r_public, sizeof(prov->r_public));
-	} else {
-		memcpy(prov->conf_inputs.prv_pub_key,
-					prov->r_public, sizeof(prov->r_public));
-		memcpy(prov->conf_inputs.dev_pub_key,
-					prov->l_public, sizeof(prov->l_public));
-	}
-
-	/* Convert to Mesh byte order */
-	memcpy(tmp, prov->r_public, 64);
-	swap_u256_bytes(tmp);
-	swap_u256_bytes(tmp + 32);
-
-	ecdh_shared_secret(tmp, priv_key, prov->secret);
-
-	/* Convert to Mesh byte order */
-	swap_u256_bytes(prov->secret);
-
-	mesh_crypto_s1(&prov->conf_inputs,
-			sizeof(prov->conf_inputs), prov->conf_salt);
-
-
-	mesh_crypto_prov_conf_key(prov->secret, prov->conf_salt,
-							prov->conf_key);
-
-	if (test_mode) {
-		print_packet("PublicKeyRemote", prov->r_public, 64);
-		print_packet("PublicKeyLocal", prov->l_public, 64);
-		print_packet("PrivateKeyLocal", priv_key, 32);
-		print_packet("ConfirmationInputs", &prov->conf_inputs,
-						sizeof(prov->conf_inputs));
-		print_packet("ECDHSecret", prov->secret,
-						sizeof(prov->secret));
-		print_packet("ConfirmationSalt", prov->conf_salt, 16);
-		print_packet("ConfirmationKey", prov->conf_key,
-						sizeof(prov->conf_key));
-	}
-}
-
-static void send_prov_key(struct mesh_prov *prov,
-					mesh_prov_send_func_t send_callback)
-{
-	uint8_t send_pub_key[65] = { PROV_PUB_KEY };
-
-	memcpy(send_pub_key + 1, prov->l_public, 64);
-	mesh_prov_send(prov, send_pub_key, 65,
-			send_callback, prov);
-}
-
-static void send_prov_data(struct mesh_prov *prov)
-{
-	struct mesh_net *net = prov->net;
-	struct mesh_net_prov_caps *caps = mesh_net_prov_caps_get(net);
-	uint64_t mic;
-	uint32_t iv_index;
-	uint32_t net_key_id;
-	uint8_t snb_flags;
-	uint16_t net_idx = mesh_prov_get_idx(prov);
-	uint8_t prov_data[1 + 16 + 2 + 1 + 4 + 2 + sizeof(mic)] = { PROV_DATA };
-	uint16_t uni_addr = mesh_net_prov_uni(net, caps->num_ele);
-	bool test_mode = mesh_net_test_mode(net);
-
-	/* Calculate Provisioning Data */
-	prov_expected = PROV_COMPLETE;
-	mesh_net_get_snb_state(net, &snb_flags, &iv_index);
-
-	mesh_net_get_key(net, !!(snb_flags & 0x01), net_idx, &net_key_id);
-	net_key_retrieve(net_key_id, prov_data + 1);
-	l_put_be16(net_idx, prov_data + 1 + 16);
-	l_put_u8(snb_flags, prov_data + 1 + 16 + 2);
-	l_put_be32(iv_index, prov_data + 1 + 16 + 2 + 1);
-	l_put_be16(uni_addr, prov_data + 1 + 16 + 2 + 1 + 4);
-
-	if (test_mode)
-		print_packet("Data", prov_data + 1, 16 + 2 + 1 + 4 + 2);
-
-	mesh_crypto_device_key(prov->secret, prov->prov_salt, prov->dev_key);
-	if (test_mode) {
-		print_packet("DevKey", prov->dev_key, 16);
-		print_packet("NetworkKey", prov_data + 1, 16);
-		print_packet("NetworkKey Index", prov_data + 1 + 16, 2);
-		print_packet("SNB Flags", prov_data + 1 + 16 + 2, 1);
-		print_packet("IVindex", prov_data + 1 + 16 + 2 + 1, 4);
-		print_packet("Unicast Addr", prov_data + 1 + 16 + 2 + 1 + 4, 2);
-	}
-
-	mesh_crypto_aes_ccm_encrypt(prov->s_nonce, prov->s_key,
-					NULL, 0,
-					&prov_data[1],
-					sizeof(prov_data) - 1 - sizeof(mic),
-					&prov_data[1],
-					&mic, sizeof(mic));
-	if (test_mode)
-		print_packet("DataEncrypted + mic", prov_data + 1,
-						sizeof(prov_data) - 1);
-
-	int_prov_state = INT_PROV_DATA_SENT;
-	mesh_prov_send(prov, prov_data, sizeof(prov_data),
-			int_prov_send_cmplt, prov);
-	mesh_prov_set_addr(prov, uni_addr);
-}
-
-static void send_prov_conf(struct mesh_prov *prov,
-			mesh_prov_send_func_t send_callback)
-{
-	struct mesh_net *net = prov->net;
-	uint8_t *test_rand = mesh_net_prov_rand(net);
-	uint8_t prov_conf[1 + sizeof(prov->conf)] = { PROV_CONFIRM };
-	bool test_mode = mesh_net_test_mode(net);
-
-	if (test_mode && test_rand[0])
-		memcpy(prov->rand_auth, test_rand, 16);
-	else
-		l_getrandom(prov->rand_auth, 16);
-
-	/* Calculate Confirmation */
-	mesh_crypto_aes_cmac(prov->conf_key, prov->rand_auth,
-				sizeof(prov->rand_auth), prov->conf);
-
-	/* Marshal Confirmation */
-	memcpy(prov_conf + 1, prov->conf, sizeof(prov->conf));
-
-	if (test_mode) {
-		print_packet("ConfirmationKey", prov->conf_key,
-						sizeof(prov->conf_key));
-		print_packet("RandomAuthValue", prov->rand_auth,
-						sizeof(prov->rand_auth));
-		print_packet("Sending Confirmation", prov->conf,
-						sizeof(prov->conf));
-	}
-
-	mesh_prov_send(prov, prov_conf, sizeof(prov_conf),
-					send_callback, prov);
-}
-
-static void send_prov_rand(struct mesh_prov *prov,
-			mesh_prov_send_func_t send_callback)
-{
-	struct mesh_net *net = prov->net;
-	uint8_t prov_rand[17] = { PROV_RANDOM };
-	bool test_mode = mesh_net_test_mode(net);
-
-	/* Marshal Random */
-	memcpy(prov_rand + 1, prov->rand_auth, 16);
-
-	if (test_mode)
-		print_packet("Sending Random", prov->rand_auth, 16);
-
-	mesh_prov_send(prov, prov_rand, sizeof(prov_rand),
-					send_callback, prov);
-}
-
-enum inputType {
-	INP_key,
-	INP_dec,
-	INP_text,
-};
-
-struct input_data {
-	struct mesh_prov *prov;
-	enum inputType type;
-	bool initiator;
-	void *dest;
-	void *user_data;
-	union {
-		struct {
-			uint8_t idx;
-			char data[129];
-		} key;
-		struct {
-			uint64_t value;
-		} dec;
-		struct {
-			uint8_t idx;
-			char str[16];
-		} text;
-	} u;
-};
-
-static void collectInput(struct mesh_prov *prov, char *prompt,
-					enum inputType type, bool initiator,
-					void *dest, void *user_data)
-{
-	struct input_data *inp = l_new(struct input_data, 1);
-
-	inp->prov = prov;
-	inp->type = type;
-	inp->dest = dest;
-	inp->initiator = initiator;
-	inp->user_data = user_data;
-
-	if (prompt)
-		l_info("%s", prompt);
-
-	/* TODO: Request agent get OOB data */
-}
-
-static uint32_t digit_mod(uint8_t power)
-{
-	uint32_t ret = 1;
-
-	while (power--)
-		ret *= 10;
-
-	return ret;
-}
-
-static char *key_type(uint8_t type)
-{
-	switch (type) {
-	case 0x01:
-		return "QR-Code";
-	case 0x02:
-		return "Barcode";
-	case 0x03:
-		return "NFC Tag";
-	case 0x04:
-		return "Printed Number";
-	default:
-		return "unknown Source";
-	}
-}
-
-static void int_prov_send_cmplt(bool success, struct mesh_prov *prov)
-{
-	struct mesh_net *net = prov->net;
-	struct mesh_net_prov_caps *caps = mesh_net_prov_caps_get(net);
-
-	l_debug("Provision sending complete");
-
-	switch (int_prov_state) {
-	case INT_PROV_INVITE_SENT:
-		int_prov_state = INT_PROV_INVITE_ACKED;
-		if (acp_prov_state == ACP_PROV_CAPS_SENT)
-			send_prov_start(prov);
-		break;
-	case INT_PROV_START_SENT:
-		int_prov_state = INT_PROV_START_ACKED;
-		if (pub_key_type == PUB_KEY_TYPE_ephemeral) {
-			int_prov_state = INT_PROV_KEY_SENT;
-			send_prov_key(prov, int_prov_send_cmplt);
-		} else {
-			collectInput(prov, NULL, INP_key, true,
-						prov->r_public, prov);
-			l_info("\n\nEnter key from %s:\n",
-				key_type(caps->pub_type));
-		}
-		break;
-	case INT_PROV_KEY_SENT:
-		int_prov_state = INT_PROV_KEY_ACKED;
-		if (pub_key_type == PUB_KEY_TYPE_ephemeral) {
-			prov_expected = PROV_PUB_KEY;
-			break;
-		}
-
-		/* Start Step 3 */
-		memset(prov->rand_auth + 16, 0, 16);
-		if (prov_auth_type == AUTH_TYPE_3a)
-			collectInput(prov,
-				"\n\nEnter prompted number from device:",
-				INP_dec, true,
-				prov->rand_auth + 32 - sizeof(uint32_t),
-				prov);
-
-		else if (prov_auth_type == AUTH_TYPE_3b) {
-			uint32_t oob_key;
-
-			l_getrandom(&oob_key, sizeof(uint32_t));
-			oob_key %= digit_mod(caps->input_size);
-			l_put_be32(oob_key,
-					prov->rand_auth + 32 -
-					sizeof(uint32_t));
-			l_info("\n\nEnter %d on Device\n", oob_key);
-			prov_expected = PROV_INP_CMPLT;
-
-		} else if (caps->static_type) {
-			collectInput(prov, NULL, INP_text, true,
-					prov->rand_auth + 16, prov);
-			l_info("\n\nstatic OOB str from %s:\n",
-				key_type(caps->static_type));
-
-		} else {
-			int_prov_state = INT_PROV_CONF_SENT;
-			send_prov_conf(prov, int_prov_send_cmplt);
-		}
-
-		break;
-	case INT_PROV_CONF_SENT:
-		int_prov_state = INT_PROV_CONF_ACKED;
-		if (acp_prov_state == ACP_PROV_CONF_SENT) {
-			int_prov_state = INT_PROV_RAND_SENT;
-			prov_expected = PROV_RANDOM;
-			send_prov_rand(prov, int_prov_send_cmplt);
-		}
-		break;
-	case INT_PROV_RAND_SENT:
-		int_prov_state = INT_PROV_RAND_ACKED;
-		if (acp_prov_state == ACP_PROV_RAND_SENT)
-			send_prov_data(prov);
-		break;
-	case INT_PROV_DATA_SENT:
-		int_prov_state = INT_PROV_DATA_ACKED;
-		break;
-	default:
-	case INT_PROV_INVITE_ACKED:
-	case INT_PROV_START_ACKED:
-	case INT_PROV_KEY_ACKED:
-	case INT_PROV_CONF_ACKED:
-	case INT_PROV_RAND_ACKED:
-	case INT_PROV_DATA_ACKED:
-	case INT_PROV_IDLE:
-		break;
-	}
-}
-
-void initiator_prov_open(struct mesh_prov *prov)
-{
-	uint8_t invite[] = { PROV_INVITE, 30 };
-	uint8_t *priv_key;
-
-	l_info("Provisioning link opened");
-
-	priv_key = mesh_net_priv_key_get(prov->net);
-	ecc_make_key(prov->l_public, priv_key);
-
-	int_prov_state = INT_PROV_INVITE_SENT;
-	prov_expected = PROV_CAPS;
-	prov_last = -1;
-	prov->conf_inputs.invite.attention = invite[1];
-	mesh_prov_send(prov, invite, sizeof(invite),
-					int_prov_send_cmplt, prov);
-}
-
-void initiator_prov_close(struct mesh_prov *prov, uint8_t reason)
-{
-	struct mesh_net *net = prov->net;
-	uint32_t iv_index;
-	uint8_t snb_flags;
-
-	l_info("Provisioning link closed");
-
-	/* Get the provisioned node's composition data*/
-	if (reason == 0) {
-		mesh_net_get_snb_state(net, &snb_flags, &iv_index);
-
-		l_info("Save provisioner's DB");
-	}
-}
-
-void initiator_prov_receive(const void *pkt, uint16_t size,
-							struct mesh_prov *prov)
-{
-	struct mesh_net *net = prov->net;
-	struct mesh_net_prov_caps *caps = mesh_net_prov_caps_get(net);
-	bool test_mode = mesh_net_test_mode(net);
-	const uint8_t *data = pkt;
-	uint8_t tmp[16];
-	uint8_t type = *data++;
-	uint8_t err = 0;
-
-
-	l_debug("Provisioning packet received type: %2.2x (%u octets)",
-								type, size);
-
-	if (type == prov_last) {
-		l_error("Ignore repeated %2.2x packet", type);
-		return;
-	} else if ((type > prov_expected || type < prov_last) &&
-						type != PROV_FAILED) {
-		l_error("Expected %2.2x, Got:%2.2x", prov_expected, type);
-		err = PROV_ERR_UNEXPECTED_PDU;
-		goto failure;
-	}
-
-	if (type >= L_ARRAY_SIZE(expected_pdu_size) ||
-					size != expected_pdu_size[type]) {
-		l_error("Expected PDU size %d, Got %d (type: %2.2x)",
-					expected_pdu_size[type], size, type);
-		err = PROV_ERR_INVALID_FORMAT;
-		goto failure;
-	}
-
-	prov_last = type;
-
-	switch (type) {
-	case PROV_CAPS: /* Capabilities */
-		int_prov_state = INT_PROV_INVITE_ACKED;
-		acp_prov_state = ACP_PROV_CAPS_SENT;
-		caps->num_ele = data[0];
-		if (test_mode)
-			l_info("Got Num Ele %d", data[0]);
-
-		caps->algorithms = l_get_be16(data + 1);
-		if (test_mode)
-			l_info("Got alg %d", caps->algorithms);
-
-		caps->pub_type = data[3];
-		if (test_mode)
-			l_info("Got pub_type %d", data[3]);
-
-		caps->static_type = data[4];
-		if (test_mode)
-			l_info("Got static_type %d", data[4]);
-
-		caps->output_size = data[5];
-		if (test_mode)
-			l_info("Got output_size %d", data[5]);
-
-		caps->output_action = l_get_be16(data + 6);
-		if (test_mode)
-			l_info("Got output_action %d", l_get_be16(data + 6));
-
-		caps->input_size = data[8];
-		if (test_mode)
-			l_info("Got input_size %d", data[8]);
-
-		caps->input_action = l_get_be16(data + 9);
-		if (test_mode)
-			l_info("Got input_action %d", l_get_be16(data + 9));
-
-		if (caps->algorithms != 0x0001) {
-			l_error("Unsupported Algorithm");
-			err = PROV_ERR_INVALID_FORMAT;
-			goto failure;
-		}
-
-		memcpy(&prov->conf_inputs.caps, data, 11);
-
-		if (int_prov_state == INT_PROV_INVITE_ACKED)
-			send_prov_start(prov);
-		break;
-
-	case PROV_PUB_KEY: /* Public Key */
-		int_prov_state = INT_PROV_KEY_ACKED;
-		acp_prov_state = ACP_PROV_KEY_SENT;
-		memcpy(prov->r_public, data, 64);
-		calculate_secrets(prov, true);
-		prov_expected = PROV_CONFIRM;
-
-		memset(prov->rand_auth + 16, 0, 16);
-		if (prov_auth_type == AUTH_TYPE_3a) {
-			collectInput(prov,
-				"\n\nEnter number from device:",
-				INP_dec, true,
-				prov->rand_auth + 32 - sizeof(uint32_t),
-				prov);
-
-		} else if (prov_auth_type == AUTH_TYPE_3b) {
-
-			uint32_t oob_key;
-
-			l_getrandom(&oob_key, sizeof(uint32_t));
-			oob_key %= digit_mod(caps->input_size);
-			l_put_be32(oob_key,
-					prov->rand_auth + 32 -
-					sizeof(uint32_t));
-			l_info("\n\nEnter %d on Device\n", oob_key);
-			prov_expected = PROV_INP_CMPLT;
-
-		} else if (caps->static_type) {
-			collectInput(prov, NULL, INP_dec, true,
-					prov->rand_auth + 16, prov);
-			l_info("\n\nstatic OOB str from %s:\n",
-				key_type(caps->static_type));
-
-		} else
-			send_prov_conf(prov, int_prov_send_cmplt);
-		break;
-
-	case PROV_INP_CMPLT: /* Provisioning Input Complete */
-		acp_prov_state = ACP_PROV_INP_CMPLT_SENT;
-		prov_expected = PROV_CONFIRM;
-		send_prov_conf(prov, int_prov_send_cmplt);
-		break;
-
-	case PROV_CONFIRM: /* Confirmation */
-		int_prov_state = INT_PROV_CONF_ACKED;
-		acp_prov_state = ACP_PROV_CONF_SENT;
-		/* RXed Device Confirmation */
-		memcpy(prov->conf, data, sizeof(prov->conf));
-		if (test_mode)
-			print_packet("ConfirmationDevice", prov->conf,
-							sizeof(prov->conf));
-
-		if (int_prov_state == INT_PROV_CONF_ACKED) {
-			prov_expected = PROV_RANDOM;
-			send_prov_rand(prov, int_prov_send_cmplt);
-		}
-		break;
-
-	case PROV_RANDOM: /* Random */
-		int_prov_state = INT_PROV_RAND_ACKED;
-		acp_prov_state = ACP_PROV_RAND_SENT;
-
-		/* Calculate SessionKey while the data is fresh */
-		mesh_crypto_prov_prov_salt(prov->conf_salt,
-						prov->rand_auth, data,
-						prov->prov_salt);
-		mesh_crypto_session_key(prov->secret, prov->prov_salt,
-							prov->s_key);
-		mesh_crypto_nonce(prov->secret, prov->prov_salt, prov->s_nonce);
-		if (test_mode) {
-			print_packet("SessionKey", prov->s_key,
-					sizeof(prov->s_key));
-			print_packet("Nonce", prov->s_nonce,
-					sizeof(prov->s_nonce));
-		}
-
-		/* RXed Device Confirmation */
-		memcpy(prov->rand_auth, data, sizeof(prov->conf));
-		if (test_mode)
-			print_packet("RandomDevice", prov->rand_auth, 16);
-
-		mesh_crypto_aes_cmac(prov->conf_key, prov->rand_auth,
-					sizeof(prov->rand_auth), tmp);
-
-		if (memcmp(tmp, prov->conf, sizeof(prov->conf))) {
-			l_error("Provisioning Failed-Confirm compare)");
-			err = PROV_ERR_CONFIRM_FAILED;
-			goto failure;
-		}
-
-		if (int_prov_state == INT_PROV_RAND_ACKED) {
-			prov_expected = PROV_COMPLETE;
-			send_prov_data(prov);
-		}
-		break;
-
-	case PROV_COMPLETE: /* Complete */
-		l_info("Provisioning Complete");
-		int_prov_state = INT_PROV_IDLE;
-		mesh_prov_close(prov, 0);
-		break;
-
-	case PROV_FAILED: /* Failed */
-		l_error("Provisioning Failed (reason: %d)", data[0]);
-		err = data[0];
-		goto failure;
-
-	default:
-		l_error("Unknown Pkt %2.2x", type);
-		err = PROV_ERR_UNEXPECTED_PDU;
-		goto failure;
-	}
-
-	return;
-
-failure:
-	int_prov_state = INT_PROV_IDLE;
-	mesh_prov_close(prov, err);
-}
-
-static void acp_prov_send_cmplt(bool success, struct mesh_prov *prov)
-{
-	l_debug("Provision sending complete");
-
-	switch (acp_prov_state) {
-	case ACP_PROV_CAPS_SENT:
-		acp_prov_state = ACP_PROV_CAPS_ACKED;
-		if (int_prov_state == INT_PROV_KEY_SENT) {
-			acp_prov_state = ACP_PROV_KEY_SENT;
-			prov_expected = PROV_CONFIRM;
-			send_prov_key(prov, acp_prov_send_cmplt);
-		}
-		break;
-	case ACP_PROV_KEY_SENT:
-		acp_prov_state = ACP_PROV_KEY_ACKED;
-		if (int_prov_state == INT_PROV_CONF_SENT) {
-			acp_prov_state = ACP_PROV_CONF_SENT;
-			prov_expected = PROV_RANDOM;
-			send_prov_conf(prov, acp_prov_send_cmplt);
-		}
-		break;
-	case ACP_PROV_INP_CMPLT_SENT:
-		acp_prov_state = ACP_PROV_INP_CMPLT_ACKED;
-		break;
-	case ACP_PROV_CONF_SENT:
-		acp_prov_state = ACP_PROV_CONF_ACKED;
-		if (int_prov_state == INT_PROV_RAND_SENT) {
-			acp_prov_state = ACP_PROV_RAND_SENT;
-			prov_expected = PROV_DATA;
-			send_prov_rand(prov, acp_prov_send_cmplt);
-		}
-		break;
-	case ACP_PROV_RAND_SENT:
-		acp_prov_state = ACP_PROV_RAND_ACKED;
-		break;
-	case ACP_PROV_CMPLT_SENT:
-		acp_prov_state = ACP_PROV_IDLE;
-		mesh_net_provisioned_set(prov->net, true);
-	default:
-	case ACP_PROV_IDLE:
-	case ACP_PROV_CAPS_ACKED:
-	case ACP_PROV_KEY_ACKED:
-	case ACP_PROV_INP_CMPLT_ACKED:
-	case ACP_PROV_CONF_ACKED:
-	case ACP_PROV_RAND_ACKED:
-	case ACP_PROV_FAIL_SENT:
-		break;
-	}
-}
-
-void acceptor_prov_open(struct mesh_prov *prov)
-{
-	uint8_t *priv_key;
-
-	l_info("Provisioning link opened");
-
-	priv_key = mesh_net_priv_key_get(prov->net);
-	ecc_make_key(prov->l_public, priv_key);
-
-	prov_expected = PROV_INVITE;
-	prov_last = -1;
-}
-
-void acceptor_prov_close(struct mesh_prov *prov, uint8_t reason)
-{
-	l_info("Provisioning link closed");
-	mesh_prov_unref(prov);
-}
-
-static void prov_store_cfm(void *user_data, bool result)
-{
-	struct mesh_prov *prov = user_data;
-	uint8_t out[2];
-
-	if (result) {
-		acp_prov_state = ACP_PROV_CMPLT_SENT;
-		out[0] = PROV_COMPLETE;
-		mesh_prov_send(prov, out, 1,
-				acp_prov_send_cmplt,
-				prov);
-	} else {
-		acp_prov_state = ACP_PROV_FAIL_SENT;
-		out[0] = PROV_FAILED;
-		out[1] = PROV_ERR_INSUF_RESOURCE;
-		mesh_prov_send(prov, out, 2, NULL, NULL);
-	}
-}
-
-void acceptor_prov_receive(const void *pkt, uint16_t size,
-							struct mesh_prov *prov)
-{
-	struct mesh_net *net = prov->net;
-	struct mesh_net_prov_caps *caps = mesh_net_prov_caps_get(net);
-	uint8_t *priv_key = mesh_net_priv_key_get(net);
-	bool test_mode = mesh_net_test_mode(net);
-	bool ret;
-	const uint8_t *data = pkt;
-	uint8_t type = *data++;
-	uint8_t out[129];
-	uint8_t tmp[16];
-	uint8_t rand_dev[16];
-	uint64_t rx_mic, decode_mic;
-
-	l_debug("Provisioning packet received type: %2.2x (%u octets)",
-								type, size);
-
-	if (type == prov_last) {
-		l_error("Ignore repeated %2.2x packet", type);
-		return;
-	} else if (type > prov_expected || type < prov_last) {
-		l_error("Expected %2.2x, Got:%2.2x", prov_expected, type);
-		out[1] = PROV_ERR_UNEXPECTED_PDU;
-		goto failure;
-	}
-
-	if (type >= L_ARRAY_SIZE(expected_pdu_size) ||
-					size != expected_pdu_size[type]) {
-		l_error("Expected PDU size %d, Got %d (type: %2.2x)",
-			size, expected_pdu_size[type], type);
-		out[1] = PROV_ERR_INVALID_FORMAT;
-		goto failure;
-	}
-
-	prov_last = type;
-
-	switch (type) {
-	case PROV_INVITE: /* Prov Invite */
-		int_prov_state = INT_PROV_INVITE_SENT;
-		/* Prov Capabilities */
-		out[0] = PROV_CAPS;
-		out[1] = caps->num_ele;
-		l_put_be16(caps->algorithms, out + 2);
-		out[4] = caps->pub_type;
-		out[5] = caps->static_type;
-		out[6] = caps->output_size;
-		l_put_be16(caps->output_action, out + 7);
-		out[9] = caps->input_size;
-		l_put_be16(caps->input_action, out + 10);
-
-		prov->conf_inputs.invite.attention = data[0];
-		memcpy(&prov->conf_inputs.caps, out + 1,
-				sizeof(prov->conf_inputs.caps));
-
-		acp_prov_state = ACP_PROV_CAPS_SENT;
-		prov_expected = PROV_START;
-		mesh_prov_send(prov, out, sizeof(*caps) + 1,
-				acp_prov_send_cmplt, prov);
-		break;
-
-	case PROV_START: /* Prov Start */
-		if (data[0]) {
-			/* Only Algorithm 0x00 supported */
-			l_error("Invalid Algorithm: %2.2x", data[0]);
-			out[1] = PROV_ERR_INVALID_FORMAT;
-			goto failure;
-		}
-
-		acp_prov_state = ACP_PROV_CAPS_ACKED;
-		int_prov_state = INT_PROV_START_SENT;
-		prov_expected = PROV_PUB_KEY;
-		memcpy(&prov->conf_inputs.start, data,
-				sizeof(prov->conf_inputs.start));
-		if (data[1] == 1 && caps->pub_type) {
-			pub_key_type = PUB_KEY_TYPE_available;
-			ecc_make_key(prov->l_public, priv_key);
-		} else if (data[1] == 0) {
-			pub_key_type = PUB_KEY_TYPE_ephemeral;
-			/* Use Ephemeral Key */
-			l_getrandom(priv_key, 32);
-			ecc_make_key(prov->l_public, priv_key);
-		} else {
-			out[1] = PROV_ERR_INVALID_FORMAT;
-			goto failure;
-		}
-
-		swap_u256_bytes(prov->l_public);
-		swap_u256_bytes(prov->l_public + 32);
-
-		switch (data[2]) {
-		default:
-			out[1] = PROV_ERR_INVALID_FORMAT;
-			goto failure;
-
-		case 0x00:
-		case 0x01:
-			prov_auth_type = AUTH_TYPE_3c;
-			break;
-
-		case 0x02:
-			prov_auth_type = AUTH_TYPE_3a;
-			caps->output_action = 1 << data[3];
-			caps->output_size = data[4];
-			break;
-
-		case 0x03:
-			prov_auth_type = AUTH_TYPE_3b;
-			caps->input_action = 1 << data[3];
-			caps->input_size = data[4];
-			break;
-		}
-		break;
-
-	case PROV_PUB_KEY: /* Public Key */
-		int_prov_state = INT_PROV_KEY_SENT;
-		prov_expected = PROV_CONFIRM;
-		/* Save Key */
-		memcpy(prov->r_public, data, 64);
-		calculate_secrets(prov, false);
-
-		if (pub_key_type == PUB_KEY_TYPE_ephemeral) {
-			acp_prov_state = ACP_PROV_KEY_SENT;
-			send_prov_key(prov, acp_prov_send_cmplt);
-		}
-
-		/* Start Step 3 */
-		memset(prov->rand_auth + 16, 0, 16);
-		if (prov_auth_type == AUTH_TYPE_3a) {
-			uint32_t oob_key;
-
-			l_getrandom(&oob_key, sizeof(uint32_t));
-			oob_key %= digit_mod(caps->output_size);
-			l_put_be32(oob_key,
-				prov->rand_auth + 32 - sizeof(uint32_t));
-			l_info("\n\nEnter %d on Provisioner\n",
-							oob_key);
-
-		} else if (prov_auth_type == AUTH_TYPE_3b) {
-			if (caps->input_action == (1 << 3)) {
-				/* TODO: Collect Text Input data */
-				;
-			} else {
-				/* TODO: Collect Decimal Input data */
-				;
-			}
-
-		} else {
-			if (caps->static_type) {
-				/* TODO: Collect Static Input data */
-				/* (If needed) */
-				;
-			}
-		}
-
-		break;
-
-	case PROV_CONFIRM: /* Confirmation */
-		int_prov_state = INT_PROV_CONF_SENT;
-		acp_prov_state = ACP_PROV_KEY_ACKED;
-		/* RXed Provision Confirmation */
-		memcpy(prov->r_conf, data, sizeof(prov->r_conf));
-		if (test_mode)
-			print_packet("ConfirmationProvisioner",
-					prov->r_conf,
-					sizeof(prov->r_conf));
-
-		if (acp_prov_state == ACP_PROV_KEY_ACKED) {
-			prov_expected = PROV_RANDOM;
-			send_prov_conf(prov, acp_prov_send_cmplt);
-		}
-		break;
-
-	case PROV_RANDOM: /* Random */
-		int_prov_state = INT_PROV_RAND_SENT;
-		acp_prov_state = ACP_PROV_CONF_ACKED;
-
-		/* Calculate Session key while the data is fresh */
-		mesh_crypto_prov_prov_salt(prov->conf_salt, data,
-						prov->rand_auth,
-						prov->prov_salt);
-		mesh_crypto_session_key(prov->secret, prov->prov_salt,
-							prov->s_key);
-		mesh_crypto_nonce(prov->secret, prov->prov_salt, prov->s_nonce);
-
-		if (test_mode) {
-			print_packet("SessionKey", prov->s_key,
-					sizeof(prov->s_key));
-			print_packet("Nonce", prov->s_nonce,
-					sizeof(prov->s_nonce));
-		}
-
-
-		/* Save Local Random data to send after verification */
-		memcpy(rand_dev, prov->rand_auth, 16);
-		/* RXed Provisioner Confirmation */
-		memcpy(prov->rand_auth, data, 16);
-		if (test_mode)
-			print_packet("RandomProvisioner", prov->rand_auth, 16);
-
-		mesh_crypto_aes_cmac(prov->conf_key, prov->rand_auth,
-					sizeof(prov->rand_auth), tmp);
-
-		if (memcmp(tmp, prov->r_conf,
-					sizeof(prov->r_conf))) {
-			l_error("Provisioning Failed-Confirm compare");
-			out[1] = PROV_ERR_CONFIRM_FAILED;
-			goto failure;
-		}
-
-
-		memcpy(prov->rand_auth, rand_dev, 16);
-		if (acp_prov_state == ACP_PROV_CONF_ACKED) {
-			prov_expected = PROV_DATA;
-			send_prov_rand(prov, acp_prov_send_cmplt);
-		}
-		break;
-
-	case PROV_DATA: /* Provisioning Data */
-		int_prov_state = INT_PROV_DATA_SENT;
-		acp_prov_state = ACP_PROV_RAND_ACKED;
-		if (test_mode) {
-			print_packet("DataEncrypted + mic", data, size - 1);
-			print_packet("Rxed-mic", data + 16 + 2 + 1 + 4 + 2, 8);
-		}
-
-		rx_mic = l_get_be64(data + 16 + 2 + 1 + 4 + 2);
-		mesh_crypto_aes_ccm_decrypt(prov->s_nonce, prov->s_key,
-				NULL, 0,
-				data, size - 1, out + 1,
-				&decode_mic, sizeof(decode_mic));
-
-		if (test_mode) {
-			print_packet("Data", out + 1, 16 + 2 + 1 + 4 + 2);
-			l_info("Calc-mic: %16.16lx", decode_mic);
-		}
-
-		if (rx_mic == decode_mic) {
-			mesh_crypto_device_key(prov->secret,
-						prov->prov_salt,
-						prov->dev_key);
-			if (test_mode) {
-				print_packet("DevKey", prov->dev_key, 16);
-				print_packet("NetworkKey", out + 1, 16);
-				print_packet("NetworkKey Index",
-					out + 1 + 16, 2);
-				print_packet("SNB Flags",
-					out + 1 + 16 + 2, 1);
-				print_packet("IVindex",
-					out + 1 + 16 + 2 + 1, 4);
-				print_packet("Unicast Addr",
-					out + 1 + 16 + 2 + 1 + 4, 2);
-			}
-
-			/* Set Provisioned Data */
-			ret = mesh_net_provisioned_new(prov->net,
-					prov->dev_key,
-					l_get_be16(out + 17),
-					out + 1,
-					l_get_be16(out + 24),
-					out[19],
-					l_get_be32(out + 20),
-					prov_store_cfm, prov);
-
-			if (!ret) {
-				out[1] = PROV_ERR_INSUF_RESOURCE;
-				goto failure;
-			}
-		} else {
-			l_error("Provisioning Failed-MIC compare");
-			out[1] = PROV_ERR_DECRYPT_FAILED;
-			goto failure;
-		}
-		break;
-
-	default:
-		l_error("Unknown Pkt %2.2x", type);
-		out[1] = PROV_ERR_UNEXPECTED_PDU;
-		goto failure;
-	}
-
-	return;
-
-failure:
-	acp_prov_state = ACP_PROV_FAIL_SENT;
-	out[0] = PROV_FAILED;
-	mesh_prov_send(prov, out, 2, acp_prov_send_cmplt, prov);
-}
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 03/30] mesh: Utilities for DBus support
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 01/30] mesh: Staging for Mesh DBus API rewrite Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 02/30] mesh: Delete obsolete files Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 23:04   ` Marcel Holtmann
  2018-12-18 22:31 ` [PATCH BlueZ v4 04/30] mesh: Internal errors Brian Gix
                   ` (27 subsequent siblings)
  30 siblings, 1 reply; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel

From: Inga Stotland <inga.stotland@intel.com>

---
 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

diff --git a/mesh/dbus.c b/mesh/dbus.c
new file mode 100644
index 000000000..a8b398f9e
--- /dev/null
+++ b/mesh/dbus.c
@@ -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);
+}
diff --git a/mesh/dbus.h b/mesh/dbus.h
new file mode 100644
index 000000000..90cbe9e5c
--- /dev/null
+++ b/mesh/dbus.h
@@ -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);
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 04/30] mesh: Internal errors
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (2 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 03/30] mesh: Utilities for DBus support Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 23:05   ` Marcel Holtmann
  2018-12-18 22:31 ` [PATCH BlueZ v4 05/30] mesh: Re-write storage for Multiple Nodes Brian Gix
                   ` (26 subsequent siblings)
  30 siblings, 1 reply; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel

From: Inga Stotland <inga.stotland@intel.com>

---
 mesh/error.h | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)
 create mode 100644 mesh/error.h

diff --git a/mesh/error.h b/mesh/error.h
new file mode 100644
index 000000000..e7bac445b
--- /dev/null
+++ b/mesh/error.h
@@ -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;
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 05/30] mesh: Re-write storage for Multiple Nodes
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (3 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 04/30] mesh: Internal errors Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 06/30] mesh: Rewrite Node handling for multiple nodes Brian Gix
                   ` (25 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel

From: Inga Stotland <inga.stotland@intel.com>

---
 mesh/storage.c | 570 +++++++++++++++++++++++++--------------------------------
 mesh/storage.h |  39 ++--
 2 files changed, 269 insertions(+), 340 deletions(-)

diff --git a/mesh/storage.c b/mesh/storage.c
index 1f3b25886..459c9f4fa 100644
--- a/mesh/storage.c
+++ b/mesh/storage.c
@@ -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);
 }
diff --git a/mesh/storage.h b/mesh/storage.h
index 341932dba..9583669f0 100644
--- a/mesh/storage.h
+++ b/mesh/storage.h
@@ -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);
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 06/30] mesh: Rewrite Node handling for multiple nodes
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (4 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 05/30] mesh: Re-write storage for Multiple Nodes Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 07/30] mesh: Rewite Network layer " Brian Gix
                   ` (24 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel

From: Inga Stotland <inga.stotland@intel.com>

---
 mesh/node.c | 1338 +++++++++++++++++++++++++++++++++++++++++++++++++----------
 mesh/node.h |   42 +-
 2 files changed, 1158 insertions(+), 222 deletions(-)

diff --git a/mesh/node.c b/mesh/node.c
index 501ab8eea..fbf46b995 100644
--- a/mesh/node.c
+++ b/mesh/node.c
@@ -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;
+}
diff --git a/mesh/node.h b/mesh/node.h
index f417fe503..196b54c4d 100644
--- a/mesh/node.h
+++ b/mesh/node.h
@@ -18,35 +18,40 @@
  *
  */
 
-#include "mesh/mesh-db.h"
-
 struct mesh_net;
 struct mesh_node;
+struct mesh_io;
+struct mesh_agent;
 
 /* To prevent local node JSON cache thrashing, minimum update times */
 #define MIN_SEQ_TRIGGER	32
 #define MIN_SEQ_CACHE		(2*MIN_SEQ_TRIGGER)
 #define MIN_SEQ_CACHE_TIME	(5*60)
 
+typedef void (*node_attach_ready_func_t) (int status, char *node_path,
+								uint64_t token);
+
+typedef void (*node_join_ready_func_t) (struct mesh_node *node,
+						struct mesh_agent *agent);
+
 struct mesh_node *node_new(void);
 void node_free(struct mesh_node *node);
+void node_join(const char *app_path, const char *sender, const uint8_t *uuid,
+						node_join_ready_func_t cb);
 uint8_t *node_uuid_get(struct mesh_node *node);
+struct mesh_net *node_get_net(struct mesh_node *node);
 struct mesh_node *node_find_by_addr(uint16_t addr);
 struct mesh_node *node_find_by_uuid(uint8_t uuid[16]);
 bool node_is_provisioned(struct mesh_node *node);
 bool node_app_key_delete(struct mesh_net *net, uint16_t addr,
 				uint16_t net_idx, uint16_t idx);
-bool node_net_key_delete(struct mesh_node *node, uint16_t index);
-bool node_set_primary(struct mesh_node *node, uint16_t unicast);
 uint16_t node_get_primary(struct mesh_node *node);
 uint16_t node_get_primary_net_idx(struct mesh_node *node);
-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]);
 const uint8_t *node_get_device_key(struct mesh_node *node);
 void node_set_num_elements(struct mesh_node *node, uint8_t num_ele);
 uint8_t node_get_num_elements(struct mesh_node *node);
 bool node_parse_composition(struct mesh_node *node, uint8_t *buf, uint16_t len);
-struct l_queue *node_get_net_keys(struct mesh_node *node);
-struct l_queue *node_get_app_keys(struct mesh_node *node);
 bool node_add_binding(struct mesh_node *node, uint8_t ele_idx,
 			uint32_t model_id, uint16_t app_idx);
 bool node_del_binding(struct mesh_node *node, uint8_t ele_idx,
@@ -58,12 +63,8 @@ uint32_t node_get_sequence_number(struct mesh_node *node);
 int node_get_element_idx(struct mesh_node *node, uint16_t ele_addr);
 struct l_queue *node_get_element_models(struct mesh_node *node, uint8_t ele_idx,
 								int *status);
-struct mesh_model *node_get_model(struct mesh_node *node, uint8_t ele_idx,
-						uint32_t id, int *status);
 uint16_t node_get_crpl(struct mesh_node *node);
-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);
 uint16_t node_generate_comp(struct mesh_node *node, uint8_t *buf, uint16_t sz);
 uint8_t node_lpn_mode_get(struct mesh_node *node);
 bool node_relay_mode_set(struct mesh_node *node, bool enable, uint8_t cnt,
@@ -77,4 +78,19 @@ uint8_t node_beacon_mode_get(struct mesh_node *node);
 bool node_friend_mode_set(struct mesh_node *node, bool enable);
 uint8_t node_friend_mode_get(struct mesh_node *node);
 uint32_t node_seq_cache(struct mesh_node *node);
-void node_cleanup(struct mesh_net *net);
+const char *node_get_element_path(struct mesh_node *node, uint8_t ele_idx);
+const char *node_get_owner(struct mesh_node *node);
+bool node_add_pending_local(struct mesh_node *node, void *info,
+							struct mesh_io *io);
+void node_attach_io(struct mesh_io *io);
+int node_attach(const char *app_path, const char *sender, uint64_t token,
+						node_attach_ready_func_t cb);
+void node_build_attach_reply(struct l_dbus_message *reply, uint64_t token);
+void node_id_set(struct mesh_node *node, uint16_t node_id);
+bool node_dbus_init(struct l_dbus *bus);
+void node_cleanup(void *node);
+void node_cleanup_all(void);
+void node_jconfig_set(struct mesh_node *node, void *jconfig);
+void *node_jconfig_get(struct mesh_node *node);
+void node_cfg_file_set(struct mesh_node *node, char *cfg);
+char *node_cfg_file_get(struct mesh_node *node);
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 07/30] mesh: Rewite Network layer for multiple nodes
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (5 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 06/30] mesh: Rewrite Node handling for multiple nodes Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 08/30] mesh: Direction agnostic PB-Adv implimentation Brian Gix
                   ` (23 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, Brian Gix

---
 mesh/net.c | 293 ++++++++++++++++---------------------------------------------
 mesh/net.h |  31 ++-----
 2 files changed, 83 insertions(+), 241 deletions(-)

diff --git a/mesh/net.c b/mesh/net.c
index 97b6f5b16..b47df7c04 100644
--- a/mesh/net.c
+++ b/mesh/net.c
@@ -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;
-}
diff --git a/mesh/net.h b/mesh/net.h
index b8eb0699d..c63ea59ee 100644
--- a/mesh/net.h
+++ b/mesh/net.h
@@ -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);
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 08/30] mesh: Direction agnostic PB-Adv implimentation
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (6 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 07/30] mesh: Rewite Network layer " Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 09/30] mesh: Acceptor side provisioning implimentation Brian Gix
                   ` (22 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, 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

diff --git a/mesh/pb-adv.c b/mesh/pb-adv.c
new file mode 100644
index 000000000..57647e184
--- /dev/null
+++ b/mesh/pb-adv.c
@@ -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;
+}
diff --git a/mesh/pb-adv.h b/mesh/pb-adv.h
new file mode 100644
index 000000000..a5870d5a2
--- /dev/null
+++ b/mesh/pb-adv.h
@@ -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);
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 09/30] mesh: Acceptor side provisioning implimentation
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (7 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 08/30] mesh: Direction agnostic PB-Adv implimentation Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 23:09   ` Marcel Holtmann
  2018-12-18 22:31 ` [PATCH BlueZ v4 10/30] mesh: Initiator " Brian Gix
                   ` (21 subsequent siblings)
  30 siblings, 1 reply; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, Brian Gix

---
 mesh/prov-acceptor.c | 711 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 711 insertions(+)
 create mode 100644 mesh/prov-acceptor.c

diff --git a/mesh/prov-acceptor.c b/mesh/prov-acceptor.c
new file mode 100644
index 000000000..ac42e1e2c
--- /dev/null
+++ b/mesh/prov-acceptor.c
@@ -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();
+}
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 10/30] mesh: Initiator side provisioning implimentation
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (8 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 09/30] mesh: Acceptor side provisioning implimentation Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 11/30] mesh: Rewrite Controler interface for full init Brian Gix
                   ` (20 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, Brian Gix

---
 mesh/prov-initiator.c | 650 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 650 insertions(+)
 create mode 100644 mesh/prov-initiator.c

diff --git a/mesh/prov-initiator.c b/mesh/prov-initiator.c
new file mode 100644
index 000000000..6c97bc6c8
--- /dev/null
+++ b/mesh/prov-initiator.c
@@ -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();
+}
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 11/30] mesh: Rewrite Controler interface for full init
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (9 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 10/30] mesh: Initiator " Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 12/30] mesh: Unchanged variables set to const Brian Gix
                   ` (19 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, Brian Gix

---
 mesh/mesh-io-generic.c | 149 +++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 138 insertions(+), 11 deletions(-)

diff --git a/mesh/mesh-io-generic.c b/mesh/mesh-io-generic.c
index 52514e280..48e47e7a4 100644
--- a/mesh/mesh-io-generic.c
+++ b/mesh/mesh-io-generic.c
@@ -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;
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 12/30] mesh: Unchanged variables set to const
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (10 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 11/30] mesh: Rewrite Controler interface for full init Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 13/30] mesh: centralize generic utilities Brian Gix
                   ` (18 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, Brian Gix

---
 mesh/mesh-io-api.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mesh/mesh-io-api.h b/mesh/mesh-io-api.h
index f69fceeb2..acf12445d 100644
--- a/mesh/mesh-io-api.h
+++ b/mesh/mesh-io-api.h
@@ -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 {
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 13/30] mesh: centralize generic utilities
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (11 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 12/30] mesh: Unchanged variables set to const Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 14/30] mesh: re-arrange provisioning for DBus API Brian Gix
                   ` (17 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel

From: Inga Stotland <inga.stotland@intel.com>

---
 mesh/util.c | 26 ++++++++++++++++++++++++++
 mesh/util.h |  1 +
 2 files changed, 27 insertions(+)

diff --git a/mesh/util.c b/mesh/util.c
index 2cdcdf37d..ac0294742 100644
--- a/mesh/util.c
+++ b/mesh/util.c
@@ -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;
diff --git a/mesh/util.h b/mesh/util.h
index 61110104a..b8efb6521 100644
--- a/mesh/util.h
+++ b/mesh/util.h
@@ -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);
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 14/30] mesh: re-arrange provisioning for DBus API
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (12 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 13/30] mesh: centralize generic utilities Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 15/30] mesh: Re-architect " Brian Gix
                   ` (16 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, Brian Gix

---
 mesh/prov.h      |  14 +++++--
 mesh/provision.h | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 112 insertions(+), 14 deletions(-)

diff --git a/mesh/prov.h b/mesh/prov.h
index 09fe6c3cd..61ec08e10 100644
--- a/mesh/prov.h
+++ b/mesh/prov.h
@@ -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;
diff --git a/mesh/provision.h b/mesh/provision.h
index 0c59bf037..6b61a45be 100644
--- a/mesh/provision.h
+++ b/mesh/provision.h
@@ -17,14 +17,106 @@
  *
  */
 
+
+/*
+ * size: hard define (mesh.conf - OOB_NUMBEROOB_NUMBER)
+ *      oob size - 8 if alpha or numeric
+ *	else 1 if mask is non zero
+ *	else 0
+ */
+struct bt_mesh;
 struct mesh_prov;
-struct l_queue;
-
-void initiator_prov_open(struct mesh_prov *prov);
-void initiator_prov_close(struct mesh_prov *prov, uint8_t reason);
-void initiator_prov_receive(const void *pkt, uint16_t size,
-							struct mesh_prov *prov);
-void acceptor_prov_open(struct mesh_prov *prov);
-void acceptor_prov_close(struct mesh_prov *prov, uint8_t reason);
-void acceptor_prov_receive(const void *pkt, uint16_t size,
-							struct mesh_prov *prov);
+struct mesh_agent;
+
+/* Provisioner Agent Response Types */
+#define OOB_CANCEL		0x00
+#define OOB_PRIV_KEY		0x01
+#define OOB_PUB_KEY		0x02
+#define OOB_NUMBER		0x03
+#define OOB_STATIC		0x04
+#define OOB_NUMBER_DISPLAY	0x05
+
+/* Spec defined Provisioning message types */
+#define PROV_INVITE	0x00
+#define PROV_CAPS	0x01
+#define PROV_START	0x02
+#define PROV_PUB_KEY	0x03
+#define PROV_INP_CMPLT	0x04
+#define PROV_CONFIRM	0x05
+#define PROV_RANDOM	0x06
+#define PROV_DATA	0x07
+#define PROV_COMPLETE	0x08
+#define PROV_FAILED	0x09
+
+/* Spec defined Error Codes */
+#define PROV_ERR_SUCCESS		0x00
+#define PROV_ERR_INVALID_PDU		0x01
+#define PROV_ERR_INVALID_FORMAT		0x02
+#define PROV_ERR_UNEXPECTED_PDU		0x03
+#define PROV_ERR_CONFIRM_FAILED		0x04
+#define PROV_ERR_INSUF_RESOURCE		0x05
+#define PROV_ERR_DECRYPT_FAILED		0x06
+#define PROV_ERR_UNEXPECTED_ERR		0x07
+#define PROV_ERR_CANT_ASSIGN_ADDR	0x08
+/* Internally generated Error Codes */
+#define PROV_ERR_TIMEOUT		0xFF
+
+/* Provisioner Action values */
+/* IN */
+#define PROV_ACTION_PUSH		0x00
+#define PROV_ACTION_TWIST		0x01
+#define PROV_ACTION_IN_NUMERIC		0x02
+#define PROV_ACTION_IN_ALPHA		0x03
+/* OUT */
+#define PROV_ACTION_BLINK		0x00
+#define PROV_ACTION_BEEP		0x01
+#define PROV_ACTION_VIBRATE		0x02
+#define PROV_ACTION_OUT_NUMERIC		0x03
+#define PROV_ACTION_OUT_ALPHA		0x04
+
+/* OOB_Info defines from Table 3.54 of Mesh profile Specification v1.0 */
+#define OOB_INFO_URI_HASH	0x0002
+
+/* PB_REMOTE not supported from unprovisioned state */
+enum trans_type {
+	PB_ADV = 0,
+	PB_GATT,
+};
+
+#define PROV_FLAG_KR	0x01
+#define PROV_FLAG_IVU	0x02
+
+struct mesh_prov_node_info {
+	uint32_t iv_index;
+	uint16_t unicast;
+	uint16_t net_index;
+	uint8_t net_key[16];
+	uint8_t device_key[16];
+	uint8_t flags; /* IVU and KR bits */
+};
+
+typedef bool (*mesh_prov_acceptor_complete_func_t)(void *user_data,
+					uint8_t status,
+					struct mesh_prov_node_info *info);
+
+typedef bool (*mesh_prov_initiator_complete_func_t)(void *user_data,
+					uint8_t status,
+					struct mesh_prov_node_info *info);
+
+/* 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);
+void acceptor_cancel(void *user_data);
+
+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);
+void initiator_cancel(void *user_data);
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 15/30] mesh: Re-architect for DBus API
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (13 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 14/30] mesh: re-arrange provisioning for DBus API Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 16/30] mesh: Make config model handle multiple nodes Brian Gix
                   ` (15 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel

From: Inga Stotland <inga.stotland@intel.com>

---
 mesh/mesh.c | 625 ++++++++++++++++++++++++++++++++++++++++++++++--------------
 mesh/mesh.h |  27 ++-
 2 files changed, 505 insertions(+), 147 deletions(-)

diff --git a/mesh/mesh.c b/mesh/mesh.c
index d1d409672..05232b225 100644
--- a/mesh/mesh.c
+++ b/mesh/mesh.c
@@ -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;
 }
diff --git a/mesh/mesh.h b/mesh/mesh.h
index 8d389883b..1189f8276 100644
--- a/mesh/mesh.h
+++ b/mesh/mesh.h
@@ -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);
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 16/30] mesh: Make config model handle multiple nodes
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (14 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 15/30] mesh: Re-architect " Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 17/30] mesh: Multi node Config Server model Brian Gix
                   ` (14 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel

From: Inga Stotland <inga.stotland@intel.com>

---
 mesh/cfgmod.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mesh/cfgmod.h b/mesh/cfgmod.h
index bedb0c6f6..c849923ca 100644
--- a/mesh/cfgmod.h
+++ b/mesh/cfgmod.h
@@ -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);
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 17/30] mesh: Multi node Config Server model
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (15 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 16/30] mesh: Make config model handle multiple nodes Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 18/30] mesh: restructure I/O for multiple nodes Brian Gix
                   ` (13 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel

From: Inga Stotland <inga.stotland@intel.com>

---
 mesh/cfgmod-server.c | 173 ++++++++++++++++++++++++++-------------------------
 1 file changed, 88 insertions(+), 85 deletions(-)

diff --git a/mesh/cfgmod-server.c b/mesh/cfgmod-server.c
index 2c4a02912..6cddb8eac 100644
--- a/mesh/cfgmod-server.c
+++ b/mesh/cfgmod-server.c
@@ -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);
 }
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 18/30] mesh: restructure I/O for multiple nodes
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (16 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 17/30] mesh: Multi node Config Server model Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 19/30] mesh: Restrusture DB to support " Brian Gix
                   ` (12 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, Brian Gix

---
 mesh/mesh-io.c | 3 ++-
 mesh/mesh-io.h | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/mesh/mesh-io.c b/mesh/mesh-io.c
index 5cdfdc5ff..8cf6c486a 100644
--- a/mesh/mesh-io.c
+++ b/mesh/mesh-io.c
@@ -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);
 
diff --git a/mesh/mesh-io.h b/mesh/mesh-io.h
index 754f6129c..71d3cb980 100644
--- a/mesh/mesh-io.h
+++ b/mesh/mesh-io.h
@@ -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);
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 19/30] mesh: Restrusture DB to support multiple nodes
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (17 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 18/30] mesh: restructure I/O for multiple nodes Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 20/30] mesh: restructure model services for " Brian Gix
                   ` (11 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel

From: Inga Stotland <inga.stotland@intel.com>

---
 mesh/mesh-db.c | 454 +++++++++++++++++++++++++++++++++++++--------------------
 mesh/mesh-db.h |   6 +-
 2 files changed, 296 insertions(+), 164 deletions(-)

diff --git a/mesh/mesh-db.c b/mesh/mesh-db.c
index 86e17ed9a..e6aa51340 100644
--- a/mesh/mesh-db.c
+++ b/mesh/mesh-db.c
@@ -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;
+}
diff --git a/mesh/mesh-db.h b/mesh/mesh-db.h
index 336302f28..9a32e6c76 100644
--- a/mesh/mesh-db.h
+++ b/mesh/mesh-db.h
@@ -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);
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 20/30] mesh: restructure model services for multiple nodes
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (18 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 19/30] mesh: Restrusture DB to support " Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 21/30] mesh: DBUS interface for Provisioning Agent Brian Gix
                   ` (10 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel

From: Inga Stotland <inga.stotland@intel.com>

---
 mesh/model.c | 811 ++++++++++++++++++++++++++++++++++++++++++-----------------
 mesh/model.h |  66 ++---
 2 files changed, 612 insertions(+), 265 deletions(-)

diff --git a/mesh/model.c b/mesh/model.c
index d50817843..5687e5cfa 100644
--- a/mesh/model.c
+++ b/mesh/model.c
@@ -30,12 +30,15 @@
 #include "mesh/mesh.h"
 #include "mesh/crypto.h"
 #include "mesh/node.h"
+#include "mesh/mesh-db.h"
 #include "mesh/net.h"
 #include "mesh/appkey.h"
-#include "mesh/model.h"
-#include "mesh/display.h"
 #include "mesh/cfgmod.h"
 #include "mesh/storage.h"
+#include "mesh/error.h"
+#include "mesh/dbus.h"
+#include "mesh/util.h"
+#include "mesh/model.h"
 
 struct mesh_model {
 	const struct mesh_model_ops *cbs;
@@ -67,6 +70,7 @@ struct mod_forward {
 	uint8_t ttl;
 	int8_t rssi;
 	bool szmict;
+	bool has_dst;
 	bool done;
 };
 
@@ -75,6 +79,14 @@ static struct l_queue *mesh_virtuals;
 static uint32_t virt_id_next = VIRTUAL_BASE;
 static struct timeval tx_start;
 
+static bool is_internal(uint32_t id)
+{
+	if (id == CONFIG_SRV_MODEL || id == CONFIG_CLI_MODEL)
+		return true;
+
+	return false;
+}
+
 static void unref_virt(void *data)
 {
 	struct mesh_virtual *virt = data;
@@ -94,6 +106,17 @@ static bool simple_match(const void *a, const void *b)
 	return a == b;
 }
 
+static bool has_binding(struct l_queue *bindings, uint16_t idx)
+{
+	const struct l_queue_entry *l;
+
+	for (l = l_queue_get_entries(bindings); l; l = l->next) {
+		if (L_PTR_TO_UINT(l->data) == idx)
+			return true;
+	}
+	return false;
+}
+
 static bool find_virt_by_id(const void *a, const void *b)
 {
 	const struct mesh_virtual *virt = a;
@@ -110,13 +133,39 @@ static bool find_virt_by_addr(const void *a, const void *b)
 	return memcmp(virt->addr, addr, 16) == 0;
 }
 
-static struct mesh_model *find_model(struct mesh_net *net, uint16_t addr,
+static bool match_model_id(const void *a, const void *b)
+{
+	const struct mesh_model *model = a;
+	uint32_t id = L_PTR_TO_UINT(b);
+
+	return (mesh_model_get_model_id(model) == id);
+}
+
+static struct mesh_model *get_model(struct mesh_node *node, uint8_t ele_idx,
+						uint32_t id, int *status)
+{
+	struct l_queue *models;
+	struct mesh_model *model;
+
+	models = node_get_element_models(node, ele_idx, status);
+	if (!models) {
+		*status = MESH_STATUS_INVALID_ADDRESS;
+		return NULL;
+	}
+
+	model = l_queue_find(models, match_model_id, L_UINT_TO_PTR(id));
+
+	if (status)
+		*status = (model) ? MESH_STATUS_SUCCESS :
+						MESH_STATUS_INVALID_MODEL;
+
+	return model;
+}
+
+static struct mesh_model *find_model(struct mesh_node *node, uint16_t addr,
 						uint32_t mod_id, int *fail)
 {
 	int ele_idx;
-	struct mesh_node *node;
-
-	node = mesh_net_local_node_get(net);
 
 	ele_idx = node_get_element_idx(node, addr);
 
@@ -126,7 +175,126 @@ static struct mesh_model *find_model(struct mesh_net *net, uint16_t addr,
 		return NULL;
 	}
 
-	return node_get_model(node, (uint8_t) ele_idx, mod_id, fail);
+	return get_model(node, (uint8_t) ele_idx, mod_id, fail);
+}
+
+static uint32_t convert_pub_period_to_ms(uint8_t pub_period)
+{
+	int n;
+
+	n = (pub_period & 0x3f);
+
+	switch (pub_period >> 6) {
+	default:
+		return n * 100;
+	case 2:
+		n *= 10;
+		/* Fall Through */
+	case 1:
+		return n * 1000;
+	case 3:
+		return n * 10 * 60 * 1000;
+	}
+}
+
+static struct l_dbus_message *create_config_update_msg(struct mesh_node *node,
+					uint8_t ele_idx, uint32_t id,
+					struct l_dbus_message_builder **builder)
+{
+	struct l_dbus *dbus = dbus_get_bus();
+	struct l_dbus_message *msg;
+	const char *owner;
+	const char *path;
+	uint16_t model_id;
+
+	owner = node_get_owner(node);
+	path = node_get_element_path(node, ele_idx);
+	if (!path || !owner)
+		return NULL;
+
+	l_debug("Send \"UpdateModelConfiguration\"");
+	msg = l_dbus_message_new_method_call(dbus, owner, path,
+						MESH_ELEMENT_INTERFACE,
+						"UpdateModelConfiguration");
+
+	*builder = l_dbus_message_builder_new(msg);
+
+	model_id = (uint16_t) id;
+
+	l_dbus_message_builder_append_basic(*builder, 'q', &model_id);
+
+	l_dbus_message_builder_enter_array(*builder, "{sv}");
+
+	if ((id & VENDOR_ID_MASK) != VENDOR_ID_MASK) {
+		uint16_t vendor = id >> 16;
+		dbus_append_dict_entry_basic(*builder, "Vendor", "q", &vendor);
+	}
+
+	return msg;
+}
+
+static void config_update_model_pub_period(struct mesh_node *node,
+					uint8_t ele_idx, uint32_t model_id,
+					uint32_t period)
+{
+	struct l_dbus *dbus = dbus_get_bus();
+	struct l_dbus_message *msg;
+	struct l_dbus_message_builder *builder;
+
+	msg = create_config_update_msg(node, ele_idx, model_id, &builder);
+	if (!msg)
+		return;
+
+	dbus_append_dict_entry_basic(builder, "PublicationPeriod", "u",
+								&period);
+
+	l_dbus_message_builder_leave_array(builder);
+	if (l_dbus_message_builder_finalize(builder))
+		l_dbus_send(dbus, msg);
+
+	l_dbus_message_builder_destroy(builder);
+}
+
+static void append_dict_uint16_array(struct l_dbus_message_builder *builder,
+					struct l_queue *q, const char *key)
+{
+	const struct l_queue_entry *entry;
+
+	l_dbus_message_builder_enter_dict(builder, "sv");
+	l_dbus_message_builder_append_basic(builder, 's', key);
+	l_dbus_message_builder_enter_variant(builder, "aq");
+	l_dbus_message_builder_enter_array(builder, "q");
+
+	for (entry = l_queue_get_entries(q); entry; entry = entry->next) {
+		uint16_t value = (uint16_t) L_PTR_TO_UINT(entry->data);
+
+		l_dbus_message_builder_append_basic(builder,'q', &value);
+	}
+
+	l_dbus_message_builder_leave_array(builder);
+	l_dbus_message_builder_leave_variant(builder);
+	l_dbus_message_builder_leave_dict(builder);
+}
+
+static void config_update_model_bindings(struct mesh_node *node,
+							struct mesh_model *mod)
+{
+	struct l_dbus *dbus = dbus_get_bus();
+	struct l_dbus_message *msg;
+	struct l_dbus_message_builder *builder;
+
+	msg = create_config_update_msg(node, mod->ele_idx, mod->id,
+								&builder);
+	if (!msg)
+		return;
+
+	append_dict_uint16_array(builder, mod->bindings, "Bindings");
+
+	l_dbus_message_builder_leave_array(builder);
+	if (l_dbus_message_builder_finalize(builder))
+		l_dbus_send(dbus, msg);
+
+	l_dbus_message_builder_destroy(builder);
 }
 
 static void forward_model(void *a, void *b)
@@ -135,22 +303,22 @@ static void forward_model(void *a, void *b)
 	struct mod_forward *fwd = b;
 	struct mesh_virtual *virt;
 	uint32_t dst;
-	bool has_dst = false;
-
-	if (!mod->cbs || !mod->cbs->recv)
-		return;
+	bool result;
 
 	l_debug("model %8.8x with idx %3.3x", mod->id, fwd->idx);
-	if (fwd->idx != APP_IDX_DEV &&
-		!l_queue_find(mod->bindings, simple_match,
-						L_UINT_TO_PTR(fwd->idx)))
+	if (fwd->idx != APP_IDX_DEV && !has_binding(mod->bindings, fwd->idx))
 		return;
 
 	dst = fwd->dst;
 	if (dst == fwd->unicast || IS_ALL_NODES(dst))
-		has_dst = true;
+		fwd->has_dst = true;
 	else if (fwd->virt) {
 		virt = l_queue_find(mod->virtuals, simple_match, fwd->virt);
+
+		/* Check that this is not own publication */
+		if (mod->pub && (virt && virt->id == mod->pub->addr))
+			return;
+
 		if (virt) {
 			/*
 			 * Map Virtual addresses to a usable namespace that
@@ -158,42 +326,38 @@ static void forward_model(void *a, void *b)
 			 * (multiple Virtual Addresses that map to the same
 			 * u16 OTA addr)
 			 */
-			has_dst = true;
+			fwd->has_dst = true;
 			dst = virt->id;
 		}
 	} else {
 		if (l_queue_find(mod->subs, simple_match, L_UINT_TO_PTR(dst)))
-			has_dst = true;
+			fwd->has_dst = true;
 	}
 
+	if (!fwd->has_dst)
+		return;
 
-	if (!has_dst)
+	/* Return, if this is not a internal model */
+	if (!mod->cbs)
 		return;
 
-	/*
-	 * TODO: models shall be registered with a list of supported opcodes and
-	 * element address. Iterate through the list of opcodes to see if the
-	 * model is an addressee.
-	 * If this is an internal registered model, check for a "bind" callback.
-	 * For an external ("user") model, send D-Bus method (signal?) (TBD)
-	 */
+	result = false;
+
 	if (mod->cbs->recv)
-		mod->cbs->recv(fwd->src, dst, fwd->unicast, fwd->idx,
+		result = mod->cbs->recv(fwd->src, dst, fwd->unicast, fwd->idx,
 				fwd->data, fwd->size, fwd->ttl, mod->user_data);
 
-	if (dst == fwd->unicast)
+	if (dst == fwd->unicast && result)
 		fwd->done = true;
 }
 
-static int dev_packet_decrypt(struct mesh_net *net, const uint8_t *data,
+static int dev_packet_decrypt(struct mesh_node *node, const uint8_t *data,
 				uint16_t size, bool szmict, uint16_t src,
 				uint16_t dst, uint8_t key_id, uint32_t seq,
 				uint32_t iv_idx, uint8_t *out)
 {
-	struct mesh_node *node;
 	const uint8_t *dev_key;
 
-	node = mesh_net_local_node_get(net);
 	dev_key = node_get_device_key(node);
 	if (!dev_key)
 		return false;
@@ -241,32 +405,32 @@ static void cmplt(uint16_t remote, uint8_t status,
 	struct timeval tx_end;
 
 	if (status)
-		l_info("Tx-->%4.4x (%d octets) Failed (%d)",
+		l_debug("Tx-->%4.4x (%d octets) Failed (%d)",
 				remote, size, status);
 	else
-		l_info("Tx-->%4.4x (%d octets) Succeeded", remote, size);
+		l_debug("Tx-->%4.4x (%d octets) Succeeded", remote, size);
 
 	/* print_packet("Sent Data", data, size); */
 
 	gettimeofday(&tx_end, NULL);
 	if (tx_end.tv_sec == tx_start.tv_sec) {
-		l_info("Duration 0.%zu seconds",
+		l_debug("Duration 0.%zu seconds",
 				tx_end.tv_usec - tx_start.tv_usec);
 	} else {
 		if (tx_start.tv_usec > tx_end.tv_usec)
-			l_info("Duration %zu.%zu seconds",
+			l_debug("Duration %zu.%zu seconds",
 				tx_end.tv_sec - tx_start.tv_sec - 1,
 				tx_end.tv_usec + 1000000 - tx_start.tv_usec);
 		else
-			l_info("Duration %zu.%zu seconds",
+			l_debug("Duration %zu.%zu seconds",
 					tx_end.tv_sec - tx_start.tv_sec,
 					tx_end.tv_usec - tx_start.tv_usec);
 	}
 }
 
-static bool pub_frnd_cred(struct mesh_net *net, uint16_t src, uint32_t mod_id)
+static bool pub_frnd_cred(struct mesh_node *node, uint16_t src, uint32_t mod_id)
 {
-	struct mesh_model *mod = find_model(net, src, mod_id, NULL);
+	struct mesh_model *mod = find_model(node, src, mod_id, NULL);
 
 	if (!mod || !mod->pub)
 		return false;
@@ -274,17 +438,16 @@ static bool pub_frnd_cred(struct mesh_net *net, uint16_t src, uint32_t mod_id)
 	return (mod->pub->credential != 0);
 }
 
-static unsigned int msg_send(struct mesh_net *net, uint32_t mod_id,
-				uint16_t src, uint32_t dst,
-				uint8_t key_id, const uint8_t *key,
-				uint8_t *aad, uint8_t ttl,
-				const void *msg, uint16_t msg_len)
+static bool msg_send(struct mesh_node *node, bool credential, uint16_t src,
+		uint32_t dst, uint8_t key_id, const uint8_t *key,
+		uint8_t *aad, uint8_t ttl, const void *msg, uint16_t msg_len)
 {
-	unsigned int ret = 0;
+	bool ret = false;
 	uint32_t iv_index, seq_num;
 	uint8_t *out;
 	bool szmic = false;
 	uint16_t out_len = msg_len + sizeof(uint32_t);
+	struct mesh_net *net = node_get_net(node);
 
 	/* Use large MIC if it doesn't affect segmentation */
 	if (msg_len > 11 && msg_len <= 376) {
@@ -309,7 +472,7 @@ static unsigned int msg_send(struct mesh_net *net, uint32_t mod_id,
 
 	/* print_packet("Encrypted with", key, 16); */
 
-	ret = mesh_net_app_send(net, pub_frnd_cred(net, src, mod_id),
+	ret = mesh_net_app_send(net, credential,
 				src, dst, key_id, ttl,
 				seq_num, iv_index,
 				szmic,
@@ -320,79 +483,100 @@ done:
 	return ret;
 }
 
-static void model_unbind_idx(void *a, void *b)
+static void remove_pub(struct mesh_node *node, struct mesh_model *mod)
 {
-	struct mesh_model *mod = a;
-	uint16_t idx = L_PTR_TO_UINT(b);
+	l_free(mod->pub);
+	mod->pub = NULL;
 
-	if (idx == mod->pub->idx) {
-		mod->pub->addr = UNASSIGNED_ADDRESS;
-		/*
-		 * TODO: callback for internal model or
-		 * D-Bus signal/method "model publication changed" (TBD)
-		 */
-	}
+	/* TODO: remove from storage */
 
-	l_queue_remove(mod->bindings, b);
+	if (!mod->cbs)
+		/* External models */
+		config_update_model_pub_period(node, mod->ele_idx, mod->id, 0);
+	else if (mod->cbs && mod->cbs->pub)
+		/* Internal models */
+		mod->cbs->pub(NULL);
+}
+
+static void model_unbind_idx(struct mesh_node *node, struct mesh_model *mod,
+								uint16_t idx)
+{
+	l_queue_remove(mod->bindings, L_UINT_TO_PTR(idx));
 
-	if (mod->cbs->bind)
+	if (!mod->cbs)
+		/* External model */
+		config_update_model_bindings(node, mod);
+	else if (mod->cbs->bind)
+		/* Internal model */
 		mod->cbs->bind(idx, ACTION_DELETE);
+
+	if (mod->pub && idx != mod->pub->idx)
+		return;
+
+	/* Remove model publication if the publication key is unbound */
+	remove_pub(node, mod);
 }
 
-static int model_bind_idx(struct mesh_model *mod, uint16_t idx)
+static void model_bind_idx(struct mesh_node *node, struct mesh_model *mod,
+								uint16_t idx)
 {
-	if (l_queue_length(mod->bindings) >= MAX_BINDINGS)
-		return MESH_STATUS_INSUFF_RESOURCES;
+	l_queue_push_tail(mod->bindings, L_UINT_TO_PTR(idx));
 
-	if (!l_queue_push_tail(mod->bindings, L_UINT_TO_PTR(idx)))
-		return MESH_STATUS_INSUFF_RESOURCES;
+	l_debug("Add %4.4x to model %8.8x", idx, mod->id);
 
-	if (mod->cbs->bind)
+	if (!mod->cbs)
+		/* External model */
+		config_update_model_bindings(node, mod);
+	else if (mod->cbs->bind)
+		/* Internal model */
 		mod->cbs->bind(idx, ACTION_ADD);
-
-	return MESH_STATUS_SUCCESS;
-
 }
 
-static int update_binding(struct mesh_net *net, uint16_t addr, uint32_t id,
+static int update_binding(struct mesh_node *node, uint16_t addr, uint32_t id,
 				uint16_t app_idx, bool unbind)
 {
 	int fail;
 	struct mesh_model *mod;
-	int status;
+	bool is_present;
 
-	mod = find_model(net, addr, id, &fail);
+	mod = find_model(node, addr, id, &fail);
 	if (!mod) {
-		l_info("model not found");
+		l_debug("Model not found");
 		return fail;
 	}
 
+	id = (id >= VENDOR_ID_MASK) ? (id & 0xffff) : id;
+
 	if (id == CONFIG_SRV_MODEL || id == CONFIG_CLI_MODEL)
 		return MESH_STATUS_INVALID_MODEL;
 
-	if (!l_queue_find(mod->bindings, simple_match, L_UINT_TO_PTR(app_idx)))
-		return MESH_STATUS_CANNOT_BIND;
-
-	if (!appkey_have_key(net, app_idx))
+	if (!appkey_have_key(node_get_net(node), app_idx))
 		return MESH_STATUS_INVALID_APPKEY;
 
+	is_present = has_binding(mod->bindings, app_idx);
+
+	if (!is_present && unbind)
+		return MESH_STATUS_SUCCESS;
+
+	if (is_present && !unbind)
+		return MESH_STATUS_SUCCESS;
+
 	if (unbind) {
-		model_unbind_idx(mod, &app_idx);
+		model_unbind_idx(node, mod, app_idx);
 
-		if (!storage_model_bind(net, addr, id, app_idx, true))
+		if (!storage_model_bind(node, addr, id, app_idx, true))
 			return MESH_STATUS_STORAGE_FAIL;
 
 		return MESH_STATUS_SUCCESS;
 	}
 
-	status = model_bind_idx(mod, app_idx);
-	if (status != MESH_STATUS_SUCCESS)
-		return status;
+	if (l_queue_length(mod->bindings) >= MAX_BINDINGS)
+		return MESH_STATUS_INSUFF_RESOURCES;
 
-	if (!storage_model_bind(net, addr, id, app_idx, false)) {
-		model_unbind_idx(mod, &app_idx);
+	if (!storage_model_bind(node, addr, id, app_idx, false))
 		return MESH_STATUS_STORAGE_FAIL;
-	}
+
+	model_bind_idx(node, mod, app_idx);
 
 	return MESH_STATUS_SUCCESS;
 
@@ -428,6 +612,7 @@ static int set_pub(struct mesh_model *mod, const uint8_t *mod_addr,
 		}
 	}
 
+	mod->pub = l_new(struct mesh_model_pub, 1);
 	if (b_virt) {
 		virt = l_queue_find(mesh_virtuals, find_virt_by_addr, mod_addr);
 		if (!virt) {
@@ -511,14 +696,57 @@ static int add_sub(struct mesh_net *net, struct mesh_model *mod,
 
 	l_queue_push_tail(mod->subs, L_UINT_TO_PTR(grp));
 
-	l_info("Added %4.4x", grp);
-	if (net)
-		mesh_net_dst_reg(net, grp);
+	l_debug("Added %4.4x", grp);
+
+	mesh_net_dst_reg(net, grp);
 
 	return MESH_STATUS_SUCCESS;
 }
 
-bool mesh_model_rx(struct mesh_net *net, bool szmict, uint32_t seq0,
+static void send_msg_rcvd(struct mesh_node *node, uint8_t ele_idx, bool is_sub,
+					uint16_t src, uint16_t key_idx,
+					uint16_t size, const uint8_t *data)
+{
+	struct l_dbus *dbus = dbus_get_bus();
+	struct l_dbus_message *msg;
+	struct l_dbus_message_builder *builder;
+	const char *owner;
+	const char *path;
+
+	owner = node_get_owner(node);
+	path = node_get_element_path(node, ele_idx);
+	if (!path || !owner)
+		return;
+
+	l_debug("Send \"MessageReceived\"");
+
+	msg = l_dbus_message_new_method_call(dbus, owner, path,
+				MESH_ELEMENT_INTERFACE, "MessageReceived");
+
+	builder = l_dbus_message_builder_new(msg);
+
+	if (!l_dbus_message_builder_append_basic(builder, 'q', &src))
+		goto error;
+
+	if (!l_dbus_message_builder_append_basic(builder, 'q', &key_idx))
+		goto error;
+
+	if (!l_dbus_message_builder_append_basic(builder, 'b', &is_sub))
+		goto error;
+
+	if (!dbus_append_byte_array(builder, data, size))
+		goto error;
+
+	if (!l_dbus_message_builder_finalize(builder))
+		goto error;
+
+	l_dbus_send(dbus, msg);
+
+error:
+	l_dbus_message_builder_destroy(builder);
+}
+
+bool mesh_model_rx(struct mesh_node *node, bool szmict, uint32_t seq0,
 			uint32_t seq, uint32_t iv_index, uint8_t ttl,
 			uint16_t src, uint16_t dst, uint8_t key_id,
 			const uint8_t *data, uint16_t size)
@@ -531,30 +759,25 @@ bool mesh_model_rx(struct mesh_net *net, bool szmict, uint32_t seq0,
 		.size = size - (szmict ? 8 : 4),
 		.ttl = ttl,
 		.virt = NULL,
-		.done = false,
 	};
-
-	struct mesh_node *node;
+	struct mesh_net *net = node_get_net(node);
 	uint8_t num_ele;
 	int decrypt_idx, i, ele_idx;
 	uint16_t addr;
 	struct mesh_virtual *decrypt_virt = NULL;
+	bool result = false;
+	bool is_subscription;
 
 	l_debug("iv_index %8.8x key_id = %2.2x", iv_index, key_id);
 	if (!dst)
 		return false;
 
-	node = mesh_net_local_node_get(net);
-	if (!node)
-		return false;
-
 	ele_idx = node_get_element_idx(node, dst);
 
 	if (dst < 0x8000 && ele_idx < 0)
 		/* Unicast and not addressed to us */
 		return false;
 
-
 	clear_text = l_malloc(size);
 	if (!clear_text)
 		return false;
@@ -566,7 +789,7 @@ bool mesh_model_rx(struct mesh_net *net, bool szmict, uint32_t seq0,
 	 * is hinted by key_id, but is not necessarily definitive
 	 */
 	if (key_id == APP_ID_DEV || mesh_net_provisioner_mode_get(net))
-		decrypt_idx = dev_packet_decrypt(net, data, size, szmict, src,
+		decrypt_idx = dev_packet_decrypt(node, data, size, szmict, src,
 						dst, key_id, seq0, iv_index,
 						clear_text);
 	else if ((dst & 0xc000) == 0x8000)
@@ -582,18 +805,18 @@ bool mesh_model_rx(struct mesh_net *net, bool szmict, uint32_t seq0,
 
 	if (decrypt_idx < 0) {
 		l_error("model.c - Failed to decrypt application payload");
-		forward.done = false;
+		result = false;
 		goto done;
 	}
 
 	/* print_packet("Clr Rx (pre-cache-check)", clear_text, size - 4); */
 
 	if (key_id != APP_ID_DEV) {
-		uint16_t crpl = mesh_net_get_crpl(net);
+		uint16_t crpl = node_get_crpl(node);
 
 		if (appkey_msg_in_replay_cache(net, (uint16_t) decrypt_idx, src,
 							crpl, seq, iv_index)) {
-			forward.done = true;
+			result = true;
 			goto done;
 		}
 	}
@@ -608,59 +831,86 @@ bool mesh_model_rx(struct mesh_net *net, bool szmict, uint32_t seq0,
 	if (!num_ele || IS_UNASSIGNED(addr))
 		goto done;
 
+	is_subscription = !(IS_UNICAST(dst));
+
 	for (i = 0; i < num_ele; i++) {
 		struct l_queue *models;
 
-		if (dst < 0x8000 && ele_idx != i)
+		if (!is_subscription && ele_idx != i)
 			continue;
 
 		forward.unicast = addr + i;
+		forward.has_dst = false;
+
 		models = node_get_element_models(node, i, NULL);
+
+		/* Internal models */
 		l_queue_foreach(models, forward_model, &forward);
 
-		if (dst < 0x8000 && ele_idx == i)
+		/*
+		 * Cycle through external models if the message has not been
+		 * handled by internal models
+		 */
+		if (forward.has_dst && !forward.done)
+			send_msg_rcvd(node, i, is_subscription, src,
+					forward.idx, forward.size,
+					forward.data);
+
+		/*
+		 * Either the message has been processed internally or
+		 * has been passed on to an external model.
+		 */
+		result = forward.has_dst | forward.done;
+
+		/* If the message was to unicast address, we are done */
+		if (!is_subscription && ele_idx == i)
 			break;
 	}
+
 done:
 	l_free(clear_text);
-	return forward.done;
+	return result;
 }
 
-unsigned int mesh_model_send(struct mesh_net *net, uint32_t mod_id,
-				uint16_t src, uint32_t target,
-				uint16_t app_idx, uint8_t ttl,
+int mesh_model_publish(struct mesh_node *node, uint32_t mod_id,
+				uint16_t src, uint8_t ttl,
 				const void *msg, uint16_t msg_len)
 {
+	struct mesh_net *net = node_get_net(node);
 	struct mesh_model *mod;
+	uint32_t target;
 	uint8_t *aad = NULL;
 	uint16_t dst;
 	uint8_t key_id;
 	const uint8_t *key;
+	bool result;
 
 	/* print_packet("Mod Tx", msg, msg_len); */
 
 	if (!net || msg_len > 380)
-		return 0;
+		return MESH_ERROR_INVALID_ARGS;
 
 	/* If SRC is 0, use the Primary Element */
 	if (src == 0)
 		src = mesh_net_get_address(net);
 
-	mod = find_model(net, src, mod_id, NULL);
+	mod = find_model(node, src, mod_id, NULL);
 	if (!mod) {
-		l_info("model %x not found", mod_id);
-		return 0;
+		l_debug("model %x not found", mod_id);
+		return MESH_ERROR_NOT_FOUND;
+	}
+
+	if (!mod->pub) {
+		l_debug("publication doesn't exist (model %x)", mod_id);
+		return MESH_ERROR_DOES_NOT_EXIST;
 	}
 
 	gettimeofday(&tx_start, NULL);
 
-	if (target == USE_PUB_VALUE) {
-		target = mod->pub->addr;
-		app_idx = mod->pub->idx;
-	}
+	target = mod->pub->addr;
 
 	if (IS_UNASSIGNED(target))
-		return 0;
+		return false;
 
 	if (target >= VIRTUAL_BASE) {
 		struct mesh_virtual *virt = l_queue_find(mesh_virtuals,
@@ -668,101 +918,139 @@ unsigned int mesh_model_send(struct mesh_net *net, uint32_t mod_id,
 				L_UINT_TO_PTR(target));
 
 		if (!virt)
-			return 0;
+			return false;
 
 		aad = virt->addr;
 		dst = virt->ota;
-	} else
+	} else {
 		dst = target;
+	}
+
+	l_debug("publish dst=%x", dst);
+
+	key = appkey_get_key(net, mod->pub->idx, &key_id);
+	if (!key) {
+		l_debug("no app key for (%x)", mod->pub->idx);
+		return false;
+	}
+
+	l_debug("(%x) %p", mod->pub->idx, key);
+	l_debug("key_id %x", key_id);
+
+	result = msg_send(node, pub_frnd_cred(node, src, mod_id), src,
+				dst, key_id, key, aad, ttl, msg, msg_len);
+
+	return result ? MESH_ERROR_NONE : MESH_ERROR_FAILED;
+
+}
+
+bool mesh_model_send(struct mesh_node *node, uint16_t src, uint16_t target,
+					uint16_t app_idx, uint8_t ttl,
+					const void *msg, uint16_t msg_len)
+{
+	uint8_t key_id;
+	const uint8_t *key;
+
+	/* print_packet("Mod Tx", msg, msg_len); */
+
+	/* If SRC is 0, use the Primary Element */
+	if (src == 0)
+		src = node_get_primary(node);
 
-	l_debug("dst=%x", dst);
-	if (app_idx == APP_IDX_DEV && mesh_net_provisioner_mode_get(net)) {
-		key = node_get_device_key(mesh_net_local_node_get(net));
-	} else if (app_idx == APP_IDX_DEV) {
-		key = node_get_device_key(mesh_net_local_node_get(net));
+	gettimeofday(&tx_start, NULL);
+
+	if (IS_UNASSIGNED(target))
+		return false;
+
+	if (app_idx == APP_IDX_DEV) {
+		key = node_get_device_key(node);
 		if (!key)
-			return 0;
+			return false;
 
 		l_debug("(%x)", app_idx);
 		key_id = APP_ID_DEV;
 	} else {
-		key = appkey_get_key(net, app_idx, &key_id);
+		key = appkey_get_key(node_get_net(node), app_idx, &key_id);
 		if (!key) {
 			l_debug("no app key for (%x)", app_idx);
-			return 0;
+			return false;
 		}
 
 		l_debug("(%x) %p", app_idx, key);
 		l_debug("key_id %x", key_id);
 	}
 
-	return msg_send(net, mod_id, src, dst, key_id, key, aad, ttl,
+	return msg_send(node, false, src, target, key_id, key, NULL, ttl,
 			msg, msg_len);
-
 }
 
-int mesh_model_pub_set(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_pub_set(struct mesh_node *node, uint16_t addr, uint32_t id,
 			const uint8_t *mod_addr, uint16_t idx, bool cred_flag,
 			uint8_t ttl, uint8_t period, uint8_t retransmit,
 			bool b_virt, uint16_t *dst)
 {
 	int fail = MESH_STATUS_SUCCESS;
-	int ele_idx = -1;
+	int ele_idx;
 	struct mesh_model *mod;
-	struct mesh_node *node;
+	int result;
 
-	node = mesh_net_local_node_get(net);
-	if (node)
-		ele_idx = node_get_element_idx(node, addr);
+	ele_idx = node_get_element_idx(node, addr);
 
-	if (!node || ele_idx < 0) {
+	if (ele_idx < 0) {
 		fail = MESH_STATUS_INVALID_ADDRESS;
 		return false;
 	}
 
-	mod = node_get_model(node, (uint8_t) ele_idx, id, &fail);
+	mod = get_model(node, (uint8_t) ele_idx, id, &fail);
 	if (!mod)
 		return fail;
 
 	if (id == CONFIG_SRV_MODEL || id == CONFIG_CLI_MODEL)
 		return MESH_STATUS_INVALID_PUB_PARAM;
 
-	if (!appkey_have_key(net, idx))
+	if (!appkey_have_key(node_get_net(node), idx))
 		return MESH_STATUS_INVALID_APPKEY;
 
-	return set_pub(mod, mod_addr, idx, cred_flag, ttl, period, retransmit,
+	result = set_pub(mod, mod_addr, idx, cred_flag, ttl, period, retransmit,
 								b_virt, dst);
+
+	if (result != MESH_STATUS_SUCCESS)
+		return result;
+
+	/* TODO: save to storage */
+
 	/*
-	 * TODO: Add standardized Publication Change notification to model
-	 * definition
+	 * If the publication address is set to unassigned address value,
+	 * remove publication
 	 */
+	if (IS_UNASSIGNED(*dst))
+		remove_pub(node, mod);
+
+	/* Internal model, call registered callbacks */
+	if (mod->cbs && mod->cbs->pub) {
+		mod->cbs->pub(mod->pub);
+		return MESH_STATUS_SUCCESS;
+	}
+
+	/* External model */
+	config_update_model_pub_period(node, ele_idx, id,
+					convert_pub_period_to_ms(period));
+
+	return MESH_STATUS_SUCCESS;
 }
 
-struct mesh_model_pub *mesh_model_pub_get(struct mesh_net *net, uint8_t ele_idx,
-						uint32_t mod_id, int *status)
+struct mesh_model_pub *mesh_model_pub_get(struct mesh_node *node,
+				 uint8_t ele_idx, uint32_t mod_id, int *status)
 {
 	struct mesh_model *mod;
-	struct mesh_node *node = mesh_net_local_node_get(net);
-
-	if (!node) {
-		*status = MESH_STATUS_INVALID_ADDRESS;
-		return NULL;
-	}
 
-	mod = node_get_model(node, ele_idx, mod_id, status);
+	mod = get_model(node, ele_idx, mod_id, status);
 	if (!mod)
 		return NULL;
 
 	return mod->pub;
 }
 
-uint32_t mesh_model_get_model_id(const struct mesh_model *model)
-{
-	if (!model)
-		return 0xffffffff; /* TODO: use define */
-	return model->id;
-}
-
 void mesh_model_free(void *data)
 {
 	struct mesh_model *mod = data;
@@ -774,33 +1062,39 @@ void mesh_model_free(void *data)
 	l_free(mod);
 }
 
-struct mesh_model *mesh_model_new(uint8_t ele_idx, uint32_t id, bool vendor)
+static struct mesh_model *model_new(uint8_t ele_idx, uint32_t id)
 {
 	struct mesh_model *mod = l_new(struct mesh_model, 1);
 
-	if (!mod)
-		return NULL;
-
-	if (vendor)
-		id |= VENDOR_ID_MASK;
-
 	mod->id = id;
 	mod->ele_idx = ele_idx;
 	mod->virtuals = l_queue_new();
-	if (!mod->virtuals) {
-		l_free(mod);
-		return NULL;
-	}
 	return mod;
 }
 
-static void restore_model_state(void *data)
+struct mesh_model *mesh_model_new(uint8_t ele_idx, uint16_t id)
 {
-	struct mesh_model *mod = data;
+	return model_new(ele_idx, id | VENDOR_ID_MASK);
+}
+
+struct mesh_model *mesh_model_vendor_new(uint8_t ele_idx, uint16_t vendor_id,
+								uint16_t mod_id)
+{
+	uint32_t id = mod_id | (vendor_id << 16);
+
+	return model_new(ele_idx, id);
+}
+
+/* Internal models only */
+static void restore_model_state(struct mesh_model *mod)
+{
+
 	const struct mesh_model_ops *cbs;
 	const struct l_queue_entry *b;
 
 	cbs = mod->cbs;
+	if (!cbs)
+		return;
 
 	if (l_queue_isempty(mod->bindings) || !mod->cbs->bind) {
 		for (b = l_queue_get_entries(mod->bindings); b; b = b->next) {
@@ -812,63 +1106,64 @@ static void restore_model_state(void *data)
 
 	if (mod->pub && cbs->pub)
 		cbs->pub(mod->pub);
+
 }
 
-bool mesh_model_vendor_register(struct mesh_net *net, uint8_t ele_idx,
+uint32_t mesh_model_get_model_id(const struct mesh_model *model)
+{
+	return model->id;
+}
+
+/* This registers an internal model, i.e. implemented within meshd */
+bool mesh_model_register(struct mesh_node *node, uint8_t ele_idx,
 					uint32_t mod_id,
 					const struct mesh_model_ops *cbs,
 					void *user_data)
 {
 	struct mesh_model *mod;
-	struct mesh_node *node;
 
-	node = mesh_net_local_node_get(net);
-	if (!node)
-		return false;
+	/* Internal models are always SIG models */
+	mod_id = VENDOR_ID_MASK | mod_id;
 
-	mod = node_get_model(node, ele_idx, mod_id, NULL);
+	mod = get_model(node, ele_idx, mod_id, NULL);
 	if (!mod)
 		return false;
 
 	mod->cbs = cbs;
 	mod->user_data = user_data;
 
-	l_idle_oneshot(restore_model_state, mod, NULL);
+	restore_model_state(mod);
 
 	return true;
 }
 
-bool mesh_model_register(struct mesh_net *net, uint8_t ele_idx,
-					uint32_t mod_id,
-					const struct mesh_model_ops *cbs,
-					void *user_data)
+void mesh_model_app_key_delete(struct mesh_node *node, struct l_queue *models,
+							uint16_t app_idx)
 {
-	uint32_t id = VENDOR_ID_MASK | mod_id;
+	const struct l_queue_entry *entry = l_queue_get_entries(models);
 
-	return mesh_model_vendor_register(net, ele_idx, id, cbs, user_data);
-}
+	for (; entry; entry = entry->next) {
+		struct mesh_model *model = entry->data;
 
-void mesh_model_app_key_delete(struct mesh_net *net, struct l_queue *models,
-							uint16_t app_idx)
-{
-	l_queue_foreach(models, model_unbind_idx, L_UINT_TO_PTR(app_idx));
+		model_unbind_idx(node, model, app_idx);
+	}
 }
 
-int mesh_model_binding_del(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_binding_del(struct mesh_node *node, uint16_t addr, uint32_t id,
 						uint16_t app_idx)
 {
 	l_debug("0x%x, 0x%x, %d", addr, id, app_idx);
-	return update_binding(net, addr, id, app_idx, true);
+	return update_binding(node, addr, id, app_idx, true);
 }
 
-int mesh_model_binding_add(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_binding_add(struct mesh_node *node, uint16_t addr, uint32_t id,
 						uint16_t app_idx)
 {
 	l_debug("0x%x, 0x%x, %d", addr, id, app_idx);
-	return update_binding(net, addr, id, app_idx, false);
+	return update_binding(node, addr, id, app_idx, false);
 }
 
-int mesh_model_get_bindings(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_get_bindings(struct mesh_node *node, uint16_t addr, uint32_t id,
 				uint8_t *buf, uint16_t buf_size, uint16_t *size)
 {
 	int fail;
@@ -878,7 +1173,7 @@ int mesh_model_get_bindings(struct mesh_net *net, uint16_t addr, uint32_t id,
 	uint32_t idx_pair;
 	int i;
 
-	mod = find_model(net, addr, id, &fail);
+	mod = find_model(node, addr, id, &fail);
 
 	if (!mod) {
 		*size = 0;
@@ -922,7 +1217,7 @@ done:
 	return MESH_STATUS_SUCCESS;
 }
 
-int mesh_model_sub_get(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_sub_get(struct mesh_node *node, uint16_t addr, uint32_t id,
 			uint8_t *buf, uint16_t buf_size, uint16_t *size)
 {
 	int fail = MESH_STATUS_SUCCESS;
@@ -930,7 +1225,7 @@ int mesh_model_sub_get(struct mesh_net *net, uint16_t addr, uint32_t id,
 	struct mesh_model *mod;
 	const struct l_queue_entry *entry;
 
-	mod = find_model(net, addr, id, &fail);
+	mod = find_model(node, addr, id, &fail);
 	if (!mod)
 		return fail;
 
@@ -951,32 +1246,29 @@ int mesh_model_sub_get(struct mesh_net *net, uint16_t addr, uint32_t id,
 	return MESH_STATUS_SUCCESS;
 }
 
-int mesh_model_sub_add(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_sub_add(struct mesh_node *node, uint16_t addr, uint32_t id,
 			const uint8_t *group, bool b_virt, uint16_t *dst)
 {
 	int fail = MESH_STATUS_SUCCESS;
 	int ele_idx = -1;
 	struct mesh_model *mod;
-	struct mesh_node *node;
 
-	node = mesh_net_local_node_get(net);
-	if (node)
-		ele_idx = node_get_element_idx(node, addr);
+	ele_idx = node_get_element_idx(node, addr);
 
 	if (!node || ele_idx < 0) {
 		fail = MESH_STATUS_INVALID_ADDRESS;
 		return false;
 	}
 
-	mod = node_get_model(node, (uint8_t) ele_idx, id, &fail);
+	mod = get_model(node, (uint8_t) ele_idx, id, &fail);
 	if (!mod)
 		return fail;
 
-	return add_sub(net, mod, group, b_virt, dst);
+	return add_sub(node_get_net(node), mod, group, b_virt, dst);
 	/* TODO: communicate to registered models that sub has changed */
 }
 
-int mesh_model_sub_ovr(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_sub_ovr(struct mesh_node *node, uint16_t addr, uint32_t id,
 			const uint8_t *group, bool b_virt, uint16_t *dst)
 {
 	int fail = MESH_STATUS_SUCCESS;
@@ -984,7 +1276,7 @@ int mesh_model_sub_ovr(struct mesh_net *net, uint16_t addr, uint32_t id,
 	struct mesh_virtual *virt;
 	struct mesh_model *mod;
 
-	mod = find_model(net, addr, id, &fail);
+	mod = find_model(node, addr, id, &fail);
 	if (!mod)
 		return fail;
 
@@ -1009,7 +1301,7 @@ int mesh_model_sub_ovr(struct mesh_net *net, uint16_t addr, uint32_t id,
 		}
 	}
 
-	fail = mesh_model_sub_add(net, addr, id, group, b_virt, dst);
+	fail = mesh_model_sub_add(node, addr, id, group, b_virt, dst);
 
 	if (fail) {
 		/* Adding new group failed, so revert to old list */
@@ -1019,6 +1311,7 @@ int mesh_model_sub_ovr(struct mesh_net *net, uint16_t addr, uint32_t id,
 		mod->virtuals = virtuals;
 	} else {
 		const struct l_queue_entry *entry;
+		struct mesh_net *net = node_get_net(node);
 
 		entry = l_queue_get_entries(subs);
 		for (; entry; entry = entry->next)
@@ -1032,14 +1325,14 @@ int mesh_model_sub_ovr(struct mesh_net *net, uint16_t addr, uint32_t id,
 	return fail;
 }
 
-int mesh_model_sub_del(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_sub_del(struct mesh_node *node, uint16_t addr, uint32_t id,
 			const uint8_t *group, bool b_virt, uint16_t *dst)
 {
 	int fail = MESH_STATUS_SUCCESS;
 	uint16_t grp;
 	struct mesh_model *mod;
 
-	mod = find_model(net, addr, id, &fail);
+	mod = find_model(node, addr, id, &fail);
 	if (!mod)
 		return fail;
 
@@ -1062,18 +1355,19 @@ int mesh_model_sub_del(struct mesh_net *net, uint16_t addr, uint32_t id,
 	*dst = grp;
 
 	if (l_queue_remove(mod->subs, L_UINT_TO_PTR(grp)))
-		mesh_net_dst_unreg(net, grp);
+		mesh_net_dst_unreg(node_get_net(node), grp);
 
 	return MESH_STATUS_SUCCESS;
 }
 
-int mesh_model_sub_del_all(struct mesh_net *net, uint16_t addr, uint32_t id)
+int mesh_model_sub_del_all(struct mesh_node *node, uint16_t addr, uint32_t id)
 {
 	int fail = MESH_STATUS_SUCCESS;
 	struct mesh_model *mod;
 	const struct l_queue_entry *entry;
+	struct mesh_net *net = node_get_net(node);
 
-	mod = find_model(net, addr, id, &fail);
+	mod = find_model(node, addr, id, &fail);
 	if (!mod)
 		return fail;
 
@@ -1088,15 +1382,22 @@ int mesh_model_sub_del_all(struct mesh_net *net, uint16_t addr, uint32_t id)
 	return fail;
 }
 
-struct mesh_model *mesh_model_init(struct mesh_net *net, uint8_t ele_idx,
-						struct mesh_db_model *db_mod)
+struct mesh_model *mesh_model_setup(struct mesh_node *node, uint8_t ele_idx,
+								void *data)
 {
+	struct mesh_db_model *db_mod = data;
 	struct mesh_model *mod;
+	struct mesh_net *net;
 	uint32_t i;
 
-	mod = mesh_model_new(ele_idx, db_mod->id, db_mod->vendor);
-	if (!mod)
+	if (db_mod->num_bindings > MAX_BINDINGS) {
+		l_warn("Binding list too long %u (max %u)",
+					db_mod->num_bindings, MAX_BINDINGS);
 		return NULL;
+	}
+
+	mod = model_new(ele_idx, db_mod->vendor ? db_mod->id :
+						db_mod->id | VENDOR_ID_MASK);
 
 	/* Implicitly bind config server model to device key */
 	if (db_mod->id == CONFIG_SRV_MODEL) {
@@ -1113,35 +1414,27 @@ struct mesh_model *mesh_model_init(struct mesh_net *net, uint8_t ele_idx,
 		return mod;
 	}
 
+	net = node_get_net(node);
+
 	/* Add application key bindings if present */
 	if (db_mod->bindings) {
 		mod->bindings = l_queue_new();
-
-		if (!mod->bindings) {
-			mesh_model_free(mod);
-			return NULL;
-		}
-
-		for (i = 0; i < db_mod->num_bindings; i++) {
-			if (!model_bind_idx(mod, db_mod->bindings[i])) {
-				mesh_model_free(mod);
-				return NULL;
-			}
-		}
+		for (i = 0; i < db_mod->num_bindings; i++)
+			model_bind_idx(node, mod, db_mod->bindings[i]);
 	}
 
 	/* Add publication if present */
 	if (db_mod->pub) {
-		uint16_t mod_addr;
-		uint8_t *dst;
+		struct mesh_db_pub *pub = db_mod->pub;
+		uint8_t mod_addr[2];
+		uint8_t *pub_addr;
 
-		l_put_le16(db_mod->pub->addr, &mod_addr);
-		dst = db_mod->pub->virt ? db_mod->pub->virt_addr :
-							(uint8_t *) &mod_addr;
+		/* Add publication */
+		l_put_le16(pub->addr, &mod_addr);
+		pub_addr = pub->virt ? pub->virt_addr : (uint8_t *) &mod_addr;
 
-		if (set_pub(mod, dst, db_mod->pub->idx, db_mod->pub->credential,
-			db_mod->pub->ttl, db_mod->pub->period,
-			db_mod->pub->retransmit, db_mod->pub->virt, NULL) !=
+		if (set_pub(mod, pub_addr, pub->idx, pub->credential, pub->ttl,
+			pub->period, pub->retransmit, pub->virt, NULL) !=
 							MESH_STATUS_SUCCESS) {
 			mesh_model_free(mod);
 			return NULL;
@@ -1192,7 +1485,7 @@ uint16_t mesh_model_opcode_set(uint32_t opcode, uint8_t *buf)
 		return 3;
 	}
 
-	l_info("Illegal Opcode %x", opcode);
+	l_debug("Illegal Opcode %x", opcode);
 	return 0;
 }
 
@@ -1238,7 +1531,7 @@ bool mesh_model_opcode_get(const uint8_t *buf, uint16_t size,
 	return true;
 }
 
-void mesh_model_add_virtual(struct mesh_net *net, const uint8_t *v)
+void mesh_model_add_virtual(struct mesh_node *node, const uint8_t *v)
 {
 	struct mesh_virtual *virt = l_queue_find(mesh_virtuals,
 						find_virt_by_addr, v);
@@ -1263,7 +1556,7 @@ void mesh_model_add_virtual(struct mesh_net *net, const uint8_t *v)
 	l_queue_push_head(mesh_virtuals, virt);
 }
 
-void mesh_model_del_virtual(struct mesh_net *net, uint32_t va24)
+void mesh_model_del_virtual(struct mesh_node *node, uint32_t va24)
 {
 	struct mesh_virtual *virt = l_queue_remove_if(mesh_virtuals,
 						find_virt_by_id,
@@ -1272,3 +1565,55 @@ void mesh_model_del_virtual(struct mesh_net *net, uint32_t va24)
 	if (virt)
 		unref_virt(virt);
 }
+
+void model_build_config(void *model, void *msg_builder)
+{
+	struct l_dbus_message_builder *builder = msg_builder;
+	struct mesh_model *mod = model;
+	uint16_t id;
+
+	if (is_internal(mod->id))
+		return;
+
+	if (!l_queue_length(mod->subs) && !l_queue_length(mod->virtuals) &&
+				!mod->pub && !l_queue_length(mod->bindings))
+		return;
+
+	l_dbus_message_builder_enter_struct(builder, "qa{sv}");
+
+	/* Model id */
+	id = mod->id & 0xffff;
+	l_dbus_message_builder_append_basic(builder, 'q', &id);
+
+	l_dbus_message_builder_enter_array(builder, "{sv}");
+
+	/* For vendor models, add vendor id */
+	if ((mod->id & VENDOR_ID_MASK) != VENDOR_ID_MASK) {
+		uint16_t vendor = mod->id >> 16;
+		dbus_append_dict_entry_basic(builder, "Vendor", "q", &vendor);
+	}
+
+	/* Model bindings, if present */
+	if (l_queue_length(mod->bindings))
+		append_dict_uint16_array(builder, mod->bindings, "Bindings");
+
+	/* Model periodic publication interval, if present */
+	if (mod->pub) {
+		uint32_t period = convert_pub_period_to_ms(mod->pub->period);
+		dbus_append_dict_entry_basic(builder, "PublicationPeriod", "u",
+								&period);
+	}
+
+	l_dbus_message_builder_leave_array(builder);
+	l_dbus_message_builder_leave_struct(builder);
+}
+
+void mesh_model_init(void)
+{
+	mesh_virtuals = l_queue_new();
+}
+
+void mesh_model_cleanup(void)
+{
+	l_queue_destroy(mesh_virtuals, l_free);
+}
diff --git a/mesh/model.h b/mesh/model.h
index 3a41bd722..95acfe588 100644
--- a/mesh/model.h
+++ b/mesh/model.h
@@ -85,62 +85,64 @@ struct mesh_model_ops {
 	mesh_model_sub_cb sub;
 };
 
-struct mesh_model *mesh_model_new(uint8_t ele_idx, uint32_t id, bool vendor);
+struct mesh_model *mesh_model_new(uint8_t ele_idx, uint16_t mod_id);
+struct mesh_model *mesh_model_vendor_new(uint8_t ele_idx, uint16_t vendor_id,
+							uint16_t mod_id);
 void mesh_model_free(void *data);
 uint32_t mesh_model_get_model_id(const struct mesh_model *model);
-bool mesh_model_vendor_register(struct mesh_net *net, uint8_t ele_idx,
-					uint32_t mod_id,
-					const struct mesh_model_ops *cbs,
-					void *user_data);
-bool mesh_model_register(struct mesh_net *net, uint8_t ele_idx, uint32_t mod_id,
-					const struct mesh_model_ops *cbs,
+bool mesh_model_register(struct mesh_node *node, uint8_t ele_idx,
+			uint32_t mod_id, const struct mesh_model_ops *cbs,
 							void *user_data);
-struct mesh_model_pub *mesh_model_pub_get(struct mesh_net *net, uint8_t ele_idx,
-						uint32_t mod_id, int *status);
-int mesh_model_pub_set(struct mesh_net *net, uint16_t addr, uint32_t id,
+struct mesh_model_pub *mesh_model_pub_get(struct mesh_node *node,
+				uint8_t ele_idx, uint32_t mod_id, int *status);
+int mesh_model_pub_set(struct mesh_node *node, uint16_t addr, uint32_t id,
 			const uint8_t *mod_addr, uint16_t idx, bool cred_flag,
 			uint8_t ttl, uint8_t period, uint8_t retransmit,
 			bool b_virt, uint16_t *dst);
-struct mesh_model *mesh_model_init(struct mesh_net *net, uint8_t ele_idx,
-						struct mesh_db_model *db_mod);
+struct mesh_model *mesh_model_setup(struct mesh_node *node, uint8_t ele_idx,
+								void *data);
 
-int mesh_model_binding_add(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_binding_add(struct mesh_node *node, uint16_t addr, uint32_t id,
 						uint16_t app_idx);
-int mesh_model_binding_del(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_binding_del(struct mesh_node *node, uint16_t addr, uint32_t id,
 						uint16_t idx);
-int mesh_model_get_bindings(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_get_bindings(struct mesh_node *node, uint16_t addr, uint32_t id,
 				uint8_t *buf, uint16_t buf_len, uint16_t *size);
-int mesh_model_sub_add(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_sub_add(struct mesh_node *node, uint16_t addr, uint32_t id,
 						const uint8_t *grp, bool b_virt,
 						uint16_t *dst);
-int mesh_model_sub_del(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_sub_del(struct mesh_node *node, uint16_t addr, uint32_t id,
 						const uint8_t *grp, bool b_virt,
 						uint16_t *dst);
-int mesh_model_sub_del_all(struct mesh_net *net, uint16_t addr, uint32_t id);
-int mesh_model_sub_ovr(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_sub_del_all(struct mesh_node *node, uint16_t addr, uint32_t id);
+int mesh_model_sub_ovr(struct mesh_node *node, uint16_t addr, uint32_t id,
 						const uint8_t *grp, bool b_virt,
 						uint16_t *dst);
-int mesh_model_sub_get(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_sub_get(struct mesh_node *node, uint16_t addr, uint32_t id,
 			uint8_t *buf, uint16_t buf_size, uint16_t *size);
 uint16_t mesh_model_cfg_blk(uint8_t *pkt);
-unsigned int mesh_model_send(struct mesh_net *net, uint32_t mod_id,
-				uint16_t src, uint32_t target,
-				uint16_t app_idx, uint8_t ttl,
+bool mesh_model_send(struct mesh_node *node, uint16_t src, uint16_t target,
+					uint16_t app_idx, uint8_t ttl,
+					const void *msg, uint16_t msg_len);
+int mesh_model_publish(struct mesh_node *node, uint32_t mod_id,
+				uint16_t src, uint8_t ttl,
 				const void *msg, uint16_t msg_len);
-
-bool mesh_model_rx(struct mesh_net *net, bool szmict, uint32_t seq0,
+bool mesh_model_rx(struct mesh_node *node, bool szmict, uint32_t seq0,
 			uint32_t seq, uint32_t iv_index, uint8_t ttl,
 			uint16_t src, uint16_t dst, uint8_t key_id,
 			const uint8_t *data, uint16_t size);
 
-void mesh_model_app_key_generate_new(struct mesh_net *net, uint16_t net_idx);
-void mesh_model_app_key_delete(struct mesh_net *net, struct l_queue *models,
+void mesh_model_app_key_generate_new(struct mesh_node *node, uint16_t net_idx);
+void mesh_model_app_key_delete(struct mesh_node *node, struct l_queue *models,
 								uint16_t idx);
-struct l_queue *mesh_model_get_appkeys(struct mesh_net *net);
-void *mesh_model_get_local_node_data(struct mesh_net *net);
-void mesh_model_add_virtual(struct mesh_net *net, const uint8_t *v);
-void mesh_model_del_virtual(struct mesh_net *net, uint32_t va24);
-void mesh_model_list_virtual(struct mesh_net *net);
+struct l_queue *mesh_model_get_appkeys(struct mesh_node *node);
+void mesh_model_add_virtual(struct mesh_node *node, const uint8_t *v);
+void mesh_model_del_virtual(struct mesh_node *node, uint32_t va24);
+void mesh_model_list_virtual(struct mesh_node *node);
 uint16_t mesh_model_opcode_set(uint32_t opcode, uint8_t *buf);
 bool mesh_model_opcode_get(const uint8_t *buf, uint16_t size,
 					uint32_t *opcode, uint16_t *n);
+void model_build_config(void *model, void *msg_builder);
+
+void mesh_model_init(void);
+void mesh_model_cleanup(void);
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 21/30] mesh: DBUS interface for Provisioning Agent
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (19 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 20/30] mesh: restructure model services for " Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 22/30] mesh: restructure App Key storage Brian Gix
                   ` (9 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel

From: Inga Stotland <inga.stotland@intel.com>

---
 mesh/agent.c | 665 ++++++++++++++++++++++++++++++++++++++++++++++++-----------
 mesh/agent.h |  71 +++++--
 2 files changed, 593 insertions(+), 143 deletions(-)

diff --git a/mesh/agent.c b/mesh/agent.c
index 1da10b7bd..db61e27ab 100644
--- a/mesh/agent.c
+++ b/mesh/agent.c
@@ -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);
 }
diff --git a/mesh/agent.h b/mesh/agent.h
index 6fb475691..d90e1c17d 100644
--- a/mesh/agent.h
+++ b/mesh/agent.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2017  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2018  Intel Corporation. All rights reserved.
  *
  *
  *  This library is free software; you can redistribute it and/or
@@ -18,25 +18,56 @@
  *
  */
 
-#define MAX_HEXADECIMAL_OOB_LEN	128
-#define DECIMAL_OOB_LEN		4
-#define MAX_ASCII_OOB_LEN		16
+struct mesh_agent;
 
-enum oob_type {
-	NONE,
-	HEXADECIMAL,
-	DECIMAL,
-	ASCII,
-	OUTPUT,
-} oob_type_t;
+struct mesh_agent_prov_caps {
+	uint32_t uri_hash;
+	uint16_t oob_info;
+	uint16_t output_action;
+	uint16_t input_action;
+	uint8_t pub_type;
+	uint8_t static_type;
+	uint8_t output_size;
+	uint8_t input_size;
+};
 
-typedef void (*agent_input_cb)(enum oob_type type, void *input, uint16_t len,
+typedef void (*mesh_agent_cb_t) (void *user_data, mesh_error_t err);
+
+typedef void (*mesh_agent_key_cb_t) (void *user_data, mesh_error_t err,
+						uint8_t *key, uint32_t len);
+
+typedef void (*mesh_agent_number_cb_t) (void *user_data,
+					mesh_error_t err, uint32_t number);
+
+void mesh_agent_init(void);
+void mesh_agent_cleanup(void);
+struct mesh_agent *mesh_agent_create(const char *path, const char *owner,
+					struct l_dbus_message_iter *properties);
+
+void mesh_agent_remove(struct mesh_agent *agent);
+void mesh_agent_cancel(struct mesh_agent *agent);
+
+struct mesh_agent_prov_caps *mesh_agent_get_caps(struct mesh_agent *agent);
+
+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);
+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);
+mesh_error_t mesh_agent_prompt_alpha(struct mesh_agent *agent,
+							mesh_agent_key_cb_t cb,
+							void *user_data);
+mesh_error_t mesh_agent_request_static(struct mesh_agent *agent,
+							mesh_agent_key_cb_t cb,
+							void *user_data);
+mesh_error_t mesh_agent_request_private_key(struct mesh_agent *agent,
+							mesh_agent_key_cb_t cb,
+							void *user_data);
+mesh_error_t mesh_agent_request_public_key(struct mesh_agent *agent,
+							mesh_agent_key_cb_t cb,
 							void *user_data);
-bool agent_input_request(enum oob_type type, uint16_t max_len,
-					agent_input_cb cb, void *user_data);
-
-bool agent_output_request(const char *str);
-void agent_output_request_cancel(void);
-bool agent_completion(void);
-bool agent_input(const char *input);
-void agent_release(void);
+mesh_error_t mesh_agent_display_string(struct mesh_agent *agent,
+					const char *str, mesh_agent_cb_t cb,
+					void *user_data);
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 22/30] mesh: restructure App Key storage
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (20 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 21/30] mesh: DBUS interface for Provisioning Agent Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 23/30] mesh: Clean-up Comment style Brian Gix
                   ` (8 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel

From: Inga Stotland <inga.stotland@intel.com>

---
 mesh/appkey.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/mesh/appkey.c b/mesh/appkey.c
index 3d445d217..c4ebf16b6 100644
--- a/mesh/appkey.c
+++ b/mesh/appkey.c
@@ -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;
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 23/30] mesh: Clean-up Comment style
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (21 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 22/30] mesh: restructure App Key storage Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 24/30] mesh: Update for DBus API and multi-node support Brian Gix
                   ` (7 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, Brian Gix

---
 mesh/friend.c | 76 +++++++++++++++++++++++++++++------------------------------
 1 file changed, 38 insertions(+), 38 deletions(-)

diff --git a/mesh/friend.c b/mesh/friend.c
index 9ce499463..d17fde084 100644
--- a/mesh/friend.c
+++ b/mesh/friend.c
@@ -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;
 		}
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 24/30] mesh: Update for DBus API and multi-node support
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (22 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 23/30] mesh: Clean-up Comment style Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 25/30] mesh: Add default location for Mesh Node storage Brian Gix
                   ` (6 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel

From: Inga Stotland <inga.stotland@intel.com>

---
 mesh/main.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 66 insertions(+), 7 deletions(-)

diff --git a/mesh/main.c b/mesh/main.c
index 173f57a8f..95a66cc9d 100644
--- a/mesh/main.c
+++ b/mesh/main.c
@@ -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;
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 25/30] mesh: Add default location for Mesh Node storage
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (23 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 24/30] mesh: Update for DBus API and multi-node support Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 23:15   ` Marcel Holtmann
  2018-12-18 22:31 ` [PATCH BlueZ v4 26/30] mesh: Add structural changes for mesh Brian Gix
                   ` (5 subsequent siblings)
  30 siblings, 1 reply; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel

From: Inga Stotland <inga.stotland@intel.com>

---
 configure.ac | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/configure.ac b/configure.ac
index 1a095a352..901d51e0f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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}])
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 26/30] mesh: Add structural changes for mesh
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (24 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 25/30] mesh: Add default location for Mesh Node storage Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 27/30] mesh: Sample Provisioning Agent Brian Gix
                   ` (4 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel

From: Inga Stotland <inga.stotland@intel.com>

---
 Makefile.mesh | 19 ++++++-------------
 1 file changed, 6 insertions(+), 13 deletions(-)

diff --git a/Makefile.mesh b/Makefile.mesh
index 8b5af4cf6..ea6c5e939 100644
--- a/Makefile.mesh
+++ b/Makefile.mesh
@@ -3,35 +3,28 @@ if MESH
 mesh_sources = mesh/mesh.h mesh/mesh.c \
 				mesh/net_keys.h mesh/net_keys.c \
 				mesh/mesh-io.h mesh/mesh-io.c \
-				mesh/mesh-io-api.h \
+				mesh/error.h mesh/mesh-io-api.h \
 				mesh/mesh-io-generic.h \
 				mesh/mesh-io-generic.c \
 				mesh/storage.h mesh/storage.c \
 				mesh/net.h mesh/net.c \
-				mesh/display.h mesh/display.c \
 				mesh/crypto.h mesh/crypto.c \
 				mesh/friend.h mesh/friend.c \
 				mesh/appkey.h mesh/appkey.c \
 				mesh/node.h mesh/node.c \
-				mesh/prov.h mesh/prov.c \
-				mesh/provision.h mesh/provision.c \
+				mesh/provision.h mesh/prov.h \
 				mesh/model.h mesh/model.c \
 				mesh/cfgmod.h mesh/cfgmod-server.c \
 				mesh/mesh-db.h mesh/mesh-db.c \
 				mesh/util.h mesh/util.c \
+				mesh/dbus.h mesh/dbus.c \
+				mesh/agent.h mesh/agent.c \
+				mesh/prov-acceptor.c mesh/prov-initiator.c \
+				mesh/pb-adv.h mesh/pb-adv.c \
 				mesh/mesh-defs.h
 libexec_PROGRAMS += mesh/meshd
 
 mesh_meshd_SOURCES = $(mesh_sources) mesh/main.c
 mesh_meshd_LDADD = src/libshared-ell.la $(ell_ldadd) -ljson-c
 mesh_meshd_DEPENDENCIES = $(ell_dependencies) src/libshared-ell.la
-
-noinst_PROGRAMS += mesh/btmesh
-
-mesh_btmesh_SOURCES = $(mesh_sources) mesh/agent.h \
-						mesh/agent.c \
-						mesh/btmesh.c
-mesh_btmesh_LDADD = src/libshared-mainloop.la $(ell_ldadd) -lreadline -ljson-c
-mesh_btmesh_DEPENDENCIES = $(ell_dependencies)
-
 endif
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 27/30] mesh: Sample Provisioning Agent
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (25 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 26/30] mesh: Add structural changes for mesh Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 28/30] mesh: Sample On/Off Client and Server Brian Gix
                   ` (3 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel

From: Inga Stotland <inga.stotland@intel.com>

---
 mesh/test/agent.py | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)
 create mode 100755 mesh/test/agent.py

diff --git a/mesh/test/agent.py b/mesh/test/agent.py
new file mode 100755
index 000000000..22c92f952
--- /dev/null
+++ b/mesh/test/agent.py
@@ -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)
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 28/30] mesh: Sample On/Off Client and Server
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (26 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 27/30] mesh: Sample Provisioning Agent Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 29/30] mesh: Sample Mesh Joiner (provision acceptor) Brian Gix
                   ` (2 subsequent siblings)
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel

From: Inga Stotland <inga.stotland@intel.com>

---
 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

diff --git a/mesh/test/example-onoff-client b/mesh/test/example-onoff-client
new file mode 100644
index 000000000..e4a87eb12
--- /dev/null
+++ b/mesh/test/example-onoff-client
@@ -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()
diff --git a/mesh/test/example-onoff-server b/mesh/test/example-onoff-server
new file mode 100644
index 000000000..131b6415c
--- /dev/null
+++ b/mesh/test/example-onoff-server
@@ -0,0 +1,365 @@
+#!/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
+
+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
+
+app = None
+bus = None
+mainloop = None
+node = None
+
+token = numpy.uint64(0x76bd4f2372476578)
+
+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 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 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.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
+
+	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()
+		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, 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 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(OnOffServer(0x1000))
+	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()
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 29/30] mesh: Sample Mesh Joiner (provision acceptor)
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (27 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 28/30] mesh: Sample On/Off Client and Server Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 22:31 ` [PATCH BlueZ v4 30/30] mesh: Enable building Mesh Daemon Brian Gix
  2018-12-18 23:00 ` [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Marcel Holtmann
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel

From: Inga Stotland <inga.stotland@intel.com>

---
 mesh/test/test-join | 408 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 408 insertions(+)
 create mode 100644 mesh/test/test-join

diff --git a/mesh/test/test-join b/mesh/test/test-join
new file mode 100644
index 000000000..cdf92a2f1
--- /dev/null
+++ b/mesh/test/test-join
@@ -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()
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH BlueZ v4 30/30] mesh: Enable building Mesh Daemon
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (28 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 29/30] mesh: Sample Mesh Joiner (provision acceptor) Brian Gix
@ 2018-12-18 22:31 ` Brian Gix
  2018-12-18 23:00 ` [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Marcel Holtmann
  30 siblings, 0 replies; 37+ messages in thread
From: Brian Gix @ 2018-12-18 22:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, Brian Gix

---
 Makefile.am | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Makefile.am b/Makefile.am
index 7e92977b7..f84a1faba 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* Re: [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus
  2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
                   ` (29 preceding siblings ...)
  2018-12-18 22:31 ` [PATCH BlueZ v4 30/30] mesh: Enable building Mesh Daemon Brian Gix
@ 2018-12-18 23:00 ` Marcel Holtmann
  2018-12-18 23:05   ` Gix, Brian
  30 siblings, 1 reply; 37+ messages in thread
From: Marcel Holtmann @ 2018-12-18 23:00 UTC (permalink / raw)
  To: Brian Gix; +Cc: linux-bluetooth, Johan Hedberg, inga.stotland

Hi Brian,

> 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.
> 
> v4 -- Remove all trace of foreground btmesh app. It is obsolete, and
> adds no functionality not also present in the meshd executable.
> 
> 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 for mesh
>  mesh: Sample Provisioning Agent
>  mesh: Sample On/Off Client and Server
>  mesh: Sample Mesh Joiner (provision acceptor)
> 
> Makefile.mesh                  |   19 +-
> configure.ac                   |    5 +
> mesh/agent.c                   |  665 ++++++++++++++++----
> mesh/agent.h                   |   71 ++-
> mesh/appkey.c                  |   17 +-
> mesh/btmesh.c                  |  181 ------
> mesh/cfgmod-server.c           |  173 +++---
> mesh/cfgmod.h                  |    2 +-
> mesh/config/composition.json   |   44 —

I have no idea why we would create a directory config here. Put the json files in $(top_srcdir) and be done with it.

> 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 ++++++++++++

Can we please not doing this kind of nesting of directories. Use the $(top_srcdir)/test for this.
> mesh/util.c                    |   26 +
> mesh/util.h                    |    1 +
> 45 files changed, 7177 insertions(+), 3884 deletions(-)
> delete mode 100644 mesh/btmesh.c
> delete mode 100644 mesh/config/composition.json
> create mode 100644 mesh/dbus.c
> create mode 100644 mesh/dbus.h
> delete mode 100644 mesh/display.c
> create mode 100644 mesh/error.h
> create mode 100644 mesh/pb-adv.c
> rename mesh/{display.h => pb-adv.h} (71%)
> create mode 100644 mesh/prov-acceptor.c
> create mode 100644 mesh/prov-initiator.c
> delete mode 100644 mesh/prov.c
> delete mode 100644 mesh/provision.c
> create mode 100755 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-join

Regards

Marcel


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH BlueZ v4 03/30] mesh: Utilities for DBus support
  2018-12-18 22:31 ` [PATCH BlueZ v4 03/30] mesh: Utilities for DBus support Brian Gix
@ 2018-12-18 23:04   ` Marcel Holtmann
  0 siblings, 0 replies; 37+ messages in thread
From: Marcel Holtmann @ 2018-12-18 23:04 UTC (permalink / raw)
  To: Brian Gix; +Cc: linux-bluetooth, Johan Hedberg, inga.stotland

Hi Brian,

> ---
> 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
> 
> diff --git a/mesh/dbus.c b/mesh/dbus.c
> new file mode 100644
> index 000000000..a8b398f9e
> --- /dev/null
> +++ b/mesh/dbus.c
> @@ -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”

please stop these massive includes.

> +
> +struct l_dbus *dbus;

Why is this not static?

> +
> +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[] =

Everything that can be const should be const.

> +{
> +	{ 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);
> +}

Don’t we have proper helpers for this in ELL. And if not, why are they not added?

> +
> +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);
> +}
> diff --git a/mesh/dbus.h b/mesh/dbus.h
> new file mode 100644
> index 000000000..90cbe9e5c
> --- /dev/null
> +++ b/mesh/dbus.h
> @@ -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);

Regards

Marcel


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH BlueZ v4 04/30] mesh: Internal errors
  2018-12-18 22:31 ` [PATCH BlueZ v4 04/30] mesh: Internal errors Brian Gix
@ 2018-12-18 23:05   ` Marcel Holtmann
  0 siblings, 0 replies; 37+ messages in thread
From: Marcel Holtmann @ 2018-12-18 23:05 UTC (permalink / raw)
  To: Brian Gix; +Cc: linux-bluetooth, Johan Hedberg, inga.stotland

Hi Brian,

> ---
> mesh/error.h | 35 +++++++++++++++++++++++++++++++++++
> 1 file changed, 35 insertions(+)
> create mode 100644 mesh/error.h
> 
> diff --git a/mesh/error.h b/mesh/error.h
> new file mode 100644
> index 000000000..e7bac445b
> --- /dev/null
> +++ b/mesh/error.h
> @@ -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;

we are not doing typedef unless really needed. I do not see the need here.

Regards

Marcel


^ permalink raw reply	[flat|nested] 37+ messages in thread

* RE: [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus
  2018-12-18 23:00 ` [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Marcel Holtmann
@ 2018-12-18 23:05   ` Gix, Brian
  0 siblings, 0 replies; 37+ messages in thread
From: Gix, Brian @ 2018-12-18 23:05 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: linux-bluetooth, Johan Hedberg, Stotland, Inga

Hi Marcel,

> -----Original Message-----
> From: linux-bluetooth-owner@vger.kernel.org [mailto:linux-bluetooth-
> owner@vger.kernel.org] On Behalf Of Marcel Holtmann
> Sent: Tuesday, December 18, 2018 3:00 PM
> To: Gix, Brian <brian.gix@intel.com>
> Cc: linux-bluetooth@vger.kernel.org; Johan Hedberg
> <johan.hedberg@gmail.com>; Stotland, Inga <inga.stotland@intel.com>
> Subject: Re: [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus
> 
> Hi Brian,
> 
> > 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.
> >
> > v4 -- Remove all trace of foreground btmesh app. It is obsolete, and
> > adds no functionality not also present in the meshd executable.
> >
> > 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 for mesh
> >  mesh: Sample Provisioning Agent
> >  mesh: Sample On/Off Client and Server
> >  mesh: Sample Mesh Joiner (provision acceptor)
> >
> > Makefile.mesh                  |   19 +-
> > configure.ac                   |    5 +
> > mesh/agent.c                   |  665 ++++++++++++++++----
> > mesh/agent.h                   |   71 ++-
> > mesh/appkey.c                  |   17 +-
> > mesh/btmesh.c                  |  181 ------
> > mesh/cfgmod-server.c           |  173 +++---
> > mesh/cfgmod.h                  |    2 +-
> > mesh/config/composition.json   |   44 —
> 
> I have no idea why we would create a directory config here. Put the json files
> in $(top_srcdir) and be done with it.

This is a file deletion, so it will no longer be there.

> 
> > 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 ++++++++++++
> 
> Can we please not doing this kind of nesting of directories. Use the
> $(top_srcdir)/test for this.

We will move these to a different directory


> > mesh/util.c                    |   26 +
> > mesh/util.h                    |    1 +
> > 45 files changed, 7177 insertions(+), 3884 deletions(-) delete mode
> > 100644 mesh/btmesh.c delete mode 100644
> mesh/config/composition.json
> > create mode 100644 mesh/dbus.c create mode 100644 mesh/dbus.h
> delete
> > mode 100644 mesh/display.c create mode 100644 mesh/error.h create
> mode
> > 100644 mesh/pb-adv.c rename mesh/{display.h => pb-adv.h} (71%) create
> > mode 100644 mesh/prov-acceptor.c create mode 100644
> > mesh/prov-initiator.c delete mode 100644 mesh/prov.c delete mode
> > 100644 mesh/provision.c create mode 100755 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-join
> 
> Regards
> 
> Marcel


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH BlueZ v4 09/30] mesh: Acceptor side provisioning implimentation
  2018-12-18 22:31 ` [PATCH BlueZ v4 09/30] mesh: Acceptor side provisioning implimentation Brian Gix
@ 2018-12-18 23:09   ` Marcel Holtmann
  0 siblings, 0 replies; 37+ messages in thread
From: Marcel Holtmann @ 2018-12-18 23:09 UTC (permalink / raw)
  To: Brian Gix; +Cc: linux-bluetooth, Johan Hedberg, inga.stotland

Hi Brian,

> ---
> mesh/prov-acceptor.c | 711 +++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 711 insertions(+)
> create mode 100644 mesh/prov-acceptor.c
> 
> diff --git a/mesh/prov-acceptor.c b/mesh/prov-acceptor.c
> new file mode 100644
> index 000000000..ac42e1e2c
> --- /dev/null
> +++ b/mesh/prov-acceptor.c
> @@ -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

this is a simple no. Please stop hacking the code like yes. And yes, adding ifdef is hacking it. Either you abstract different bearer cleanly or they will be all always available. I am not doing two test runs to check your idea of build options.

Regards

Marcel


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH BlueZ v4 25/30] mesh: Add default location for Mesh Node storage
  2018-12-18 22:31 ` [PATCH BlueZ v4 25/30] mesh: Add default location for Mesh Node storage Brian Gix
@ 2018-12-18 23:15   ` Marcel Holtmann
  0 siblings, 0 replies; 37+ messages in thread
From: Marcel Holtmann @ 2018-12-18 23:15 UTC (permalink / raw)
  To: Brian Gix; +Cc: linux-bluetooth, Johan Hedberg, inga.stotland

Hi Brian,

> 
> ---
> configure.ac | 5 +++++
> 1 file changed, 5 insertions(+)
> 
> diff --git a/configure.ac b/configure.ac
> index 1a095a352..901d51e0f 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -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
> +

why are we bothering with the check around it. We don’t do that for ANDROID_STORAGEDIR either. If there is a reason for it, then that one needs to be fixed first. Also can we please have proper text: "Directory for the mesh daemon storage files"

Regards

Marcel


^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2018-12-18 23:15 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-12-18 22:31 [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 01/30] mesh: Staging for Mesh DBus API rewrite Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 02/30] mesh: Delete obsolete files Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 03/30] mesh: Utilities for DBus support Brian Gix
2018-12-18 23:04   ` Marcel Holtmann
2018-12-18 22:31 ` [PATCH BlueZ v4 04/30] mesh: Internal errors Brian Gix
2018-12-18 23:05   ` Marcel Holtmann
2018-12-18 22:31 ` [PATCH BlueZ v4 05/30] mesh: Re-write storage for Multiple Nodes Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 06/30] mesh: Rewrite Node handling for multiple nodes Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 07/30] mesh: Rewite Network layer " Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 08/30] mesh: Direction agnostic PB-Adv implimentation Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 09/30] mesh: Acceptor side provisioning implimentation Brian Gix
2018-12-18 23:09   ` Marcel Holtmann
2018-12-18 22:31 ` [PATCH BlueZ v4 10/30] mesh: Initiator " Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 11/30] mesh: Rewrite Controler interface for full init Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 12/30] mesh: Unchanged variables set to const Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 13/30] mesh: centralize generic utilities Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 14/30] mesh: re-arrange provisioning for DBus API Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 15/30] mesh: Re-architect " Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 16/30] mesh: Make config model handle multiple nodes Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 17/30] mesh: Multi node Config Server model Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 18/30] mesh: restructure I/O for multiple nodes Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 19/30] mesh: Restrusture DB to support " Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 20/30] mesh: restructure model services for " Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 21/30] mesh: DBUS interface for Provisioning Agent Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 22/30] mesh: restructure App Key storage Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 23/30] mesh: Clean-up Comment style Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 24/30] mesh: Update for DBus API and multi-node support Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 25/30] mesh: Add default location for Mesh Node storage Brian Gix
2018-12-18 23:15   ` Marcel Holtmann
2018-12-18 22:31 ` [PATCH BlueZ v4 26/30] mesh: Add structural changes for mesh Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 27/30] mesh: Sample Provisioning Agent Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 28/30] mesh: Sample On/Off Client and Server Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 29/30] mesh: Sample Mesh Joiner (provision acceptor) Brian Gix
2018-12-18 22:31 ` [PATCH BlueZ v4 30/30] mesh: Enable building Mesh Daemon Brian Gix
2018-12-18 23:00 ` [PATCH BlueZ v4 00/30] Major rewrite for Multi-Node and DBus Marcel Holtmann
2018-12-18 23:05   ` Gix, Brian

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).