3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2018-2019 Intel Corporation. All rights reserved.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
26 #include "mesh/mesh-io.h"
27 #include "mesh/node.h"
29 #include "mesh/provision.h"
30 #include "mesh/model.h"
31 #include "mesh/dbus.h"
32 #include "mesh/error.h"
33 #include "mesh/agent.h"
34 #include "mesh/mesh.h"
35 #include "mesh/mesh-defs.h"
38 * The default values for mesh configuration. Can be
39 * overwritten by values from mesh-main.conf
41 #define DEFAULT_PROV_TIMEOUT 60
42 #define DEFAULT_CRPL 100
43 #define DEFAULT_FRIEND_QUEUE_SZ 32
45 #define DEFAULT_ALGORITHMS 0x0001
54 struct l_queue *filters;
57 uint32_t prov_timeout;
66 uint8_t friend_queue_sz;
71 struct l_dbus_message *msg;
72 struct mesh_agent *agent;
75 struct mesh_node *node;
80 struct mesh_init_request {
85 static struct bt_mesh mesh = {
86 .algorithms = DEFAULT_ALGORITHMS,
87 .prov_timeout = DEFAULT_PROV_TIMEOUT,
88 .beacon_enabled = true,
89 .friend_support = true,
90 .relay_support = true,
92 .proxy_support = false,
94 .friend_queue_sz = DEFAULT_FRIEND_QUEUE_SZ
97 /* We allow only one outstanding Join request */
98 static struct join_data *join_pending;
100 /* Pending method requests */
101 static struct l_queue *pending_queue;
103 static const char *storage_dir;
105 static bool simple_match(const void *a, const void *b)
110 /* Used for any outbound traffic that doesn't have Friendship Constraints */
111 /* This includes Beacons, Provisioning and unrestricted Network Traffic */
112 bool mesh_send_pkt(uint8_t count, uint16_t interval,
113 void *data, uint16_t len)
115 struct mesh_io_send_info info = {
116 .type = MESH_IO_TIMING_TYPE_GENERAL,
118 .u.gen.interval = interval,
119 .u.gen.max_delay = 0,
120 .u.gen.min_delay = 0,
123 return mesh_io_send(mesh.io, &info, data, len);
126 bool mesh_send_cancel(const uint8_t *filter, uint8_t len)
128 return mesh_io_send_cancel(mesh.io, filter, len);
131 static void prov_rx(void *user_data, struct mesh_io_recv_info *info,
132 const uint8_t *data, uint16_t len)
134 if (user_data != &mesh)
138 mesh.prov_rx(mesh.prov_data, data, len);
141 bool mesh_reg_prov_rx(prov_rx_cb_t cb, void *user_data)
143 uint8_t prov_filter[] = {MESH_AD_TYPE_PROVISION};
145 if (mesh.prov_rx && mesh.prov_rx != cb)
149 mesh.prov_data = user_data;
151 return mesh_io_register_recv_cb(mesh.io, prov_filter,
152 sizeof(prov_filter), prov_rx, &mesh);
155 void mesh_unreg_prov_rx(prov_rx_cb_t cb)
157 uint8_t prov_filter[] = {MESH_AD_TYPE_PROVISION};
159 if (mesh.prov_rx != cb)
163 mesh.prov_data = NULL;
164 mesh_io_deregister_recv_cb(mesh.io, prov_filter, sizeof(prov_filter));
167 static void io_ready_callback(void *user_data, bool result)
169 struct mesh_init_request *req = user_data;
172 node_attach_io_all(mesh.io);
174 req->cb(req->user_data, result);
179 bool mesh_beacon_enabled(void)
181 return mesh.beacon_enabled;
184 bool mesh_relay_supported(void)
186 return mesh.relay_support;
189 bool mesh_friendship_supported(void)
191 return mesh.friend_support;
194 uint16_t mesh_get_crpl(void)
199 uint8_t mesh_get_friend_queue_size(void)
201 return mesh.friend_queue_sz;
204 static void parse_settings(const char *mesh_conf_fname)
206 struct l_settings *settings;
210 settings = l_settings_new();
211 if (!l_settings_load_from_file(settings, mesh_conf_fname))
214 str = l_settings_get_string(settings, "General", "Beacon");
216 if (!strcasecmp(str, "true"))
217 mesh.beacon_enabled = true;
221 str = l_settings_get_string(settings, "General", "Relay");
223 if (!strcasecmp(str, "false"))
224 mesh.relay_support = false;
228 str = l_settings_get_string(settings, "General", "Friendship");
230 if (!strcasecmp(str, "false"))
231 mesh.friend_support = false;
235 if (l_settings_get_uint(settings, "General", "CRPL", &value) &&
239 if (l_settings_get_uint(settings, "General", "FriendQueueSize", &value)
241 mesh.friend_queue_sz = value;
243 if (l_settings_get_uint(settings, "General", "ProvTimeout", &value))
244 mesh.prov_timeout = value;
247 bool mesh_init(const char *config_dir, const char *mesh_conf_fname,
248 enum mesh_io_type type, void *opts,
249 mesh_ready_func_t cb, void *user_data)
251 struct mesh_io_caps caps;
252 struct mesh_init_request *req;
260 /* TODO: read mesh.conf */
261 mesh.prov_timeout = DEFAULT_PROV_TIMEOUT;
262 mesh.algorithms = DEFAULT_ALGORITHMS;
264 storage_dir = config_dir ? config_dir : MESH_STORAGEDIR;
266 l_info("Loading node configuration from %s", storage_dir);
268 if (!mesh_conf_fname)
269 mesh_conf_fname = CONFIGDIR "/mesh-main.conf";
271 parse_settings(mesh_conf_fname);
273 if (!node_load_from_storage(storage_dir))
276 req = l_new(struct mesh_init_request, 1);
278 req->user_data = user_data;
280 mesh.io = mesh_io_new(type, opts, io_ready_callback, req);
286 l_debug("io %p", mesh.io);
287 mesh_io_get_caps(mesh.io, &caps);
288 mesh.max_filters = caps.max_num_filters;
293 static void pending_request_exit(void *data)
295 struct l_dbus_message *reply;
296 struct l_dbus_message *msg = data;
298 reply = dbus_error(msg, MESH_ERROR_FAILED, "Failed. Exiting");
299 l_dbus_send(dbus_get_bus(), reply);
302 static void free_pending_join_call(bool failed)
307 if (join_pending->disc_watch)
308 l_dbus_remove_watch(dbus_get_bus(),
309 join_pending->disc_watch);
311 mesh_agent_remove(join_pending->agent);
314 node_remove(join_pending->node);
316 l_free(join_pending->sender);
317 l_free(join_pending);
321 void mesh_cleanup(void)
323 struct l_dbus_message *reply;
325 mesh_io_destroy(mesh.io);
329 if (join_pending->msg) {
330 reply = dbus_error(join_pending->msg, MESH_ERROR_FAILED,
332 l_dbus_send(dbus_get_bus(), reply);
335 acceptor_cancel(&mesh);
336 free_pending_join_call(true);
339 l_queue_destroy(pending_queue, pending_request_exit);
341 mesh_model_cleanup();
343 l_dbus_object_remove_interface(dbus_get_bus(), BLUEZ_MESH_PATH,
344 MESH_NETWORK_INTERFACE);
345 l_dbus_unregister_interface(dbus_get_bus(), MESH_NETWORK_INTERFACE);
348 const char *mesh_status_str(uint8_t err)
351 case MESH_STATUS_SUCCESS: return "Success";
352 case MESH_STATUS_INVALID_ADDRESS: return "Invalid Address";
353 case MESH_STATUS_INVALID_MODEL: return "Invalid Model";
354 case MESH_STATUS_INVALID_APPKEY: return "Invalid AppKey";
355 case MESH_STATUS_INVALID_NETKEY: return "Invalid NetKey";
356 case MESH_STATUS_INSUFF_RESOURCES: return "Insufficient Resources";
357 case MESH_STATUS_IDX_ALREADY_STORED: return "Key Idx Already Stored";
358 case MESH_STATUS_INVALID_PUB_PARAM: return "Invalid Publish Parameters";
359 case MESH_STATUS_NOT_SUB_MOD: return "Not a Subscribe Model";
360 case MESH_STATUS_STORAGE_FAIL: return "Storage Failure";
361 case MESH_STATUS_FEATURE_NO_SUPPORT: return "Feature Not Supported";
362 case MESH_STATUS_CANNOT_UPDATE: return "Cannot Update";
363 case MESH_STATUS_CANNOT_REMOVE: return "Cannot Remove";
364 case MESH_STATUS_CANNOT_BIND: return "Cannot bind";
365 case MESH_STATUS_UNABLE_CHANGE_STATE: return "Unable to change state";
366 case MESH_STATUS_CANNOT_SET: return "Cannot set";
367 case MESH_STATUS_UNSPECIFIED_ERROR: return "Unspecified error";
368 case MESH_STATUS_INVALID_BINDING: return "Invalid Binding";
370 default: return "Unknown";
374 /* This is being called if the app exits unexpectedly */
375 static void prov_disc_cb(struct l_dbus *bus, void *user_data)
380 if (join_pending->msg) {
381 l_dbus_message_unref(join_pending->msg);
382 join_pending->msg = NULL;
385 acceptor_cancel(&mesh);
386 join_pending->disc_watch = 0;
388 free_pending_join_call(true);
391 const char *mesh_prov_status_str(uint8_t status)
394 case PROV_ERR_SUCCESS:
396 case PROV_ERR_INVALID_PDU:
397 case PROV_ERR_INVALID_FORMAT:
398 case PROV_ERR_UNEXPECTED_PDU:
400 case PROV_ERR_CONFIRM_FAILED:
401 return "confirmation-failed";
402 case PROV_ERR_INSUF_RESOURCE:
403 return "out-of-resources";
404 case PROV_ERR_DECRYPT_FAILED:
405 return "decryption-error";
406 case PROV_ERR_CANT_ASSIGN_ADDR:
407 return "cannot-assign-addresses";
408 case PROV_ERR_TIMEOUT:
410 case PROV_ERR_UNEXPECTED_ERR:
412 return "unexpected-error";
416 static void send_join_failed(const char *owner, const char *path,
419 struct l_dbus_message *msg;
420 struct l_dbus *dbus = dbus_get_bus();
422 msg = l_dbus_message_new_method_call(dbus, owner, path,
423 MESH_APPLICATION_INTERFACE,
426 l_dbus_message_set_arguments(msg, "s", mesh_prov_status_str(status));
427 l_dbus_send(dbus_get_bus(), msg);
429 free_pending_join_call(true);
432 static bool prov_complete_cb(void *user_data, uint8_t status,
433 struct mesh_prov_node_info *info)
435 struct l_dbus *dbus = dbus_get_bus();
436 struct l_dbus_message *msg;
439 const uint8_t *token;
441 l_debug("Provisioning complete %s", mesh_prov_status_str(status));
446 owner = join_pending->sender;
447 path = join_pending->app_path;
449 if (status == PROV_ERR_SUCCESS &&
450 !node_add_pending_local(join_pending->node, info))
451 status = PROV_ERR_UNEXPECTED_ERR;
453 if (status != PROV_ERR_SUCCESS) {
454 send_join_failed(owner, path, status);
458 node_attach_io(join_pending->node, mesh.io);
459 token = node_get_token(join_pending->node);
461 msg = l_dbus_message_new_method_call(dbus, owner, path,
462 MESH_APPLICATION_INTERFACE,
465 l_dbus_message_set_arguments(msg, "t", l_get_be64(token));
467 l_dbus_send(dbus, msg);
469 free_pending_join_call(false);
474 static void node_init_cb(struct mesh_node *node, struct mesh_agent *agent)
476 struct l_dbus_message *reply;
480 reply = dbus_error(join_pending->msg, MESH_ERROR_FAILED,
481 "Failed to create node from application");
485 join_pending->node = node;
486 num_ele = node_get_num_elements(node);
488 if (!acceptor_start(num_ele, join_pending->uuid, mesh.algorithms,
489 mesh.prov_timeout, agent, prov_complete_cb,
492 reply = dbus_error(join_pending->msg, MESH_ERROR_FAILED,
493 "Failed to start provisioning acceptor");
497 reply = l_dbus_message_new_method_return(join_pending->msg);
498 l_dbus_send(dbus_get_bus(), reply);
499 join_pending->msg = NULL;
501 /* Setup disconnect watch */
502 join_pending->disc_watch = l_dbus_add_disconnect_watch(dbus_get_bus(),
503 join_pending->sender,
504 prov_disc_cb, NULL, NULL);
509 l_dbus_send(dbus_get_bus(), reply);
510 free_pending_join_call(true);
513 static struct l_dbus_message *join_network_call(struct l_dbus *dbus,
514 struct l_dbus_message *msg,
517 const char *app_path, *sender;
518 struct l_dbus_message_iter iter_uuid;
521 l_debug("Join network request");
524 return dbus_error(msg, MESH_ERROR_BUSY,
525 "Provisioning in progress");
527 if (!l_dbus_message_get_arguments(msg, "oay", &app_path,
529 return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL);
531 join_pending = l_new(struct join_data, 1);
533 if (!l_dbus_message_iter_get_fixed_array(&iter_uuid,
534 &join_pending->uuid, &n)
536 l_free(join_pending);
538 return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
542 if (node_find_by_uuid(join_pending->uuid)) {
543 l_free(join_pending);
545 return dbus_error(msg, MESH_ERROR_ALREADY_EXISTS,
546 "Node already exists");
549 sender = l_dbus_message_get_sender(msg);
551 join_pending->sender = l_strdup(sender);
552 join_pending->msg = l_dbus_message_ref(msg);
553 join_pending->app_path = app_path;
555 /* Try to create a temporary node */
556 node_join(app_path, sender, join_pending->uuid, node_init_cb);
561 static struct l_dbus_message *cancel_join_call(struct l_dbus *dbus,
562 struct l_dbus_message *msg,
565 struct l_dbus_message *reply;
567 l_debug("Cancel Join");
570 reply = dbus_error(msg, MESH_ERROR_DOES_NOT_EXIST,
571 "No join in progress");
575 acceptor_cancel(&mesh);
577 /* Return error to the original Join call */
578 if (join_pending->msg) {
579 reply = dbus_error(join_pending->msg, MESH_ERROR_FAILED, NULL);
580 l_dbus_send(dbus_get_bus(), reply);
583 reply = l_dbus_message_new_method_return(msg);
584 l_dbus_message_set_arguments(reply, "");
586 free_pending_join_call(true);
591 static void attach_ready_cb(void *user_data, int status, struct mesh_node *node)
593 struct l_dbus_message *reply;
594 struct l_dbus_message *pending_msg;
596 pending_msg = l_queue_find(pending_queue, simple_match, user_data);
600 if (status != MESH_ERROR_NONE) {
601 const char *desc = (status == MESH_ERROR_NOT_FOUND) ?
602 "Node match not found" : "Attach failed";
603 reply = dbus_error(pending_msg, status, desc);
607 reply = l_dbus_message_new_method_return(pending_msg);
609 node_build_attach_reply(node, reply);
612 l_dbus_send(dbus_get_bus(), reply);
613 l_queue_remove(pending_queue, pending_msg);
616 static struct l_dbus_message *attach_call(struct l_dbus *dbus,
617 struct l_dbus_message *msg,
621 const char *app_path, *sender;
622 struct l_dbus_message *pending_msg;
627 if (!l_dbus_message_get_arguments(msg, "ot", &app_path, &token))
628 return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL);
630 sender = l_dbus_message_get_sender(msg);
632 pending_msg = l_dbus_message_ref(msg);
634 pending_queue = l_queue_new();
636 l_queue_push_tail(pending_queue, pending_msg);
638 status = node_attach(app_path, sender, token, attach_ready_cb,
640 if (status == MESH_ERROR_NONE)
643 l_queue_remove(pending_queue, pending_msg);
645 return dbus_error(msg, status, NULL);
648 static struct l_dbus_message *leave_call(struct l_dbus *dbus,
649 struct l_dbus_message *msg,
656 if (!l_dbus_message_get_arguments(msg, "t", &token))
657 return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL);
659 node_remove(node_find_by_token(token));
661 return l_dbus_message_new_method_return(msg);
664 static void create_node_ready_cb(void *user_data, int status,
665 struct mesh_node *node)
667 struct l_dbus_message *reply;
668 struct l_dbus_message *pending_msg;
669 const uint8_t *token;
671 pending_msg = l_queue_find(pending_queue, simple_match, user_data);
675 if (status != MESH_ERROR_NONE) {
676 reply = dbus_error(pending_msg, status, NULL);
680 node_attach_io(node, mesh.io);
682 reply = l_dbus_message_new_method_return(pending_msg);
683 token = node_get_token(node);
686 l_dbus_message_set_arguments(reply, "t", l_get_be64(token));
689 l_dbus_send(dbus_get_bus(), reply);
690 l_queue_remove(pending_queue, pending_msg);
693 static struct l_dbus_message *create_network_call(struct l_dbus *dbus,
694 struct l_dbus_message *msg,
697 const char *app_path, *sender;
698 struct l_dbus_message_iter iter_uuid;
699 struct l_dbus_message *pending_msg;
703 l_debug("Create network request");
705 if (!l_dbus_message_get_arguments(msg, "oay", &app_path,
707 return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL);
709 if (!l_dbus_message_iter_get_fixed_array(&iter_uuid, &uuid, &n)
711 return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
714 sender = l_dbus_message_get_sender(msg);
715 pending_msg = l_dbus_message_ref(msg);
717 pending_queue = l_queue_new();
719 l_queue_push_tail(pending_queue, pending_msg);
721 node_create(app_path, sender, uuid, create_node_ready_cb,
727 static struct l_dbus_message *import_call(struct l_dbus *dbus,
728 struct l_dbus_message *msg,
731 const char *app_path, *sender;
732 struct l_dbus_message *pending_msg = NULL;
733 struct l_dbus_message_iter iter_uuid;
734 struct l_dbus_message_iter iter_dev_key;
735 struct l_dbus_message_iter iter_net_key;
736 struct l_dbus_message_iter iter_flags;
738 struct l_dbus_message_iter var;
750 l_debug("Import local node request");
752 if (!l_dbus_message_get_arguments(msg, "oayayayqa{sv}uq",
753 &app_path, &iter_uuid,
754 &iter_dev_key, &iter_net_key,
755 &net_idx, &iter_flags,
758 return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL);
760 if (!l_dbus_message_iter_get_fixed_array(&iter_uuid, &uuid, &n) ||
762 return dbus_error(msg, MESH_ERROR_INVALID_ARGS, "Bad dev UUID");
764 if (node_find_by_uuid(uuid))
765 return dbus_error(msg, MESH_ERROR_ALREADY_EXISTS,
766 "Node already exists");
768 if (!l_dbus_message_iter_get_fixed_array(&iter_dev_key, &dev_key, &n) ||
770 return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
773 if (!l_dbus_message_iter_get_fixed_array(&iter_net_key, &net_key, &n) ||
775 return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
778 if (net_idx > MAX_KEY_IDX)
779 return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
782 while (l_dbus_message_iter_next_entry(&iter_flags, &key, &var)) {
783 if (!strcmp(key, "IVUpdate")) {
784 if (!l_dbus_message_iter_get_variant(&var, "b",
790 if (!strcmp(key, "KeyRefresh")) {
791 if (!l_dbus_message_iter_get_variant(&var, "b",
797 return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
801 if (!IS_UNICAST(unicast))
802 return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
805 sender = l_dbus_message_get_sender(msg);
806 pending_msg = l_dbus_message_ref(msg);
809 pending_queue = l_queue_new();
811 l_queue_push_tail(pending_queue, pending_msg);
813 if (!node_import(app_path, sender, uuid, dev_key, net_key, net_idx,
814 kr, ivu, iv_index, unicast,
815 create_node_ready_cb, pending_msg))
822 l_dbus_message_unref(msg);
823 l_queue_remove(pending_queue, pending_msg);
826 return dbus_error(msg, MESH_ERROR_INVALID_ARGS, "Node import failed");
829 static void setup_network_interface(struct l_dbus_interface *iface)
831 l_dbus_interface_method(iface, "Join", 0, join_network_call, "",
832 "oay", "app", "uuid");
834 l_dbus_interface_method(iface, "Cancel", 0, cancel_join_call, "", "");
836 l_dbus_interface_method(iface, "Attach", 0, attach_call,
837 "oa(ya(qa{sv}))", "ot", "node",
838 "configuration", "app", "token");
840 l_dbus_interface_method(iface, "Leave", 0, leave_call, "", "t",
843 l_dbus_interface_method(iface, "CreateNetwork", 0, create_network_call,
844 "t", "oay", "token", "app", "uuid");
846 l_dbus_interface_method(iface, "Import", 0,
848 "t", "oayayayqa{sv}uq", "token",
849 "app", "uuid", "dev_key", "net_key",
850 "net_index", "flags", "iv_index",
854 bool mesh_dbus_init(struct l_dbus *dbus)
856 if (!l_dbus_register_interface(dbus, MESH_NETWORK_INTERFACE,
857 setup_network_interface,
859 l_info("Unable to register %s interface",
860 MESH_NETWORK_INTERFACE);
864 if (!l_dbus_object_add_interface(dbus, BLUEZ_MESH_PATH,
865 MESH_NETWORK_INTERFACE, NULL)) {
866 l_info("Unable to register the mesh object on '%s'",
867 MESH_NETWORK_INTERFACE);
868 l_dbus_unregister_interface(dbus, MESH_NETWORK_INTERFACE);
872 l_info("Added Network Interface on %s", BLUEZ_MESH_PATH);
877 const char *mesh_get_storage_dir(void)