Blame tools/meshctl.c

Packit Service 8264ee
/*
Packit Service 8264ee
 *
Packit Service 8264ee
 *  BlueZ - Bluetooth protocol stack for Linux
Packit Service 8264ee
 *
Packit Service 8264ee
 *  Copyright (C) 2017  Intel Corporation. All rights reserved.
Packit Service 8264ee
 *
Packit Service 8264ee
 *
Packit Service 8264ee
 *  This library is free software; you can redistribute it and/or
Packit Service 8264ee
 *  modify it under the terms of the GNU Lesser General Public
Packit Service 8264ee
 *  License as published by the Free Software Foundation; either
Packit Service 8264ee
 *  version 2.1 of the License, or (at your option) any later version.
Packit Service 8264ee
 *
Packit Service 8264ee
 *  This library is distributed in the hope that it will be useful,
Packit Service 8264ee
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 8264ee
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 8264ee
 *  Lesser General Public License for more details.
Packit Service 8264ee
 *
Packit Service 8264ee
 *  You should have received a copy of the GNU Lesser General Public
Packit Service 8264ee
 *  License along with this library; if not, write to the Free Software
Packit Service 8264ee
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
Packit Service 8264ee
 *
Packit Service 8264ee
 */
Packit Service 8264ee
Packit Service 8264ee
#ifdef HAVE_CONFIG_H
Packit Service 8264ee
#include <config.h>
Packit Service 8264ee
#endif
Packit Service 8264ee
Packit Service 8264ee
#define _GNU_SOURCE
Packit Service 8264ee
#include <stdio.h>
Packit Service 8264ee
#include <errno.h>
Packit Service 8264ee
#include <unistd.h>
Packit Service 8264ee
#include <stdlib.h>
Packit Service 8264ee
#include <stdbool.h>
Packit Service 8264ee
#include <wordexp.h>
Packit Service 8264ee
Packit Service 8264ee
#include <inttypes.h>
Packit Service 8264ee
#include <ctype.h>
Packit Service 8264ee
#include <sys/file.h>
Packit Service 8264ee
#include <sys/ioctl.h>
Packit Service 8264ee
#include <sys/stat.h>
Packit Service 8264ee
#include "bluetooth/bluetooth.h"
Packit Service 8264ee
Packit Service 8264ee
#include <glib.h>
Packit Service 8264ee
Packit Service 8264ee
#include "lib/bluetooth.h"
Packit Service 8264ee
#include "lib/uuid.h"
Packit Service 8264ee
#include "src/shared/shell.h"
Packit Service 8264ee
#include "src/shared/util.h"
Packit Service 8264ee
#include "gdbus/gdbus.h"
Packit Service 8264ee
#include "mesh/mesh-net.h"
Packit Service 8264ee
#include "mesh/gatt.h"
Packit Service 8264ee
#include "mesh/crypto.h"
Packit Service 8264ee
#include "mesh/node.h"
Packit Service 8264ee
#include "mesh/net.h"
Packit Service 8264ee
#include "mesh/keys.h"
Packit Service 8264ee
#include "mesh/prov.h"
Packit Service 8264ee
#include "mesh/util.h"
Packit Service 8264ee
#include "mesh/agent.h"
Packit Service 8264ee
#include "mesh/prov-db.h"
Packit Service 8264ee
#include "mesh/config-model.h"
Packit Service 8264ee
#include "mesh/onoff-model.h"
Packit Service 8264ee
Packit Service 8264ee
/* String display constants */
Packit Service 8264ee
#define COLORED_NEW	COLOR_GREEN "NEW" COLOR_OFF
Packit Service 8264ee
#define COLORED_CHG	COLOR_YELLOW "CHG" COLOR_OFF
Packit Service 8264ee
#define COLORED_DEL	COLOR_RED "DEL" COLOR_OFF
Packit Service 8264ee
Packit Service 8264ee
#define PROMPT_ON	COLOR_BLUE "[meshctl]" COLOR_OFF "# "
Packit Service 8264ee
#define PROMPT_OFF	"Waiting to connect to bluetoothd..."
Packit Service 8264ee
Packit Service 8264ee
#define MESH_PROV_DATA_IN_UUID_STR	"00002adb-0000-1000-8000-00805f9b34fb"
Packit Service 8264ee
#define MESH_PROV_DATA_OUT_UUID_STR	"00002adc-0000-1000-8000-00805f9b34fb"
Packit Service 8264ee
#define MESH_PROXY_DATA_IN_UUID_STR	"00002add-0000-1000-8000-00805f9b34fb"
Packit Service 8264ee
#define MESH_PROXY_DATA_OUT_UUID_STR	"00002ade-0000-1000-8000-00805f9b34fb"
Packit Service 8264ee
Packit Service 8264ee
static DBusConnection *dbus_conn;
Packit Service 8264ee
Packit Service 8264ee
struct adapter {
Packit Service 8264ee
GDBusProxy *proxy;
Packit Service 8264ee
	GList *mesh_devices;
Packit Service 8264ee
};
Packit Service 8264ee
Packit Service 8264ee
struct mesh_device {
Packit Service 8264ee
	GDBusProxy *proxy;
Packit Service 8264ee
	uint8_t dev_uuid[16];
Packit Service 8264ee
	gboolean hide;
Packit Service 8264ee
};
Packit Service 8264ee
Packit Service 8264ee
GList *service_list;
Packit Service 8264ee
GList *char_list;
Packit Service 8264ee
Packit Service 8264ee
static GList *ctrl_list;
Packit Service 8264ee
static struct adapter *default_ctrl;
Packit Service 8264ee
Packit Service 8264ee
static char *mesh_prov_db_filename;
Packit Service 8264ee
static char *mesh_local_config_filename;
Packit Service 8264ee
Packit Service 8264ee
static bool discovering = false;
Packit Service 8264ee
static bool discover_mesh;
Packit Service 8264ee
static uint16_t prov_net_key_index = NET_IDX_PRIMARY;
Packit Service 8264ee
static const struct bt_shell_menu main_menu;
Packit Service 8264ee
Packit Service 8264ee
#define CONN_TYPE_NETWORK	0x00
Packit Service 8264ee
#define CONN_TYPE_IDENTITY	0x01
Packit Service 8264ee
#define CONN_TYPE_PROVISION	0x02
Packit Service 8264ee
#define CONN_TYPE_INVALID	0xff
Packit Service 8264ee
Packit Service 8264ee
#define NET_IDX_INVALID		0xffff
Packit Service 8264ee
Packit Service 8264ee
struct {
Packit Service 8264ee
	GDBusProxy *device;
Packit Service 8264ee
	GDBusProxy *service;
Packit Service 8264ee
	GDBusProxy *data_in;
Packit Service 8264ee
	GDBusProxy *data_out;
Packit Service 8264ee
	bool session_open;
Packit Service 8264ee
	uint16_t unicast;
Packit Service 8264ee
	uint16_t net_idx;
Packit Service 8264ee
	uint8_t dev_uuid[16];
Packit Service 8264ee
	uint8_t type;
Packit Service 8264ee
} connection;
Packit Service 8264ee
Packit Service 8264ee
static bool service_is_mesh(GDBusProxy *proxy, const char *target_uuid)
Packit Service 8264ee
{
Packit Service 8264ee
	DBusMessageIter iter;
Packit Service 8264ee
	const char *uuid;
Packit Service 8264ee
Packit Service 8264ee
	if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
Packit Service 8264ee
		return false;
Packit Service 8264ee
Packit Service 8264ee
	dbus_message_iter_get_basic(&iter, &uuid);
Packit Service 8264ee
Packit Service 8264ee
	if (target_uuid)
Packit Service 8264ee
		return (!bt_uuid_strcmp(uuid, target_uuid));
Packit Service 8264ee
	else if (bt_uuid_strcmp(uuid, MESH_PROV_SVC_UUID) ||
Packit Service 8264ee
				bt_uuid_strcmp(uuid, MESH_PROXY_SVC_UUID))
Packit Service 8264ee
		return true;
Packit Service 8264ee
	else
Packit Service 8264ee
		return false;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static bool char_is_mesh(GDBusProxy *proxy, const char *target_uuid)
Packit Service 8264ee
{
Packit Service 8264ee
	DBusMessageIter iter;
Packit Service 8264ee
	const char *uuid;
Packit Service 8264ee
Packit Service 8264ee
	if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
Packit Service 8264ee
		return false;
Packit Service 8264ee
Packit Service 8264ee
	dbus_message_iter_get_basic(&iter, &uuid);
Packit Service 8264ee
Packit Service 8264ee
	if (target_uuid)
Packit Service 8264ee
		return (!bt_uuid_strcmp(uuid, target_uuid));
Packit Service 8264ee
Packit Service 8264ee
	if (!bt_uuid_strcmp(uuid, MESH_PROV_DATA_IN_UUID_STR))
Packit Service 8264ee
		return true;
Packit Service 8264ee
Packit Service 8264ee
	if (!bt_uuid_strcmp(uuid, MESH_PROV_DATA_OUT_UUID_STR))
Packit Service 8264ee
		return true;
Packit Service 8264ee
Packit Service 8264ee
	if (!bt_uuid_strcmp(uuid, MESH_PROXY_DATA_IN_UUID_STR))
Packit Service 8264ee
		return true;
Packit Service 8264ee
Packit Service 8264ee
	if (!bt_uuid_strcmp(uuid, MESH_PROXY_DATA_OUT_UUID_STR))
Packit Service 8264ee
		return true;
Packit Service 8264ee
Packit Service 8264ee
	return false;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static gboolean check_default_ctrl(void)
Packit Service 8264ee
{
Packit Service 8264ee
	if (!default_ctrl) {
Packit Service 8264ee
		bt_shell_printf("No default controller available\n");
Packit Service 8264ee
		return FALSE;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	return TRUE;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void proxy_leak(gpointer data)
Packit Service 8264ee
{
Packit Service 8264ee
	bt_shell_printf("Leaking proxy %p\n", data);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void connect_handler(DBusConnection *connection, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	bt_shell_set_prompt(PROMPT_ON);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void disconnect_handler(DBusConnection *connection, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	bt_shell_detach();
Packit Service 8264ee
Packit Service 8264ee
	bt_shell_set_prompt(PROMPT_OFF);
Packit Service 8264ee
Packit Service 8264ee
	g_list_free_full(ctrl_list, proxy_leak);
Packit Service 8264ee
	ctrl_list = NULL;
Packit Service 8264ee
Packit Service 8264ee
	default_ctrl = NULL;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void print_adapter(GDBusProxy *proxy, const char *description)
Packit Service 8264ee
{
Packit Service 8264ee
	DBusMessageIter iter;
Packit Service 8264ee
	const char *address, *name;
Packit Service 8264ee
Packit Service 8264ee
	if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
Packit Service 8264ee
		return;
Packit Service 8264ee
Packit Service 8264ee
	dbus_message_iter_get_basic(&iter, &address);
Packit Service 8264ee
Packit Service 8264ee
	if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == TRUE)
Packit Service 8264ee
		dbus_message_iter_get_basic(&iter, &name);
Packit Service 8264ee
	else
Packit Service 8264ee
		name = "<unknown>";
Packit Service 8264ee
Packit Service 8264ee
	bt_shell_printf("%s%s%sController %s %s %s\n",
Packit Service 8264ee
				description ? "[" : "",
Packit Service 8264ee
				description ? : "",
Packit Service 8264ee
				description ? "] " : "",
Packit Service 8264ee
				address, name,
Packit Service 8264ee
				default_ctrl &&
Packit Service 8264ee
				default_ctrl->proxy == proxy ?
Packit Service 8264ee
				"[default]" : "");
Packit Service 8264ee
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void print_device(GDBusProxy *proxy, const char *description)
Packit Service 8264ee
{
Packit Service 8264ee
	DBusMessageIter iter;
Packit Service 8264ee
	const char *address, *name;
Packit Service 8264ee
Packit Service 8264ee
	if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
Packit Service 8264ee
		return;
Packit Service 8264ee
Packit Service 8264ee
	dbus_message_iter_get_basic(&iter, &address);
Packit Service 8264ee
Packit Service 8264ee
	if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == TRUE)
Packit Service 8264ee
		dbus_message_iter_get_basic(&iter, &name);
Packit Service 8264ee
	else
Packit Service 8264ee
		name = "<unknown>";
Packit Service 8264ee
Packit Service 8264ee
	bt_shell_printf("%s%s%sDevice %s %s\n",
Packit Service 8264ee
				description ? "[" : "",
Packit Service 8264ee
				description ? : "",
Packit Service 8264ee
				description ? "] " : "",
Packit Service 8264ee
				address, name);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void print_iter(const char *label, const char *name,
Packit Service 8264ee
						DBusMessageIter *iter)
Packit Service 8264ee
{
Packit Service 8264ee
	dbus_bool_t valbool;
Packit Service 8264ee
	dbus_uint32_t valu32;
Packit Service 8264ee
	dbus_uint16_t valu16;
Packit Service 8264ee
	dbus_int16_t vals16;
Packit Service 8264ee
	unsigned char byte;
Packit Service 8264ee
	const char *valstr;
Packit Service 8264ee
	DBusMessageIter subiter;
Packit Service 8264ee
	char *entry;
Packit Service 8264ee
Packit Service 8264ee
	if (iter == NULL) {
Packit Service 8264ee
		bt_shell_printf("%s%s is nil\n", label, name);
Packit Service 8264ee
		return;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	switch (dbus_message_iter_get_arg_type(iter)) {
Packit Service 8264ee
	case DBUS_TYPE_INVALID:
Packit Service 8264ee
		bt_shell_printf("%s%s is invalid\n", label, name);
Packit Service 8264ee
		break;
Packit Service 8264ee
	case DBUS_TYPE_STRING:
Packit Service 8264ee
	case DBUS_TYPE_OBJECT_PATH:
Packit Service 8264ee
		dbus_message_iter_get_basic(iter, &valstr);
Packit Service 8264ee
		bt_shell_printf("%s%s: %s\n", label, name, valstr);
Packit Service 8264ee
		break;
Packit Service 8264ee
	case DBUS_TYPE_BOOLEAN:
Packit Service 8264ee
		dbus_message_iter_get_basic(iter, &valbool);
Packit Service 8264ee
		bt_shell_printf("%s%s: %s\n", label, name,
Packit Service 8264ee
					valbool == TRUE ? "yes" : "no");
Packit Service 8264ee
		break;
Packit Service 8264ee
	case DBUS_TYPE_UINT32:
Packit Service 8264ee
		dbus_message_iter_get_basic(iter, &valu32);
Packit Service 8264ee
		bt_shell_printf("%s%s: 0x%06x\n", label, name, valu32);
Packit Service 8264ee
		break;
Packit Service 8264ee
	case DBUS_TYPE_UINT16:
Packit Service 8264ee
		dbus_message_iter_get_basic(iter, &valu16);
Packit Service 8264ee
		bt_shell_printf("%s%s: 0x%04x\n", label, name, valu16);
Packit Service 8264ee
		break;
Packit Service 8264ee
	case DBUS_TYPE_INT16:
Packit Service 8264ee
		dbus_message_iter_get_basic(iter, &vals16);
Packit Service 8264ee
		bt_shell_printf("%s%s: %d\n", label, name, vals16);
Packit Service 8264ee
		break;
Packit Service 8264ee
	case DBUS_TYPE_BYTE:
Packit Service 8264ee
		dbus_message_iter_get_basic(iter, &byte);
Packit Service 8264ee
		bt_shell_printf("%s%s: 0x%02x\n", label, name, byte);
Packit Service 8264ee
		break;
Packit Service 8264ee
	case DBUS_TYPE_VARIANT:
Packit Service 8264ee
		dbus_message_iter_recurse(iter, &subiter);
Packit Service 8264ee
		print_iter(label, name, &subiter);
Packit Service 8264ee
		break;
Packit Service 8264ee
	case DBUS_TYPE_ARRAY:
Packit Service 8264ee
		dbus_message_iter_recurse(iter, &subiter);
Packit Service 8264ee
		while (dbus_message_iter_get_arg_type(&subiter) !=
Packit Service 8264ee
							DBUS_TYPE_INVALID) {
Packit Service 8264ee
			print_iter(label, name, &subiter);
Packit Service 8264ee
			dbus_message_iter_next(&subiter);
Packit Service 8264ee
		}
Packit Service 8264ee
		break;
Packit Service 8264ee
	case DBUS_TYPE_DICT_ENTRY:
Packit Service 8264ee
		dbus_message_iter_recurse(iter, &subiter);
Packit Service 8264ee
		entry = g_strconcat(name, "Key", NULL);
Packit Service 8264ee
		print_iter(label, entry, &subiter);
Packit Service 8264ee
		g_free(entry);
Packit Service 8264ee
Packit Service 8264ee
		entry = g_strconcat(name, " Value", NULL);
Packit Service 8264ee
		dbus_message_iter_next(&subiter);
Packit Service 8264ee
		print_iter(label, entry, &subiter);
Packit Service 8264ee
		g_free(entry);
Packit Service 8264ee
		break;
Packit Service 8264ee
	default:
Packit Service 8264ee
		bt_shell_printf("%s%s has unsupported type\n", label, name);
Packit Service 8264ee
		break;
Packit Service 8264ee
	}
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void print_property(GDBusProxy *proxy, const char *name)
Packit Service 8264ee
{
Packit Service 8264ee
	DBusMessageIter iter;
Packit Service 8264ee
Packit Service 8264ee
	if (g_dbus_proxy_get_property(proxy, name, &iter) == FALSE)
Packit Service 8264ee
		return;
Packit Service 8264ee
Packit Service 8264ee
	print_iter("\t", name, &iter);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void forget_mesh_devices()
Packit Service 8264ee
{
Packit Service 8264ee
	g_list_free_full(default_ctrl->mesh_devices, g_free);
Packit Service 8264ee
	default_ctrl->mesh_devices = NULL;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static struct mesh_device *find_device_by_uuid(GList *source, uint8_t uuid[16])
Packit Service 8264ee
{
Packit Service 8264ee
	GList *list;
Packit Service 8264ee
Packit Service 8264ee
	for (list = g_list_first(source); list; list = g_list_next(list)) {
Packit Service 8264ee
		struct mesh_device *dev = list->data;
Packit Service 8264ee
Packit Service 8264ee
		if (!memcmp(dev->dev_uuid, uuid, 16))
Packit Service 8264ee
			return dev;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	return NULL;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void print_prov_service(struct prov_svc_data *prov_data)
Packit Service 8264ee
{
Packit Service 8264ee
	const char *prefix = "\t\t";
Packit Service 8264ee
	char txt_uuid[16 * 2 + 1];
Packit Service 8264ee
	int i;
Packit Service 8264ee
Packit Service 8264ee
	bt_shell_printf("%sMesh Provisioning Service (%s)\n", prefix,
Packit Service 8264ee
							MESH_PROV_SVC_UUID);
Packit Service 8264ee
	for (i = 0; i < 16; ++i) {
Packit Service 8264ee
		sprintf(txt_uuid + (i * 2), "%2.2x", prov_data->dev_uuid[i]);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	bt_shell_printf("%s\tDevice UUID: %s\n", prefix, txt_uuid);
Packit Service 8264ee
	bt_shell_printf("%s\tOOB: %4.4x\n", prefix, prov_data->oob);
Packit Service 8264ee
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static bool parse_prov_service_data(const char *uuid, uint8_t *data, int len,
Packit Service 8264ee
								void *data_out)
Packit Service 8264ee
{
Packit Service 8264ee
	struct prov_svc_data *prov_data = data_out;
Packit Service 8264ee
	int i;
Packit Service 8264ee
Packit Service 8264ee
	if (len < 18)
Packit Service 8264ee
		return false;
Packit Service 8264ee
Packit Service 8264ee
	for (i = 0; i < 16; ++i) {
Packit Service 8264ee
		prov_data->dev_uuid[i] = data[i];
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	prov_data->oob = get_be16(&data[16]);
Packit Service 8264ee
Packit Service 8264ee
	return true;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static bool parse_mesh_service_data(const char *uuid, uint8_t *data, int len,
Packit Service 8264ee
								void *data_out)
Packit Service 8264ee
{
Packit Service 8264ee
	const char *prefix = "\t\t";
Packit Service 8264ee
Packit Service 8264ee
	if (!(len == 9 && data[0] == 0x00) && !(len == 17 && data[0] == 0x01)) {
Packit Service 8264ee
		bt_shell_printf("Unexpected mesh proxy service data length %d\n",
Packit Service 8264ee
									len);
Packit Service 8264ee
		return false;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	if (data[0] != connection.type)
Packit Service 8264ee
		return false;
Packit Service 8264ee
Packit Service 8264ee
	if (data[0] == CONN_TYPE_IDENTITY) {
Packit Service 8264ee
		uint8_t *key;
Packit Service 8264ee
Packit Service 8264ee
		if (IS_UNASSIGNED(connection.unicast)) {
Packit Service 8264ee
			/* This would be a bug */
Packit Service 8264ee
			bt_shell_printf("Error: Searching identity with "
Packit Service 8264ee
							"unicast 0000\n");
Packit Service 8264ee
			return false;
Packit Service 8264ee
		}
Packit Service 8264ee
Packit Service 8264ee
		key = keys_net_key_get(prov_net_key_index, true);
Packit Service 8264ee
		if (!key)
Packit Service 8264ee
			return false;
Packit Service 8264ee
Packit Service 8264ee
		if (!mesh_crypto_identity_check(key, connection.unicast,
Packit Service 8264ee
					       &data[1]))
Packit Service 8264ee
			return false;
Packit Service 8264ee
Packit Service 8264ee
		if (discovering) {
Packit Service 8264ee
			bt_shell_printf("\n%sMesh Proxy Service (%s)\n", prefix,
Packit Service 8264ee
									uuid);
Packit Service 8264ee
			bt_shell_printf("%sIdentity for node %4.4x\n", prefix,
Packit Service 8264ee
							connection.unicast);
Packit Service 8264ee
		}
Packit Service 8264ee
Packit Service 8264ee
	} else if (data[0] == CONN_TYPE_NETWORK) {
Packit Service 8264ee
		uint16_t net_idx = net_validate_proxy_beacon(data + 1);
Packit Service 8264ee
Packit Service 8264ee
		if (net_idx == NET_IDX_INVALID || net_idx != connection.net_idx)
Packit Service 8264ee
			return false;
Packit Service 8264ee
Packit Service 8264ee
		if (discovering) {
Packit Service 8264ee
			bt_shell_printf("\n%sMesh Proxy Service (%s)\n", prefix,
Packit Service 8264ee
									uuid);
Packit Service 8264ee
			bt_shell_printf("%sNetwork Beacon for net index %4.4x\n",
Packit Service 8264ee
							prefix, net_idx);
Packit Service 8264ee
		}
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	return true;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static bool parse_service_data(GDBusProxy *proxy, const char *target_uuid,
Packit Service 8264ee
					void *data_out)
Packit Service 8264ee
{
Packit Service 8264ee
	DBusMessageIter iter, entries;
Packit Service 8264ee
	bool mesh_prov = false;
Packit Service 8264ee
	bool mesh_proxy = false;
Packit Service 8264ee
Packit Service 8264ee
	if (target_uuid) {
Packit Service 8264ee
		mesh_prov = !strcmp(target_uuid, MESH_PROV_SVC_UUID);
Packit Service 8264ee
		mesh_proxy = !strcmp(target_uuid, MESH_PROXY_SVC_UUID);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	if (!g_dbus_proxy_get_property(proxy, "ServiceData", &iter))
Packit Service 8264ee
		return false;
Packit Service 8264ee
Packit Service 8264ee
	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
Packit Service 8264ee
		return false;
Packit Service 8264ee
Packit Service 8264ee
	dbus_message_iter_recurse(&iter, &entries);
Packit Service 8264ee
Packit Service 8264ee
	while (dbus_message_iter_get_arg_type(&entries)
Packit Service 8264ee
						== DBUS_TYPE_DICT_ENTRY) {
Packit Service 8264ee
		DBusMessageIter value, entry, array;
Packit Service 8264ee
		const char *uuid_str;
Packit Service 8264ee
		bt_uuid_t uuid;
Packit Service 8264ee
		uint8_t *service_data;
Packit Service 8264ee
		int len;
Packit Service 8264ee
Packit Service 8264ee
		dbus_message_iter_recurse(&entries, &entry);
Packit Service 8264ee
		dbus_message_iter_get_basic(&entry, &uuid_str);
Packit Service 8264ee
Packit Service 8264ee
		if (bt_string_to_uuid(&uuid, uuid_str) < 0)
Packit Service 8264ee
			goto fail;
Packit Service 8264ee
Packit Service 8264ee
		dbus_message_iter_next(&entry);
Packit Service 8264ee
Packit Service 8264ee
		if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
Packit Service 8264ee
			goto fail;
Packit Service 8264ee
Packit Service 8264ee
		dbus_message_iter_recurse(&entry, &value);
Packit Service 8264ee
Packit Service 8264ee
		if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_ARRAY)
Packit Service 8264ee
			goto fail;
Packit Service 8264ee
Packit Service 8264ee
		dbus_message_iter_recurse(&value, &array);
Packit Service 8264ee
Packit Service 8264ee
		if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_BYTE)
Packit Service 8264ee
			goto fail;
Packit Service 8264ee
Packit Service 8264ee
		dbus_message_iter_get_fixed_array(&array, &service_data, &len;;
Packit Service 8264ee
Packit Service 8264ee
		if (mesh_prov && !strcmp(uuid_str, MESH_PROV_SVC_UUID)) {
Packit Service 8264ee
			return parse_prov_service_data(uuid_str, service_data,
Packit Service 8264ee
								len, data_out);
Packit Service 8264ee
		} else if (mesh_proxy &&
Packit Service 8264ee
				!strcmp(uuid_str, MESH_PROXY_SVC_UUID)) {
Packit Service 8264ee
			return parse_mesh_service_data(uuid_str, service_data,
Packit Service 8264ee
								len, data_out);
Packit Service 8264ee
		}
Packit Service 8264ee
Packit Service 8264ee
		dbus_message_iter_next(&entries);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	if (!target_uuid)
Packit Service 8264ee
		return true;
Packit Service 8264ee
fail:
Packit Service 8264ee
	return false;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void print_uuids(GDBusProxy *proxy)
Packit Service 8264ee
{
Packit Service 8264ee
	DBusMessageIter iter, value;
Packit Service 8264ee
Packit Service 8264ee
	if (g_dbus_proxy_get_property(proxy, "UUIDs", &iter) == FALSE)
Packit Service 8264ee
		return;
Packit Service 8264ee
Packit Service 8264ee
	dbus_message_iter_recurse(&iter, &value);
Packit Service 8264ee
Packit Service 8264ee
	while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
Packit Service 8264ee
		const char *uuid, *text;
Packit Service 8264ee
Packit Service 8264ee
		dbus_message_iter_get_basic(&value, &uuid);
Packit Service 8264ee
Packit Service 8264ee
		text = bt_uuidstr_to_str(uuid);
Packit Service 8264ee
		if (text) {
Packit Service 8264ee
			char str[26];
Packit Service 8264ee
			unsigned int n;
Packit Service 8264ee
Packit Service 8264ee
			str[sizeof(str) - 1] = '\0';
Packit Service 8264ee
Packit Service 8264ee
			n = snprintf(str, sizeof(str), "%s", text);
Packit Service 8264ee
			if (n > sizeof(str) - 1) {
Packit Service 8264ee
				str[sizeof(str) - 2] = '.';
Packit Service 8264ee
				str[sizeof(str) - 3] = '.';
Packit Service 8264ee
				if (str[sizeof(str) - 4] == ' ')
Packit Service 8264ee
					str[sizeof(str) - 4] = '.';
Packit Service 8264ee
Packit Service 8264ee
				n = sizeof(str) - 1;
Packit Service 8264ee
			}
Packit Service 8264ee
Packit Service 8264ee
			bt_shell_printf("\tUUID: %s%*c(%s)\n",
Packit Service 8264ee
						str, 26 - n, ' ', uuid);
Packit Service 8264ee
		} else
Packit Service 8264ee
			bt_shell_printf("\tUUID: %*c(%s)\n", 26, ' ', uuid);
Packit Service 8264ee
Packit Service 8264ee
		dbus_message_iter_next(&value);
Packit Service 8264ee
	}
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static gboolean device_is_child(GDBusProxy *device, GDBusProxy *master)
Packit Service 8264ee
{
Packit Service 8264ee
	DBusMessageIter iter;
Packit Service 8264ee
	const char *adapter, *path;
Packit Service 8264ee
Packit Service 8264ee
	if (!master)
Packit Service 8264ee
		return FALSE;
Packit Service 8264ee
Packit Service 8264ee
	if (g_dbus_proxy_get_property(device, "Adapter", &iter) == FALSE)
Packit Service 8264ee
		return FALSE;
Packit Service 8264ee
Packit Service 8264ee
	dbus_message_iter_get_basic(&iter, &adapter);
Packit Service 8264ee
	path = g_dbus_proxy_get_path(master);
Packit Service 8264ee
Packit Service 8264ee
	if (!strcmp(path, adapter))
Packit Service 8264ee
		return TRUE;
Packit Service 8264ee
Packit Service 8264ee
	return FALSE;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static struct adapter *find_parent(GDBusProxy *device)
Packit Service 8264ee
{
Packit Service 8264ee
	GList *list;
Packit Service 8264ee
Packit Service 8264ee
	for (list = g_list_first(ctrl_list); list; list = g_list_next(list)) {
Packit Service 8264ee
		struct adapter *adapter = list->data;
Packit Service 8264ee
Packit Service 8264ee
		if (device_is_child(device, adapter->proxy) == TRUE)
Packit Service 8264ee
			return adapter;
Packit Service 8264ee
	}
Packit Service 8264ee
	return NULL;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void set_connected_device(GDBusProxy *proxy)
Packit Service 8264ee
{
Packit Service 8264ee
	char *desc = NULL;
Packit Service 8264ee
	DBusMessageIter iter;
Packit Service 8264ee
	char buf[10];
Packit Service 8264ee
	bool mesh;
Packit Service 8264ee
Packit Service 8264ee
	connection.device = proxy;
Packit Service 8264ee
Packit Service 8264ee
	if (proxy == NULL) {
Packit Service 8264ee
		memset(&connection, 0, sizeof(connection));
Packit Service 8264ee
		connection.type = CONN_TYPE_INVALID;
Packit Service 8264ee
		goto done;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	if (connection.type == CONN_TYPE_IDENTITY) {
Packit Service 8264ee
		mesh = true;
Packit Service 8264ee
		snprintf(buf, 10, "Node-%4.4x", connection.unicast);
Packit Service 8264ee
	} else if (connection.type == CONN_TYPE_NETWORK) {
Packit Service 8264ee
		mesh = true;
Packit Service 8264ee
		snprintf(buf, 9, "Net-%4.4x", connection.net_idx);
Packit Service 8264ee
	} else {
Packit Service 8264ee
		mesh = false;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	if (!g_dbus_proxy_get_property(proxy, "Alias", &iter) && !mesh)
Packit Service 8264ee
			goto done;
Packit Service 8264ee
Packit Service 8264ee
	dbus_message_iter_get_basic(&iter, &desc);
Packit Service 8264ee
	desc = g_strdup_printf(COLOR_BLUE "[%s%s%s]" COLOR_OFF "# ", desc,
Packit Service 8264ee
			       (desc && mesh) ? "-" : "",
Packit Service 8264ee
				mesh ? buf : "");
Packit Service 8264ee
Packit Service 8264ee
done:
Packit Service 8264ee
	bt_shell_set_prompt(desc ? desc : PROMPT_ON);
Packit Service 8264ee
	g_free(desc);
Packit Service 8264ee
Packit Service 8264ee
	/* If disconnected, return to main menu */
Packit Service 8264ee
	if (proxy == NULL)
Packit Service 8264ee
		bt_shell_set_menu(&main_menu);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void connect_reply(DBusMessage *message, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	GDBusProxy *proxy = user_data;
Packit Service 8264ee
	DBusError error;
Packit Service 8264ee
Packit Service 8264ee
	dbus_error_init(&error);
Packit Service 8264ee
Packit Service 8264ee
	if (dbus_set_error_from_message(&error, message) == TRUE) {
Packit Service 8264ee
		bt_shell_printf("Failed to connect: %s\n", error.name);
Packit Service 8264ee
		dbus_error_free(&error);
Packit Service 8264ee
		set_connected_device(NULL);
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	bt_shell_printf("Connection successful\n");
Packit Service 8264ee
Packit Service 8264ee
	set_connected_device(proxy);
Packit Service 8264ee
Packit Service 8264ee
	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void update_device_info(GDBusProxy *proxy)
Packit Service 8264ee
{
Packit Service 8264ee
	struct adapter *adapter = find_parent(proxy);
Packit Service 8264ee
	DBusMessageIter iter;
Packit Service 8264ee
	struct prov_svc_data prov_data;
Packit Service 8264ee
Packit Service 8264ee
	if (!adapter) {
Packit Service 8264ee
		/* TODO: Error */
Packit Service 8264ee
		return;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	if (adapter != default_ctrl)
Packit Service 8264ee
		return;
Packit Service 8264ee
Packit Service 8264ee
	if (!g_dbus_proxy_get_property(proxy, "Address", &iter))
Packit Service 8264ee
		return;
Packit Service 8264ee
Packit Service 8264ee
	if (parse_service_data(proxy, MESH_PROV_SVC_UUID, &prov_data)) {
Packit Service 8264ee
		struct mesh_device *dev;
Packit Service 8264ee
Packit Service 8264ee
		dev = find_device_by_uuid(adapter->mesh_devices,
Packit Service 8264ee
							prov_data.dev_uuid);
Packit Service 8264ee
Packit Service 8264ee
		/* Display provisioning service once per discovery session */
Packit Service 8264ee
		if (discovering && (!dev || !dev->hide))
Packit Service 8264ee
						print_prov_service(&prov_data);
Packit Service 8264ee
Packit Service 8264ee
		if (dev) {
Packit Service 8264ee
			dev->proxy = proxy;
Packit Service 8264ee
			dev->hide = discovering;
Packit Service 8264ee
			return;
Packit Service 8264ee
		}
Packit Service 8264ee
Packit Service 8264ee
		dev = g_malloc0(sizeof(struct mesh_device));
Packit Service 8264ee
		if (!dev)
Packit Service 8264ee
			return;
Packit Service 8264ee
Packit Service 8264ee
		dev->proxy = proxy;
Packit Service 8264ee
		dev->hide = discovering;
Packit Service 8264ee
Packit Service 8264ee
		memcpy(dev->dev_uuid, prov_data.dev_uuid, 16);
Packit Service 8264ee
Packit Service 8264ee
		adapter->mesh_devices = g_list_append(adapter->mesh_devices,
Packit Service 8264ee
							dev);
Packit Service 8264ee
		print_device(proxy, COLORED_NEW);
Packit Service 8264ee
Packit Service 8264ee
		node_create_new(&prov_data);
Packit Service 8264ee
Packit Service 8264ee
	} else if (parse_service_data(proxy, MESH_PROXY_SVC_UUID, NULL) &&
Packit Service 8264ee
								discover_mesh) {
Packit Service 8264ee
		bool res;
Packit Service 8264ee
Packit Service 8264ee
		g_dbus_proxy_method_call(default_ctrl->proxy, "StopDiscovery",
Packit Service 8264ee
						NULL, NULL, NULL, NULL);
Packit Service 8264ee
		discover_mesh = false;
Packit Service 8264ee
Packit Service 8264ee
		forget_mesh_devices();
Packit Service 8264ee
Packit Service 8264ee
		res = g_dbus_proxy_method_call(proxy, "Connect", NULL,
Packit Service 8264ee
						connect_reply, proxy, NULL);
Packit Service 8264ee
Packit Service 8264ee
		if (!res)
Packit Service 8264ee
			bt_shell_printf("Failed to connect to mesh\n");
Packit Service 8264ee
Packit Service 8264ee
		else
Packit Service 8264ee
			bt_shell_printf("Trying to connect to mesh\n");
Packit Service 8264ee
Packit Service 8264ee
	}
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void adapter_added(GDBusProxy *proxy)
Packit Service 8264ee
{
Packit Service 8264ee
	struct adapter *adapter = g_malloc0(sizeof(struct adapter));
Packit Service 8264ee
Packit Service 8264ee
	adapter->proxy = proxy;
Packit Service 8264ee
	ctrl_list = g_list_append(ctrl_list, adapter);
Packit Service 8264ee
Packit Service 8264ee
	if (!default_ctrl)
Packit Service 8264ee
		default_ctrl = adapter;
Packit Service 8264ee
Packit Service 8264ee
	print_adapter(proxy, COLORED_NEW);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void data_out_notify(GDBusProxy *proxy, bool enable,
Packit Service 8264ee
				GDBusReturnFunction cb)
Packit Service 8264ee
{
Packit Service 8264ee
	struct mesh_node *node;
Packit Service 8264ee
Packit Service 8264ee
	node = node_find_by_uuid(connection.dev_uuid);
Packit Service 8264ee
Packit Service 8264ee
	if (!mesh_gatt_notify(proxy, enable, cb, node))
Packit Service 8264ee
		bt_shell_printf("Failed to %s notification on %s\n", enable ?
Packit Service 8264ee
				"start" : "stop", g_dbus_proxy_get_path(proxy));
Packit Service 8264ee
	else
Packit Service 8264ee
		bt_shell_printf("%s notification on %s\n", enable ?
Packit Service 8264ee
			  "Start" : "Stop", g_dbus_proxy_get_path(proxy));
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
struct disconnect_data {
Packit Service 8264ee
	GDBusReturnFunction cb;
Packit Service 8264ee
	void *data;
Packit Service 8264ee
};
Packit Service 8264ee
Packit Service 8264ee
static void disconnect(GDBusReturnFunction cb, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	GDBusProxy *proxy;
Packit Service 8264ee
	DBusMessageIter iter;
Packit Service 8264ee
	const char *addr;
Packit Service 8264ee
Packit Service 8264ee
	proxy = connection.device;
Packit Service 8264ee
	if (!proxy)
Packit Service 8264ee
		return;
Packit Service 8264ee
Packit Service 8264ee
	if (g_dbus_proxy_method_call(proxy, "Disconnect", NULL, cb, user_data,
Packit Service 8264ee
							NULL) == FALSE) {
Packit Service 8264ee
		bt_shell_printf("Failed to disconnect\n");
Packit Service 8264ee
		return;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	if (g_dbus_proxy_get_property(proxy, "Address", &iter) == TRUE)
Packit Service 8264ee
			dbus_message_iter_get_basic(&iter, &addr);
Packit Service 8264ee
Packit Service 8264ee
	bt_shell_printf("Attempting to disconnect from %s\n", addr);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void disc_notify_cb(DBusMessage *message, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	struct disconnect_data *disc_data = user_data;
Packit Service 8264ee
Packit Service 8264ee
	disconnect(disc_data->cb, disc_data->data);
Packit Service 8264ee
Packit Service 8264ee
	g_free(user_data);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void disconnect_device(GDBusReturnFunction cb, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	DBusMessageIter iter;
Packit Service 8264ee
Packit Service 8264ee
	net_session_close(connection.data_in);
Packit Service 8264ee
Packit Service 8264ee
	/* Stop notificiation on prov_out or proxy out characteristics */
Packit Service 8264ee
	if (connection.data_out) {
Packit Service 8264ee
		if (g_dbus_proxy_get_property(connection.data_out, "Notifying",
Packit Service 8264ee
							&iter) == TRUE) {
Packit Service 8264ee
			struct disconnect_data *disc_data;
Packit Service 8264ee
			disc_data = g_malloc(sizeof(struct disconnect_data));
Packit Service 8264ee
			disc_data->cb = cb;
Packit Service 8264ee
			disc_data->data = user_data;
Packit Service 8264ee
Packit Service 8264ee
			if (mesh_gatt_notify(connection.data_out, false,
Packit Service 8264ee
						disc_notify_cb, disc_data))
Packit Service 8264ee
				return;
Packit Service 8264ee
		}
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	disconnect(cb, user_data);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void mesh_prov_done(void *user_data, int status);
Packit Service 8264ee
Packit Service 8264ee
static void notify_prov_out_cb(DBusMessage *message, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	struct mesh_node *node = user_data;
Packit Service 8264ee
	DBusError error;
Packit Service 8264ee
Packit Service 8264ee
	dbus_error_init(&error);
Packit Service 8264ee
Packit Service 8264ee
	if (dbus_set_error_from_message(&error, message) == TRUE) {
Packit Service 8264ee
		bt_shell_printf("Failed to start notify: %s\n", error.name);
Packit Service 8264ee
		dbus_error_free(&error);
Packit Service 8264ee
		return;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	bt_shell_printf("Notify for Mesh Provisioning Out Data started\n");
Packit Service 8264ee
Packit Service 8264ee
	if (connection.type != CONN_TYPE_PROVISION) {
Packit Service 8264ee
		bt_shell_printf("Error: wrong connection type %d (expected %d)\n",
Packit Service 8264ee
			connection.type, CONN_TYPE_PROVISION);
Packit Service 8264ee
		return;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	if (!connection.data_in) {
Packit Service 8264ee
		bt_shell_printf("Error: don't have mesh provisioning data in\n");
Packit Service 8264ee
		return;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	if (!node) {
Packit Service 8264ee
		bt_shell_printf("Error: provisioning node not present\n");
Packit Service 8264ee
		return;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	if(!prov_open(node, connection.data_in, prov_net_key_index,
Packit Service 8264ee
			mesh_prov_done, node))
Packit Service 8264ee
	{
Packit Service 8264ee
		bt_shell_printf("Failed to start provisioning\n");
Packit Service 8264ee
		node_free(node);
Packit Service 8264ee
		disconnect_device(NULL, NULL);
Packit Service 8264ee
	} else
Packit Service 8264ee
		bt_shell_printf("Initiated provisioning\n");
Packit Service 8264ee
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void session_open_cb (int status)
Packit Service 8264ee
{
Packit Service 8264ee
	if (status) {
Packit Service 8264ee
		bt_shell_printf("Failed to open Mesh session\n");
Packit Service 8264ee
		disconnect_device(NULL, NULL);
Packit Service 8264ee
		return;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	bt_shell_printf("Mesh session is open\n");
Packit Service 8264ee
Packit Service 8264ee
	/* Get composition data for a newly provisioned node */
Packit Service 8264ee
	if (connection.type == CONN_TYPE_IDENTITY)
Packit Service 8264ee
		config_client_get_composition(connection.unicast);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void notify_proxy_out_cb(DBusMessage *message, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	DBusError error;
Packit Service 8264ee
Packit Service 8264ee
	dbus_error_init(&error);
Packit Service 8264ee
Packit Service 8264ee
	if (dbus_set_error_from_message(&error, message) == TRUE) {
Packit Service 8264ee
		bt_shell_printf("Failed to start notify: %s\n", error.name);
Packit Service 8264ee
		dbus_error_free(&error);
Packit Service 8264ee
		return;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	bt_shell_printf("Notify for Mesh Proxy Out Data started\n");
Packit Service 8264ee
Packit Service 8264ee
	if (connection.type != CONN_TYPE_IDENTITY &&
Packit Service 8264ee
			connection.type != CONN_TYPE_NETWORK) {
Packit Service 8264ee
		bt_shell_printf("Error: wrong connection type %d "
Packit Service 8264ee
				"(expected %d or %d)\n", connection.type,
Packit Service 8264ee
				CONN_TYPE_IDENTITY, CONN_TYPE_NETWORK);
Packit Service 8264ee
		return;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	if (!connection.data_in) {
Packit Service 8264ee
		bt_shell_printf("Error: don't have mesh proxy data in\n");
Packit Service 8264ee
		return;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	bt_shell_printf("Trying to open mesh session\n");
Packit Service 8264ee
	net_session_open(connection.data_in, true, session_open_cb);
Packit Service 8264ee
	connection.session_open = true;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static GDBusProxy *get_characteristic(GDBusProxy *device, const char *char_uuid)
Packit Service 8264ee
{
Packit Service 8264ee
	GList *l;
Packit Service 8264ee
	GDBusProxy *service;
Packit Service 8264ee
	const char *svc_uuid;
Packit Service 8264ee
Packit Service 8264ee
	if (connection.type == CONN_TYPE_PROVISION) {
Packit Service 8264ee
		svc_uuid = MESH_PROV_SVC_UUID;
Packit Service 8264ee
	} else {
Packit Service 8264ee
		svc_uuid = MESH_PROXY_SVC_UUID;
Packit Service 8264ee
	}
Packit Service 8264ee
	for (l = service_list; l; l = l->next) {
Packit Service 8264ee
		if (mesh_gatt_is_child(l->data, device, "Device") &&
Packit Service 8264ee
					service_is_mesh(l->data, svc_uuid))
Packit Service 8264ee
			break;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	if (l)
Packit Service 8264ee
		service = l->data;
Packit Service 8264ee
	else {
Packit Service 8264ee
		bt_shell_printf("Mesh service not found\n");
Packit Service 8264ee
		return	NULL;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	for (l = char_list; l; l = l->next) {
Packit Service 8264ee
		if (mesh_gatt_is_child(l->data, service, "Service") &&
Packit Service 8264ee
					char_is_mesh(l->data, char_uuid)) {
Packit Service 8264ee
			bt_shell_printf("Found matching char: path %s,"
Packit Service 8264ee
					" uuid %s\n",
Packit Service 8264ee
					g_dbus_proxy_get_path(l->data),
Packit Service 8264ee
					char_uuid);
Packit Service 8264ee
			return l->data;
Packit Service 8264ee
		}
Packit Service 8264ee
	}
Packit Service 8264ee
	return NULL;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void mesh_session_setup(GDBusProxy *proxy)
Packit Service 8264ee
{
Packit Service 8264ee
	if (connection.type == CONN_TYPE_PROVISION) {
Packit Service 8264ee
		connection.data_in = get_characteristic(proxy,
Packit Service 8264ee
						MESH_PROV_DATA_IN_UUID_STR);
Packit Service 8264ee
		if (!connection.data_in)
Packit Service 8264ee
			goto fail;
Packit Service 8264ee
Packit Service 8264ee
		connection.data_out = get_characteristic(proxy,
Packit Service 8264ee
						MESH_PROV_DATA_OUT_UUID_STR);
Packit Service 8264ee
		if (!connection.data_out)
Packit Service 8264ee
			goto fail;
Packit Service 8264ee
Packit Service 8264ee
		data_out_notify(connection.data_out, true, notify_prov_out_cb);
Packit Service 8264ee
Packit Service 8264ee
	} else if (connection.type != CONN_TYPE_INVALID){
Packit Service 8264ee
		connection.data_in = get_characteristic(proxy,
Packit Service 8264ee
						MESH_PROXY_DATA_IN_UUID_STR);
Packit Service 8264ee
		if (!connection.data_in)
Packit Service 8264ee
			goto fail;
Packit Service 8264ee
Packit Service 8264ee
		connection.data_out = get_characteristic(proxy,
Packit Service 8264ee
						MESH_PROXY_DATA_OUT_UUID_STR);
Packit Service 8264ee
		if (!connection.data_out)
Packit Service 8264ee
			goto fail;
Packit Service 8264ee
Packit Service 8264ee
		data_out_notify(connection.data_out, true, notify_proxy_out_cb);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	return;
Packit Service 8264ee
Packit Service 8264ee
fail:
Packit Service 8264ee
Packit Service 8264ee
	bt_shell_printf("Services resolved, mesh characteristics not found\n");
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void proxy_added(GDBusProxy *proxy, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	const char *interface;
Packit Service 8264ee
Packit Service 8264ee
	interface = g_dbus_proxy_get_interface(proxy);
Packit Service 8264ee
Packit Service 8264ee
	if (!strcmp(interface, "org.bluez.Device1")) {
Packit Service 8264ee
		update_device_info(proxy);
Packit Service 8264ee
Packit Service 8264ee
	} else if (!strcmp(interface, "org.bluez.Adapter1")) {
Packit Service 8264ee
Packit Service 8264ee
		adapter_added(proxy);
Packit Service 8264ee
Packit Service 8264ee
	} else if (!strcmp(interface, "org.bluez.GattService1") &&
Packit Service 8264ee
						service_is_mesh(proxy, NULL)) {
Packit Service 8264ee
Packit Service 8264ee
		bt_shell_printf("Service added %s\n",
Packit Service 8264ee
				g_dbus_proxy_get_path(proxy));
Packit Service 8264ee
		service_list = g_list_append(service_list, proxy);
Packit Service 8264ee
Packit Service 8264ee
	} else if (!strcmp(interface, "org.bluez.GattCharacteristic1") &&
Packit Service 8264ee
						char_is_mesh(proxy, NULL)) {
Packit Service 8264ee
Packit Service 8264ee
		bt_shell_printf("Char added %s:\n",
Packit Service 8264ee
				g_dbus_proxy_get_path(proxy));
Packit Service 8264ee
Packit Service 8264ee
		char_list = g_list_append(char_list, proxy);
Packit Service 8264ee
	}
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void start_discovery_reply(DBusMessage *message, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	dbus_bool_t enable = GPOINTER_TO_UINT(user_data);
Packit Service 8264ee
	DBusError error;
Packit Service 8264ee
Packit Service 8264ee
	dbus_error_init(&error);
Packit Service 8264ee
Packit Service 8264ee
	if (dbus_set_error_from_message(&error, message) == TRUE) {
Packit Service 8264ee
		bt_shell_printf("Failed to %s discovery: %s\n",
Packit Service 8264ee
				enable == TRUE ? "start" : "stop", error.name);
Packit Service 8264ee
		dbus_error_free(&error);
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	bt_shell_printf("Discovery %s\n",
Packit Service 8264ee
			enable == TRUE ? "started" : "stopped");
Packit Service 8264ee
Packit Service 8264ee
	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static struct mesh_device *find_device_by_proxy(GList *source,
Packit Service 8264ee
							GDBusProxy *proxy)
Packit Service 8264ee
{
Packit Service 8264ee
	GList *list;
Packit Service 8264ee
Packit Service 8264ee
	for (list = g_list_first(source); list; list = g_list_next(list)) {
Packit Service 8264ee
		struct mesh_device *dev = list->data;
Packit Service 8264ee
		GDBusProxy *proxy = dev->proxy;
Packit Service 8264ee
Packit Service 8264ee
		if (dev->proxy == proxy)
Packit Service 8264ee
			return dev;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	return NULL;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void device_removed(GDBusProxy *proxy)
Packit Service 8264ee
{
Packit Service 8264ee
	struct adapter *adapter = find_parent(proxy);
Packit Service 8264ee
	struct mesh_device *dev;
Packit Service 8264ee
Packit Service 8264ee
	if (!adapter) {
Packit Service 8264ee
		/* TODO: Error */
Packit Service 8264ee
		return;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	dev = find_device_by_proxy(adapter->mesh_devices, proxy);
Packit Service 8264ee
	if (dev)
Packit Service 8264ee
		adapter->mesh_devices = g_list_remove(adapter->mesh_devices,
Packit Service 8264ee
									dev);
Packit Service 8264ee
Packit Service 8264ee
	print_device(proxy, COLORED_DEL);
Packit Service 8264ee
Packit Service 8264ee
	if (connection.device == proxy)
Packit Service 8264ee
		set_connected_device(NULL);
Packit Service 8264ee
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void adapter_removed(GDBusProxy *proxy)
Packit Service 8264ee
{
Packit Service 8264ee
	GList *ll;
Packit Service 8264ee
	for (ll = g_list_first(ctrl_list); ll; ll = g_list_next(ll)) {
Packit Service 8264ee
		struct adapter *adapter = ll->data;
Packit Service 8264ee
Packit Service 8264ee
		if (adapter->proxy == proxy) {
Packit Service 8264ee
			print_adapter(proxy, COLORED_DEL);
Packit Service 8264ee
Packit Service 8264ee
			if (default_ctrl && default_ctrl->proxy == proxy) {
Packit Service 8264ee
				default_ctrl = NULL;
Packit Service 8264ee
				set_connected_device(NULL);
Packit Service 8264ee
			}
Packit Service 8264ee
Packit Service 8264ee
			ctrl_list = g_list_remove_link(ctrl_list, ll);
Packit Service 8264ee
Packit Service 8264ee
			g_list_free_full(adapter->mesh_devices, g_free);
Packit Service 8264ee
			g_free(adapter);
Packit Service 8264ee
			g_list_free(ll);
Packit Service 8264ee
			return;
Packit Service 8264ee
		}
Packit Service 8264ee
	}
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void proxy_removed(GDBusProxy *proxy, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	const char *interface;
Packit Service 8264ee
Packit Service 8264ee
	interface = g_dbus_proxy_get_interface(proxy);
Packit Service 8264ee
Packit Service 8264ee
	if (!strcmp(interface, "org.bluez.Device1")) {
Packit Service 8264ee
		device_removed(proxy);
Packit Service 8264ee
	} else if (!strcmp(interface, "org.bluez.Adapter1")) {
Packit Service 8264ee
		adapter_removed(proxy);
Packit Service 8264ee
	} else if (!strcmp(interface, "org.bluez.GattService1")) {
Packit Service 8264ee
		if (proxy == connection.service) {
Packit Service 8264ee
			if (service_is_mesh(proxy, MESH_PROXY_SVC_UUID)) {
Packit Service 8264ee
				data_out_notify(connection.data_out,
Packit Service 8264ee
								false, NULL);
Packit Service 8264ee
				net_session_close(connection.data_in);
Packit Service 8264ee
			}
Packit Service 8264ee
			connection.service = NULL;
Packit Service 8264ee
			connection.data_in = NULL;
Packit Service 8264ee
			connection.data_out = NULL;
Packit Service 8264ee
		}
Packit Service 8264ee
Packit Service 8264ee
		service_list = g_list_remove(service_list, proxy);
Packit Service 8264ee
Packit Service 8264ee
	} else if (!strcmp(interface, "org.bluez.GattCharacteristic1")) {
Packit Service 8264ee
		char_list = g_list_remove(char_list, proxy);
Packit Service 8264ee
	}
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static int get_characteristic_value(DBusMessageIter *value, uint8_t *buf)
Packit Service 8264ee
{
Packit Service 8264ee
	DBusMessageIter array;
Packit Service 8264ee
	uint8_t *data;
Packit Service 8264ee
	int len;
Packit Service 8264ee
Packit Service 8264ee
	if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_ARRAY)
Packit Service 8264ee
		return 0;
Packit Service 8264ee
Packit Service 8264ee
	dbus_message_iter_recurse(value, &array);
Packit Service 8264ee
Packit Service 8264ee
	if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_BYTE)
Packit Service 8264ee
		return 0;
Packit Service 8264ee
Packit Service 8264ee
	dbus_message_iter_get_fixed_array(&array, &data, &len;;
Packit Service 8264ee
	memcpy(buf, data, len);
Packit Service 8264ee
Packit Service 8264ee
	return len;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static bool process_mesh_characteristic(GDBusProxy *proxy)
Packit Service 8264ee
{
Packit Service 8264ee
	DBusMessageIter iter;
Packit Service 8264ee
	const char *uuid;
Packit Service 8264ee
	uint8_t *res;
Packit Service 8264ee
	uint8_t buf[256];
Packit Service 8264ee
	bool is_prov;
Packit Service 8264ee
Packit Service 8264ee
	if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
Packit Service 8264ee
		return false;
Packit Service 8264ee
Packit Service 8264ee
	dbus_message_iter_get_basic(&iter, &uuid);
Packit Service 8264ee
Packit Service 8264ee
	if (g_dbus_proxy_get_property(proxy, "Value", &iter) == FALSE)
Packit Service 8264ee
		return false;
Packit Service 8264ee
Packit Service 8264ee
	is_prov = !bt_uuid_strcmp(uuid, MESH_PROV_DATA_OUT_UUID_STR);
Packit Service 8264ee
Packit Service 8264ee
	if (is_prov || !bt_uuid_strcmp(uuid, MESH_PROXY_DATA_OUT_UUID_STR))
Packit Service 8264ee
	{
Packit Service 8264ee
		struct mesh_node *node;
Packit Service 8264ee
		uint16_t len;
Packit Service 8264ee
Packit Service 8264ee
		len = get_characteristic_value(&iter, buf);
Packit Service 8264ee
Packit Service 8264ee
		if (!len || len > 69)
Packit Service 8264ee
			return false;
Packit Service 8264ee
Packit Service 8264ee
		res = buf;
Packit Service 8264ee
		len = mesh_gatt_sar(&res, len);
Packit Service 8264ee
Packit Service 8264ee
		if (!len)
Packit Service 8264ee
			return false;
Packit Service 8264ee
Packit Service 8264ee
		if (is_prov) {
Packit Service 8264ee
			node = node_find_by_uuid(connection.dev_uuid);
Packit Service 8264ee
Packit Service 8264ee
			if (!node) {
Packit Service 8264ee
				bt_shell_printf("Node not found?\n");
Packit Service 8264ee
				return false;
Packit Service 8264ee
			}
Packit Service 8264ee
Packit Service 8264ee
			return prov_data_ready(node, res, len);
Packit Service 8264ee
		}
Packit Service 8264ee
Packit Service 8264ee
		return net_data_ready(res, len);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	return false;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
Packit Service 8264ee
static void property_changed(GDBusProxy *proxy, const char *name,
Packit Service 8264ee
					DBusMessageIter *iter, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	const char *interface;
Packit Service 8264ee
Packit Service 8264ee
	interface = g_dbus_proxy_get_interface(proxy);
Packit Service 8264ee
Packit Service 8264ee
	if (!strcmp(interface, "org.bluez.Device1")) {
Packit Service 8264ee
Packit Service 8264ee
		if (default_ctrl && device_is_child(proxy,
Packit Service 8264ee
					default_ctrl->proxy) == TRUE) {
Packit Service 8264ee
Packit Service 8264ee
			if (strcmp(name, "Connected") == 0) {
Packit Service 8264ee
				dbus_bool_t connected;
Packit Service 8264ee
				dbus_message_iter_get_basic(iter, &connected);
Packit Service 8264ee
Packit Service 8264ee
				if (connected && connection.device == NULL)
Packit Service 8264ee
					set_connected_device(proxy);
Packit Service 8264ee
				else if (!connected &&
Packit Service 8264ee
						connection.device == proxy) {
Packit Service 8264ee
					net_session_close(connection.data_in);
Packit Service 8264ee
					set_connected_device(NULL);
Packit Service 8264ee
				}
Packit Service 8264ee
			} else if ((strcmp(name, "Alias") == 0) &&
Packit Service 8264ee
						connection.device == proxy) {
Packit Service 8264ee
				/* Re-generate prompt */
Packit Service 8264ee
				set_connected_device(proxy);
Packit Service 8264ee
			} else if (!strcmp(name, "ServiceData")) {
Packit Service 8264ee
				update_device_info(proxy);
Packit Service 8264ee
			} else if (!strcmp(name, "ServicesResolved")) {
Packit Service 8264ee
				gboolean resolved;
Packit Service 8264ee
Packit Service 8264ee
				dbus_message_iter_get_basic(iter, &resolved);
Packit Service 8264ee
Packit Service 8264ee
				bt_shell_printf("Services resolved %s\n",
Packit Service 8264ee
						resolved ? "yes" : "no");
Packit Service 8264ee
Packit Service 8264ee
				if (resolved)
Packit Service 8264ee
					mesh_session_setup(connection.device);
Packit Service 8264ee
			}
Packit Service 8264ee
Packit Service 8264ee
		}
Packit Service 8264ee
	} else if (!strcmp(interface, "org.bluez.Adapter1")) {
Packit Service 8264ee
		DBusMessageIter addr_iter;
Packit Service 8264ee
		char *str;
Packit Service 8264ee
Packit Service 8264ee
		bt_shell_printf("Adapter property changed \n");
Packit Service 8264ee
		if (g_dbus_proxy_get_property(proxy, "Address",
Packit Service 8264ee
						&addr_iter) == TRUE) {
Packit Service 8264ee
			const char *address;
Packit Service 8264ee
Packit Service 8264ee
			dbus_message_iter_get_basic(&addr_iter, &address);
Packit Service 8264ee
			str = g_strdup_printf("[" COLORED_CHG
Packit Service 8264ee
						"] Controller %s ", address);
Packit Service 8264ee
		} else
Packit Service 8264ee
			str = g_strdup("");
Packit Service 8264ee
Packit Service 8264ee
		if (strcmp(name, "Discovering") == 0) {
Packit Service 8264ee
			int temp;
Packit Service 8264ee
Packit Service 8264ee
			dbus_message_iter_get_basic(iter, &temp);
Packit Service 8264ee
			discovering = !!temp;
Packit Service 8264ee
		}
Packit Service 8264ee
Packit Service 8264ee
		print_iter(str, name, iter);
Packit Service 8264ee
		g_free(str);
Packit Service 8264ee
	} else if (!strcmp(interface, "org.bluez.GattService1")) {
Packit Service 8264ee
		bt_shell_printf("Service property changed %s\n",
Packit Service 8264ee
						g_dbus_proxy_get_path(proxy));
Packit Service 8264ee
	} else if (!strcmp(interface, "org.bluez.GattCharacteristic1")) {
Packit Service 8264ee
		bt_shell_printf("Characteristic property changed %s\n",
Packit Service 8264ee
						g_dbus_proxy_get_path(proxy));
Packit Service 8264ee
Packit Service 8264ee
		if ((strcmp(name, "Value") == 0) &&
Packit Service 8264ee
				((connection.type == CONN_TYPE_PROVISION) ||
Packit Service 8264ee
						connection.session_open))
Packit Service 8264ee
			process_mesh_characteristic(proxy);
Packit Service 8264ee
	}
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void message_handler(DBusConnection *connection,
Packit Service 8264ee
					DBusMessage *message, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	bt_shell_printf("[SIGNAL] %s.%s\n", dbus_message_get_interface(message),
Packit Service 8264ee
					dbus_message_get_member(message));
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static struct adapter *find_ctrl_by_address(GList *source, const char *address)
Packit Service 8264ee
{
Packit Service 8264ee
	GList *list;
Packit Service 8264ee
Packit Service 8264ee
	for (list = g_list_first(source); list; list = g_list_next(list)) {
Packit Service 8264ee
		struct adapter *adapter = list->data;
Packit Service 8264ee
		DBusMessageIter iter;
Packit Service 8264ee
		const char *str;
Packit Service 8264ee
Packit Service 8264ee
		if (g_dbus_proxy_get_property(adapter->proxy,
Packit Service 8264ee
					"Address", &iter) == FALSE)
Packit Service 8264ee
			continue;
Packit Service 8264ee
Packit Service 8264ee
		dbus_message_iter_get_basic(&iter, &str);
Packit Service 8264ee
Packit Service 8264ee
		if (!strcmp(str, address))
Packit Service 8264ee
			return adapter;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	return NULL;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static gboolean parse_argument_on_off(int argc, char *argv[],
Packit Service 8264ee
					dbus_bool_t *value)
Packit Service 8264ee
{
Packit Service 8264ee
	if (!strcmp(argv[1], "on") || !strcmp(argv[1], "yes")) {
Packit Service 8264ee
		*value = TRUE;
Packit Service 8264ee
		return TRUE;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	if (!strcmp(argv[1], "off") || !strcmp(argv[1], "no")) {
Packit Service 8264ee
		*value = FALSE;
Packit Service 8264ee
		return TRUE;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	bt_shell_printf("Invalid argument %s\n", argv[1]);
Packit Service 8264ee
	return FALSE;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void cmd_list(int argc, char *argv[])
Packit Service 8264ee
{
Packit Service 8264ee
	GList *list;
Packit Service 8264ee
Packit Service 8264ee
	for (list = g_list_first(ctrl_list); list; list = g_list_next(list)) {
Packit Service 8264ee
		struct adapter *adapter = list->data;
Packit Service 8264ee
		print_adapter(adapter->proxy, NULL);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void cmd_show(int argc, char *argv[])
Packit Service 8264ee
{
Packit Service 8264ee
	struct adapter *adapter;
Packit Service 8264ee
	GDBusProxy *proxy;
Packit Service 8264ee
	DBusMessageIter iter;
Packit Service 8264ee
	const char *address;
Packit Service 8264ee
Packit Service 8264ee
Packit Service 8264ee
	if (argc < 2 || !strlen(argv[1])) {
Packit Service 8264ee
		if (check_default_ctrl() == FALSE)
Packit Service 8264ee
			return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
Packit Service 8264ee
		proxy = default_ctrl->proxy;
Packit Service 8264ee
	} else {
Packit Service 8264ee
		adapter = find_ctrl_by_address(ctrl_list, argv[1]);
Packit Service 8264ee
		if (!adapter) {
Packit Service 8264ee
			bt_shell_printf("Controller %s not available\n",
Packit Service 8264ee
								argv[1]);
Packit Service 8264ee
			return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
		}
Packit Service 8264ee
		proxy = adapter->proxy;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
Packit Service 8264ee
	dbus_message_iter_get_basic(&iter, &address);
Packit Service 8264ee
	bt_shell_printf("Controller %s\n", address);
Packit Service 8264ee
Packit Service 8264ee
	print_property(proxy, "Name");
Packit Service 8264ee
	print_property(proxy, "Alias");
Packit Service 8264ee
	print_property(proxy, "Class");
Packit Service 8264ee
	print_property(proxy, "Powered");
Packit Service 8264ee
	print_property(proxy, "Discoverable");
Packit Service 8264ee
	print_uuids(proxy);
Packit Service 8264ee
	print_property(proxy, "Modalias");
Packit Service 8264ee
	print_property(proxy, "Discovering");
Packit Service 8264ee
Packit Service 8264ee
	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void cmd_select(int argc, char *argv[])
Packit Service 8264ee
{
Packit Service 8264ee
	struct adapter *adapter;
Packit Service 8264ee
Packit Service 8264ee
	adapter = find_ctrl_by_address(ctrl_list, argv[1]);
Packit Service 8264ee
	if (!adapter) {
Packit Service 8264ee
		bt_shell_printf("Controller %s not available\n", argv[1]);
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	if (default_ctrl && default_ctrl->proxy == adapter->proxy)
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
Packit Service 8264ee
Packit Service 8264ee
	forget_mesh_devices();
Packit Service 8264ee
Packit Service 8264ee
	default_ctrl = adapter;
Packit Service 8264ee
	print_adapter(adapter->proxy, NULL);
Packit Service 8264ee
Packit Service 8264ee
	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void generic_callback(const DBusError *error, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	char *str = user_data;
Packit Service 8264ee
Packit Service 8264ee
	if (dbus_error_is_set(error)) {
Packit Service 8264ee
		bt_shell_printf("Failed to set %s: %s\n", str, error->name);
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
	} else {
Packit Service 8264ee
		bt_shell_printf("Changing %s succeeded\n", str);
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
Packit Service 8264ee
	}
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void cmd_power(int argc, char *argv[])
Packit Service 8264ee
{
Packit Service 8264ee
	dbus_bool_t powered;
Packit Service 8264ee
	char *str;
Packit Service 8264ee
Packit Service 8264ee
	if (parse_argument_on_off(argc, argv, &powered) == FALSE)
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
Packit Service 8264ee
	if (check_default_ctrl() == FALSE)
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
Packit Service 8264ee
	str = g_strdup_printf("power %s", powered == TRUE ? "on" : "off");
Packit Service 8264ee
Packit Service 8264ee
	if (g_dbus_proxy_set_property_basic(default_ctrl->proxy, "Powered",
Packit Service 8264ee
					DBUS_TYPE_BOOLEAN, &powered,
Packit Service 8264ee
					generic_callback, str, g_free) == TRUE)
Packit Service 8264ee
		return;
Packit Service 8264ee
Packit Service 8264ee
	g_free(str);
Packit Service 8264ee
Packit Service 8264ee
	return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
#define	DISTANCE_VAL_INVALID	0x7FFF
Packit Service 8264ee
Packit Service 8264ee
struct set_discovery_filter_args {
Packit Service 8264ee
	char *transport;
Packit Service 8264ee
	dbus_uint16_t rssi;
Packit Service 8264ee
	dbus_int16_t pathloss;
Packit Service 8264ee
	char **uuids;
Packit Service 8264ee
	size_t uuids_len;
Packit Service 8264ee
	dbus_bool_t duplicate;
Packit Service 8264ee
};
Packit Service 8264ee
Packit Service 8264ee
static void set_discovery_filter_setup(DBusMessageIter *iter, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	struct set_discovery_filter_args *args = user_data;
Packit Service 8264ee
	DBusMessageIter dict;
Packit Service 8264ee
Packit Service 8264ee
	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
Packit Service 8264ee
				DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
Packit Service 8264ee
				DBUS_TYPE_STRING_AS_STRING
Packit Service 8264ee
				DBUS_TYPE_VARIANT_AS_STRING
Packit Service 8264ee
				DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
Packit Service 8264ee
Packit Service 8264ee
	g_dbus_dict_append_array(&dict, "UUIDs", DBUS_TYPE_STRING,
Packit Service 8264ee
							&args->uuids,
Packit Service 8264ee
							args->uuids_len);
Packit Service 8264ee
Packit Service 8264ee
	if (args->pathloss != DISTANCE_VAL_INVALID)
Packit Service 8264ee
		g_dbus_dict_append_entry(&dict, "Pathloss", DBUS_TYPE_UINT16,
Packit Service 8264ee
						&args->pathloss);
Packit Service 8264ee
Packit Service 8264ee
	if (args->rssi != DISTANCE_VAL_INVALID)
Packit Service 8264ee
		g_dbus_dict_append_entry(&dict, "RSSI", DBUS_TYPE_INT16,
Packit Service 8264ee
						&args->rssi);
Packit Service 8264ee
Packit Service 8264ee
	if (args->transport != NULL)
Packit Service 8264ee
		g_dbus_dict_append_entry(&dict, "Transport", DBUS_TYPE_STRING,
Packit Service 8264ee
						&args->transport);
Packit Service 8264ee
	if (args->duplicate)
Packit Service 8264ee
		g_dbus_dict_append_entry(&dict, "DuplicateData",
Packit Service 8264ee
						DBUS_TYPE_BOOLEAN,
Packit Service 8264ee
						&args->duplicate);
Packit Service 8264ee
Packit Service 8264ee
	dbus_message_iter_close_container(iter, &dict);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
Packit Service 8264ee
static void set_discovery_filter_reply(DBusMessage *message, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	DBusError error;
Packit Service 8264ee
Packit Service 8264ee
	dbus_error_init(&error);
Packit Service 8264ee
	if (dbus_set_error_from_message(&error, message) == TRUE) {
Packit Service 8264ee
		bt_shell_printf("SetDiscoveryFilter failed: %s\n", error.name);
Packit Service 8264ee
		dbus_error_free(&error);
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	bt_shell_printf("SetDiscoveryFilter success\n");
Packit Service 8264ee
Packit Service 8264ee
	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static gint filtered_scan_rssi = DISTANCE_VAL_INVALID;
Packit Service 8264ee
static gint filtered_scan_pathloss = DISTANCE_VAL_INVALID;
Packit Service 8264ee
static char **filtered_scan_uuids;
Packit Service 8264ee
static size_t filtered_scan_uuids_len;
Packit Service 8264ee
static char *filtered_scan_transport = "le";
Packit Service 8264ee
Packit Service 8264ee
static void set_scan_filter_commit(void)
Packit Service 8264ee
{
Packit Service 8264ee
	struct set_discovery_filter_args args;
Packit Service 8264ee
Packit Service 8264ee
	args.pathloss = filtered_scan_pathloss;
Packit Service 8264ee
	args.rssi = filtered_scan_rssi;
Packit Service 8264ee
	args.transport = filtered_scan_transport;
Packit Service 8264ee
	args.uuids = filtered_scan_uuids;
Packit Service 8264ee
	args.uuids_len = filtered_scan_uuids_len;
Packit Service 8264ee
	args.duplicate = TRUE;
Packit Service 8264ee
Packit Service 8264ee
	if (check_default_ctrl() == FALSE)
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
Packit Service 8264ee
	if (g_dbus_proxy_method_call(default_ctrl->proxy, "SetDiscoveryFilter",
Packit Service 8264ee
		set_discovery_filter_setup, set_discovery_filter_reply,
Packit Service 8264ee
		&args, NULL) == FALSE) {
Packit Service 8264ee
		bt_shell_printf("Failed to set discovery filter\n");
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
	}
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void set_scan_filter_uuids(char *filters[])
Packit Service 8264ee
{
Packit Service 8264ee
	g_strfreev(filtered_scan_uuids);
Packit Service 8264ee
	filtered_scan_uuids = NULL;
Packit Service 8264ee
	filtered_scan_uuids_len = 0;
Packit Service 8264ee
Packit Service 8264ee
	if (!filters)
Packit Service 8264ee
		goto commit;
Packit Service 8264ee
Packit Service 8264ee
	filtered_scan_uuids = g_strdupv(filters);
Packit Service 8264ee
	if (!filtered_scan_uuids) {
Packit Service 8264ee
		bt_shell_printf("Failed to parse input\n");
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	filtered_scan_uuids_len = g_strv_length(filtered_scan_uuids);
Packit Service 8264ee
Packit Service 8264ee
commit:
Packit Service 8264ee
	set_scan_filter_commit();
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void cmd_scan_unprovisioned(int argc, char *argv[])
Packit Service 8264ee
{
Packit Service 8264ee
	dbus_bool_t enable;
Packit Service 8264ee
	char *filters[] = { MESH_PROV_SVC_UUID, NULL };
Packit Service 8264ee
	const char *method;
Packit Service 8264ee
Packit Service 8264ee
	if (parse_argument_on_off(argc, argv, &enable) == FALSE)
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
Packit Service 8264ee
	if (check_default_ctrl() == FALSE)
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
Packit Service 8264ee
	if (enable == TRUE) {
Packit Service 8264ee
		discover_mesh = false;
Packit Service 8264ee
		set_scan_filter_uuids(filters);
Packit Service 8264ee
		method = "StartDiscovery";
Packit Service 8264ee
	} else {
Packit Service 8264ee
		method = "StopDiscovery";
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	if (g_dbus_proxy_method_call(default_ctrl->proxy, method,
Packit Service 8264ee
				NULL, start_discovery_reply,
Packit Service 8264ee
				GUINT_TO_POINTER(enable), NULL) == FALSE) {
Packit Service 8264ee
		bt_shell_printf("Failed to %s discovery\n",
Packit Service 8264ee
					enable == TRUE ? "start" : "stop");
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
	}
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void cmd_info(int argc, char *argv[])
Packit Service 8264ee
{
Packit Service 8264ee
	GDBusProxy *proxy;
Packit Service 8264ee
	DBusMessageIter iter;
Packit Service 8264ee
	const char *address;
Packit Service 8264ee
Packit Service 8264ee
	proxy = connection.device;
Packit Service 8264ee
	if (!proxy)
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
Packit Service 8264ee
	if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
Packit Service 8264ee
	dbus_message_iter_get_basic(&iter, &address);
Packit Service 8264ee
	bt_shell_printf("Device %s\n", address);
Packit Service 8264ee
Packit Service 8264ee
	print_property(proxy, "Name");
Packit Service 8264ee
	print_property(proxy, "Alias");
Packit Service 8264ee
	print_property(proxy, "Class");
Packit Service 8264ee
	print_property(proxy, "Appearance");
Packit Service 8264ee
	print_property(proxy, "Icon");
Packit Service 8264ee
	print_property(proxy, "Trusted");
Packit Service 8264ee
	print_property(proxy, "Blocked");
Packit Service 8264ee
	print_property(proxy, "Connected");
Packit Service 8264ee
	print_uuids(proxy);
Packit Service 8264ee
	print_property(proxy, "Modalias");
Packit Service 8264ee
	print_property(proxy, "ManufacturerData");
Packit Service 8264ee
	print_property(proxy, "ServiceData");
Packit Service 8264ee
	print_property(proxy, "RSSI");
Packit Service 8264ee
	print_property(proxy, "TxPower");
Packit Service 8264ee
Packit Service 8264ee
	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static const char *security2str(uint8_t level)
Packit Service 8264ee
{
Packit Service 8264ee
	switch (level) {
Packit Service 8264ee
	case 0:
Packit Service 8264ee
		return "low";
Packit Service 8264ee
	case 1:
Packit Service 8264ee
		return "medium";
Packit Service 8264ee
	case 2:
Packit Service 8264ee
		return "high";
Packit Service 8264ee
	default:
Packit Service 8264ee
		return "invalid";
Packit Service 8264ee
	}
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void cmd_security(int argc, char *argv[])
Packit Service 8264ee
{
Packit Service 8264ee
	uint8_t level;
Packit Service 8264ee
	char *end;
Packit Service 8264ee
Packit Service 8264ee
	if (argc == 1)
Packit Service 8264ee
		goto done;
Packit Service 8264ee
Packit Service 8264ee
	level = strtol(argv[1], &end, 10);
Packit Service 8264ee
	if (end == argv[1] || !prov_set_sec_level(level)) {
Packit Service 8264ee
		bt_shell_printf("Invalid security level %s\n", argv[1]);
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
done:
Packit Service 8264ee
	bt_shell_printf("Provision Security Level set to %u (%s)\n",
Packit Service 8264ee
			prov_get_sec_level(),
Packit Service 8264ee
			security2str(prov_get_sec_level()));
Packit Service 8264ee
Packit Service 8264ee
	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void cmd_connect(int argc, char *argv[])
Packit Service 8264ee
{
Packit Service 8264ee
	char *filters[] = { MESH_PROXY_SVC_UUID, NULL };
Packit Service 8264ee
Packit Service 8264ee
	if (check_default_ctrl() == FALSE)
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
Packit Service 8264ee
	memset(&connection, 0, sizeof(connection));
Packit Service 8264ee
Packit Service 8264ee
	if (argc < 2 || !strlen(argv[1])) {
Packit Service 8264ee
		connection.net_idx = NET_IDX_PRIMARY;
Packit Service 8264ee
	} else {
Packit Service 8264ee
		char *end;
Packit Service 8264ee
		connection.net_idx = strtol(argv[1], &end, 16);
Packit Service 8264ee
		if (end == argv[1]) {
Packit Service 8264ee
			connection.net_idx = NET_IDX_INVALID;
Packit Service 8264ee
			bt_shell_printf("Invalid network index %s\n", argv[1]);
Packit Service 8264ee
			return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
		}
Packit Service 8264ee
Packit Service 8264ee
		if (argc > 2)
Packit Service 8264ee
			connection.unicast = strtol(argv[2], NULL, 16);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	if (discovering)
Packit Service 8264ee
		g_dbus_proxy_method_call(default_ctrl->proxy, "StopDiscovery",
Packit Service 8264ee
						NULL, NULL, NULL, NULL);
Packit Service 8264ee
Packit Service 8264ee
	set_scan_filter_uuids(filters);
Packit Service 8264ee
	discover_mesh = true;
Packit Service 8264ee
Packit Service 8264ee
	if (connection.unicast == UNASSIGNED_ADDRESS) {
Packit Service 8264ee
		connection.type = CONN_TYPE_NETWORK;
Packit Service 8264ee
		bt_shell_printf("Looking for mesh network with net index "
Packit Service 8264ee
				"%4.4x\n", connection.net_idx);
Packit Service 8264ee
	} else {
Packit Service 8264ee
		connection.type = CONN_TYPE_IDENTITY;
Packit Service 8264ee
		bt_shell_printf("Looking for node id %4.4x"
Packit Service 8264ee
				" on network with net index %4.4x\n",
Packit Service 8264ee
				connection.unicast, connection.net_idx);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	if (g_dbus_proxy_method_call(default_ctrl->proxy,
Packit Service 8264ee
			"StartDiscovery", NULL, start_discovery_reply,
Packit Service 8264ee
				GUINT_TO_POINTER(TRUE), NULL) == FALSE) {
Packit Service 8264ee
		bt_shell_printf("Failed to start mesh proxy discovery\n");
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	g_dbus_proxy_method_call(default_ctrl->proxy, "StartDiscovery",
Packit Service 8264ee
						NULL, NULL, NULL, NULL);
Packit Service 8264ee
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void prov_disconn_reply(DBusMessage *message, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	struct mesh_node *node = user_data;
Packit Service 8264ee
	char *filters[] = { MESH_PROXY_SVC_UUID, NULL };
Packit Service 8264ee
	DBusError error;
Packit Service 8264ee
Packit Service 8264ee
	dbus_error_init(&error);
Packit Service 8264ee
Packit Service 8264ee
	if (dbus_set_error_from_message(&error, message) == TRUE) {
Packit Service 8264ee
		bt_shell_printf("Failed to disconnect: %s\n", error.name);
Packit Service 8264ee
		dbus_error_free(&error);
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	set_connected_device(NULL);
Packit Service 8264ee
Packit Service 8264ee
	set_scan_filter_uuids(filters);
Packit Service 8264ee
	discover_mesh = true;
Packit Service 8264ee
Packit Service 8264ee
	connection.type = CONN_TYPE_IDENTITY;
Packit Service 8264ee
	connection.data_in = NULL;
Packit Service 8264ee
	connection.data_out = NULL;
Packit Service 8264ee
	connection.unicast = node_get_primary(node);
Packit Service 8264ee
Packit Service 8264ee
	if (g_dbus_proxy_method_call(default_ctrl->proxy,
Packit Service 8264ee
			"StartDiscovery", NULL, start_discovery_reply,
Packit Service 8264ee
				GUINT_TO_POINTER(TRUE), NULL) == FALSE) {
Packit Service 8264ee
		bt_shell_printf("Failed to start mesh proxy discovery\n");
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void disconn_reply(DBusMessage *message, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	GDBusProxy *proxy = user_data;
Packit Service 8264ee
	DBusError error;
Packit Service 8264ee
Packit Service 8264ee
	dbus_error_init(&error);
Packit Service 8264ee
Packit Service 8264ee
	if (dbus_set_error_from_message(&error, message) == TRUE) {
Packit Service 8264ee
		bt_shell_printf("Failed to disconnect: %s\n", error.name);
Packit Service 8264ee
		dbus_error_free(&error);
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	bt_shell_printf("Successfully disconnected\n");
Packit Service 8264ee
Packit Service 8264ee
	if (proxy != connection.device)
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
Packit Service 8264ee
Packit Service 8264ee
	set_connected_device(NULL);
Packit Service 8264ee
Packit Service 8264ee
	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void cmd_disconn(int argc, char *argv[])
Packit Service 8264ee
{
Packit Service 8264ee
	if (connection.type == CONN_TYPE_PROVISION) {
Packit Service 8264ee
		struct mesh_node *node = node_find_by_uuid(connection.dev_uuid);
Packit Service 8264ee
		if (node)
Packit Service 8264ee
			node_free(node);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	disconnect_device(disconn_reply, connection.device);
Packit Service 8264ee
Packit Service 8264ee
	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void mesh_prov_done(void *user_data, int status)
Packit Service 8264ee
{
Packit Service 8264ee
	struct mesh_node *node = user_data;
Packit Service 8264ee
Packit Service 8264ee
	if (status){
Packit Service 8264ee
		bt_shell_printf("Provisioning failed\n");
Packit Service 8264ee
		node_free(node);
Packit Service 8264ee
		disconnect_device(NULL, NULL);
Packit Service 8264ee
		return;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	bt_shell_printf("Provision success. Assigned Primary Unicast %4.4x\n",
Packit Service 8264ee
						node_get_primary(node));
Packit Service 8264ee
Packit Service 8264ee
	if (!prov_db_add_new_node(node))
Packit Service 8264ee
		bt_shell_printf("Failed to add node to provisioning DB\n");
Packit Service 8264ee
Packit Service 8264ee
	disconnect_device(prov_disconn_reply, node);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void cmd_start_prov(int argc, char *argv[])
Packit Service 8264ee
{
Packit Service 8264ee
	GDBusProxy *proxy;
Packit Service 8264ee
	struct mesh_device *dev;
Packit Service 8264ee
	struct mesh_node *node;
Packit Service 8264ee
	int len;
Packit Service 8264ee
Packit Service 8264ee
	len = strlen(argv[1]);
Packit Service 8264ee
	if ( len > 32 || len % 2) {
Packit Service 8264ee
		bt_shell_printf("Incorrect UUID size %d\n", len);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	disconnect_device(NULL, NULL);
Packit Service 8264ee
Packit Service 8264ee
	memset(connection.dev_uuid, 0, 16);
Packit Service 8264ee
	str2hex(argv[1], len, connection.dev_uuid, len/2);
Packit Service 8264ee
Packit Service 8264ee
	node = node_find_by_uuid(connection.dev_uuid);
Packit Service 8264ee
	if (!node) {
Packit Service 8264ee
		bt_shell_printf("Device with UUID %s not found.\n", argv[1]);
Packit Service 8264ee
		bt_shell_printf("Stale services? Remove device and "
Packit Service 8264ee
						"re-discover\n");
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	/* TODO: add command to remove a node from mesh, i.e., "unprovision" */
Packit Service 8264ee
	if (node_is_provisioned(node)) {
Packit Service 8264ee
		bt_shell_printf("Already provisioned with unicast %4.4x\n",
Packit Service 8264ee
				node_get_primary(node));
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	dev = find_device_by_uuid(default_ctrl->mesh_devices,
Packit Service 8264ee
				  connection.dev_uuid);
Packit Service 8264ee
	if (!dev || !dev->proxy) {
Packit Service 8264ee
		bt_shell_printf("Could not find device proxy\n");
Packit Service 8264ee
		memset(connection.dev_uuid, 0, 16);
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	proxy = dev->proxy;
Packit Service 8264ee
	if (discovering)
Packit Service 8264ee
		g_dbus_proxy_method_call(default_ctrl->proxy, "StopDiscovery",
Packit Service 8264ee
						NULL, NULL, NULL, NULL);
Packit Service 8264ee
	forget_mesh_devices();
Packit Service 8264ee
Packit Service 8264ee
	connection.type = CONN_TYPE_PROVISION;
Packit Service 8264ee
Packit Service 8264ee
	if (g_dbus_proxy_method_call(proxy, "Connect", NULL, connect_reply,
Packit Service 8264ee
							proxy, NULL) == FALSE) {
Packit Service 8264ee
		bt_shell_printf("Failed to connect ");
Packit Service 8264ee
		print_device(proxy, NULL);
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
	} else {
Packit Service 8264ee
		bt_shell_printf("Trying to connect ");
Packit Service 8264ee
		print_device(proxy, NULL);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void cmd_print_mesh(int argc, char *argv[])
Packit Service 8264ee
{
Packit Service 8264ee
	if (!prov_db_show(mesh_prov_db_filename)) {
Packit Service 8264ee
		bt_shell_printf("Unavailable\n");
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
 static void cmd_print_local(int argc, char *argv[])
Packit Service 8264ee
{
Packit Service 8264ee
	if (!prov_db_show(mesh_local_config_filename)) {
Packit Service 8264ee
		bt_shell_printf("Unavailable\n");
Packit Service 8264ee
		return bt_shell_noninteractive_quit(EXIT_FAILURE);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static const struct bt_shell_menu main_menu = {
Packit Service 8264ee
	.name = "main",
Packit Service 8264ee
	.entries = {
Packit Service 8264ee
	{ "list",         NULL,       cmd_list, "List available controllers"},
Packit Service 8264ee
	{ "show",         "[ctrl]",   cmd_show, "Controller information"},
Packit Service 8264ee
	{ "select",       "<ctrl>",   cmd_select, "Select default controller"},
Packit Service 8264ee
	{ "security",     "[0(low)/1(medium)/2(high)]", cmd_security,
Packit Service 8264ee
				"Display or change provision security level"},
Packit Service 8264ee
	{ "info",         "[dev]",    cmd_info, "Device information"},
Packit Service 8264ee
	{ "connect",      "[net_idx] [dst]", cmd_connect,
Packit Service 8264ee
				"Connect to mesh network or node on network"},
Packit Service 8264ee
	{ "discover-unprovisioned", "<on/off>", cmd_scan_unprovisioned,
Packit Service 8264ee
					"Look for devices to provision" },
Packit Service 8264ee
	{ "provision",    "<uuid>",   cmd_start_prov, "Initiate provisioning"},
Packit Service 8264ee
	{ "power",        "<on/off>", cmd_power, "Set controller power" },
Packit Service 8264ee
	{ "disconnect",   "[dev]",    cmd_disconn, "Disconnect device"},
Packit Service 8264ee
	{ "mesh-info",    NULL,       cmd_print_mesh,
Packit Service 8264ee
					"Mesh networkinfo (provisioner)" },
Packit Service 8264ee
	{ "local-info",    NULL,      cmd_print_local, "Local mesh node info" },
Packit Service 8264ee
	{ } },
Packit Service 8264ee
};
Packit Service 8264ee
Packit Service 8264ee
static const char *config_dir;
Packit Service 8264ee
Packit Service 8264ee
static const struct option options[] = {
Packit Service 8264ee
	{ "config",	required_argument, 0, 'c' },
Packit Service 8264ee
	{ 0, 0, 0, 0 }
Packit Service 8264ee
};
Packit Service 8264ee
Packit Service 8264ee
static const char **optargs[] = {
Packit Service 8264ee
	&config_dir
Packit Service 8264ee
};
Packit Service 8264ee
Packit Service 8264ee
static const char *help[] = {
Packit Service 8264ee
	"Read local mesh config JSON files from <directory>"
Packit Service 8264ee
};
Packit Service 8264ee
Packit Service 8264ee
static const struct bt_shell_opt opt = {
Packit Service 8264ee
	.options = options,
Packit Service 8264ee
	.optno = sizeof(options) / sizeof(struct option),
Packit Service 8264ee
	.optstr = "c:",
Packit Service 8264ee
	.optarg = optargs,
Packit Service 8264ee
	.help = help,
Packit Service 8264ee
};
Packit Service 8264ee
Packit Service 8264ee
static void client_ready(GDBusClient *client, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	bt_shell_attach(fileno(stdin));
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
int main(int argc, char *argv[])
Packit Service 8264ee
{
Packit Service 8264ee
	GDBusClient *client;
Packit Service 8264ee
	int status;
Packit Service 8264ee
	int len;
Packit Service 8264ee
	int extra;
Packit Service 8264ee
	char *mesh_dir = NULL;
Packit Service 8264ee
Packit Service 8264ee
	bt_shell_init(argc, argv, &opt;;
Packit Service 8264ee
	bt_shell_set_menu(&main_menu);
Packit Service 8264ee
	bt_shell_set_prompt(PROMPT_OFF);
Packit Service 8264ee
Packit Service 8264ee
	if (!config_dir) {
Packit Service 8264ee
		char *home;
Packit Service 8264ee
Packit Service 8264ee
		home = getenv("XDG_CONFIG_HOME");
Packit Service 8264ee
		if (home) {
Packit Service 8264ee
			mesh_dir = g_strdup_printf("%s/meshctl", home);
Packit Service 8264ee
		}
Packit Service 8264ee
Packit Service 8264ee
		if (!mesh_dir) {
Packit Service 8264ee
			home = getenv("HOME");
Packit Service 8264ee
			if (home)
Packit Service 8264ee
				mesh_dir = g_strdup_printf("%s/.config/meshctl",
Packit Service 8264ee
									home);
Packit Service 8264ee
		}
Packit Service 8264ee
Packit Service 8264ee
		if (!mesh_dir) {
Packit Service 8264ee
			g_printerr("Configuration directory not found\n");
Packit Service 8264ee
			goto fail;
Packit Service 8264ee
		}
Packit Service 8264ee
Packit Service 8264ee
	} else {
Packit Service 8264ee
		mesh_dir = g_strdup_printf("%s", config_dir);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
Packit Service 8264ee
	g_print("Reading prov_db.json and local_node.json from %s directory\n",
Packit Service 8264ee
								mesh_dir);
Packit Service 8264ee
Packit Service 8264ee
	len = strlen(mesh_dir);
Packit Service 8264ee
Packit Service 8264ee
	if (len && mesh_dir[len - 1] != '/')
Packit Service 8264ee
		extra = 1;
Packit Service 8264ee
	else
Packit Service 8264ee
		extra = 0;
Packit Service 8264ee
Packit Service 8264ee
	mesh_local_config_filename = g_malloc(len + strlen("local_node.json")
Packit Service 8264ee
									+ 2);
Packit Service 8264ee
	if (!mesh_local_config_filename)
Packit Service 8264ee
		goto fail;
Packit Service 8264ee
Packit Service 8264ee
	mesh_prov_db_filename = g_malloc(len + strlen("prov_db.json") + 2);
Packit Service 8264ee
	if (!mesh_prov_db_filename)
Packit Service 8264ee
		goto fail;
Packit Service 8264ee
Packit Service 8264ee
	sprintf(mesh_local_config_filename, "%s", mesh_dir);
Packit Service 8264ee
Packit Service 8264ee
	if (extra)
Packit Service 8264ee
		sprintf(mesh_local_config_filename + len , "%c", '/');
Packit Service 8264ee
Packit Service 8264ee
	sprintf(mesh_local_config_filename + len + extra, "%s",
Packit Service 8264ee
							"local_node.json");
Packit Service 8264ee
	len = len + extra + strlen("local_node.json");
Packit Service 8264ee
Packit Service 8264ee
	if (!prov_db_read_local_node(mesh_local_config_filename, true)) {
Packit Service 8264ee
		g_printerr("Failed to parse local node configuration file %s\n",
Packit Service 8264ee
			mesh_local_config_filename);
Packit Service 8264ee
		goto fail;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	sprintf(mesh_prov_db_filename, "%s", mesh_dir);
Packit Service 8264ee
	len = strlen(mesh_dir);
Packit Service 8264ee
Packit Service 8264ee
	g_free(mesh_dir);
Packit Service 8264ee
Packit Service 8264ee
	if (extra)
Packit Service 8264ee
		sprintf(mesh_prov_db_filename + len , "%c", '/');
Packit Service 8264ee
Packit Service 8264ee
	sprintf(mesh_prov_db_filename + len + extra, "%s", "prov_db.json");
Packit Service 8264ee
Packit Service 8264ee
	if (!prov_db_read(mesh_prov_db_filename)) {
Packit Service 8264ee
		g_printerr("Failed to parse provisioning database file %s\n",
Packit Service 8264ee
			mesh_prov_db_filename);
Packit Service 8264ee
		goto fail;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
Packit Service 8264ee
	client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
Packit Service 8264ee
Packit Service 8264ee
	g_dbus_client_set_connect_watch(client, connect_handler, NULL);
Packit Service 8264ee
	g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
Packit Service 8264ee
	g_dbus_client_set_signal_watch(client, message_handler, NULL);
Packit Service 8264ee
Packit Service 8264ee
	g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
Packit Service 8264ee
							property_changed, NULL);
Packit Service 8264ee
Packit Service 8264ee
	g_dbus_client_set_ready_watch(client, client_ready, NULL);
Packit Service 8264ee
Packit Service 8264ee
	if (!config_client_init())
Packit Service 8264ee
		g_printerr("Failed to initialize mesh configuration client\n");
Packit Service 8264ee
Packit Service 8264ee
	if (!config_server_init())
Packit Service 8264ee
		g_printerr("Failed to initialize mesh configuration server\n");
Packit Service 8264ee
Packit Service 8264ee
	if (!onoff_client_init(PRIMARY_ELEMENT_IDX))
Packit Service 8264ee
		g_printerr("Failed to initialize mesh generic On/Off client\n");
Packit Service 8264ee
Packit Service 8264ee
	status = bt_shell_run();
Packit Service 8264ee
Packit Service 8264ee
	g_dbus_client_unref(client);
Packit Service 8264ee
Packit Service 8264ee
	dbus_connection_unref(dbus_conn);
Packit Service 8264ee
Packit Service 8264ee
	node_cleanup();
Packit Service 8264ee
Packit Service 8264ee
	g_list_free(char_list);
Packit Service 8264ee
	g_list_free(service_list);
Packit Service 8264ee
	g_list_free_full(ctrl_list, proxy_leak);
Packit Service 8264ee
Packit Service 8264ee
	return status;
Packit Service 8264ee
Packit Service 8264ee
fail:
Packit Service 8264ee
	bt_shell_cleanup();
Packit Service 8264ee
	g_free(mesh_dir);
Packit Service 8264ee
Packit Service 8264ee
	return EXIT_FAILURE;
Packit Service 8264ee
}