Linux-Bluetooth Archive on lore.kernel.org
 help / color / Atom feed
From: Brian Gix <brian.gix@intel.com>
To: linux-bluetooth@vger.kernel.org
Cc: inga.stotland@intel.com, michal.lowas-rzechonek@silvair.com,
	brian.gix@intel.com
Subject: [PATCH BlueZ v2 7/9] mesh: Implement DBus Provisioning methods
Date: Thu, 11 Jul 2019 15:59:50 -0700
Message-ID: <20190711225952.1599-8-brian.gix@intel.com> (raw)
In-Reply-To: <20190711225952.1599-1-brian.gix@intel.com>

This implements the Interface and Methods for:
UnprovisionedScan()
UnprovisionedScanCancel()
AddNode()
---
 mesh/manager.c | 304 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 296 insertions(+), 8 deletions(-)

diff --git a/mesh/manager.c b/mesh/manager.c
index ca3562512..77d7b7516 100644
--- a/mesh/manager.c
+++ b/mesh/manager.c
@@ -28,19 +28,202 @@
 #include "mesh/dbus.h"
 #include "mesh/error.h"
 #include "mesh/mesh.h"
+#include "mesh/mesh-io.h"
 #include "mesh/node.h"
+#include "mesh/net.h"
 #include "mesh/keyring.h"
+#include "mesh/agent.h"
+#include "mesh/provision.h"
 #include "mesh/manager.h"
 
