// SPDX-License-Identifier: LGPL-2.1-or-later /* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2019 Intel Corporation. All rights reserved. * * */ #ifdef HAVE_CONFIG_H #include #endif #define _GNU_SOURCE #include #include "mesh/mesh-defs.h" #include "mesh/dbus.h" #include "mesh/error.h" #include "mesh/mesh.h" #include "mesh/mesh-io.h" #include "mesh/node.h" #include "mesh/net.h" #include "mesh/keyring.h" #include "mesh/agent.h" #include "mesh/provision.h" #include "mesh/manager.h" struct add_data{ struct l_dbus_message *msg; struct mesh_agent *agent; struct mesh_node *node; uint32_t disc_watch; uint16_t primary; uint16_t net_idx; uint8_t num_ele; uint8_t uuid[16]; }; static int8_t scan_rssi; static uint8_t scan_uuid[16]; static struct mesh_node *scan_node; static struct l_timeout *scan_timeout; static struct add_data *add_pending; static const uint8_t prvb[2] = {MESH_AD_TYPE_BEACON, 0x00}; static void scan_cancel(struct l_timeout *timeout, void *user_data) { struct mesh_node *node = user_data; struct mesh_io *io; struct mesh_net *net; l_debug(""); if (scan_timeout) l_timeout_remove(scan_timeout); net = node_get_net(node); io = mesh_net_get_io(net); mesh_io_deregister_recv_cb(io, prvb, sizeof(prvb)); scan_node = NULL; scan_timeout = NULL; } static void free_pending_add_call() { if (!add_pending) return; if (add_pending->disc_watch) l_dbus_remove_watch(dbus_get_bus(), add_pending->disc_watch); if (add_pending->msg) l_dbus_message_unref(add_pending->msg); l_free(add_pending); add_pending = NULL; } static void prov_disc_cb(struct l_dbus *bus, void *user_data) { if (!add_pending) return; initiator_cancel(add_pending); add_pending->disc_watch = 0; free_pending_add_call(); } static void send_add_failed(const char *owner, const char *path, uint8_t status) { struct l_dbus *dbus = dbus_get_bus(); struct l_dbus_message_builder *builder; struct l_dbus_message *msg; msg = l_dbus_message_new_method_call(dbus, owner, path, MESH_PROVISIONER_INTERFACE, "AddNodeFailed"); builder = l_dbus_message_builder_new(msg); dbus_append_byte_array(builder, add_pending->uuid, 16); l_dbus_message_builder_append_basic(builder, 's', mesh_prov_status_str(status)); l_dbus_message_builder_finalize(builder); l_dbus_message_builder_destroy(builder); l_dbus_send(dbus, msg); free_pending_add_call(); } static bool add_cmplt(void *user_data, uint8_t status, struct mesh_prov_node_info *info) { struct add_data *pending = user_data; struct mesh_node *node = pending->node; struct l_dbus *dbus = dbus_get_bus(); struct l_dbus_message_builder *builder; struct l_dbus_message *msg; bool result; if (pending != add_pending) return false; if (status != PROV_ERR_SUCCESS) { send_add_failed(node_get_owner(node), node_get_app_path(node), status); return false; } result = keyring_put_remote_dev_key(add_pending->node, info->unicast, info->num_ele, info->device_key); if (!result) { send_add_failed(node_get_owner(node), node_get_app_path(node), PROV_ERR_CANT_ASSIGN_ADDR); return false; } msg = l_dbus_message_new_method_call(dbus, node_get_owner(node), node_get_app_path(node), MESH_PROVISIONER_INTERFACE, "AddNodeComplete"); builder = l_dbus_message_builder_new(msg); dbus_append_byte_array(builder, add_pending->uuid, 16); l_dbus_message_builder_append_basic(builder, 'q', &info->unicast); l_dbus_message_builder_append_basic(builder, 'y', &info->num_ele); l_dbus_message_builder_finalize(builder); l_dbus_message_builder_destroy(builder); l_dbus_send(dbus, msg); free_pending_add_call(); return true; } static void mgr_prov_data (struct l_dbus_message *reply, void *user_data) { struct add_data *pending = user_data; uint16_t net_idx; uint16_t primary; if (pending != add_pending) return; if (l_dbus_message_is_error(reply)) return; if (!l_dbus_message_get_arguments(reply, "qq", &net_idx, &primary)) return; add_pending->primary = primary; add_pending->net_idx = net_idx; initiator_prov_data(net_idx, primary, add_pending); } static bool add_data_get(void *user_data, uint8_t num_ele) { struct add_data *pending = user_data; struct l_dbus_message *msg; struct l_dbus *dbus; const char *app_path; const char *sender; if (pending != add_pending) return false; dbus = dbus_get_bus(); app_path = node_get_app_path(add_pending->node); sender = node_get_owner(add_pending->node); msg = l_dbus_message_new_method_call(dbus, sender, app_path, MESH_PROVISIONER_INTERFACE, "RequestProvData"); l_dbus_message_set_arguments(msg, "y", num_ele); l_dbus_send_with_reply(dbus, msg, mgr_prov_data, add_pending, NULL); add_pending->num_ele = num_ele; return true; } static void add_start(void *user_data, int err) { struct l_dbus_message *reply; l_debug("Start callback"); if (err == MESH_ERROR_NONE) reply = l_dbus_message_new_method_return(add_pending->msg); else reply = dbus_error(add_pending->msg, MESH_ERROR_FAILED, "Failed to start provisioning initiator"); l_dbus_send(dbus_get_bus(), reply); l_dbus_message_unref(add_pending->msg); add_pending->msg = NULL; } static struct l_dbus_message *add_node_call(struct l_dbus *dbus, struct l_dbus_message *msg, void *user_data) { struct mesh_node *node = user_data; struct l_dbus_message_iter iter_uuid, options; struct l_dbus_message *reply; uint8_t *uuid; uint32_t n = 22; l_debug("AddNode request"); if (!l_dbus_message_get_arguments(msg, "aya{sv}", &iter_uuid, &options)) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL); if (!l_dbus_message_iter_get_fixed_array(&iter_uuid, &uuid, &n) || n != 16) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, "Bad device UUID"); /* Allow AddNode to cancel Scanning if from the same node */ if (scan_node) { if (scan_node != node) return dbus_error(msg, MESH_ERROR_BUSY, NULL); scan_cancel(NULL, node); } /* Invoke Prov Initiator */ add_pending = l_new(struct add_data, 1); memcpy(add_pending->uuid, uuid, 16); add_pending->node = node; add_pending->agent = node_get_agent(node); if (!node_is_provisioner(node) || (add_pending->agent == NULL)) { l_debug("Provisioner: %d", node_is_provisioner(node)); l_debug("Agent: %p", add_pending->agent); reply = dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, "Missing Interfaces"); goto fail; } add_pending->msg = l_dbus_message_ref(msg); initiator_start(PB_ADV, uuid, 99, 60, add_pending->agent, add_start, add_data_get, add_cmplt, node, add_pending); add_pending->disc_watch = l_dbus_add_disconnect_watch(dbus, node_get_owner(node), prov_disc_cb, NULL, NULL); return NULL; fail: l_free(add_pending); add_pending = NULL; return reply; } static struct l_dbus_message *import_node_call(struct l_dbus *dbus, struct l_dbus_message *msg, void *user_data) { struct mesh_node *node = user_data; struct l_dbus_message_iter iter_key; uint16_t primary; uint8_t num_ele; uint8_t *key; uint32_t n; const char *sender = l_dbus_message_get_sender(msg); if (strcmp(sender, node_get_owner(node))) return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL); if (!l_dbus_message_get_arguments(msg, "qyay", &primary, &num_ele, &iter_key)) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL); if (!l_dbus_message_iter_get_fixed_array(&iter_key, &key, &n) || n != 16) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, "Bad device key"); if (!keyring_put_remote_dev_key(node, primary, num_ele, key)) return dbus_error(msg, MESH_ERROR_FAILED, NULL); return l_dbus_message_new_method_return(msg); } static struct l_dbus_message *delete_node_call(struct l_dbus *dbus, struct l_dbus_message *msg, void *user_data) { struct mesh_node *node = user_data; struct mesh_net *net = node_get_net(node); uint16_t primary; uint8_t num_ele; const char *sender = l_dbus_message_get_sender(msg); if (strcmp(sender, node_get_owner(node))) return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL); if (!l_dbus_message_get_arguments(msg, "qy", &primary, &num_ele)) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL); if (mesh_net_is_local_address(net, primary, num_ele)) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, "Cannot remove local device key"); keyring_del_remote_dev_key(node, primary, num_ele); return l_dbus_message_new_method_return(msg); } static void prov_beacon_recv(void *user_data, struct mesh_io_recv_info *info, const uint8_t *data, uint16_t len) { struct mesh_node *node = user_data; struct l_dbus_message_builder *builder; struct l_dbus_message *msg; struct l_dbus *dbus; int16_t rssi; if (scan_node != node || len < sizeof(scan_uuid) + 2 || data[1] != 0x00) return; if (!memcmp(data + 2, scan_uuid, sizeof(scan_uuid))) { if (info->rssi <= scan_rssi) return; } memcpy(scan_uuid, data + 2, sizeof(scan_uuid)); scan_rssi = info->rssi; rssi = info->rssi; dbus = dbus_get_bus(); msg = l_dbus_message_new_method_call(dbus, node_get_owner(node), node_get_app_path(node), MESH_PROVISIONER_INTERFACE, "ScanResult"); builder = l_dbus_message_builder_new(msg); l_dbus_message_builder_append_basic(builder, 'n', &rssi); dbus_append_byte_array(builder, data + 2, len -2); l_dbus_message_builder_enter_array(builder, "{sv}"); /* TODO: populate with options when defined */ l_dbus_message_builder_leave_array(builder); l_dbus_message_builder_finalize(builder); l_dbus_message_builder_destroy(builder); l_dbus_send(dbus, msg); } static struct l_dbus_message *start_scan_call(struct l_dbus *dbus, struct l_dbus_message *msg, void *user_data) { struct mesh_node *node = user_data; uint16_t duration = 0; struct mesh_io *io; struct mesh_net *net; const char *key; struct l_dbus_message_iter options, var; const char *sender = l_dbus_message_get_sender(msg); if (strcmp(sender, node_get_owner(node))) return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL); if (!l_dbus_message_get_arguments(msg, "a{sv}", &options)) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL); while (l_dbus_message_iter_next_entry(&options, &key, &var)) { bool failed = true; if (!strcmp(key, "Seconds")) { if (l_dbus_message_iter_get_variant(&var, "q", &duration)) { failed = false; } } if (failed) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, "Invalid options"); } if (scan_node && scan_node != node) return dbus_error(msg, MESH_ERROR_BUSY, NULL); if (!node_is_provisioner(node)) return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL); if (scan_timeout) l_timeout_remove(scan_timeout); memset(scan_uuid, 0, sizeof(scan_uuid)); scan_rssi = -128; scan_timeout = NULL; net = node_get_net(node); io = mesh_net_get_io(net); scan_node = node; mesh_io_register_recv_cb(io, prvb, sizeof(prvb), prov_beacon_recv, node); if (duration) scan_timeout = l_timeout_create(duration, scan_cancel, node, NULL); return l_dbus_message_new_method_return(msg); } static struct l_dbus_message *cancel_scan_call(struct l_dbus *dbus, struct l_dbus_message *msg, void *user_data) { struct mesh_node *node = user_data; const char *sender = l_dbus_message_get_sender(msg); if (strcmp(sender, node_get_owner(node)) || !node_is_provisioner(node)) return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL); if (scan_node) { if (scan_node != node) return dbus_error(msg, MESH_ERROR_BUSY, NULL); scan_cancel(NULL, node); } return l_dbus_message_new_method_return(msg); } static struct l_dbus_message *store_new_subnet(struct mesh_node *node, struct l_dbus_message *msg, uint16_t net_idx, uint8_t *new_key) { struct keyring_net_key key; if (net_idx > MAX_KEY_IDX) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL); if (keyring_get_net_key(node, net_idx, &key)) { /* Allow redundant calls only if key values match */ if (!memcmp(key.old_key, new_key, 16)) return l_dbus_message_new_method_return(msg); return dbus_error(msg, MESH_ERROR_ALREADY_EXISTS, NULL); } memcpy(key.old_key, new_key, 16); memcpy(key.new_key, new_key, 16); key.net_idx = net_idx; key.phase = KEY_REFRESH_PHASE_NONE; if (!keyring_put_net_key(node, net_idx, &key)) return dbus_error(msg, MESH_ERROR_FAILED, NULL); return l_dbus_message_new_method_return(msg); } static struct l_dbus_message *create_subnet_call(struct l_dbus *dbus, struct l_dbus_message *msg, void *user_data) { struct mesh_node *node = user_data; uint8_t key[16]; uint16_t net_idx; const char *sender = l_dbus_message_get_sender(msg); if (strcmp(sender, node_get_owner(node))) return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL); if (!l_dbus_message_get_arguments(msg, "q", &net_idx) || net_idx == PRIMARY_NET_IDX) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL); /* Generate key and store */ l_getrandom(key, sizeof(key)); return store_new_subnet(node, msg, net_idx, key); } static struct l_dbus_message *update_subnet_call(struct l_dbus *dbus, struct l_dbus_message *msg, void *user_data) { struct mesh_node *node = user_data; struct keyring_net_key key; uint16_t net_idx; const char *sender = l_dbus_message_get_sender(msg); if (strcmp(sender, node_get_owner(node))) return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL); if (!l_dbus_message_get_arguments(msg, "q", &net_idx) || net_idx > MAX_KEY_IDX) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL); if (!keyring_get_net_key(node, net_idx, &key)) return dbus_error(msg, MESH_ERROR_DOES_NOT_EXIST, NULL); switch (key.phase) { case KEY_REFRESH_PHASE_NONE: /* Generate Key and update phase */ l_getrandom(key.new_key, sizeof(key.new_key)); key.phase = KEY_REFRESH_PHASE_ONE; if (!keyring_put_net_key(node, net_idx, &key)) return dbus_error(msg, MESH_ERROR_FAILED, NULL); /* Fall Through */ case KEY_REFRESH_PHASE_ONE: /* Allow redundant calls to start Key Refresh */ return l_dbus_message_new_method_return(msg); default: break; } /* All other phases mean KR already in progress over-the-air */ return dbus_error(msg, MESH_ERROR_IN_PROGRESS, "Key Refresh in progress"); } static struct l_dbus_message *delete_subnet_call(struct l_dbus *dbus, struct l_dbus_message *msg, void *user_data) { struct mesh_node *node = user_data; uint16_t net_idx; const char *sender = l_dbus_message_get_sender(msg); if (strcmp(sender, node_get_owner(node))) return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL); if (!l_dbus_message_get_arguments(msg, "q", &net_idx) || net_idx > MAX_KEY_IDX) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL); keyring_del_net_key(node, net_idx); return l_dbus_message_new_method_return(msg); } static struct l_dbus_message *import_subnet_call(struct l_dbus *dbus, struct l_dbus_message *msg, void *user_data) { struct mesh_node *node = user_data; struct l_dbus_message_iter iter_key; uint16_t net_idx; uint8_t *key; uint32_t n; const char *sender = l_dbus_message_get_sender(msg); if (strcmp(sender, node_get_owner(node))) return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL); if (!l_dbus_message_get_arguments(msg, "qay", &net_idx, &iter_key)) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL); if (!l_dbus_message_iter_get_fixed_array(&iter_key, &key, &n) || n != 16) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, "Bad network key"); return store_new_subnet(node, msg, net_idx, key); } static struct l_dbus_message *store_new_appkey(struct mesh_node *node, struct l_dbus_message *msg, uint16_t net_idx, uint16_t app_idx, uint8_t *new_key) { struct keyring_net_key net_key; struct keyring_app_key app_key; if (net_idx > MAX_KEY_IDX || app_idx > MAX_KEY_IDX) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL); if (!keyring_get_net_key(node, net_idx, &net_key)) return dbus_error(msg, MESH_ERROR_DOES_NOT_EXIST, "Bound net key not found"); if (keyring_get_app_key(node, app_idx, &app_key)) { /* Allow redundant calls with identical values */ if (!memcmp(app_key.old_key, new_key, 16) && app_key.net_idx == net_idx) return l_dbus_message_new_method_return(msg); return dbus_error(msg, MESH_ERROR_ALREADY_EXISTS, NULL); } memcpy(app_key.old_key, new_key, 16); memcpy(app_key.new_key, new_key, 16); app_key.net_idx = net_idx; app_key.app_idx = app_idx; if (!keyring_put_app_key(node, app_idx, net_idx, &app_key)) return dbus_error(msg, MESH_ERROR_FAILED, NULL); return l_dbus_message_new_method_return(msg); } static struct l_dbus_message *create_appkey_call(struct l_dbus *dbus, struct l_dbus_message *msg, void *user_data) { struct mesh_node *node = user_data; uint16_t net_idx, app_idx; uint8_t key[16]; const char *sender = l_dbus_message_get_sender(msg); if (strcmp(sender, node_get_owner(node))) return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL); if (!l_dbus_message_get_arguments(msg, "qq", &net_idx, &app_idx)) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL); l_getrandom(key, sizeof(key)); return store_new_appkey(node, msg, net_idx, app_idx, key); } static struct l_dbus_message *update_appkey_call(struct l_dbus *dbus, struct l_dbus_message *msg, void *user_data) { struct mesh_node *node = user_data; struct keyring_net_key net_key; struct keyring_app_key app_key; uint16_t app_idx; const char *sender = l_dbus_message_get_sender(msg); if (strcmp(sender, node_get_owner(node))) return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL); if (!l_dbus_message_get_arguments(msg, "q", &app_idx) || app_idx > MAX_KEY_IDX) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL); if (!keyring_get_app_key(node, app_idx, &app_key) || !keyring_get_net_key(node, app_key.net_idx, &net_key)) return dbus_error(msg, MESH_ERROR_DOES_NOT_EXIST, NULL); if (net_key.phase != KEY_REFRESH_PHASE_ONE) return dbus_error(msg, MESH_ERROR_FAILED, "Invalid Phase"); /* Generate Key if in acceptable phase */ l_getrandom(app_key.new_key, sizeof(app_key.new_key)); if (!keyring_put_app_key(node, app_idx, app_key.net_idx, &app_key)) return dbus_error(msg, MESH_ERROR_FAILED, NULL); return l_dbus_message_new_method_return(msg); } static struct l_dbus_message *delete_appkey_call(struct l_dbus *dbus, struct l_dbus_message *msg, void *user_data) { struct mesh_node *node = user_data; uint16_t app_idx; const char *sender = l_dbus_message_get_sender(msg); if (strcmp(sender, node_get_owner(node))) return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL); if (!l_dbus_message_get_arguments(msg, "q", &app_idx)) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL); keyring_del_app_key(node, app_idx); return l_dbus_message_new_method_return(msg); } static struct l_dbus_message *import_appkey_call(struct l_dbus *dbus, struct l_dbus_message *msg, void *user_data) { struct mesh_node *node = user_data; struct l_dbus_message_iter iter_key; uint16_t net_idx, app_idx; uint8_t *key; uint32_t n; const char *sender = l_dbus_message_get_sender(msg); if (strcmp(sender, node_get_owner(node))) return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL); if (!l_dbus_message_get_arguments(msg, "qqay", &net_idx, &app_idx, &iter_key)) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL); if (!l_dbus_message_iter_get_fixed_array(&iter_key, &key, &n) || n != 16) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, "Bad application key"); return store_new_appkey(node, msg, net_idx, app_idx, key); } static struct l_dbus_message *set_key_phase_call(struct l_dbus *dbus, struct l_dbus_message *msg, void *user_data) { struct mesh_node *node = user_data; struct keyring_net_key key; uint16_t net_idx; uint8_t phase; const char *sender = l_dbus_message_get_sender(msg); if (strcmp(sender, node_get_owner(node))) return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL); if (!l_dbus_message_get_arguments(msg, "qy", &net_idx, &phase) || phase == KEY_REFRESH_PHASE_ONE || phase > KEY_REFRESH_PHASE_THREE) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL); if (!keyring_get_net_key(node, net_idx, &key)) return dbus_error(msg, MESH_ERROR_DOES_NOT_EXIST, NULL); /* Canceling Key Refresh only valid from Phase One */ if (phase == KEY_REFRESH_PHASE_NONE && key.phase >= KEY_REFRESH_PHASE_TWO) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL); if (phase == KEY_REFRESH_PHASE_THREE) { /* If we are already in Phase None, then nothing to do */ if (key.phase == KEY_REFRESH_PHASE_NONE) return l_dbus_message_new_method_return(msg); memcpy(key.old_key, key.new_key, 16); key.phase = KEY_REFRESH_PHASE_THREE; if (!keyring_put_net_key(node, net_idx, &key)) return dbus_error(msg, MESH_ERROR_FAILED, NULL); if (!keyring_finalize_app_keys(node, net_idx)) return dbus_error(msg, MESH_ERROR_FAILED, NULL); key.phase = KEY_REFRESH_PHASE_NONE; } else key.phase = phase; if (!keyring_put_net_key(node, net_idx, &key)) return dbus_error(msg, MESH_ERROR_FAILED, NULL); return l_dbus_message_new_method_return(msg); } static struct l_dbus_message *export_keys_call(struct l_dbus *dbus, struct l_dbus_message *msg, void *user_data) { const char *sender = l_dbus_message_get_sender(msg); struct l_dbus_message_builder *builder; struct l_dbus_message *reply; struct mesh_node *node = user_data; l_debug("Export Keys"); if (strcmp(sender, node_get_owner(node))) return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL); reply = l_dbus_message_new_method_return(msg); builder = l_dbus_message_builder_new(reply); l_dbus_message_builder_enter_array(builder, "{sv}"); if (!keyring_build_export_keys_reply(node, builder)) { l_dbus_message_builder_destroy(builder); l_dbus_message_unref(reply); return dbus_error(msg, MESH_ERROR_FAILED, NULL); } l_dbus_message_builder_leave_array(builder); l_dbus_message_builder_finalize(builder); l_dbus_message_builder_destroy(builder); return reply; } static void setup_management_interface(struct l_dbus_interface *iface) { l_dbus_interface_method(iface, "AddNode", 0, add_node_call, "", "aya{sv}", "uuid", "options"); l_dbus_interface_method(iface, "ImportRemoteNode", 0, import_node_call, "", "qyay", "primary", "count", "dev_key"); l_dbus_interface_method(iface, "DeleteRemoteNode", 0, delete_node_call, "", "qy", "primary", "count"); l_dbus_interface_method(iface, "UnprovisionedScan", 0, start_scan_call, "", "a{sv}", "options"); l_dbus_interface_method(iface, "UnprovisionedScanCancel", 0, cancel_scan_call, "", ""); l_dbus_interface_method(iface, "CreateSubnet", 0, create_subnet_call, "", "q", "net_index"); l_dbus_interface_method(iface, "UpdateSubnet", 0, update_subnet_call, "", "q", "net_index"); l_dbus_interface_method(iface, "DeleteSubnet", 0, delete_subnet_call, "", "q", "net_index"); l_dbus_interface_method(iface, "ImportSubnet", 0, import_subnet_call, "", "qay", "net_index", "net_key"); l_dbus_interface_method(iface, "CreateAppKey", 0, create_appkey_call, "", "qq", "net_index", "app_index"); l_dbus_interface_method(iface, "UpdateAppKey", 0, update_appkey_call, "", "q", "app_index"); l_dbus_interface_method(iface, "DeleteAppKey", 0, delete_appkey_call, "", "q", "app_index"); l_dbus_interface_method(iface, "ImportAppKey", 0, import_appkey_call, "", "qqay", "net_index", "app_index", "app_key"); l_dbus_interface_method(iface, "SetKeyPhase", 0, set_key_phase_call, "", "qy", "net_index", "phase"); l_dbus_interface_method(iface, "ExportKeys", 0, export_keys_call, "a(qaya{sv})a(qay)", "", "net_keys", "dev_keys"); } bool manager_dbus_init(struct l_dbus *bus) { if (!l_dbus_register_interface(bus, MESH_MANAGEMENT_INTERFACE, setup_management_interface, NULL, false)) { l_info("Unable to register %s interface", MESH_MANAGEMENT_INTERFACE); return false; } return true; } void manager_scan_cancel(struct mesh_node *node) { if (scan_node != node) return; scan_cancel(NULL, node); }