+struct add_data{
+	struct l_dbus_message *msg;
+	struct mesh_agent *agent;
+	struct mesh_node *node;
+	uint32_t disc_watch;
+	uint16_t primary;
+	uint16_t net_idx;
+	uint8_t num_ele;
+	uint8_t uuid[16];
+};
+
+static int8_t scan_rssi;
+static uint8_t scan_uuid[16];
+static struct mesh_node *scan_node;
+static struct l_timeout *scan_timeout;
+static struct add_data *add_pending;
+
+static void scan_cancel(struct l_timeout *timeout, void *user_data)
+{
+	struct mesh_node *node = user_data;
+	struct mesh_io *io;
+	struct mesh_net *net;
+
+	l_debug("scan_cancel");
+
+	if (scan_timeout)
+		l_timeout_remove(scan_timeout);
+
+	net = node_get_net(node);
+	io = mesh_net_get_io(net);
+	mesh_io_deregister_recv_cb(io, MESH_IO_FILTER_PROV_BEACON);
+	scan_node = NULL;
+	scan_timeout = NULL;
+}
+
+static void free_pending_add_call()
+{
+	if (!add_pending)
+		return;
+
+	if (add_pending->disc_watch)
+		l_dbus_remove_watch(dbus_get_bus(),
+						add_pending->disc_watch);
+
+	mesh_agent_remove(add_pending->agent);
+
+	l_free(add_pending);
+	add_pending = NULL;
+}
+
+static void prov_disc_cb(struct l_dbus *bus, void *user_data)
+{
+	if (!add_pending)
+		return;
+
+	initiator_cancel(add_pending);
+	add_pending->disc_watch = 0;
+
+	free_pending_add_call();
+}
+
+static void send_add_failed(const char *owner, const char *path,
+							uint8_t status)
+{
+	struct l_dbus *dbus = dbus_get_bus();
+	struct l_dbus_message_builder *builder;
+	struct l_dbus_message *msg;
+
+	msg = l_dbus_message_new_method_call(dbus, owner, path,
+						MESH_PROVISIONER_INTERFACE,
+						"AddNodeFailed");
+
+	builder = l_dbus_message_builder_new(msg);
+	dbus_append_byte_array(builder, add_pending->uuid, 16);
+	l_dbus_message_builder_append_basic(builder, 's',
+						mesh_prov_status_str(status));
+	l_dbus_message_builder_finalize(builder);
+	l_dbus_message_builder_destroy(builder);
+	l_dbus_send(dbus, msg);
+
+	free_pending_add_call();
+}
+
+static bool add_cmplt(void *user_data, uint8_t status,
+					struct mesh_prov_node_info *info)
+{
+	struct add_data *pending = user_data;
+	struct mesh_node *node = pending->node;
+	struct l_dbus *dbus = dbus_get_bus();
+	struct l_dbus_message_builder *builder;
+	struct l_dbus_message *msg;
+	bool result;
+
+	if (pending != add_pending)
+		return false;
+
+	if (status != PROV_ERR_SUCCESS) {
+		send_add_failed(node_get_owner(node), node_get_app_path(node),
+									status);
+		return false;
+	}
+
+	result = keyring_put_remote_dev_key(add_pending->node, info->unicast,
+					info->num_ele, info->device_key);
+
+	if (!result) {
+		send_add_failed(node_get_owner(node), node_get_app_path(node),
+						PROV_ERR_CANT_ASSIGN_ADDR);
+		return false;
+	}
+
+	msg = l_dbus_message_new_method_call(dbus, node_get_owner(node),
+						node_get_app_path(node),
+						MESH_PROVISIONER_INTERFACE,
+						"AddNodeComplete");
+
+	builder = l_dbus_message_builder_new(msg);
+	dbus_append_byte_array(builder, add_pending->uuid, 16);
+	l_dbus_message_builder_append_basic(builder, 'q', &info->unicast);
+	l_dbus_message_builder_append_basic(builder, 'y', &info->num_ele);
+	l_dbus_message_builder_finalize(builder);
+	l_dbus_message_builder_destroy(builder);
+
+	l_dbus_send(dbus, msg);
+
+	free_pending_add_call();
+
+	return true;
+}
+
+static void mgr_prov_data (struct l_dbus_message *reply, void *user_data)
+{
+	struct add_data *pending = user_data;
+	uint16_t net_idx;
+	uint16_t primary;
+
+	if (pending != add_pending)
+		return;
+
+	if (l_dbus_message_is_error(reply))
+		return;
+
+	if (!l_dbus_message_get_arguments(reply, "qq", &net_idx, &primary))
+		return;
+
+	add_pending->primary = primary;
+	add_pending->net_idx = net_idx;
+	initiator_prov_data(net_idx, primary, add_pending);
+}
+
+static bool add_data_get(void *user_data, uint8_t num_ele)
+{
+	struct add_data *pending = user_data;
+	struct l_dbus_message *msg;
+	struct l_dbus *dbus;
+	const char *app_path;
+	const char *sender;
+
+	if (pending != add_pending)
+		return false;
+
+	dbus = dbus_get_bus();
+	app_path = node_get_app_path(add_pending->node);
+	sender = node_get_owner(add_pending->node);
+
+	msg = l_dbus_message_new_method_call(dbus, sender, app_path,
+						MESH_PROVISIONER_INTERFACE,
+						"RequestProvData");
+
+	l_dbus_message_set_arguments(msg, "y", num_ele);
+	l_dbus_send_with_reply(dbus, msg, mgr_prov_data, add_pending, NULL);
+
+	add_pending->num_ele = num_ele;
+
+	return true;
+}
+
 static struct l_dbus_message *add_node_call(struct l_dbus *dbus,
 						struct l_dbus_message *msg,
 						void *user_data)
 {
+	struct mesh_node *node = user_data;
 	struct l_dbus_message_iter iter_uuid;
+	struct l_dbus_message *reply;
 	uint8_t *uuid;
 	uint32_t n;
 
-	l_debug("Add node request");
+	l_debug("AddNode request");
 
 	if (!l_dbus_message_get_arguments(msg, "ay", &iter_uuid))
 		return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL);
@@ -50,8 +233,47 @@ static struct l_dbus_message *add_node_call(struct l_dbus *dbus,
 		return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
 							"Bad device UUID");
 
-	/* TODO */
-	return dbus_error(msg, MESH_ERROR_NOT_IMPLEMENTED, NULL);
+	/* Allow AddNode to cancel Scanning if from the same node */
+	if (scan_node) {
+		if (scan_node != node)
+			return dbus_error(msg, MESH_ERROR_BUSY, NULL);
+
+		scan_cancel(NULL, node);
+	}
+
+	/* Invoke Prov Initiator */
+
+	add_pending = l_new(struct add_data, 1);
+	memcpy(add_pending->uuid, uuid, 16);
+	add_pending->node = node;
+	add_pending->agent = node_get_agent(node);;
+
+	if (!node_is_provisioner(node) || (add_pending->agent == NULL)) {
+		l_info("Provisioner: %d", node_is_provisioner(node));
+		l_info("Agent: %p", add_pending->agent);
+		reply = dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED,
+							"Missing Interfaces");
+		goto fail;
+	}
+
+
+	if (!initiator_start(PB_ADV, uuid, 99, 0, 60, add_pending->agent,
+				add_data_get, add_cmplt, node, add_pending)) {
+		reply = dbus_error(msg, MESH_ERROR_FAILED,
+				"Failed to start provisioning initiator");
+		goto fail;
+	}
+
+	add_pending->disc_watch = l_dbus_add_disconnect_watch(dbus,
+						node_get_owner(node),
+						prov_disc_cb, NULL, NULL);
+
+	return l_dbus_message_new_method_return(msg);
+
+fail:
+	l_free(add_pending);
+	add_pending = NULL;
+	return reply;
 }
 
 
@@ -97,25 +319,91 @@ static struct l_dbus_message *delete_node_call(struct l_dbus *dbus,
 	return l_dbus_message_new_method_return(msg);
 }
 
+static void prov_beacon_recv(void *user_data, struct mesh_io_recv_info *info,
+					const uint8_t *data, uint16_t len)
+{
+	struct mesh_node *node = user_data;
+	struct l_dbus_message_builder *builder;
+	struct l_dbus_message *msg;
+	struct l_dbus *dbus;
+	int16_t rssi;
+
+	if (scan_node != node || len < sizeof(scan_uuid) + 2 || data[1] != 0x00)
+		return;
+
+	if (!memcmp(data + 2, scan_uuid, sizeof(scan_uuid))) {
+		if (info->rssi <= scan_rssi)
+			return;
+	}
+
+	memcpy(scan_uuid, data + 2, sizeof(scan_uuid));
+	scan_rssi = info->rssi;
+	rssi = info->rssi;
+
+	dbus = dbus_get_bus();
+	msg = l_dbus_message_new_method_call(dbus, node_get_owner(node),
+						node_get_app_path(node),
+						MESH_PROVISIONER_INTERFACE,
+						"ScanResult");
+
+	builder = l_dbus_message_builder_new(msg);
+	l_dbus_message_builder_append_basic(builder, 'n', &rssi);
+	dbus_append_byte_array(builder, data + 2, len -2);
+	l_dbus_message_builder_finalize(builder);
+	l_dbus_message_builder_destroy(builder);
+
+	l_dbus_send(dbus, msg);
+}
+
 static struct l_dbus_message *start_scan_call(struct l_dbus *dbus,
 						struct l_dbus_message *msg,
 						void *user_data)
 {
+	struct mesh_node *node = user_data;
 	uint16_t duration;
+	struct mesh_io *io;
+	struct mesh_net *net;
 
 	if (!l_dbus_message_get_arguments(msg, "q", &duration))
 		return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL);
 
-	/* TODO */
-	return dbus_error(msg, MESH_ERROR_NOT_IMPLEMENTED, NULL);
+	if (scan_node && scan_node != node)
+		return dbus_error(msg, MESH_ERROR_BUSY, NULL);
+
+	if (!node_is_provisioner(node))
+		return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL);
+
+	if (scan_timeout)
+		l_timeout_remove(scan_timeout);
+
+	memset(scan_uuid, 0, sizeof(scan_uuid));
+	scan_rssi = -128;
+	scan_timeout = NULL;
+	net = node_get_net(node);
+	io = mesh_net_get_io(net);
+	scan_node = node;
+	mesh_io_register_recv_cb(io, MESH_IO_FILTER_PROV_BEACON,
+						prov_beacon_recv, node);
+
+	if (duration)
+		scan_timeout = l_timeout_create(duration, scan_cancel,
+								node, NULL);
+
+	return l_dbus_message_new_method_return(msg);
 }
 
 static struct l_dbus_message *cancel_scan_call(struct l_dbus *dbus,
 						struct l_dbus_message *msg,
 						void *user_data)
 {
-	/* TODO */
-	return dbus_error(msg, MESH_ERROR_NOT_IMPLEMENTED, NULL);
+	struct mesh_node *node = user_data;
+
+	if (scan_node != node)
+		return dbus_error(msg, MESH_ERROR_BUSY, NULL);
+
+	scan_cancel(NULL, node);
+
+	return l_dbus_message_new_method_return(msg);
 }
 
 static struct l_dbus_message *store_new_subnet(struct mesh_node *node,
@@ -416,7 +704,7 @@ static struct l_dbus_message *set_key_phase_call(struct l_dbus *dbus,
 static void setup_management_interface(struct l_dbus_interface *iface)
 {
 	l_dbus_interface_method(iface, "AddNode", 0, add_node_call, "", "ay",
-								"", "uuid");
+								"uuid");
 	l_dbus_interface_method(iface, "ImportRemoteNode", 0, import_node_call,
 						"", "qyay", "", "primary",
 						"count", "dev_key");
-- 
2.14.5


  parent reply index

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-07-11 22:59 [PATCH BlueZ v2 0/9] mesh: Provisioner Initiator added Brian Gix
2019-07-11 22:59 ` [PATCH BlueZ v2 1/9] doc: Cleanup API Provisioner1 interface Brian Gix
2019-07-11 22:59 ` [PATCH BlueZ v2 2/9] mesh: Fix support for Provisioner Initiator Brian Gix
2019-07-11 22:59 ` [PATCH BlueZ v2 3/9] mesh: Add special Beacon handler for Provisioning Brian Gix
2019-07-11 22:59 ` [PATCH BlueZ v2 4/9] mesh: Expose mapping function for D-Bus errors Brian Gix
2019-07-11 22:59 ` [PATCH BlueZ v2 5/9] mesh: Expose resources needed by Management1 interface Brian Gix
2019-07-11 22:59 ` [PATCH BlueZ v2 6/9] mesh: Fix implementation of Provisioner Initiator Brian Gix
2019-07-11 22:59 ` Brian Gix [this message]
2019-07-11 22:59 ` [PATCH BlueZ v2 8/9] mesh: Convert provisioning pkts to packed structs Brian Gix
2019-07-11 22:59 ` [PATCH BlueZ v2 9/9] test: This extends the mesh tool to exercise Provisioning methods Brian Gix
2019-07-12  8:39 ` [PATCH BlueZ v2 0/9] mesh: Provisioner Initiator added Michał Lowas-Rzechonek
2019-07-14 15:47 ` Gix, Brian

Reply instructions:

You may reply publically to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190711225952.1599-8-brian.gix@intel.com \
    --to=brian.gix@intel.com \
    --cc=inga.stotland@intel.com \
    --cc=linux-bluetooth@vger.kernel.org \
    --cc=michal.lowas-rzechonek@silvair.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Linux-Bluetooth Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-bluetooth/0 linux-bluetooth/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-bluetooth linux-bluetooth/ https://lore.kernel.org/linux-bluetooth \
		linux-bluetooth@vger.kernel.org linux-bluetooth@archiver.kernel.org
	public-inbox-index linux-bluetooth

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-bluetooth


AGPL code for this site: git clone https://public-inbox.org/ public-inbox