Message ID | 20230124202616.310544-3-brian.gix@gmail.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | Mesh v1.1 additions | expand |
Context | Check | Description |
---|---|---|
tedd_an/pre-ci_am | success | Success |
tedd_an/CheckPatch | warning | WARNING:PREFER_FALLTHROUGH: Prefer 'fallthrough;' over fallthrough comment #3307: FILE: mesh/remprv-server.c:238: + /* fall through */ WARNING:PREFER_FALLTHROUGH: Prefer 'fallthrough;' over fallthrough comment #3516: FILE: mesh/remprv-server.c:447: + /* fall through */ WARNING:PREFER_FALLTHROUGH: Prefer 'fallthrough;' over fallthrough comment #3520: FILE: mesh/remprv-server.c:451: + /* fall through */ WARNING:PREFER_FALLTHROUGH: Prefer 'fallthrough;' over fallthrough comment #3798: FILE: mesh/remprv-server.c:729: + /* fall through */ /github/workspace/src/src/13114772.patch total: 0 errors, 4 warnings, 3742 lines checked NOTE: For some of the reported defects, checkpatch may be able to mechanically convert to the typical style using --fix or --fix-inplace. /github/workspace/src/src/13114772.patch has style problems, please review. NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO NOTE: If any of the errors are false positives, please report them to the maintainer, see CHECKPATCH in MAINTAINERS. |
tedd_an/GitLint | success | Gitlint PASS |
tedd_an/IncrementalBuild | success | Incremental Build PASS |
Tiny fix and a question below On Tue, 2023-01-24 at 12:26 -0800, Brian Gix wrote: > From: Brian Gix <brian.gix@intel.com> > > Add Remote Provisioning Server > Add Remote Provisioning Client > Remove local scanning/provisioning > Add delete-all dev key function > Add NPPI procedures > --- > Makefile.mesh | 1 + > mesh/cfgmod-server.c | 2 +- > mesh/keyring.c | 29 +- > mesh/keyring.h | 1 + > mesh/manager.c | 535 +++++++++++++++++++----- > mesh/mesh-config-json.c | 380 +++++++++++------ > mesh/mesh-config.h | 6 +- > mesh/model.c | 27 +- > mesh/node.c | 255 +++++++++-- > mesh/node.h | 3 + > mesh/pb-adv.c | 4 +- > mesh/pb-adv.h | 2 +- > mesh/prov-acceptor.c | 87 ++-- > mesh/prov-initiator.c | 269 +++++++++++- > mesh/prov.h | 4 +- > mesh/provision.h | 23 +- > mesh/remprv-server.c | 907 > ++++++++++++++++++++++++++++++++++++++++ > mesh/remprv.h | 78 ++++ > 18 files changed, 2246 insertions(+), 367 deletions(-) > create mode 100644 mesh/remprv-server.c > create mode 100644 mesh/remprv.h > > diff --git a/Makefile.mesh b/Makefile.mesh > index 3047f362b..e18a169eb 100644 > --- a/Makefile.mesh > +++ b/Makefile.mesh > @@ -26,6 +26,7 @@ mesh_sources = mesh/mesh.h mesh/mesh.c \ > mesh/provision.h mesh/prov.h \ > mesh/model.h mesh/model.c \ > mesh/cfgmod.h mesh/cfgmod-server.c \ > + mesh/remprv.h mesh/remprv-server.c \ > mesh/mesh-config.h mesh/mesh-config- > json.c \ > mesh/util.h mesh/util.c \ > mesh/dbus.h mesh/dbus.c \ > diff --git a/mesh/cfgmod-server.c b/mesh/cfgmod-server.c > index be90ef8c5..3d7efc44b 100644 > --- a/mesh/cfgmod-server.c > +++ b/mesh/cfgmod-server.c > @@ -30,8 +30,8 @@ > (SET_ID(SIG_VENDOR, l_get_le16(pkt)))) > > /* Supported composition pages, sorted high to low */ > -/* Only page 0 is currently supported */ > static const uint8_t supported_pages[] = { > + 128, > 0 > }; > > diff --git a/mesh/keyring.c b/mesh/keyring.c > index 995a4b88f..894fb14fa 100644 > --- a/mesh/keyring.c > +++ b/mesh/keyring.c > @@ -30,9 +30,9 @@ > #include "mesh/node.h" > #include "mesh/keyring.h" > > -const char *dev_key_dir = "/dev_keys"; > -const char *app_key_dir = "/app_keys"; > -const char *net_key_dir = "/net_keys"; > +static const char *dev_key_dir = "/dev_keys"; > +static const char *app_key_dir = "/app_keys"; > +static const char *net_key_dir = "/net_keys"; > > static int open_key_file(struct mesh_node *node, const char > *key_dir, > uint16_t idx, > int flags) > @@ -295,6 +295,7 @@ bool keyring_get_remote_dev_key(struct mesh_node > *node, uint16_t unicast, > close(fd); > } > > + ingas: Did you accidentally add an extra empty line? > return result; > } > > @@ -371,6 +372,28 @@ bool keyring_del_remote_dev_key(struct mesh_node > *node, uint16_t unicast, > return true; > } > > +bool keyring_del_remote_dev_key_all(struct mesh_node *node, uint16_t > unicast) > +{ > + uint8_t dev_key[16]; > + uint8_t test_key[16]; > + uint8_t cnt = 1; > + > + if (!keyring_get_remote_dev_key(node, unicast, dev_key)) > + return false; > + > + while (keyring_get_remote_dev_key(node, unicast + cnt, > test_key)) { > + if (memcmp(dev_key, test_key, sizeof(dev_key))) > + break; > + > + cnt++; > + } > + > + if (cnt > 1) > + return keyring_del_remote_dev_key(node, unicast + 1, > cnt - 1); > + ingas: Just checking if this is your intent here: delete all the DevKey entries from the secondary elements and keep the one associated with the primary element? > + return true; > +} > + > static DIR *open_key_dir(const char *node_path, const char > *key_dir_name) > { > char dir_path[PATH_MAX]; > diff --git a/mesh/keyring.h b/mesh/keyring.h > index ecf62cbc1..efc499ac2 100644 > --- a/mesh/keyring.h > +++ b/mesh/keyring.h > @@ -39,5 +39,6 @@ bool keyring_put_remote_dev_key(struct mesh_node > *node, uint16_t unicast, > uint8_t count, uint8_t > dev_key[16]); > bool keyring_del_remote_dev_key(struct mesh_node *node, uint16_t > unicast, > uint8 > _t count); > +bool keyring_del_remote_dev_key_all(struct mesh_node *node, uint16_t > unicast); > bool keyring_build_export_keys_reply(struct mesh_node *node, > struct l_dbus_message_builder > *builder); > diff --git a/mesh/manager.c b/mesh/manager.c > index e66b1a45b..e16dbc513 100644 > --- a/mesh/manager.c > +++ b/mesh/manager.c > @@ -21,75 +21,137 @@ > #include "mesh/mesh.h" > #include "mesh/mesh-io.h" > #include "mesh/node.h" > +#include "mesh/model.h" > #include "mesh/net.h" > #include "mesh/keyring.h" > #include "mesh/agent.h" > #include "mesh/provision.h" > +#include "mesh/prov.h" > +#include "mesh/remprv.h" > #include "mesh/manager.h" > > -struct add_data{ > +struct prov_remote_data { > struct l_dbus_message *msg; > struct mesh_agent *agent; > struct mesh_node *node; > uint32_t disc_watch; > + uint16_t original; > uint16_t primary; > uint16_t net_idx; > + uint8_t transport; > 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; > +struct scan_req { > + struct mesh_node *node; > + struct l_timeout *timeout; > + uint16_t server; > + uint16_t net_idx; > + uint8_t uuid[16]; > + int8_t rssi; > + bool ext; > +}; > + > +static struct l_queue *scans; > +static struct prov_remote_data *prov_pending; > static const uint8_t prvb[2] = {MESH_AD_TYPE_BEACON, 0x00}; > > +static bool by_scan(const void *a, const void *b) > +{ > + return a == b; > +} > + > +static bool by_node(const void *a, const void *b) > +{ > + const struct scan_req *req = a; > + const struct mesh_node *node = b; > + > + return req->node == node; > +} > + > +static bool by_node_svr(const void *a, const void *b) > +{ > + const struct scan_req *req = a; > + const struct scan_req *test = b; > + > + return req->node == test->node && req->server == test- > >server; > +} > + > static void scan_cancel(struct l_timeout *timeout, void *user_data) > { > - struct mesh_node *node = user_data; > + struct scan_req *req = user_data; > struct mesh_io *io; > struct mesh_net *net; > + uint8_t msg[4]; > + int n; > > l_debug(""); > > - if (scan_timeout) > - l_timeout_remove(scan_timeout); > + req = l_queue_remove_if(scans, by_scan, req); > + > + if (!req) > + return; > + > + l_timeout_remove(req->timeout); > + > + if (req->server) { > + n = mesh_model_opcode_set(OP_REM_PROV_SCAN_STOP, > msg); > + mesh_model_send(req->node, 0, req->server, > APP_IDX_DEV_REMOTE, > + req->net_idx, > DEFAULT_TTL, > + true, n, msg); > + } else { > + net = node_get_net(req->node); > + io = mesh_net_get_io(net); > + mesh_io_deregister_recv_cb(io, prvb, sizeof(prvb)); > + } > > - 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; > + initiator_scan_unreg(req->node); > + l_free(req); > } > > -static void free_pending_add_call() > +static void free_pending_add_call(void) > { > - if (!add_pending) > + if (!prov_pending) > return; > > - if (add_pending->disc_watch) > + if (prov_pending->disc_watch) > l_dbus_remove_watch(dbus_get_bus(), > - add_pending- > >disc_watch); > + prov_pending- > >disc_watch); > > - if (add_pending->msg) > - l_dbus_message_unref(add_pending->msg); > + if (prov_pending->msg) > + l_dbus_message_unref(prov_pending->msg); > > - l_free(add_pending); > - add_pending = NULL; > + l_free(prov_pending); > + prov_pending = NULL; > } > > static void prov_disc_cb(struct l_dbus *bus, void *user_data) > { > - if (!add_pending) > + if (!prov_pending) > return; > > - initiator_cancel(add_pending); > - add_pending->disc_watch = 0; > + initiator_cancel(prov_pending); > + prov_pending->disc_watch = 0; > > free_pending_add_call(); > } > > +static void append_dict_entry_basic(struct l_dbus_message_builder > *builder, > + const char *key, const char > *signature, > + const void *data) > +{ > + if (!builder) > + return; > + > + l_dbus_message_builder_enter_dict(builder, "sv"); > + l_dbus_message_builder_append_basic(builder, 's', key); > + l_dbus_message_builder_enter_variant(builder, signature); > + l_dbus_message_builder_append_basic(builder, signature[0], > data); > + l_dbus_message_builder_leave_variant(builder); > + l_dbus_message_builder_leave_dict(builder); > +} > + > static void send_add_failed(const char *owner, const char *path, > uint8_t > status) > { > @@ -102,7 +164,7 @@ static void send_add_failed(const char *owner, > const char *path, > "AddNodeFailed"); > > builder = l_dbus_message_builder_new(msg); > - dbus_append_byte_array(builder, add_pending->uuid, 16); > + dbus_append_byte_array(builder, prov_pending->uuid, 16); > l_dbus_message_builder_append_basic(builder, 's', > mesh_prov_status_str( > status)); > l_dbus_message_builder_finalize(builder); > @@ -115,14 +177,14 @@ static void send_add_failed(const char *owner, > const char *path, > static bool add_cmplt(void *user_data, uint8_t status, > struct mesh_prov_node_info > *info) > { > - struct add_data *pending = user_data; > + struct prov_remote_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) > + if (pending != prov_pending) > return false; > > if (status != PROV_ERR_SUCCESS) { > @@ -131,7 +193,12 @@ static bool add_cmplt(void *user_data, uint8_t > status, > return false; > } > > - result = keyring_put_remote_dev_key(add_pending->node, info- > >unicast, > + /* If Unicast address changing, delete old dev key */ > + if (pending->transport == PB_NPPI_01) > + keyring_del_remote_dev_key_all(pending->node, > + pending- > >original); > + > + result = keyring_put_remote_dev_key(pending->node, info- > >unicast, > info->num_ele, info- > >device_key); > > if (!result) { > @@ -140,13 +207,29 @@ static bool add_cmplt(void *user_data, uint8_t > status, > return false; > } > > - msg = l_dbus_message_new_method_call(dbus, > node_get_owner(node), > + if (pending->transport > PB_NPPI_02) > + msg = l_dbus_message_new_method_call(dbus, > node_get_owner(node), > node_get_app_path(nod > e), > MESH_PROVISIONER_INTE > RFACE, > "AddNodeComplete"); > + else > + msg = l_dbus_message_new_method_call(dbus, > node_get_owner(node), > + node_get_app_path(nod > e), > + MESH_PROVISIONER_INTE > RFACE, > + "ReprovComplete"); > > builder = l_dbus_message_builder_new(msg); > - dbus_append_byte_array(builder, add_pending->uuid, 16); > + > + if (pending->transport > PB_NPPI_02) > + dbus_append_byte_array(builder, pending->uuid, 16); > + else { > + uint8_t nppi = (uint8_t) pending->transport; > + > + l_dbus_message_builder_append_basic(builder, 'q', > + &pending- > >original); > + l_dbus_message_builder_append_basic(builder, 'y', > &nppi); > + } > + > 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); > @@ -161,47 +244,66 @@ static bool add_cmplt(void *user_data, uint8_t > status, > > static void mgr_prov_data (struct l_dbus_message *reply, void > *user_data) > { > - struct add_data *pending = user_data; > + struct prov_remote_data *pending = user_data; > uint16_t net_idx; > uint16_t primary; > > - if (pending != add_pending) > + if (pending != prov_pending) > return; > > if (l_dbus_message_is_error(reply)) > return; > > - if (!l_dbus_message_get_arguments(reply, "qq", &net_idx, > &primary)) > + if (pending->transport == PB_NPPI_01) { > + /* If performing NPPI, we only get new primary > unicast here */ > + if (!l_dbus_message_get_arguments(reply, "q", > &primary)) > + return; > + > + net_idx = pending->net_idx; > + > + } else if (!l_dbus_message_get_arguments(reply, "qq", > &net_idx, > + &prim > ary)) > return; > > - add_pending->primary = primary; > - add_pending->net_idx = net_idx; > - initiator_prov_data(net_idx, primary, add_pending); > + pending->primary = primary; > + pending->net_idx = net_idx; > + initiator_prov_data(net_idx, primary, pending); > } > > static bool add_data_get(void *user_data, uint8_t num_ele) > { > - struct add_data *pending = user_data; > + struct prov_remote_data *pending = user_data; > struct l_dbus_message *msg; > struct l_dbus *dbus; > const char *app_path; > const char *sender; > > - if (pending != add_pending) > + if (pending != prov_pending) > return false; > > dbus = dbus_get_bus(); > - app_path = node_get_app_path(add_pending->node); > - sender = node_get_owner(add_pending->node); > + app_path = node_get_app_path(pending->node); > + sender = node_get_owner(pending->node); > > - msg = l_dbus_message_new_method_call(dbus, sender, app_path, > + if (pending->transport > PB_NPPI_02) { > + msg = l_dbus_message_new_method_call(dbus, sender, > app_path, > MESH_PROVISIONER_INTE > RFACE, > "RequestProvData"); > > - l_dbus_message_set_arguments(msg, "y", num_ele); > - l_dbus_send_with_reply(dbus, msg, mgr_prov_data, add_pending, > NULL); > + l_dbus_message_set_arguments(msg, "y", num_ele); > + } else if (pending->transport == PB_NPPI_01) { > + msg = l_dbus_message_new_method_call(dbus, sender, > app_path, > + MESH_PROVISIONER_INTE > RFACE, > + "RequestReprovData"); > + > + l_dbus_message_set_arguments(msg, "qy", pending- > >original, > + num_e > le); > + } else > + return false; > > - add_pending->num_ele = num_ele; > + l_dbus_send_with_reply(dbus, msg, mgr_prov_data, pending, > NULL); > + > + pending->num_ele = num_ele; > > return true; > } > @@ -213,15 +315,95 @@ static void add_start(void *user_data, int err) > l_debug("Start callback"); > > if (err == MESH_ERROR_NONE) > - reply = l_dbus_message_new_method_return(add_pending- > >msg); > + reply = > l_dbus_message_new_method_return(prov_pending->msg); > else > - reply = dbus_error(add_pending->msg, > MESH_ERROR_FAILED, > + reply = dbus_error(prov_pending->msg, > MESH_ERROR_FAILED, > "Failed to start provisioning > initiator"); > > l_dbus_send(dbus_get_bus(), reply); > - l_dbus_message_unref(add_pending->msg); > + l_dbus_message_unref(prov_pending->msg); > + > + prov_pending->msg = NULL; > +} > + > +static struct l_dbus_message *reprovision_call(struct l_dbus *dbus, > + struct l_dbus_message > *msg, > + void *user_data) > +{ > + struct mesh_node *node = user_data; > + struct l_dbus_message_iter options, var; > + struct l_dbus_message *reply; > + struct mesh_net *net = node_get_net(node); > + const char *key; > + uint16_t subidx; > + uint16_t server = 0; > + uint8_t nppi = 0; > + > + l_debug("Reprovision request"); > + > + if (!l_dbus_message_get_arguments(msg, "qa{sv}", &server, > &options)) > + return dbus_error(msg, MESH_ERROR_INVALID_ARGS, > NULL); > + > + if (!IS_UNICAST(server)) > + return dbus_error(msg, MESH_ERROR_INVALID_ARGS, "Bad > Unicast"); > + > + /* Default to nodes primary subnet index */ > + subidx = mesh_net_get_primary_idx(net); > + > + /* Get Provisioning Options */ > + while (l_dbus_message_iter_next_entry(&options, &key, &var)) > { > + bool failed = true; > + > + if (!strcmp(key, "NPPI")) { > + if (l_dbus_message_iter_get_variant(&var, > "y", &nppi)) { > + if (nppi <= 2) > + failed = false; > + } > + } else if (!strcmp(key, "Subnet")) { > + if (l_dbus_message_iter_get_variant(&var, > "q", > + &subi > dx)) { > + if (subidx <= MAX_KEY_IDX) > + failed = false; > + } > + } > + > + if (failed) > + return dbus_error(msg, > MESH_ERROR_INVALID_ARGS, > + "Invalid > options"); > + } > + > + /* AddNode cancels all outstanding Scanning from node */ > + manager_scan_cancel(node); > > - add_pending->msg = NULL; > + /* Invoke Prov Initiator */ > + prov_pending = l_new(struct prov_remote_data, 1); > + > + prov_pending->transport = nppi; > + prov_pending->node = node; > + prov_pending->original = server; > + prov_pending->agent = node_get_agent(node); > + > + if (!node_is_provisioner(node) || (prov_pending->agent == > NULL)) { > + reply = dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, > + "Missing > Interfaces"); > + goto fail; > + } > + > + prov_pending->msg = l_dbus_message_ref(msg); > + initiator_start(prov_pending->transport, server, subidx, > NULL, 99, 60, > + prov_pending->agent, > add_start, > + add_data_get, add_cmplt, > node, > + prov_pending); > + > + prov_pending->disc_watch = l_dbus_add_disconnect_watch(dbus, > + node_get_owner(node), > + prov_disc_cb, NULL, > NULL); > + > + return NULL; > +fail: > + l_free(prov_pending); > + prov_pending = NULL; > + return reply; > } > > static struct l_dbus_message *add_node_call(struct l_dbus *dbus, > @@ -229,55 +411,101 @@ static struct l_dbus_message > *add_node_call(struct l_dbus *dbus, > void *user_data) > { > struct mesh_node *node = user_data; > - struct l_dbus_message_iter iter_uuid, options; > + struct l_dbus_message_iter iter_uuid, options, var; > struct l_dbus_message *reply; > + struct mesh_net *net = node_get_net(node); > + const char *key; > uint8_t *uuid; > - uint32_t n = 22; > + uint32_t n = 0; > + uint16_t subidx; > + uint16_t sec = 60; > + uint16_t server = 0; > > 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) > + 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); > + /* Default to nodes primary subnet index */ > + subidx = mesh_net_get_primary_idx(net); > > - scan_cancel(NULL, node); > + /* Get Provisioning Options */ > + 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", &sec)) > + failed = false; > + } else if (!strcmp(key, "Server")) { > + if (l_dbus_message_iter_get_variant(&var, > "q", > + &serv > er)) { > + if (server < 0x8000) > + failed = false; > + } > + } else if (!strcmp(key, "Subnet")) { > + if (l_dbus_message_iter_get_variant(&var, > "q", > + &subi > dx)) { > + if (subidx <= MAX_KEY_IDX) > + failed = false; > + } > + } > + > + if (failed) > + return dbus_error(msg, > MESH_ERROR_INVALID_ARGS, > + "Invalid > options"); > } > > + /* Device Key update/Composition update requires remote > server */ > + if (!n && !server) > + return dbus_error(msg, MESH_ERROR_INVALID_ARGS, > + "Invalid > options"); > + > + /* If no server specified, use local */ > + if (!server) > + server = node_get_primary(node); > + > + /* AddNode cancels all outstanding Scanning from node */ > + manager_scan_cancel(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); > + prov_pending = l_new(struct prov_remote_data, 1); > + > + if (n) > + memcpy(prov_pending->uuid, uuid, 16); > + else > + uuid = NULL; > > - if (!node_is_provisioner(node) || (add_pending->agent == > NULL)) { > + prov_pending->transport = PB_ADV; > + prov_pending->node = node; > + prov_pending->agent = node_get_agent(node); > + > + if (!node_is_provisioner(node) || (prov_pending->agent == > NULL)) { > l_debug("Provisioner: %d", > node_is_provisioner(node)); > - l_debug("Agent: %p", add_pending->agent); > + l_debug("Agent: %p", prov_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); > + prov_pending->msg = l_dbus_message_ref(msg); > + initiator_start(PB_ADV, server, subidx, uuid, 99, sec, > + prov_pending->agent, > add_start, > + add_data_get, add_cmplt, > node, > + prov_pending); > > - add_pending->disc_watch = l_dbus_add_disconnect_watch(dbus, > + prov_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; > + l_free(prov_pending); > + prov_pending = NULL; > return reply; > } > > @@ -337,38 +565,50 @@ static struct l_dbus_message > *delete_node_call(struct l_dbus *dbus, > return l_dbus_message_new_method_return(msg); > } > > -static void prov_beacon_recv(void *user_data, struct > mesh_io_recv_info *info, > +static void manager_scan_result(void *user_data, uint16_t server, > bool ext, > const uint8_t *data, uint16_t > len) > { > - struct mesh_node *node = user_data; > + struct scan_req node_svr = { > + .node = user_data, > + .server = server, > + }; > + struct scan_req *req; > 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) > + l_debug("scan_result %4.4x %p", server, user_data); > + req = l_queue_find(scans, by_node_svr, &node_svr); > + if (!req) { > + l_debug("No scan_result req"); > return; > + } > > - if (!memcmp(data + 2, scan_uuid, sizeof(scan_uuid))) { > - if (info->rssi <= scan_rssi) > + /* Filter repeats with weaker signal */ > + if (!memcmp(data + 1, req->uuid, sizeof(req->uuid))) { > + if (!ext && ((int8_t) data[0] <= req->rssi)) { > + l_debug("Already Seen"); > return; > + } > } > > - memcpy(scan_uuid, data + 2, sizeof(scan_uuid)); > - scan_rssi = info->rssi; > - rssi = info->rssi; > + if (!ext && ((int8_t) data[0] > req->rssi)) > + req->rssi = (int8_t) data[0]; > > + rssi = req->rssi; > + memcpy(req->uuid, data + 1, sizeof(req->uuid)); > dbus = dbus_get_bus(); > - msg = l_dbus_message_new_method_call(dbus, > node_get_owner(node), > - > node_get_app_path(node) > , > + msg = l_dbus_message_new_method_call(dbus, > node_get_owner(req->node), > + node_get_app_path(req > ->node), > MESH_PROVISIONER_INTE > RFACE, > "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); > + dbus_append_byte_array(builder, data + 1, len - 1); > l_dbus_message_builder_enter_array(builder, "{sv}"); > - /* TODO: populate with options when defined */ > + append_dict_entry_basic(builder, "Server", "q", &server); > l_dbus_message_builder_leave_array(builder); > l_dbus_message_builder_finalize(builder); > l_dbus_message_builder_destroy(builder); > @@ -380,27 +620,71 @@ 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 scan_req new_req = { > + .node = user_data, > + .server = 0, > + .timeout = NULL, > + .ext = false, > + }; > + struct scan_req *req; > struct mesh_net *net; > + uint8_t *uuid, *ext = NULL; > + uint8_t scan_req[21]; > + int n; > + uint32_t ext_len; > + uint32_t flen = 0; > + uint16_t sec = 60; > 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))) > + if (strcmp(sender, node_get_owner(new_req.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); > > + if (!node_is_provisioner(new_req.node)) > + return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, > NULL); > + > + net = node_get_net(new_req.node); > + new_req.net_idx = mesh_net_get_primary_idx(net); > + memset(new_req.uuid, 0, sizeof(new_req.uuid)); > + > 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)) { > + if (l_dbus_message_iter_get_variant(&var, > "q", &sec)) > failed = false; > + } else if (!strcmp(key, "Subnet")) { > + if (l_dbus_message_iter_get_variant(&var, > "q", > + &new_req.net_ > idx)) { > + if (new_req.net_idx <= MAX_KEY_IDX) > + failed = false; > + } > + } else if (!strcmp(key, "Server")) { > + if (l_dbus_message_iter_get_variant(&var, > "q", > + &new_req.serv > er)) { > + if (new_req.server < 0x8000) > + failed = false; > + } > + } else if (!strcmp(key, "Filter")) { > + if (l_dbus_message_iter_get_variant(&var, > "ay", &var)) { > + if > (l_dbus_message_iter_get_fixed_array(&var, > + &uuid > , &flen)) { > + if (flen == 16) { > + memcpy(new_req.uuid, > uuid, > + > flen); > + failed = false; > + } > + } > + } > + } else if (!strcmp(key, "Extended")) { > + if (l_dbus_message_iter_get_variant(&var, > "ay", &var)) { > + if > (l_dbus_message_iter_get_fixed_array(&var, > + &ext, > &ext_len)) > + failed = false; > } > } > > @@ -409,27 +693,51 @@ static struct l_dbus_message > *start_scan_call(struct l_dbus *dbus, > "Invalid > options"); > } > > - if (scan_node && scan_node != node) > - return dbus_error(msg, MESH_ERROR_BUSY, NULL); > + if (!scans) > + scans = l_queue_new(); > > - if (!node_is_provisioner(node)) > - return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, > NULL); > + if (new_req.server) { > + if (!sec || sec > 60) > + return dbus_error(msg, > MESH_ERROR_INVALID_ARGS, > + "Invalid > options"); > + } else { > + new_req.server = node_get_primary(new_req.node); > + if (!sec || sec > 60) > + sec = 60; > + } > + > + req = l_queue_remove_if(scans, by_node_svr, &new_req); > + > + if (!req) > + req = l_malloc(sizeof(new_req)); > + > + if (req->timeout) { > + l_timeout_remove(req->timeout); > + req->timeout = NULL; > + } > + > + *req = new_req; > + req->rssi = -128; > + > + if (sec) > + req->timeout = l_timeout_create(sec, scan_cancel, > req, 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); > + n = mesh_model_opcode_set(OP_REM_PROV_SCAN_START, scan_req); > + scan_req[n++] = 5; > + scan_req[n++] = sec; > + if (flen) { > + memcpy(scan_req + n, req->uuid, flen); > + n += flen; > + } > + > + mesh_model_send(req->node, 0, req->server, > APP_IDX_DEV_REMOTE, > + req->net_idx, > DEFAULT_TTL, > + true, n, scan_req); > > - if (duration) > - scan_timeout = l_timeout_create(duration, > scan_cancel, > - node, > NULL); > + initiator_scan_reg(manager_scan_result, req->node); > + > + l_queue_push_tail(scans, req); > > return l_dbus_message_new_method_return(msg); > } > @@ -444,12 +752,7 @@ static struct l_dbus_message > *cancel_scan_call(struct l_dbus *dbus, > 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); > - } > + manager_scan_cancel(node); > > return l_dbus_message_new_method_return(msg); > } > @@ -814,6 +1117,8 @@ static void setup_management_interface(struct > l_dbus_interface *iface) > "aya{sv}", "uuid", > "options"); > l_dbus_interface_method(iface, "ImportRemoteNode", 0, > import_node_call, > "", "qyay", "primary", "count", > "dev_key"); > + l_dbus_interface_method(iface, "Reprovision", 0, > reprovision_call, > + "", "qa{sv}", "unicast", > "options"); > l_dbus_interface_method(iface, "DeleteRemoteNode", 0, > delete_node_call, > "", "qy", "primary", > "count"); > l_dbus_interface_method(iface, "UnprovisionedScan", 0, > start_scan_call, > @@ -849,7 +1154,7 @@ bool manager_dbus_init(struct l_dbus *bus) > if (!l_dbus_register_interface(bus, > MESH_MANAGEMENT_INTERFACE, > setup_management_inte > rface, > NULL, false)) { > - l_info("Unable to register %s interface", > + l_debug("Unable to register %s interface", > MESH_MANAGEMENT_INTER > FACE); > return false; > } > @@ -859,8 +1164,8 @@ bool manager_dbus_init(struct l_dbus *bus) > > void manager_scan_cancel(struct mesh_node *node) > { > - if (scan_node != node) > - return; > + struct scan_req *req; > > - scan_cancel(NULL, node); > + while ((req = l_queue_find(scans, by_node, node))) > + scan_cancel(NULL, req); > } > diff --git a/mesh/mesh-config-json.c b/mesh/mesh-config-json.c > index 7f46c8582..8f321a731 100644 > --- a/mesh/mesh-config-json.c > +++ b/mesh/mesh-config-json.c > @@ -58,6 +58,33 @@ static const char *cfgnode_name = "/node.json"; > static const char *bak_ext = ".bak"; > static const char *tmp_ext = ".tmp"; > > +/* JSON key words */ > +static const char *unicastAddress = "unicastAddress"; > +static const char *deviceCan = "deviceCan"; > +static const char *deviceKey = "deviceKey"; > +static const char *defaultTTL = "defaultTTL"; > +static const char *sequenceNumber = "sequenceNumber"; > +static const char *netKeys = "netKeys"; > +static const char *appKeys = "appKeys"; > +static const char *elements = "elements"; > +static const char *models = "models"; > +static const char *modelId = "modelId"; > +static const char *address = "address"; > +static const char *bind = "bind"; > +static const char *publish = "publish"; > +static const char *subscribe = "subscribe"; > +static const char *boundNetKey = "boundNetKey"; > +static const char *keyRefresh = "keyRefresh"; > +static const char *subEnabled = "subEnabled"; > +static const char *pubEnabled = "pubEnabled"; > +static const char *retransmit = "retransmit"; > + > +/* Common JSON values */ > +static const char *enabled = "enabled"; > +static const char *disabled = "disabled"; > +static const char *unsupported = "unsupported"; > + > + > static bool save_config(json_object *jnode, const char *fname) > { > FILE *outfile; > @@ -134,14 +161,14 @@ static int get_element_index(json_object > *jnode, uint16_t ele_addr) > uint16_t addr, num_ele; > char *str; > > - if (!json_object_object_get_ex(jnode, "unicastAddress", > &jvalue)) > + if (!json_object_object_get_ex(jnode, unicastAddress, > &jvalue)) > return -1; > > str = (char *)json_object_get_string(jvalue); > if (sscanf(str, "%04hx", &addr) != 1) > return -1; > > - if (!json_object_object_get_ex(jnode, "elements", > &jelements)) > + if (!json_object_object_get_ex(jnode, elements, &jelements)) > return -1; > > num_ele = json_object_array_length(jelements); > @@ -160,14 +187,14 @@ static json_object > *get_element_model(json_object *jnode, int ele_idx, > size_t len; > char buf[9]; > > - if (!json_object_object_get_ex(jnode, "elements", > &jelements)) > + if (!json_object_object_get_ex(jnode, elements, &jelements)) > return NULL; > > jelement = json_object_array_get_idx(jelements, ele_idx); > if (!jelement) > return NULL; > > - if (!json_object_object_get_ex(jelement, "models", &jmodels)) > + if (!json_object_object_get_ex(jelement, models, &jmodels)) > return NULL; > > num_mods = json_object_array_length(jmodels); > @@ -189,7 +216,7 @@ static json_object *get_element_model(json_object > *jnode, int ele_idx, > char *str; > > jmodel = json_object_array_get_idx(jmodels, i); > - if (!json_object_object_get_ex(jmodel, "modelId", > &jvalue)) > + if (!json_object_object_get_ex(jmodel, modelId, > &jvalue)) > return NULL; > > str = (char *)json_object_get_string(jvalue); > @@ -298,7 +325,7 @@ static bool read_unicast_address(json_object > *jobj, uint16_t *unicast) > json_object *jvalue; > char *str; > > - if (!json_object_object_get_ex(jobj, "unicastAddress", > &jvalue)) > + if (!json_object_object_get_ex(jobj, unicastAddress, > &jvalue)) > return false; > > str = (char *)json_object_get_string(jvalue); > @@ -314,7 +341,7 @@ static bool read_default_ttl(json_object *jobj, > uint8_t *ttl) > int val; > > /* defaultTTL is optional */ > - if (!json_object_object_get_ex(jobj, "defaultTTL", &jvalue)) > + if (!json_object_object_get_ex(jobj, defaultTTL, &jvalue)) > return true; > > val = json_object_get_int(jvalue); > @@ -336,7 +363,7 @@ static bool read_seq_number(json_object *jobj, > uint32_t *seq_number) > int val; > > /* sequenceNumber is optional */ > - if (!json_object_object_get_ex(jobj, "sequenceNumber", > &jvalue)) > + if (!json_object_object_get_ex(jobj, sequenceNumber, > &jvalue)) > return true; > > val = json_object_get_int(jvalue); > @@ -396,7 +423,25 @@ static bool read_device_key(json_object *jobj, > uint8_t key_buf[16]) > if (!key_buf) > return false; > > - if (!json_object_object_get_ex(jobj, "deviceKey", &jvalue)) > + if (!json_object_object_get_ex(jobj, deviceKey, &jvalue)) > + return false; > + > + str = (char *)json_object_get_string(jvalue); > + if (!str2hex(str, strlen(str), key_buf, 16)) > + return false; > + > + return true; > +} > + > +static bool read_candidate(json_object *jobj, uint8_t key_buf[16]) > +{ > + json_object *jvalue; > + char *str; > + > + if (!key_buf) > + return false; > + > + if (!json_object_object_get_ex(jobj, deviceCan, &jvalue)) > return false; > > str = (char *)json_object_get_string(jvalue); > @@ -460,7 +505,7 @@ static bool read_app_keys(json_object *jobj, > struct mesh_config_node *node) > int len; > int i; > > - if (!json_object_object_get_ex(jobj, "appKeys", &jarray)) > + if (!json_object_object_get_ex(jobj, appKeys, &jarray)) > return true; > > if (json_object_get_type(jarray) != json_type_array) > @@ -484,7 +529,7 @@ static bool read_app_keys(json_object *jobj, > struct mesh_config_node *node) > if (!get_key_index(jtemp, "index", &appkey->app_idx)) > goto fail; > > - if (!get_key_index(jtemp, "boundNetKey", &appkey- > >net_idx)) > + if (!get_key_index(jtemp, boundNetKey, &appkey- > >net_idx)) > goto fail; > > if (!json_object_object_get_ex(jtemp, "key", > &jvalue)) > @@ -516,7 +561,7 @@ static bool read_net_keys(json_object *jobj, > struct mesh_config_node *node) > int i; > > /* At least one NetKey must be present for a provisioned node > */ > - if (!json_object_object_get_ex(jobj, "netKeys", &jarray)) > + if (!json_object_object_get_ex(jobj, netKeys, &jarray)) > return false; > > if (json_object_get_type(jarray) != json_type_array) > @@ -547,7 +592,7 @@ static bool read_net_keys(json_object *jobj, > struct mesh_config_node *node) > if (!str2hex(str, strlen(str), netkey->new_key, 16)) > goto fail; > > - if (!json_object_object_get_ex(jtemp, "keyRefresh", > &jvalue)) > + if (!json_object_object_get_ex(jtemp, keyRefresh, > &jvalue)) > netkey->phase = KEY_REFRESH_PHASE_NONE; > else > netkey->phase = (uint8_t) > json_object_get_int(jvalue); > @@ -598,7 +643,7 @@ bool mesh_config_net_key_add(struct mesh_config > *cfg, uint16_t idx, > jnode = cfg->jnode; > > l_debug("netKey %4.4x", idx); > - json_object_object_get_ex(jnode, "netKeys", &jarray); > + json_object_object_get_ex(jnode, netKeys, &jarray); > if (jarray) > jentry = get_key_object(jarray, idx); > > @@ -616,14 +661,14 @@ bool mesh_config_net_key_add(struct mesh_config > *cfg, uint16_t idx, > if (!add_key_value(jentry, "key", key)) > goto fail; > > - json_object_object_add(jentry, "keyRefresh", > + json_object_object_add(jentry, keyRefresh, > json_object_new_int(KEY_REFRESH_PHASE > _NONE)); > > if (!jarray) { > jarray = json_object_new_array(); > if (!jarray) > goto fail; > - json_object_object_add(jnode, "netKeys", jarray); > + json_object_object_add(jnode, netKeys, jarray); > } > > json_object_array_add(jarray, jentry); > @@ -648,7 +693,7 @@ bool mesh_config_net_key_update(struct > mesh_config *cfg, uint16_t idx, > > jnode = cfg->jnode; > > - if (!json_object_object_get_ex(jnode, "netKeys", &jarray)) > + if (!json_object_object_get_ex(jnode, netKeys, &jarray)) > return false; > > jentry = get_key_object(jarray, idx); > @@ -667,7 +712,7 @@ bool mesh_config_net_key_update(struct > mesh_config *cfg, uint16_t idx, > if (!add_key_value(jentry, "key", key)) > return false; > > - json_object_object_add(jentry, "keyRefresh", > + json_object_object_add(jentry, keyRefresh, > json_object_new_int(KEY_REFRESH_PHASE > _ONE)); > > return save_config(jnode, cfg->node_dir_path); > @@ -682,20 +727,55 @@ bool mesh_config_net_key_del(struct mesh_config > *cfg, uint16_t idx) > > jnode = cfg->jnode; > > - if (!json_object_object_get_ex(jnode, "netKeys", &jarray)) > + if (!json_object_object_get_ex(jnode, netKeys, &jarray)) > return true; > > jarray_key_del(jarray, idx); > > if (!json_object_array_length(jarray)) > - json_object_object_del(jnode, "netKeys"); > + json_object_object_del(jnode, netKeys); > > return save_config(jnode, cfg->node_dir_path); > } > > bool mesh_config_write_device_key(struct mesh_config *cfg, uint8_t > *key) > { > - if (!cfg || !add_key_value(cfg->jnode, "deviceKey", key)) > + if (!cfg || !add_key_value(cfg->jnode, deviceKey, key)) > + return false; > + > + return save_config(cfg->jnode, cfg->node_dir_path); > +} > + > +bool mesh_config_write_candidate(struct mesh_config *cfg, uint8_t > *key) > +{ > + if (!cfg || !add_key_value(cfg->jnode, deviceCan, key)) > + return false; > + > + return save_config(cfg->jnode, cfg->node_dir_path); > +} > + > +bool mesh_config_read_candidate(struct mesh_config *cfg, uint8_t > *key) > +{ > + if (!cfg) > + return false; > + > + return read_candidate(cfg->jnode, key); > +} > + > +bool mesh_config_finalize_candidate(struct mesh_config *cfg) > +{ > + uint8_t key[16]; > + > + if (!cfg) > + return false; > + > + if (!read_candidate(cfg->jnode, key)) > + return false; > + > + json_object_object_del(cfg->jnode, deviceCan); > + json_object_object_del(cfg->jnode, deviceKey); > + > + if (!add_key_value(cfg->jnode, deviceKey, key)) > return false; > > return save_config(cfg->jnode, cfg->node_dir_path); > @@ -719,7 +799,7 @@ bool mesh_config_app_key_add(struct mesh_config > *cfg, uint16_t net_idx, > > jnode = cfg->jnode; > > - json_object_object_get_ex(jnode, "appKeys", &jarray); > + json_object_object_get_ex(jnode, appKeys, &jarray); > if (jarray) > jentry = get_key_object(jarray, app_idx); > > @@ -734,7 +814,7 @@ bool mesh_config_app_key_add(struct mesh_config > *cfg, uint16_t net_idx, > if (!write_int(jentry, "index", app_idx)) > goto fail; > > - if (!write_int(jentry, "boundNetKey", net_idx)) > + if (!write_int(jentry, boundNetKey, net_idx)) > goto fail; > > if (!add_key_value(jentry, "key", key)) > @@ -744,7 +824,7 @@ bool mesh_config_app_key_add(struct mesh_config > *cfg, uint16_t net_idx, > jarray = json_object_new_array(); > if (!jarray) > goto fail; > - json_object_object_add(jnode, "appKeys", jarray); > + json_object_object_add(jnode, appKeys, jarray); > } > > json_object_array_add(jarray, jentry); > @@ -770,7 +850,7 @@ bool mesh_config_app_key_update(struct > mesh_config *cfg, uint16_t app_idx, > > jnode = cfg->jnode; > > - if (!json_object_object_get_ex(jnode, "appKeys", &jarray)) > + if (!json_object_object_get_ex(jnode, appKeys, &jarray)) > return false; > > /* The key entry should exist if the key is updated */ > @@ -804,13 +884,13 @@ bool mesh_config_app_key_del(struct mesh_config > *cfg, uint16_t net_idx, > > jnode = cfg->jnode; > > - if (!json_object_object_get_ex(jnode, "appKeys", &jarray)) > + if (!json_object_object_get_ex(jnode, appKeys, &jarray)) > return true; > > jarray_key_del(jarray, idx); > > if (!json_object_array_length(jarray)) > - json_object_object_del(jnode, "appKeys"); > + json_object_object_del(jnode, appKeys); > > return save_config(jnode, cfg->node_dir_path); > } > @@ -840,7 +920,7 @@ bool mesh_config_model_binding_add(struct > mesh_config *cfg, uint16_t ele_addr, > if (!jmodel) > return false; > > - json_object_object_get_ex(jmodel, "bind", &jarray); > + json_object_object_get_ex(jmodel, bind, &jarray); > if (jarray && jarray_has_string(jarray, buf, 4)) > return true; > > @@ -854,7 +934,7 @@ bool mesh_config_model_binding_add(struct > mesh_config *cfg, uint16_t ele_addr, > json_object_put(jstring); > return false; > } > - json_object_object_add(jmodel, "bind", jarray); > + json_object_object_add(jmodel, bind, jarray); > } > > json_object_array_add(jarray, jstring); > @@ -887,13 +967,13 @@ bool mesh_config_model_binding_del(struct > mesh_config *cfg, uint16_t ele_addr, > if (!jmodel) > return false; > > - if (!json_object_object_get_ex(jmodel, "bind", &jarray)) > + if (!json_object_object_get_ex(jmodel, bind, &jarray)) > return true; > > jarray_string_del(jarray, buf, 4); > > if (!json_object_array_length(jarray)) > - json_object_object_del(jmodel, "bind"); > + json_object_object_del(jmodel, bind); > > return save_config(jnode, cfg->node_dir_path); > } > @@ -963,7 +1043,7 @@ static struct mesh_config_pub > *parse_model_publication(json_object *jpub) > int len, value; > char *str; > > - if (!json_object_object_get_ex(jpub, "address", &jvalue)) > + if (!json_object_object_get_ex(jpub, address, &jvalue)) > return NULL; > > str = (char *)json_object_get_string(jvalue); > @@ -998,9 +1078,10 @@ static struct mesh_config_pub > *parse_model_publication(json_object *jpub) > > if (!get_int(jpub, "credentials", &value)) > goto fail; > + > pub->credential = (uint8_t) value; > > - if (!json_object_object_get_ex(jpub, "retransmit", &jvalue)) > + if (!json_object_object_get_ex(jpub, retransmit, &jvalue)) > goto fail; > > if (!get_int(jvalue, "count", &value)) > @@ -1093,7 +1174,7 @@ static bool parse_models(json_object *jmodels, > struct mesh_config_element *ele) > > l_queue_push_tail(ele->models, mod); > > - if (!json_object_object_get_ex(jmodel, "modelId", > &jvalue)) > + if (!json_object_object_get_ex(jmodel, modelId, > &jvalue)) > goto fail; > > str = (char *)json_object_get_string(jvalue); > @@ -1112,29 +1193,32 @@ static bool parse_models(json_object > *jmodels, struct mesh_config_element *ele) > > mod->id = id; > > - if (json_object_object_get_ex(jmodel, "bind", > &jarray)) { > + if (len == 8) > + mod->vendor = true; > + > + if (json_object_object_get_ex(jmodel, bind, &jarray)) > { > if (json_object_get_type(jarray) != > json_type_array || > !parse_bindings(jarray, mod)) > goto fail; > } > > - if (json_object_object_get_ex(jmodel, "pubEnabled", > &jvalue)) > + if (json_object_object_get_ex(jmodel, pubEnabled, > &jvalue)) > mod->pub_enabled = > json_object_get_boolean(jvalue); > else > mod->pub_enabled = true; > > - if (json_object_object_get_ex(jmodel, "subEnabled", > &jvalue)) > + if (json_object_object_get_ex(jmodel, subEnabled, > &jvalue)) > mod->sub_enabled = > json_object_get_boolean(jvalue); > else > mod->sub_enabled = true; > > - if (json_object_object_get_ex(jmodel, "publish", > &jvalue)) { > + if (json_object_object_get_ex(jmodel, publish, > &jvalue)) { > mod->pub = parse_model_publication(jvalue); > if (!mod->pub) > goto fail; > } > > - if (json_object_object_get_ex(jmodel, "subscribe", > &jarray)) { > + if (json_object_object_get_ex(jmodel, subscribe, > &jarray)) { > if (!parse_model_subscriptions(jarray, mod)) > goto fail; > } > @@ -1187,7 +1271,7 @@ static bool parse_elements(json_object *jelems, > struct mesh_config_node *node) > if (sscanf(str, "%04hx", &(ele->location)) != 1) > goto fail; > > - if (json_object_object_get_ex(jelement, "models", > &jmodels)) { > + if (json_object_object_get_ex(jelement, models, > &jmodels)) { > if (json_object_get_type(jmodels) != > json_type_array || > !parse_models(jmodels > , ele)) > goto fail; > @@ -1211,13 +1295,13 @@ static int get_mode(json_object *jvalue) > if (!str) > return 0xffffffff; > > - if (!strncasecmp(str, "disabled", strlen("disabled"))) > + if (!strncasecmp(str, disabled, strlen(disabled))) > return MESH_MODE_DISABLED; > > - if (!strncasecmp(str, "enabled", strlen("enabled"))) > + if (!strncasecmp(str, enabled, strlen(enabled))) > return MESH_MODE_ENABLED; > > - if (!strncasecmp(str, "unsupported", strlen("unsupported"))) > + if (!strncasecmp(str, unsupported, strlen(unsupported))) > return MESH_MODE_UNSUPPORTED; > > return 0xffffffff; > @@ -1323,7 +1407,7 @@ static bool read_net_transmit(json_object > *jobj, struct mesh_config_node *node) > uint16_t interval; > uint8_t cnt; > > - if (!json_object_object_get_ex(jobj, "retransmit", &jrtx)) > + if (!json_object_object_get_ex(jobj, retransmit, &jrtx)) > return true; > > if (!json_object_object_get_ex(jrtx, "count", &jvalue)) > @@ -1386,7 +1470,7 @@ static bool read_node(json_object *jnode, > struct mesh_config_node *node) > } > > /* Check for required "elements" property */ > - if (!json_object_object_get_ex(jnode, "elements", &jvalue)) > + if (!json_object_object_get_ex(jnode, elements, &jvalue)) > return false; > > if (!read_net_transmit(jnode, node)) { > @@ -1460,11 +1544,11 @@ static const char *mode_to_string(int mode) > { > switch (mode) { > case MESH_MODE_DISABLED: > - return "disabled"; > + return disabled; > case MESH_MODE_ENABLED: > - return "enabled"; > + return enabled; > default: > - return "unsupported"; > + return unsupported; > } > } > > @@ -1522,7 +1606,7 @@ fail: > > bool mesh_config_write_unicast(struct mesh_config *cfg, uint16_t > unicast) > { > - if (!cfg || !write_uint16_hex(cfg->jnode, "unicastAddress", > unicast)) > + if (!cfg || !write_uint16_hex(cfg->jnode, unicastAddress, > unicast)) > return false; > > return save_config(cfg->jnode, cfg->node_dir_path); > @@ -1558,8 +1642,8 @@ bool mesh_config_write_net_transmit(struct > mesh_config *cfg, uint8_t cnt, > if (!write_int(jrtx, "interval", interval)) > goto fail; > > - json_object_object_del(jnode, "retransmit"); > - json_object_object_add(jnode, "retransmit", jrtx); > + json_object_object_del(jnode, retransmit); > + json_object_object_add(jnode, retransmit, jrtx); > > return save_config(cfg->jnode, cfg->node_dir_path); > > @@ -1599,8 +1683,8 @@ static void add_model(void *a, void *b) > if (!jmodel) > return; > > - result = (mod->vendor) ? write_uint32_hex(jmodel, "modelId", > mod->id) : > - write_uint16_hex(jmodel, "modelId", > (uint16_t) mod->id); > + result = (mod->vendor) ? write_uint32_hex(jmodel, modelId, > mod->id) : > + write_uint16_hex(jmodel, modelId, (uint16_t) > mod->id); > > if (!result) { > json_object_put(jmodel); > @@ -1608,10 +1692,10 @@ static void add_model(void *a, void *b) > } > > jval = json_object_new_boolean(mod->sub_enabled); > - json_object_object_add(jmodel, "subEnabled", jval); > + json_object_object_add(jmodel, subEnabled, jval); > > jval = json_object_new_boolean(mod->pub_enabled); > - json_object_object_add(jmodel, "pubEnabled", jval); > + json_object_object_add(jmodel, pubEnabled, jval); > > json_object_array_add(jmodels, jmodel); > } > @@ -1663,11 +1747,11 @@ static struct mesh_config > *create_config(const char *cfg_path, > return NULL; > > /* Sequence number */ > - json_object_object_add(jnode, "sequenceNumber", > + json_object_object_add(jnode, sequenceNumber, > json_object_new_int(node- > >seq_number)); > > /* Default TTL */ > - json_object_object_add(jnode, "defaultTTL", > + json_object_object_add(jnode, defaultTTL, > json_object_new_int(n > ode->ttl)); > > /* Elements */ > @@ -1702,11 +1786,11 @@ static struct mesh_config > *create_config(const char *cfg_path, > if (!jmodels) > goto fail; > > - json_object_object_add(jelement, "models", jmodels); > + json_object_object_add(jelement, models, jmodels); > l_queue_foreach(ele->models, add_model, jmodels); > } > > - json_object_object_add(jnode, "elements", jelems); > + json_object_object_add(jnode, elements, jelems); > > cfg = l_new(struct mesh_config, 1); > > @@ -1724,6 +1808,55 @@ fail: > return NULL; > } > > +void mesh_config_reset(struct mesh_config *cfg, struct > mesh_config_node *node) > +{ > + json_object *jelems; > + const struct l_queue_entry *entry; > + > + if (!cfg || !cfg->jnode) > + return; > + > + /* TODO: Recreate Element Array */ > + jelems = json_object_new_array(); > + if (!jelems) > + return; > + > + entry = l_queue_get_entries(node->elements); > + > + for (; entry; entry = entry->next) { > + struct mesh_config_element *ele = entry->data; > + json_object *jelement, *jmodels; > + > + jelement = json_object_new_object(); > + > + if (!jelement) { > + json_object_put(jelems); > + return; > + } > + > + write_int(jelement, "elementIndex", ele->index); > + write_uint16_hex(jelement, "location", ele- > >location); > + json_object_array_add(jelems, jelement); > + > + /* Models */ > + if (l_queue_isempty(ele->models)) > + continue; > + > + jmodels = json_object_new_array(); > + if (!jmodels) { > + json_object_put(jelems); > + return; > + } > + > + json_object_object_add(jelement, models, jmodels); > + l_queue_foreach(ele->models, add_model, jmodels); > + } > + > + /* Replace element array */ > + json_object_object_del(cfg->jnode, elements); > + json_object_object_add(cfg->jnode, elements, jelems); > +} > + > struct mesh_config *mesh_config_create(const char *cfgdir_name, > const uint8_t uuid[16], struct mesh_config_node > *db_node) > { > @@ -1768,7 +1901,7 @@ static void finish_key_refresh(json_object > *jobj, uint16_t net_idx) > int i, len; > > /* Clean up all the bound appkeys */ > - if (!json_object_object_get_ex(jobj, "appKeys", &jarray)) > + if (!json_object_object_get_ex(jobj, appKeys, &jarray)) > return; > > len = json_object_array_length(jarray); > @@ -1779,7 +1912,7 @@ static void finish_key_refresh(json_object > *jobj, uint16_t net_idx) > > jentry = json_object_array_get_idx(jarray, i); > > - if (!get_key_index(jentry, "boundNetKey", &idx)) > + if (!get_key_index(jentry, boundNetKey, &idx)) > continue; > > if (idx != net_idx) > @@ -1803,14 +1936,14 @@ bool mesh_config_net_key_set_phase(struct > mesh_config *cfg, uint16_t idx, > > jnode = cfg->jnode; > > - if (json_object_object_get_ex(jnode, "netKeys", &jarray)) > + if (json_object_object_get_ex(jnode, netKeys, &jarray)) > jentry = get_key_object(jarray, idx); > > if (!jentry) > return false; > > - json_object_object_del(jentry, "keyRefresh"); > - json_object_object_add(jentry, "keyRefresh", > + json_object_object_del(jentry, keyRefresh); > + json_object_object_add(jentry, keyRefresh, > json_object_new_int(phase)); > > if (phase == KEY_REFRESH_PHASE_NONE) { > @@ -1842,16 +1975,16 @@ bool mesh_config_model_pub_add(struct > mesh_config *cfg, uint16_t ele_addr, > if (!jmodel) > return false; > > - json_object_object_del(jmodel, "publish"); > + json_object_object_del(jmodel, publish); > > jpub = json_object_new_object(); > if (!jpub) > return false; > > if (pub->virt) > - res = add_key_value(jpub, "address", pub->virt_addr); > + res = add_key_value(jpub, address, pub->virt_addr); > else > - res = write_uint16_hex(jpub, "address", pub->addr); > + res = write_uint16_hex(jpub, address, pub->addr); > > if (!res) > goto fail; > @@ -1878,8 +2011,8 @@ bool mesh_config_model_pub_add(struct > mesh_config *cfg, uint16_t ele_addr, > if (!write_int(jrtx, "interval", pub->interval)) > goto fail; > > - json_object_object_add(jpub, "retransmit", jrtx); > - json_object_object_add(jmodel, "publish", jpub); > + json_object_object_add(jpub, retransmit, jrtx); > + json_object_object_add(jmodel, publish, jpub); > > return save_config(jnode, cfg->node_dir_path); > > @@ -1911,23 +2044,23 @@ bool mesh_config_model_pub_del(struct > mesh_config *cfg, uint16_t addr, > uint32_t mod_id, bool > vendor) > { > if (!cfg || !delete_model_property(cfg->jnode, addr, mod_id, > vendor, > - > "publis > h")) > + publi > sh)) > return false; > > return save_config(cfg->jnode, cfg->node_dir_path); > } > > -static void del_page(json_object *jarray, uint8_t page) > +static bool del_page(json_object *jarray, uint8_t page) > { > char buf[3]; > int i, len, ret; > > if (!jarray) > - return; > + return false; > > ret = snprintf(buf, 3, "%2.2x", page); > if (ret < 0) > - return; > + return false; > > len = json_object_array_length(jarray); > > @@ -1938,10 +2071,29 @@ static void del_page(json_object *jarray, > uint8_t page) > jentry = json_object_array_get_idx(jarray, i); > str = (char *)json_object_get_string(jentry); > > - /* Delete matching page(s) */ > - if (!memcmp(str, buf, 2)) > + /* Delete matching page */ > + if (!memcmp(str, buf, 2)) { > json_object_array_del_idx(jarray, i, 1); > + break; > + } > } > + > + return true; > +} > + > +void mesh_config_comp_page_del(struct mesh_config *cfg, uint8_t > page) > +{ > + json_object *jnode, *jarray = NULL; > + > + if (!cfg) > + return; > + > + jnode = cfg->jnode; > + > + json_object_object_get_ex(jnode, "pages", &jarray); > + > + if (del_page(jarray, page)) > + save_config(jnode, cfg->node_dir_path); > } > > bool mesh_config_comp_page_add(struct mesh_config *cfg, uint8_t > page, > @@ -1984,56 +2136,6 @@ bool mesh_config_comp_page_add(struct > mesh_config *cfg, uint8_t page, > return save_config(jnode, cfg->node_dir_path); > } > > -bool mesh_config_comp_page_mv(struct mesh_config *cfg, uint8_t old, > uint8_t nw) > -{ > - json_object *jnode, *jarray = NULL; > - uint8_t *data; > - char *str; > - char old_buf[3]; > - int i, len, ret, dlen = 0; > - bool status = true; > - > - if (!cfg || old == nw) > - return false; > - > - ret = snprintf(old_buf, 3, "%2.2x", old); > - if (ret < 0) > - return false; > - > - jnode = cfg->jnode; > - > - json_object_object_get_ex(jnode, "pages", &jarray); > - > - if (!jarray) > - return false; > - > - data = l_malloc(MAX_MSG_LEN); > - > - len = json_object_array_length(jarray); > - > - for (i = 0; i < len; i++) { > - json_object *jentry; > - > - jentry = json_object_array_get_idx(jarray, i); > - str = (char *)json_object_get_string(jentry); > - > - /* Delete matching page(s) but save data*/ > - if (!memcmp(str, old_buf, 2)) { > - dlen = strlen(str + 2); > - str2hex(str + 2, dlen, data, MAX_MSG_LEN); > - dlen /= 2; > - json_object_array_del_idx(jarray, i, 1); > - } > - } > - > - if (dlen) > - status = mesh_config_comp_page_add(cfg, nw, data, > dlen); > - > - l_free(data); > - > - return status; > -} > - > bool mesh_config_model_sub_add(struct mesh_config *cfg, uint16_t > ele_addr, > uint32_t mod_id, bool > vendor, > struct > mesh_config_sub *sub) > @@ -2064,7 +2166,7 @@ bool mesh_config_model_sub_add(struct > mesh_config *cfg, uint16_t ele_addr, > len = 32; > } > > - json_object_object_get_ex(jmodel, "subscribe", &jarray); > + json_object_object_get_ex(jmodel, subscribe, &jarray); > if (jarray && jarray_has_string(jarray, buf, len)) > return true; > > @@ -2078,7 +2180,7 @@ bool mesh_config_model_sub_add(struct > mesh_config *cfg, uint16_t ele_addr, > json_object_put(jstring); > return false; > } > - json_object_object_add(jmodel, "subscribe", jarray); > + json_object_object_add(jmodel, subscribe, jarray); > } > > json_object_array_add(jarray, jstring); > @@ -2107,7 +2209,7 @@ bool mesh_config_model_sub_del(struct > mesh_config *cfg, uint16_t ele_addr, > if (!jmodel) > return false; > > - if (!json_object_object_get_ex(jmodel, "subscribe", &jarray)) > + if (!json_object_object_get_ex(jmodel, subscribe, &jarray)) > return true; > > if (!sub->virt) { > @@ -2122,7 +2224,7 @@ bool mesh_config_model_sub_del(struct > mesh_config *cfg, uint16_t ele_addr, > jarray_string_del(jarray, buf, len); > > if (!json_object_array_length(jarray)) > - json_object_object_del(jmodel, "subscribe"); > + json_object_object_del(jmodel, subscribe); > > return save_config(jnode, cfg->node_dir_path); > } > @@ -2131,7 +2233,7 @@ bool mesh_config_model_sub_del_all(struct > mesh_config *cfg, uint16_t addr, > uint32_t mod_id, bool > vendor) > { > if (!cfg || !delete_model_property(cfg->jnode, addr, mod_id, > vendor, > - > "subscr > ibe")) > + subsc > ribe)) > return false; > > return save_config(cfg->jnode, cfg->node_dir_path); > @@ -2161,7 +2263,7 @@ bool mesh_config_model_pub_enable(struct > mesh_config *cfg, uint16_t ele_addr, > json_object_object_add(jmodel, "pubDisabled", jval); > > if (!enable) > - json_object_object_del(jmodel, "publish"); > + json_object_object_del(jmodel, publish); > > return save_config(cfg->jnode, cfg->node_dir_path); > } > @@ -2184,13 +2286,13 @@ bool mesh_config_model_sub_enable(struct > mesh_config *cfg, uint16_t ele_addr, > if (!jmodel) > return false; > > - json_object_object_del(jmodel, "subEnabled"); > + json_object_object_del(jmodel, subEnabled); > > jval = json_object_new_boolean(enable); > - json_object_object_add(jmodel, "subEnabled", jval); > + json_object_object_add(jmodel, subEnabled, jval); > > if (!enable) > - json_object_object_del(jmodel, "subscribe"); > + json_object_object_del(jmodel, subscribe); > > return save_config(cfg->jnode, cfg->node_dir_path); > } > @@ -2205,14 +2307,14 @@ bool mesh_config_write_seq_number(struct > mesh_config *cfg, uint32_t seq, > return false; > > if (!cache) { > - if (!write_int(cfg->jnode, "sequenceNumber", seq)) > + if (!write_int(cfg->jnode, sequenceNumber, seq)) > return false; > > return mesh_config_save(cfg, true, NULL, NULL); > } > > /* If resetting seq to Zero, make sure cached value reset as > well */ > - if (seq && get_int(cfg->jnode, "sequenceNumber", &value)) > + if (seq && get_int(cfg->jnode, sequenceNumber, &value)) > cached = (uint32_t)value; > > /* > @@ -2262,8 +2364,8 @@ bool mesh_config_write_seq_number(struct > mesh_config *cfg, uint32_t seq, > > l_debug("Seq Cache: %d -> %d", seq, cached); > > - if (!write_int(cfg->jnode, "sequenceNumber", cached)) > - return false; > + if (!write_int(cfg->jnode, sequenceNumber, cached)) > + return false; > > return mesh_config_save(cfg, false, NULL, NULL); > } > @@ -2273,7 +2375,7 @@ bool mesh_config_write_seq_number(struct > mesh_config *cfg, uint32_t seq, > > bool mesh_config_write_ttl(struct mesh_config *cfg, uint8_t ttl) > { > - if (!cfg || !write_int(cfg->jnode, "defaultTTL", ttl)) > + if (!cfg || !write_int(cfg->jnode, defaultTTL, ttl)) > return false; > > return save_config(cfg->jnode, cfg->node_dir_path); > diff --git a/mesh/mesh-config.h b/mesh/mesh-config.h > index 420775829..ed1b610de 100644 > --- a/mesh/mesh-config.h > +++ b/mesh/mesh-config.h > @@ -119,6 +119,7 @@ void mesh_config_release(struct mesh_config > *cfg); > void mesh_config_destroy_nvm(struct mesh_config *cfg); > bool mesh_config_save(struct mesh_config *cfg, bool no_wait, > mesh_config_status_func_t cb, void > *user_data); > +void mesh_config_reset(struct mesh_config *cfg, struct > mesh_config_node *node); > struct mesh_config *mesh_config_create(const char *cfgdir_name, > const uint8_t > uuid[16], > struct > mesh_config_node *node); > @@ -126,6 +127,9 @@ struct mesh_config *mesh_config_create(const char > *cfgdir_name, > bool mesh_config_write_net_transmit(struct mesh_config *cfg, uint8_t > cnt, > uint16_t > interval); > bool mesh_config_write_device_key(struct mesh_config *cfg, uint8_t > *key); > +bool mesh_config_write_candidate(struct mesh_config *cfg, uint8_t > *key); > +bool mesh_config_read_candidate(struct mesh_config *cfg, uint8_t > *key); > +bool mesh_config_finalize_candidate(struct mesh_config *cfg); > bool mesh_config_write_token(struct mesh_config *cfg, uint8_t > *token); > bool mesh_config_write_network_key(struct mesh_config *cfg, uint16_t > idx, > uint8_t *key, uint8_t *new_key, int > phase); > @@ -141,7 +145,7 @@ bool mesh_config_write_mode(struct mesh_config > *cfg, const char *keyword, > int > value); > bool mesh_config_comp_page_add(struct mesh_config *cfg, uint8_t > page, > uint8_t *data, > uint16_t size); > -bool mesh_config_comp_page_mv(struct mesh_config *cfg, uint8_t old, > uint8_t nw); > +void mesh_config_comp_page_del(struct mesh_config *cfg, uint8_t > page); > bool mesh_config_model_binding_add(struct mesh_config *cfg, uint16_t > ele_addr, > uint32_t mod_id, bool > vendor, > uint16_t > app_idx); > diff --git a/mesh/model.c b/mesh/model.c > index d48e6ef12..e2babea10 100644 > --- a/mesh/model.c > +++ b/mesh/model.c > @@ -24,6 +24,8 @@ > #include "mesh/net.h" > #include "mesh/appkey.h" > #include "mesh/cfgmod.h" > +#include "mesh/prov.h" > +#include "mesh/remprv.h" > #include "mesh/error.h" > #include "mesh/dbus.h" > #include "mesh/util.h" > @@ -76,6 +78,9 @@ static bool is_internal(uint32_t id) > if (id == CONFIG_SRV_MODEL || id == CONFIG_CLI_MODEL) > return true; > > + if (id == REM_PROV_SRV_MODEL || id == REM_PROV_CLI_MODEL) > + return true; > + > return false; > } > > @@ -457,13 +462,25 @@ static int dev_packet_decrypt(struct mesh_node > *node, const uint8_t *data, > dst, key_aid, seq, iv_idx, > out, key)) > return APP_IDX_DEV_LOCAL; > > - if (!keyring_get_remote_dev_key(node, src, dev_key)) > + key = dev_key; > + > + if (keyring_get_remote_dev_key(node, src, dev_key)) { > + if (mesh_crypto_payload_decrypt(NULL, 0, data, size, > szmict, > + src, dst, key_aid, seq, iv_idx, out, > key)) > + return APP_IDX_DEV_REMOTE; > + } > + > + /* See if there is a local Device Key Candidate as last > resort */ > + if (!node_get_device_key_candidate(node, dev_key)) > return -1; > > - key = dev_key; > - if (mesh_crypto_payload_decrypt(NULL, 0, data, size, szmict, > src, > - dst, key_aid, seq, iv_idx, > out, key)) > - return APP_IDX_DEV_REMOTE; > + if (mesh_crypto_payload_decrypt(NULL, 0, data, size, szmict, > + src, dst, key_aid, seq, iv_idx, out, > key)) { > + > + /* If candidate dev_key worked, it is considered > finalized */ > + node_finalize_candidate(node); > + return APP_IDX_DEV_LOCAL; > + } > > return -1; > } > diff --git a/mesh/node.c b/mesh/node.c > index cf4ed140e..5150a085a 100644 > --- a/mesh/node.c > +++ b/mesh/node.c > @@ -27,9 +27,11 @@ > #include "mesh/appkey.h" > #include "mesh/mesh-config.h" > #include "mesh/provision.h" > +#include "mesh/prov.h" > #include "mesh/keyring.h" > #include "mesh/model.h" > #include "mesh/cfgmod.h" > +#include "mesh/remprv.h" > #include "mesh/util.h" > #include "mesh/error.h" > #include "mesh/dbus.h" > @@ -347,6 +349,15 @@ static bool add_elements_from_storage(struct > mesh_node *node, > if (!add_element_from_storage(node, entry->data)) > return false; > > + /* Add configuration server model on the primary element */ > + mesh_model_add(node, PRIMARY_ELE_IDX, CONFIG_SRV_MODEL, > NULL); > + > + /* Add remote provisioning models on the primary element */ > + mesh_model_add(node, PRIMARY_ELE_IDX, REM_PROV_SRV_MODEL, > NULL); > + > + if (node->provisioner) > + mesh_model_add(node, PRIMARY_ELE_IDX, > REM_PROV_CLI_MODEL, NULL); > + > return true; > } > > @@ -489,6 +500,10 @@ static bool init_from_storage(struct > mesh_config_node *db_node, > /* Initialize configuration server model */ > cfgmod_server_init(node, PRIMARY_ELE_IDX); > > + /* Initialize remote provisioning models */ > + remote_prov_server_init(node, PRIMARY_ELE_IDX); > + remote_prov_client_init(node, PRIMARY_ELE_IDX); > + > node->cfg = cfg; > > return true; > @@ -550,12 +565,78 @@ uint16_t node_get_primary(struct mesh_node > *node) > return node->primary; > } > > +bool node_refresh(struct mesh_node *node, bool hard, void > *prov_info) > +{ > + struct mesh_prov_node_info *info = prov_info; > + bool res = true; > + > + if (!node || !info) > + return false; > + > + if (!IS_UNICAST(info->unicast)) > + return false; > + > + /* Changing Unicast addresses requires a hard node reset */ > + if (!hard && info->unicast != node->primary) > + return false; > + > + /* > + * Hard refresh results in immediate use of new Device Key. > + * Soft refresh saves new device key as Candidate until we > + * successfully receive new incoming message on that key. > + */ > + if (hard) { > + if (!mesh_config_write_device_key(node->cfg, info- > >device_key)) > + return false; > + > + memcpy(node->dev_key, info->device_key, sizeof(node- > >dev_key)); > + > + } else if (!mesh_config_write_candidate(node->cfg, info- > >device_key)) > + return false; > + > + /* Replace Primary Unicast address if it has changed */ > + if (node->primary != info->unicast) { > + res = mesh_config_write_unicast(node->cfg, info- > >unicast); > + if (res) { > + node->primary = info->unicast; > + node->num_ele = info->num_ele; > + mesh_net_register_unicast(node->net, node- > >primary, > + node- > >num_ele); > + } > + } > + > + /* Replace Page 0 with Page 128 if it exists */ > + if (res) { > + if (node_replace_comp(node, 0, 128)) > + return true; > + } > + > + return res; > +} > + > const uint8_t *node_get_device_key(struct mesh_node *node) > { > if (!node) > return NULL; > - else > - return node->dev_key; > + > + return node->dev_key; > +} > + > +bool node_get_device_key_candidate(struct mesh_node *node, uint8_t > *key) > +{ > + if (!node) > + return false; > + > + return mesh_config_read_candidate(node->cfg, key); > +} > + > +void node_finalize_candidate(struct mesh_node *node) > +{ > + if (!node) > + return; > + > + if (mesh_config_read_candidate(node->cfg, node->dev_key)) > + mesh_config_finalize_candidate(node->cfg); > } > > void node_set_token(struct mesh_node *node, uint8_t token[8]) > @@ -785,7 +866,7 @@ uint8_t node_friend_mode_get(struct mesh_node > *node) > return node->friend; > } > > -static uint16_t generate_node_comp(struct mesh_node *node, uint8_t > *buf, > +static uint16_t node_generate_comp(struct mesh_node *node, uint8_t > *buf, > uint1 > 6_t sz) > { > uint16_t n, features, num_ele = 0; > @@ -895,6 +976,21 @@ static void convert_node_to_storage(struct > mesh_node *node, > > } > > +static void free_db_storage(struct mesh_config_node *db_node) > +{ > + const struct l_queue_entry *entry; > + > + /* Free temporarily allocated resources */ > + entry = l_queue_get_entries(db_node->elements); > + for (; entry; entry = entry->next) { > + struct mesh_config_element *db_ele = entry->data; > + > + l_queue_destroy(db_ele->models, l_free); > + } > + > + l_queue_destroy(db_node->elements, l_free); > +} > + > static bool create_node_config(struct mesh_node *node, const uint8_t > uuid[16]) > { > struct mesh_config_node db_node; > @@ -922,7 +1018,22 @@ static bool create_node_config(struct mesh_node > *node, const uint8_t uuid[16]) > return node->cfg != NULL; > } > > -static bool set_node_comp(struct mesh_node *node, uint8_t page_num, > +static void node_del_comp(struct mesh_node *node, uint8_t page_num) > +{ > + struct mesh_config_comp_page *page; > + > + if (!node) > + return; > + > + page = l_queue_remove_if(node->pages, match_page, > + L_UINT_TO_PTR(page_nu > m)); > + > + l_free(page); > + > + mesh_config_comp_page_del(node->cfg, page_num); > +} > + > +static bool node_set_comp(struct mesh_node *node, uint8_t page_num, > const uint8_t *data, uint16_t > len) > { > struct mesh_config_comp_page *page; > @@ -944,16 +1055,6 @@ static bool set_node_comp(struct mesh_node > *node, uint8_t page_num, > return mesh_config_comp_page_add(node->cfg, page_num, page- > >data, len); > } > > -static bool create_node_comp(struct mesh_node *node) > -{ > - uint16_t len; > - uint8_t comp[MAX_MSG_LEN - 2]; > - > - len = generate_node_comp(node, comp, sizeof(comp)); > - > - return set_node_comp(node, 0, comp, len); > -} > - > const uint8_t *node_get_comp(struct mesh_node *node, uint8_t > page_num, > uint1 > 6_t *len) > { > @@ -975,6 +1076,7 @@ const uint8_t *node_get_comp(struct mesh_node > *node, uint8_t page_num, > bool node_replace_comp(struct mesh_node *node, uint8_t retire, > uint8_t with) > { > struct mesh_config_comp_page *old_page, *keep; > + bool status; > > if (!node) > return false; > @@ -989,9 +1091,13 @@ bool node_replace_comp(struct mesh_node *node, > uint8_t retire, uint8_t with) > > l_free(old_page); > keep->page_num = retire; > - mesh_config_comp_page_mv(node->cfg, with, retire); > + status = mesh_config_comp_page_add(node->cfg, keep->page_num, > + keep->data, > keep->len); > > - return true; > + if (with != retire) > + mesh_config_comp_page_del(node->cfg, with); > + > + return status; > } > > static void attach_io(void *a, void *b) > @@ -1170,8 +1276,13 @@ static bool get_element_properties(struct > mesh_node *node, const char *path, > * daemon. If the model is present in the application > properties, > * the operation below will be a "no-op". > */ > - if (ele->idx == PRIMARY_ELE_IDX) > + if (ele->idx == PRIMARY_ELE_IDX) { > mesh_model_add(node, ele->models, CONFIG_SRV_MODEL, > NULL); > + mesh_model_add(node, ele->models, REM_PROV_SRV_MODEL, > NULL); > + if (node->provisioner) > + mesh_model_add(node, ele->models, > REM_PROV_CLI_MODEL, > + > NULL); > + } > > return true; > fail: > @@ -1232,6 +1343,15 @@ static bool get_app_properties(struct > mesh_node *node, const char *path, > return true; > } > > +static void save_pages(void *data, void *user_data) > +{ > + struct mesh_config_comp_page *page = data; > + struct mesh_node *node = user_data; > + > + mesh_config_comp_page_add(node->cfg, page->page_num, page- > >data, > + page- > >len); > +} > + > static bool add_local_node(struct mesh_node *node, uint16_t unicast, > bool kr, > bool ivu, uint32_t iv_idx, uint8_t > dev_key[16], > uint16_t net_key_idx, uint8_t > net_key[16]) > @@ -1275,10 +1395,14 @@ static bool add_local_node(struct mesh_node > *node, uint16_t unicast, bool kr, > return false; > } > > + l_queue_foreach(node->pages, save_pages, node); > + > update_net_settings(node); > > - /* Initialize configuration server model */ > + /* Initialize internal server models */ > cfgmod_server_init(node, PRIMARY_ELE_IDX); > + remote_prov_server_init(node, PRIMARY_ELE_IDX); > + remote_prov_client_init(node, PRIMARY_ELE_IDX); > > node->busy = true; > > @@ -1326,39 +1450,59 @@ static void update_model_options(struct > mesh_node *node, > > static bool check_req_node(struct managed_obj_request *req) > { > + struct mesh_node *node; > const int offset = 8; > uint16_t node_len, len; > uint8_t comp[MAX_MSG_LEN - 2]; > const uint8_t *node_comp; > > - len = generate_node_comp(req->node, comp, sizeof(comp)); > + if (req->type != REQUEST_TYPE_ATTACH) { > + node = req->node; > > - if (len < MIN_COMP_SIZE) > - return false; > + if (!create_node_config(node, node->uuid)) > + return false; > + } else > + node = req->attach; > > - node_comp = node_get_comp(req->attach, 0, &node_len); > + node_comp = node_get_comp(node, 0, &node_len); > + len = node_generate_comp(req->node, comp, sizeof(comp)); > > - /* If no page 0 exists, create it and accept */ > - if (!node_len || !node_comp) > - return set_node_comp(req->attach, 0, comp, len); > + /* If no page 0 exists, then current composition as valid */ > + if (req->type != REQUEST_TYPE_ATTACH || !node_len) > + goto page_zero_valid; > > - /* Test Element/Model part of composition and reject if > changed */ > + /* > + * If composition has materially changed, save new > composition > + * in page 128 until next NPPI procedure. But we do allow > + * for CID, PID, VID and/or CRPL to freely change without > + * requiring a NPPI procedure. > + */ > if (node_len != len || memcmp(&node_comp[offset], > &comp[offset], > node_len - > offset)) > - return false; > + return node_set_comp(node, 128, comp, len); > > - /* If comp has changed, but not Element/Models, resave and > accept */ > - else if (memcmp(node_comp, comp, node_len)) > - return set_node_comp(req->attach, 0, comp, len); > +page_zero_valid: > + /* If page 0 represents current App, ensure page 128 doesn't > exist */ > + node_del_comp(node, 128); > > - /* Nothing has changed */ > - return true; > + if (len == node_len && !memcmp(node_comp, comp, len)) > + return true; > + > + return node_set_comp(node, 0, comp, len); > +} > + > +static bool is_zero(const void *a, const void *b) > +{ > + const struct node_element *element = a; > + > + return !element->idx; > } > > static bool attach_req_node(struct mesh_node *attach, struct > mesh_node *node) > { > const struct l_queue_entry *attach_entry; > const struct l_queue_entry *node_entry; > + bool comp_changed = false; > > attach->obj_path = node->obj_path; > node->obj_path = NULL; > @@ -1368,6 +1512,34 @@ static bool attach_req_node(struct mesh_node > *attach, struct mesh_node *node) > return false; > } > > + if (attach->num_ele != node->num_ele) { > + struct mesh_config_node db_node; > + struct node_element *old_ele, *new_ele; > + > + convert_node_to_storage(node, &db_node); > + > + /* > + * If composition has materially changed, we need to > discard > + * everything we knew about elements in the old > application, > + * and start from what they are telling us now. > + */ > + old_ele = l_queue_remove_if(attach->elements, > is_zero, NULL); > + new_ele = l_queue_remove_if(node->elements, is_zero, > NULL); > + element_free(new_ele); > + > + l_queue_destroy(attach->elements, element_free); > + attach->elements = node->elements; > + attach->num_ele = node->num_ele; > + > + /* Restore primary elements */ > + l_queue_push_head(attach->elements, old_ele); > + > + comp_changed = true; > + > + mesh_config_reset(attach->cfg, &db_node); > + free_db_storage(&db_node); > + } > + > attach_entry = l_queue_get_entries(attach->elements); > node_entry = l_queue_get_entries(node->elements); > > @@ -1384,6 +1556,10 @@ static bool attach_req_node(struct mesh_node > *attach, struct mesh_node *node) > > attach_entry = attach_entry->next; > node_entry = node_entry->next; > + > + /* Only need the Primary element during Composition > change */ > + if (comp_changed) > + break; > } > > mesh_agent_remove(attach->agent); > @@ -1399,8 +1575,12 @@ static bool attach_req_node(struct mesh_node > *attach, struct mesh_node *node) > node->owner = NULL; > > update_composition(node, attach); > + > update_model_options(node, attach); > > + if (comp_changed) > + node->elements = NULL; > + > node_remove(node); > > return true; > @@ -1499,16 +1679,7 @@ static void get_managed_objects_cb(struct > l_dbus_message *msg, void *user_data) > > node->num_ele = num_ele; > > - if (req->type != REQUEST_TYPE_ATTACH) { > - /* Generate node configuration for a brand new node > */ > - if (!create_node_config(node, node->uuid)) > - goto fail; > - > - /* Create node composition */ > - if (!create_node_comp(node)) > - goto fail; > - } else if (!check_req_node(req)) > - /* Check the integrity of the node composition */ > + if (!check_req_node(req)) > goto fail; > > switch (req->type) { > diff --git a/mesh/node.h b/mesh/node.h > index 2e3d89812..a98945223 100644 > --- a/mesh/node.h > +++ b/mesh/node.h > @@ -38,6 +38,8 @@ uint16_t node_get_primary_net_idx(struct mesh_node > *node); > void node_set_token(struct mesh_node *node, uint8_t token[8]); > const uint8_t *node_get_token(struct mesh_node *node); > const uint8_t *node_get_device_key(struct mesh_node *node); > +bool node_get_device_key_candidate(struct mesh_node *node, uint8_t > *key); > +void node_finalize_candidate(struct mesh_node *node); > void node_set_num_elements(struct mesh_node *node, uint8_t num_ele); > uint8_t node_get_num_elements(struct mesh_node *node); > uint8_t node_default_ttl_get(struct mesh_node *node); > @@ -89,3 +91,4 @@ const char *node_get_storage_dir(struct mesh_node > *node); > bool node_load_from_storage(const char *storage_dir); > void node_finalize_new_node(struct mesh_node *node, struct mesh_io > *io); > void node_property_changed(struct mesh_node *node, const char > *property); > +bool node_refresh(struct mesh_node *node, bool hard, void > *prov_info); > diff --git a/mesh/pb-adv.c b/mesh/pb-adv.c > index 180b16258..385d81d65 100644 > --- a/mesh/pb-adv.c > +++ b/mesh/pb-adv.c > @@ -219,7 +219,7 @@ static void tx_timeout(struct l_timeout *timeout, > void *user_data) > cb(user_data, 1); > } > > -static void pb_adv_tx(void *user_data, void *data, uint16_t len) > +static void pb_adv_tx(void *user_data, const void *data, uint16_t > len) > { > struct pb_adv_session *session = user_data; > > @@ -478,7 +478,7 @@ static void pb_adv_packet(void *user_data, const > uint8_t *pkt, uint16_t len) > bool pb_adv_reg(bool initiator, mesh_prov_open_func_t open_cb, > mesh_prov_close_func_t close_cb, > mesh_prov_receive_func_t rx_cb, mesh_prov_ack_func_t > ack_cb, > - uint8_t uuid[16], void *user_data) > + const uint8_t *uuid, void *user_data) > { > struct pb_adv_session *session, *old_session; > > diff --git a/mesh/pb-adv.h b/mesh/pb-adv.h > index 5b1e03dae..e33ba8e35 100644 > --- a/mesh/pb-adv.h > +++ b/mesh/pb-adv.h > @@ -11,5 +11,5 @@ > bool pb_adv_reg(bool initiator, mesh_prov_open_func_t open_cb, > mesh_prov_close_func_t close_cb, > mesh_prov_receive_func_t rx_cb, mesh_prov_ack_func_t > ack_cb, > - uint8_t uuid[16], void *user_data); > + const uint8_t *uuid, void *user_data); > void pb_adv_unreg(void *user_data); > diff --git a/mesh/prov-acceptor.c b/mesh/prov-acceptor.c > index bf8c573da..fd9d4cd5d 100644 > --- a/mesh/prov-acceptor.c > +++ b/mesh/prov-acceptor.c > @@ -22,6 +22,7 @@ > #include "mesh/net.h" > #include "mesh/prov.h" > #include "mesh/provision.h" > +#include "mesh/remprv.h" > #include "mesh/pb-adv.h" > #include "mesh/mesh.h" > #include "mesh/agent.h" > @@ -169,9 +170,6 @@ static void acp_prov_open(void *user_data, > prov_trans_tx_t trans_tx, > prov->transport != transport) > return; > > - if (transport != PB_ADV) > - return; > - > prov->trans_tx = trans_tx; > prov->transport = transport; > prov->trans_data = trans_data; > @@ -425,9 +423,10 @@ static bool prov_start_check(struct prov_start > *start, > return true; > } > > -static void acp_prov_rx(void *user_data, const uint8_t *data, > uint16_t len) > +static void acp_prov_rx(void *user_data, const void *dptr, uint16_t > len) > { > struct mesh_prov_acceptor *rx_prov = user_data; > + const uint8_t *data = dptr; > struct mesh_prov_node_info *info; > struct prov_fail_msg fail; > uint8_t type = *data++; > @@ -654,14 +653,19 @@ static void acp_prov_rx(void *user_data, const > uint8_t *data, uint16_t len) > info->flags = prov->rand_auth_workspace[18]; > info->iv_index = l_get_be32(prov->rand_auth_workspace > + 19); > info->unicast = l_get_be16(prov->rand_auth_workspace > + 23); > + info->num_ele = prov->conf_inputs.caps.num_ele; > + > + /* Send prov complete */ > + prov->rand_auth_workspace[0] = PROV_COMPLETE; > + prov->trans_tx(prov->trans_data, > + prov->rand_auth_workspace, 1); > > result = prov->cmplt(prov->caller_data, > PROV_ERR_SUCCESS, info); > prov->cmplt = NULL; > l_free(info); > > if (result) { > - prov->rand_auth_workspace[0] = PROV_COMPLETE; > - prov_send(prov, prov->rand_auth_workspace, > 1); > + l_debug("PROV_COMPLETE"); > goto cleanup; > } else { > fail.reason = PROV_ERR_UNEXPECTED_ERR; > @@ -721,7 +725,7 @@ static void acp_prov_ack(void *user_data, uint8_t > msg_num) > > > /* This starts unprovisioned device beacon */ > -bool acceptor_start(uint8_t num_ele, uint8_t uuid[16], > +bool acceptor_start(uint8_t num_ele, uint8_t *uuid, > uint16_t algorithms, uint32_t timeout, > struct mesh_agent *agent, > mesh_prov_acceptor_complete_func_t complete_cb, > @@ -733,8 +737,10 @@ bool acceptor_start(uint8_t num_ele, uint8_t > uuid[16], > uint8_t len = sizeof(beacon) - sizeof(uint32_t); > bool result; > > - /* Invoked from Join() method in mesh-api.txt, to join a > - * remote mesh network. > + /* > + * Invoked from Join() method in mesh-api.txt, to join a > + * remote mesh network. May also be invoked with a NULL > + * uuid to perform a Device Key Refresh procedure. > */ > > if (prov) > @@ -752,37 +758,50 @@ bool acceptor_start(uint8_t num_ele, uint8_t > uuid[16], > > caps = mesh_agent_get_caps(agent); > > - /* TODO: Should we sanity check values here or elsewhere? */ > prov->conf_inputs.caps.num_ele = num_ele; > - prov->conf_inputs.caps.pub_type = caps->pub_type; > - prov->conf_inputs.caps.static_type = caps->static_type; > - prov->conf_inputs.caps.output_size = caps->output_size; > - prov->conf_inputs.caps.input_size = caps->input_size; > - > - /* Store UINT16 values in Over-the-Air order, in packed > structure > - * for crypto inputs > - */ > l_put_be16(algorithms, &prov->conf_inputs.caps.algorithms); > - l_put_be16(caps->output_action, &prov- > >conf_inputs.caps.output_action); > - l_put_be16(caps->input_action, &prov- > >conf_inputs.caps.input_action); > - > - /* Compose Unprovisioned Beacon */ > - memcpy(beacon + 2, uuid, 16); > - l_put_be16(caps->oob_info, beacon + 18); > - if (caps->oob_info & OOB_INFO_URI_HASH){ > - l_put_be32(caps->uri_hash, beacon + 20); > - len += sizeof(uint32_t); > + > + if (caps) { > + /* TODO: Should we sanity check values here or > elsewhere? */ > + prov->conf_inputs.caps.pub_type = caps->pub_type; > + prov->conf_inputs.caps.static_type = caps- > >static_type; > + prov->conf_inputs.caps.output_size = caps- > >output_size; > + prov->conf_inputs.caps.input_size = caps->input_size; > + > + /* Store UINT16 values in Over-the-Air order, in > packed > + * structure for crypto inputs > + */ > + l_put_be16(caps->output_action, > + &prov- > >conf_inputs.caps.output_action); > + l_put_be16(caps->input_action, > + &prov- > >conf_inputs.caps.input_action); > + > + /* Populate Caps fields of beacon */ > + l_put_be16(caps->oob_info, beacon + 18); > + if (caps->oob_info & OOB_INFO_URI_HASH) { > + l_put_be32(caps->uri_hash, beacon + 20); > + len += sizeof(uint32_t); > + } > } > > - /* Infinitely Beacon until Canceled, or Provisioning Starts > */ > - result = mesh_send_pkt(0, 500, beacon, len); > + if (uuid) { > + /* Compose Unprovisioned Beacon */ > + memcpy(beacon + 2, uuid, 16); > + > + /* Infinitely Beacon until Canceled, or Provisioning > Starts */ > + result = mesh_send_pkt(0, 500, beacon, len); > > - if (!result) > - goto error_fail; > + if (!result) > + goto error_fail; > > - /* Always register for PB-ADV */ > - result = pb_adv_reg(false, acp_prov_open, acp_prov_close, > acp_prov_rx, > - acp_prov_ack, uuid, > prov); > + /* Always register for PB-ADV */ > + result = pb_adv_reg(false, acp_prov_open, > acp_prov_close, > + acp_prov_rx, acp_prov_ack, > uuid, prov); > + } else { > + /* Run Device Key Refresh Procedure */ > + result = register_nppi_acceptor(acp_prov_open, > acp_prov_close, > + acp_prov_rx, acp_prov_ack, > prov); > + } > > if (result) > return true; > diff --git a/mesh/prov-initiator.c b/mesh/prov-initiator.c > index c62577523..653f3ae3e 100644 > --- a/mesh/prov-initiator.c > +++ b/mesh/prov-initiator.c > @@ -21,10 +21,12 @@ > #include "mesh/crypto.h" > #include "mesh/net.h" > #include "mesh/node.h" > +#include "mesh/model.h" > #include "mesh/keyring.h" > #include "mesh/prov.h" > #include "mesh/provision.h" > #include "mesh/pb-adv.h" > +#include "mesh/remprv.h" > #include "mesh/mesh.h" > #include "mesh/agent.h" > #include "mesh/error.h" > @@ -82,12 +84,16 @@ struct mesh_prov_initiator { > struct l_timeout *timeout; > uint32_t to_secs; > enum int_state state; > - enum trans_type transport; > uint16_t net_idx; > + uint16_t svr_idx; > uint16_t unicast; > + uint16_t server; > + uint8_t transport; > uint8_t material; > uint8_t expected; > int8_t previous; > + uint8_t out_num; > + uint8_t rpr_state; > struct conf_input conf_inputs; > uint8_t calc_key[16]; > uint8_t salt[16]; > @@ -100,14 +106,23 @@ struct mesh_prov_initiator { > uint8_t uuid[16]; > }; > > +struct scan_req { > + mesh_prov_initiator_scan_result_t scan_result; > + struct mesh_node *node; > + int count; > +}; > + > static struct mesh_prov_initiator *prov = NULL; > +static struct l_queue *scans; > > static void initiator_free(void) > { > - if (prov) > + if (prov) { > l_timeout_remove(prov->timeout); > > - mesh_send_cancel(&pkt_filter, sizeof(pkt_filter)); > + if (!prov->server) > + mesh_send_cancel(&pkt_filter, > sizeof(pkt_filter)); > + } > > pb_adv_unreg(prov); > > @@ -119,6 +134,15 @@ static void int_prov_close(void *user_data, > uint8_t reason) > { > struct mesh_prov_initiator *prov = user_data; > struct mesh_prov_node_info info; > + uint8_t msg[4]; > + int n; > + > + if (prov->server) { > + n = mesh_model_opcode_set(OP_REM_PROV_LINK_CLOSE, > msg); > + msg[n++] = reason == PROV_ERR_SUCCESS ? 0x00 : 0x02; > + mesh_model_send(prov->node, 0, prov->server, > APP_IDX_DEV_REMOTE, > + prov->svr_idx, DEFAULT_TTL, true, n, > msg); > + } > > if (reason != PROV_ERR_SUCCESS) { > prov->complete_cb(prov->caller_data, reason, NULL); > @@ -626,9 +650,10 @@ static void int_prov_start_auth(const struct > mesh_agent_prov_caps *prov_caps, > } > } > > -static void int_prov_rx(void *user_data, const uint8_t *data, > uint16_t len) > +static void int_prov_rx(void *user_data, const void *dptr, uint16_t > len) > { > struct mesh_prov_initiator *rx_prov = user_data; > + const uint8_t *data = dptr; > uint8_t *out; > uint8_t type = *data++; > uint8_t fail_code[2]; > @@ -651,7 +676,7 @@ static void int_prov_rx(void *user_data, const > uint8_t *data, uint16_t len) > if (type >= L_ARRAY_SIZE(expected_pdu_size) || > len != > expected_pdu_size[type]) { > l_error("Expected PDU size %d, Got %d (type: %2.2x)", > - len, expected_pdu_size[type], type); > + expected_pdu_size[type], len, type); > fail_code[1] = PROV_ERR_INVALID_FORMAT; > goto failure; > } > @@ -773,7 +798,12 @@ static void int_prov_rx(void *user_data, const > uint8_t *data, uint16_t len) > goto failure; > } > > - if (!prov->data_req_cb(prov->caller_data, > + if (prov->transport == PB_NPPI_00 || > + prov->transport == > PB_NPPI_02) { > + /* No App data needed */ > + initiator_prov_data(prov->svr_idx, prov- > >server, > + prov- > >caller_data); > + } else if (!prov->data_req_cb(prov->caller_data, > prov- > >conf_inputs.caps.num_ele)) { > l_error("Provisioning Failed-Data Get"); > fail_code[1] = PROV_ERR_CANT_ASSIGN_ADDR; > @@ -851,6 +881,8 @@ static void int_prov_ack(void *user_data, uint8_t > msg_num) > > static void initiator_open_cb(void *user_data, int err) > { > + uint8_t msg[20]; > + int n; > bool result; > > if (!prov) > @@ -859,18 +891,30 @@ static void initiator_open_cb(void *user_data, > int err) > if (err != MESH_ERROR_NONE) > goto fail; > > - /* Always register for PB-ADV */ > - result = pb_adv_reg(true, int_prov_open, int_prov_close, > int_prov_rx, > - int_prov_ack, prov- > >uuid, prov); > + if (prov->server) { > + n = mesh_model_opcode_set(OP_REM_PROV_LINK_OPEN, > msg); > + > + if (prov->transport <= PB_NPPI_02) { > + msg[n++] = prov->transport; > + } else { > + memcpy(msg + n, prov->uuid, 16); > + n += 16; > + } > + > + result = mesh_model_send(prov->node, 0, prov->server, > + APP_IDX_DEV_REMOTE, prov- > >svr_idx, > + DEFAULT_TTL, true, n, msg); > + } else { > + /* Always register for PB-ADV */ > + result = pb_adv_reg(true, int_prov_open, > int_prov_close, > + int_prov_rx, int_prov_ack, prov- > >uuid, prov); > + } > > if (!result) { > err = MESH_ERROR_FAILED; > goto fail; > } > > - if (!prov) > - return; > - > prov->start_cb(prov->caller_data, MESH_ERROR_NONE); > return; > fail: > @@ -878,10 +922,20 @@ fail: > initiator_free(); > } > > -bool initiator_start(enum trans_type transport, > - uint8_t uuid[16], > - uint16_t max_ele, > - uint32_t timeout, /* in seconds from mesh.conf */ > +static void initiate_to(struct l_timeout *timeout, void *user_data) > +{ > + struct mesh_prov_initiator *rx_prov = user_data; > + > + if (rx_prov != prov) { > + l_timeout_remove(timeout); > + return; > + } > + > + int_prov_close(user_data, PROV_ERR_TIMEOUT); > +} > + > +bool initiator_start(uint8_t transport, uint16_t server, uint16_t > svr_idx, > + uint8_t uuid[16], uint16_t max_ele, uint32_t timeout, > struct mesh_agent *agent, > mesh_prov_initiator_start_func_t start_cb, > mesh_prov_initiator_data_req_func_t data_req_cb, > @@ -904,6 +958,10 @@ bool initiator_start(enum trans_type transport, > prov->data_req_cb = data_req_cb; > prov->caller_data = caller_data; > prov->previous = -1; > + prov->server = server; > + prov->svr_idx = svr_idx; > + prov->transport = transport; > + prov->timeout = l_timeout_create(timeout, initiate_to, prov, > NULL); > memcpy(prov->uuid, uuid, 16); > > mesh_agent_refresh(prov->agent, initiator_open_cb, prov); > @@ -915,3 +973,182 @@ void initiator_cancel(void *user_data) > { > initiator_free(); > } > + > +static void rpr_tx(void *user_data, const void *data, uint16_t len) > +{ > + struct mesh_prov_initiator *prov = user_data; > + uint8_t msg[72]; > + int n; > + > + n = mesh_model_opcode_set(OP_REM_PROV_PDU_SEND, msg); > + msg[n++] = ++prov->out_num; > + memcpy(msg + n, data, len); > + l_debug("Send OB %2.2x, with packet type %d", msg[n], prov- > >out_num); > + n += len; > + > + prov->rpr_state = PB_REMOTE_STATE_OB_PKT_TX; > + mesh_model_send(prov->node, 0, prov->server, > APP_IDX_DEV_REMOTE, > + prov->svr_idx, DEFAULT_TTL, true, n, > msg); > +} > + > +static bool match_req_node(const void *a, const void *b) > +{ > + const struct scan_req *req = a; > + const struct mesh_node *node = b; > + > + return req->node == node; > +} > + > +static bool remprv_cli_pkt(uint16_t src, uint16_t unicast, uint16_t > app_idx, > + uint16_t net_idx, const > uint8_t *data, > + uint16_t size, const void > *user_data) > +{ > + struct mesh_node *node = (struct mesh_node *) user_data; > + const uint8_t *pkt = data; > + struct scan_req *req; > + uint32_t opcode; > + uint16_t n; > + > + if (mesh_model_opcode_get(pkt, size, &opcode, &n)) { > + size -= n; > + pkt += n; > + } else > + return false; > + > + if (opcode < OP_REM_PROV_SCAN_CAP_GET || > + opcode > > OP_REM_PROV_PDU_REPORT) > + return false; > + > + if (app_idx != APP_IDX_DEV_REMOTE && app_idx != > APP_IDX_DEV_LOCAL) > + return true; > + > + /* Local Dev key only allowed for Loop-backs */ > + if (app_idx == APP_IDX_DEV_LOCAL && unicast != src) > + return true; > + > + if (prov && (prov->server != src || prov->node != node)) > + return true; > + > + n = 0; > + > + switch (opcode) { > + default: > + return false; > + > + /* Provisioning Opcodes */ > + case OP_REM_PROV_LINK_STATUS: > + if (size != 2 || !prov) > + break; > + > + if (pkt[0] == PB_REM_ERR_SUCCESS) > + prov->rpr_state = pkt[1]; > + > + break; > + > + case OP_REM_PROV_LINK_REPORT: > + if (size != 2 || !prov) > + return true; > + > + if (pkt[0] != PB_REM_ERR_SUCCESS) { > + if (pkt[0] == PB_REM_ERR_CLOSED_BY_DEVICE || > + pkt[0] == > PB_REM_ERR_CLOSED_BY_SERVER) > + int_prov_close(prov, pkt[1]); > + > + break; > + } > + > + > + if (prov->rpr_state == PB_REMOTE_STATE_LINK_OPENING) > + int_prov_open(prov, rpr_tx, prov, prov- > >transport); > + else if (prov->rpr_state == > PB_REMOTE_STATE_LINK_CLOSING) { > + prov->rpr_state = PB_REMOTE_STATE_IDLE; > + int_prov_close(prov, pkt[1]); > + break; > + } > + > + prov->rpr_state = pkt[1]; > + > + break; > + > + case OP_REM_PROV_PDU_REPORT: > + int_prov_rx(prov, pkt + 1, size - 1); > + break; > + > + case OP_REM_PROV_PDU_OB_REPORT: > + if (size != 1 || !prov) > + break; > + > + l_debug("Got Ack for OB %d", pkt[0]); > + if (prov->rpr_state == PB_REMOTE_STATE_OB_PKT_TX && > + pkt[0] == > prov->out_num) > + int_prov_ack(prov, pkt[0]); > + > + break; > + > + /* Scan Opcodes */ > + case OP_REM_PROV_SCAN_CAP_STATUS: > + case OP_REM_PROV_SCAN_STATUS: > + break; > + > + case OP_REM_PROV_SCAN_REPORT: > + case OP_REM_PROV_EXT_SCAN_REPORT: > + req = l_queue_find(scans, match_req_node, node); > + if (req) { > + req->scan_result(node, src, > + opcode == > OP_REM_PROV_EXT_SCAN_REPORT, > + pkt, size); > + } > + } > + > + return true; > +} > + > +void initiator_scan_reg(mesh_prov_initiator_scan_result_t > scan_result, > + void > *user_data) > +{ > + struct scan_req *req; > + > + if (!scans) > + scans = l_queue_new(); > + > + req = l_queue_find(scans, match_req_node, user_data); > + if (!req) { > + req = l_new(struct scan_req, 1); > + l_queue_push_head(scans, req); > + } > + > + req->scan_result = scan_result; > + req->node = user_data; > + req->count++; > +} > + > +void initiator_scan_unreg(void *user_data) > +{ > + struct scan_req *req; > + > + req = l_queue_find(scans, match_req_node, user_data); > + if (req) { > + req->count--; > + if (!req->count) { > + l_queue_remove(scans, req); > + l_free(req); > + } > + } > +} > + > +static void remprv_cli_unregister(void *user_data) > +{ > +} > + > +static const struct mesh_model_ops ops = { > + .unregister = remprv_cli_unregister, > + .recv = remprv_cli_pkt, > + .bind = NULL, > + .sub = NULL, > + .pub = NULL > +}; > + > +void remote_prov_client_init(struct mesh_node *node, uint8_t > ele_idx) > +{ > + mesh_model_register(node, ele_idx, REM_PROV_CLI_MODEL, &ops, > node); > +} > diff --git a/mesh/prov.h b/mesh/prov.h > index 99e864c50..e86668fe4 100644 > --- a/mesh/prov.h > +++ b/mesh/prov.h > @@ -39,14 +39,14 @@ enum mesh_prov_mode { > > struct mesh_prov; > > -typedef void (*prov_trans_tx_t)(void *trans_data, void *data, > uint16_t len); > +typedef void (*prov_trans_tx_t)(void *tx_data, const void *data, > uint16_t len); > typedef void (*mesh_prov_open_func_t)(void *user_data, > prov_trans_tx_t trans_tx, > void *trans_data, uint8_t > trans_type); > > typedef void (*mesh_prov_close_func_t)(void *user_data, uint8_t > reason); > typedef void (*mesh_prov_send_func_t)(bool success, struct mesh_prov > *prov); > typedef void (*mesh_prov_ack_func_t)(void *user_data, uint8_t > msg_num); > -typedef void (*mesh_prov_receive_func_t)(void *user_data, const > uint8_t *data, > +typedef void (*mesh_prov_receive_func_t)(void *user_data, const void > *data, > uint1 > 6_t size); > > > diff --git a/mesh/provision.h b/mesh/provision.h > index 1634c4d40..cfeb6deba 100644 > --- a/mesh/provision.h > +++ b/mesh/provision.h > @@ -70,10 +70,11 @@ struct mesh_agent; > #define OOB_INFO_URI_HASH 0x0002 > > /* PB_REMOTE not supported from unprovisioned state */ > -enum trans_type { > - PB_ADV = 0, > - PB_GATT, > -}; > +#define PB_NPPI_00 0x00 > +#define PB_NPPI_01 0x01 > +#define PB_NPPI_02 0x02 > +#define PB_ADV 0x03 /* Internal only, and may be reassigned > */ > +#define PB_GATT 0x04 /* Internal only, and may be > reassigned */ > > #define PROV_FLAG_KR 0x01 > #define PROV_FLAG_IVU 0x02 > @@ -101,15 +102,21 @@ typedef bool > (*mesh_prov_initiator_complete_func_t)(void *user_data, > uint8_t status, > struct mesh_prov_node_info > *info); > > +typedef void (*mesh_prov_initiator_scan_result_t)(void *user_data, > + uint16_t server, bool > extended, > + const uint8_t *data, uint16_t > len); > + > /* This starts unprovisioned device beacon */ > -bool acceptor_start(uint8_t num_ele, uint8_t uuid[16], > +bool acceptor_start(uint8_t num_ele, uint8_t *uuid, > uint16_t algorithms, uint32_t timeout, > struct mesh_agent *agent, > mesh_prov_acceptor_complete_func_t > complete_cb, > void *caller_data); > void acceptor_cancel(void *user_data); > > -bool initiator_start(enum trans_type transport, > +bool initiator_start(uint8_t transport, > + uint16_t server, > + uint16_t svr_idx, > uint8_t uuid[16], > uint16_t max_ele, > uint32_t timeout, /* in seconds from mesh.conf */ > @@ -120,3 +127,7 @@ bool initiator_start(enum trans_type transport, > void *node, void *caller_data); > void initiator_prov_data(uint16_t net_idx, uint16_t primary, void > *caller_data); > void initiator_cancel(void *caller_data); > + > +void initiator_scan_reg(mesh_prov_initiator_scan_result_t > scan_result, > + void > *user_data); > +void initiator_scan_unreg(void *caller_data); > diff --git a/mesh/remprv-server.c b/mesh/remprv-server.c > new file mode 100644 > index 000000000..e24758093 > --- /dev/null > +++ b/mesh/remprv-server.c > @@ -0,0 +1,907 @@ > +/* > + * > + * BlueZ - Bluetooth protocol stack for Linux > + * > + * Copyright (C) 2020 Intel Corporation. All rights reserved. > + * > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later > version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > GNU > + * Lesser General Public License for more details. > + * > + */ > + > +#ifdef HAVE_CONFIG_H > +#include <config.h> > +#endif > + > +#include <sys/time.h> > +#include <ell/ell.h> > + > +#include "src/shared/ad.h" > + > +#include "mesh/mesh-defs.h" > +#include "mesh/mesh-io.h" > +#include "mesh/util.h" > +#include "mesh/node.h" > +#include "mesh/net.h" > +#include "mesh/appkey.h" > +#include "mesh/model.h" > +#include "mesh/prov.h" > +#include "mesh/provision.h" > +#include "mesh/pb-adv.h" > +#include "mesh/remprv.h" > + > +#define EXT_LIST_SIZE 60 > + > +#define RPR_DEV_KEY 0x00 > +#define RPR_ADDR 0x01 > +#define RPR_COMP 0x02 > +#define RPR_ADV 0xFF /* Internal use only*/ > + > +struct rem_scan_data { > + struct mesh_node *node; > + struct l_timeout *timeout; > + uint8_t *list; > + uint16_t client; > + uint16_t oob_info; > + uint16_t net_idx; > + uint8_t state; > + uint8_t scanned_limit; > + uint8_t addr[6]; > + uint8_t uuid[16]; > + uint8_t to_secs; > + uint8_t rxed_ads; > + uint8_t ext_cnt; > + bool fltr; > + uint8_t ext[0]; > +}; > + > +static struct rem_scan_data *rpb_scan; > + > +struct rem_prov_data { > + struct mesh_node *node; > + struct l_timeout *timeout; > + void *trans_data; > + uint16_t client; > + uint16_t net_idx; > + uint8_t svr_pdu_num; > + uint8_t cli_pdu_num; > + uint8_t state; > + uint8_t nppi_proc; > + union { > + struct { > + mesh_prov_open_func_t open_cb; > + mesh_prov_close_func_t close_cb; > + mesh_prov_receive_func_t rx_cb; > + mesh_prov_ack_func_t ack_cb; > + struct mesh_prov_node_info info; > + } nppi; > + struct { > + uint8_t uuid[17]; > + prov_trans_tx_t tx; > + } adv; > + } u; > +}; > + > +static struct rem_prov_data *rpb_prov; > + > +static const uint8_t prvb[2] = {BT_AD_MESH_BEACON, 0x00}; > +static const uint8_t pkt_filter = BT_AD_MESH_PROV; > +static const char *name = "Test Name"; > + > +static const uint8_t zero[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, > 0, 0, 0, 0}; > + > +static void srv_open(void *user_data, prov_trans_tx_t adv_tx, > + void *trans_data, uint8_t > nppi_proc) > +{ > + struct rem_prov_data *prov = user_data; > + uint8_t msg[5]; > + int n; > + > + if (prov != rpb_prov || prov->state != > PB_REMOTE_STATE_LINK_OPENING) > + return; > + > + l_debug("Remote Link open confirmed"); > + prov->u.adv.tx = adv_tx; > + prov->trans_data = trans_data; > + prov->state = PB_REMOTE_STATE_LINK_ACTIVE; > + > + n = mesh_model_opcode_set(OP_REM_PROV_LINK_REPORT, msg); > + msg[n++] = PB_REM_ERR_SUCCESS; > + msg[n++] = prov->state; > + > + mesh_model_send(prov->node, 0, prov->client, > APP_IDX_DEV_LOCAL, > + prov->net_idx, DEFAULT_TTL, true, n, > msg); > +} > + > +static void srv_rx(void *user_data, const void *dptr, uint16_t len) > +{ > + struct rem_prov_data *prov = user_data; > + const uint8_t *data = dptr; > + uint8_t msg[69]; > + int n; > + > + if (prov != rpb_prov || prov->state < > PB_REMOTE_STATE_LINK_ACTIVE || > + len > > 65) > + return; > + > + l_debug("Remote PB IB-PDU"); > + > + prov->svr_pdu_num++; > + n = mesh_model_opcode_set(OP_REM_PROV_PDU_REPORT, msg); > + msg[n++] = prov->svr_pdu_num; > + memcpy(msg + n, data, len); > + n += len; > + > + mesh_model_send(prov->node, 0, prov->client, > APP_IDX_DEV_LOCAL, > + prov->net_idx, DEFAULT_TTL, true, n, > msg); > +} > + > +static void srv_ack(void *user_data, uint8_t msg_num) > +{ > + struct rem_prov_data *prov = user_data; > + uint8_t msg[4]; > + int n; > + > + if (prov != rpb_prov || prov->state != > PB_REMOTE_STATE_OB_PKT_TX) > + return; > + > + l_debug("Remote PB ACK"); > + > + prov->state = PB_REMOTE_STATE_LINK_ACTIVE; > + n = mesh_model_opcode_set(OP_REM_PROV_PDU_OB_REPORT, msg); > + msg[n++] = prov->cli_pdu_num; > + > + mesh_model_send(prov->node, 0, prov->client, > APP_IDX_DEV_LOCAL, > + prov->net_idx, DEFAULT_TTL, true, n, > msg); > +} > + > +static void srv_close(void *user_data, uint8_t reason) > +{ > + struct rem_prov_data *prov = user_data; > + uint8_t msg[4]; > + int n; > + > + if (prov != rpb_prov || prov->state < > PB_REMOTE_STATE_LINK_ACTIVE) > + return; > + > + l_debug("Remote PB Close"); > + > + prov->state = PB_REMOTE_STATE_LINK_CLOSING; > + n = mesh_model_opcode_set(OP_REM_PROV_LINK_REPORT, msg); > + msg[n++] = prov->state; > + msg[n++] = reason; > + > + mesh_model_send(prov->node, 0, prov->client, > APP_IDX_DEV_LOCAL, > + prov->net_idx, DEFAULT_TTL, true, n, > msg); > +} > + > +static void send_prov_status(struct rem_prov_data *prov, uint8_t > status) > +{ > + uint16_t n; > + uint8_t msg[5]; > + bool segmented = prov->state == PB_REMOTE_STATE_LINK_CLOSING > ? > + true > : false; > + > + n = mesh_model_opcode_set(OP_REM_PROV_LINK_STATUS, msg); > + msg[n++] = status; > + msg[n++] = prov->state; > + > + l_info("RPB-Link Status(%d): dst %4.4x", prov->state, prov- > >client); > + > + mesh_model_send(prov->node, 0, prov->client, > APP_IDX_DEV_LOCAL, > + prov->net_idx, DEFAULT_TTL, > segmented, n, msg); > +} > + > +static void remprv_prov_cancel(struct l_timeout *timeout, > + void *user_data) > +{ > + struct rem_prov_data *prov = user_data; > + > + if (prov != rpb_prov) > + return; > + > + l_timeout_remove(prov->timeout); > + l_free(prov); > + rpb_prov = NULL; > +} > + > +static void deregister_ext_ad_type(uint8_t ad_type) > +{ > + uint8_t short_ad; > + > + switch (ad_type) { > + case BT_AD_MESH_BEACON: > + case BT_AD_MESH_DATA: > + case BT_AD_MESH_PROV: > + case BT_AD_UUID16_SOME: > + case BT_AD_UUID32_SOME: > + case BT_AD_UUID128_SOME: > + case BT_AD_NAME_SHORT: > + return; > + > + case BT_AD_UUID16_ALL: > + case BT_AD_UUID32_ALL: > + case BT_AD_UUID128_ALL: > + case BT_AD_NAME_COMPLETE: > + /* Automatically get short versions */ > + short_ad = ad_type - 1; > + mesh_io_deregister_recv_cb(NULL, &short_ad, 1); > + > + /* fall through */ > + default: > + mesh_io_deregister_recv_cb(NULL, &ad_type, 1); > + break; > + } > +} > + > +static void remprv_scan_cancel(struct l_timeout *timeout, > + void *user_data) > +{ > + struct rem_scan_data *scan = user_data; > + uint8_t msg[22 + EXT_LIST_SIZE]; > + uint16_t i, n; > + > + if (!scan || scan != rpb_scan) > + return; > + > + for (n = 0; n < scan->ext_cnt; n++) > + deregister_ext_ad_type(scan->ext[n]); > + > + if (scan->timeout == timeout) { > + /* Return Extended Results */ > + if (scan->ext_cnt) { > + /* Return Extended Result */ > + n = mesh_model_opcode_set( > + OP_REM_PROV_EXT_SCAN_REPORT, > msg); > + msg[n++] = PB_REM_ERR_SUCCESS; > + memcpy(msg + n, scan->uuid, 16); > + n += 16; > + > + if (scan->oob_info) { > + l_put_le16(0, msg + n); > + n += 2; > + } > + > + i = 0; > + while (scan->list[i]) { > + msg[n++] = scan->list[i]; > + memcpy(msg + n, &scan->list[i + 1], > + scan- > >list[i]); > + n += scan->list[i]; > + i += scan->list[i] + 1; > + } > + } > + } > + > + l_timeout_remove(scan->timeout); > + l_free(scan->list); > + l_free(scan); > + rpb_scan = NULL; > +} > + > +static void scan_pkt(void *user_data, struct mesh_io_recv_info > *info, > + const uint8_t *data, uint16_t > len) > +{ > + struct rem_scan_data *scan = user_data; > + uint8_t msg[22 + EXT_LIST_SIZE]; > + uint16_t i, n; > + uint8_t filled = 0; > + bool report = false; > + > + if (scan != rpb_scan) > + return; > + > + if (scan->ext_cnt) > + goto extended_scan; > + > + /* RX Unprovisioned Beacon */ > + if (data[0] != BT_AD_MESH_BEACON || data[1] || > + (len != 18 && len != 20 && len != 24)) > + return; > + > + data += 2; > + len -= 2; > + > + for (n = 0; !report && n < scan->scanned_limit; n++) { > + if (!memcmp(&scan->list[n * 17 + 1], data, 16)) { > + > + /* Repeat UUID, check RSSI */ > + if ((int8_t) scan->list[n * 17] < info->rssi) > { > + report = true; > + scan->list[n * 17] = (uint8_t) info- > >rssi; > + } > + > + } else if (!memcmp(&scan->list[n * 17 + 1], zero, > 16)) { > + > + /* Found Empty slot */ > + report = true; > + scan->list[n * 17] = (uint8_t) info->rssi; > + memcpy(&scan->list[n * 17 + 1], data, 16); > + } > + > + filled++; > + } > + > + if (!report) > + return; > + > + n = mesh_model_opcode_set(OP_REM_PROV_SCAN_REPORT, msg); > + msg[n++] = (uint8_t) info->rssi; > + memcpy(msg + n, data, len); > + n += len; > + > + /* Always return oob_info, even if it wasn't in beacon */ > + if (len == 16) { > + l_put_le16(0, msg + n); > + n += 2; > + } > + > + goto send_report; > + > +extended_scan: > + if (data[0] == BT_AD_MESH_BEACON && !data[1]) { > + if (len != 18 && len != 20 && len != 24) > + return; > + > + /* Check UUID */ > + if (memcmp(data + 2, scan->uuid, 16)) > + return; > + > + /* Zero AD list if prior data RXed from different > bd_addr */ > + if (memcmp(scan->addr, info->addr, 6)) { > + scan->list[0] = 0; > + scan->rxed_ads = 0; > + } > + > + memcpy(scan->addr, info->addr, 6); > + scan->fltr = true; > + > + if (len >= 20) > + scan->oob_info = l_get_le16(data + 18); > + > + if (scan->rxed_ads != scan->ext_cnt) > + return; > + > + > + } else if (data[0] != BT_AD_MESH_BEACON) { > + if (!scan->fltr || !memcmp(scan->addr, info->addr, > 6)) { > + i = 0; > + while (scan->list[i]) { > + /* check if seen */ > + if (scan->list[i + 1] == data[0]) > + return; > + > + i += scan->list[i] + 1; > + } > + > + /* Overflow Protection */ > + if (i + len + 1 > EXT_LIST_SIZE) > + return; > + > + scan->list[i] = len; > + scan->list[i + len + 1] = 0; > + memcpy(scan->list + i + 1, data, len); > + scan->rxed_ads++; > + } > + > + if (scan->rxed_ads != scan->ext_cnt) > + return; > + > + } else > + return; > + > + n = mesh_model_opcode_set(OP_REM_PROV_EXT_SCAN_REPORT, msg); > + msg[n++] = PB_REM_ERR_SUCCESS; > + memcpy(msg + n, scan->uuid, 16); > + n += 16; > + l_put_le16(scan->oob_info, msg + n); > + n += 2; > + > + i = 0; > + while (scan->list[i]) { > + msg[n++] = scan->list[i]; > + memcpy(msg + n, &scan->list[i + 1], scan->list[i]); > + n += scan->list[i]; > + i += scan->list[i]; > + } > + > +send_report: > + print_packet("App Tx", msg, n); > + mesh_model_send(scan->node, 0, scan->client, > APP_IDX_DEV_LOCAL, > + scan->net_idx, DEFAULT_TTL, true, n, > msg); > + > + /* Clean-up if we are done reporting*/ > + if (filled == scan->scanned_limit || scan->ext_cnt) > + remprv_scan_cancel(NULL, scan); > +} > + > +static bool register_ext_ad_type(uint8_t ad_type, struct > rem_scan_data *scan) > +{ > + uint8_t short_ad; > + > + switch (ad_type) { > + case BT_AD_MESH_PROV: > + case BT_AD_UUID16_SOME: > + case BT_AD_UUID32_SOME: > + case BT_AD_UUID128_SOME: > + case BT_AD_NAME_SHORT: > + /* Illegal Requests */ > + return false; > + > + case BT_AD_UUID16_ALL: > + case BT_AD_UUID32_ALL: > + case BT_AD_UUID128_ALL: > + case BT_AD_NAME_COMPLETE: > + /* Automatically get short versions */ > + short_ad = ad_type - 1; > + mesh_io_register_recv_cb(NULL, &short_ad, 1, > scan_pkt, scan); > + > + /* fall through */ > + default: > + mesh_io_register_recv_cb(NULL, &ad_type, 1, scan_pkt, > scan); > + > + /* fall through */ > + > + case BT_AD_MESH_BEACON: > + /* Ignored/auto request */ > + break; > + } > + > + return true; > +} > + > +static void link_active(void *user_data) > +{ > + struct rem_prov_data *prov = user_data; > + uint8_t msg[5]; > + int n; > + > + if (prov != rpb_prov || prov->state != > PB_REMOTE_STATE_LINK_OPENING) > + return; > + > + l_debug("Remote Link open confirmed"); > + prov->state = PB_REMOTE_STATE_LINK_ACTIVE; > + > + n = mesh_model_opcode_set(OP_REM_PROV_LINK_REPORT, msg); > + msg[n++] = PB_REM_ERR_SUCCESS; > + msg[n++] = PB_REMOTE_STATE_LINK_ACTIVE; > + > + mesh_model_send(prov->node, 0, prov->client, > APP_IDX_DEV_LOCAL, > + prov->net_idx, DEFAULT_TTL, true, n, > msg); > +} > + > +bool register_nppi_acceptor(mesh_prov_open_func_t open_cb, > + mesh_prov_close_func_t > close_cb, > + mesh_prov_receive_func_t > rx_cb, > + mesh_prov_ack_func_t ack_cb, > + void *user_data) > +{ > + struct rem_prov_data *prov = rpb_prov; > + > + if (!prov || prov->nppi_proc == RPR_ADV) > + return false; > + > + prov->u.nppi.open_cb = open_cb; > + prov->u.nppi.close_cb = close_cb; > + prov->u.nppi.rx_cb = rx_cb; > + prov->u.nppi.ack_cb = ack_cb; > + prov->trans_data = user_data; > + > + open_cb(user_data, srv_rx, prov, prov->nppi_proc); > + > + l_idle_oneshot(link_active, prov, NULL); > + > + return true; > +} > + > +static bool nppi_cmplt(void *user_data, uint8_t status, > + struct mesh_prov_node_info > *info) > +{ > + struct rem_prov_data *prov = user_data; > + > + if (prov != rpb_prov) > + return false; > + > + /* Save new info to apply on Link Close */ > + prov->u.nppi.info = *info; > + return true; > +} > + > +static bool start_dev_key_refresh(struct mesh_node *node, uint8_t > nppi_proc, > + struct rem_prov_data > *prov) > +{ > + uint8_t num_ele = node_get_num_elements(node); > + > + prov->nppi_proc = nppi_proc; > + return acceptor_start(num_ele, NULL, 0x0001, 60, NULL, > nppi_cmplt, > + > prov); > +} > + > +static bool remprv_srv_pkt(uint16_t src, uint16_t unicast, uint16_t > app_idx, > + uint16_t net_idx, const > uint8_t *data, > + uint16_t size, const void > *user_data) > +{ > + struct rem_prov_data *prov = rpb_prov; > + struct rem_scan_data *scan = rpb_scan; > + struct mesh_node *node = (struct mesh_node *) user_data; > + const uint8_t *pkt = data; > + bool segmented = false; > + uint32_t opcode; > + uint8_t msg[69]; > + uint8_t status; > + uint16_t n; > + > + if (app_idx != APP_IDX_DEV_LOCAL) > + return false; > + > + if (mesh_model_opcode_get(pkt, size, &opcode, &n)) { > + size -= n; > + pkt += n; > + } else > + return false; > + > + n = 0; > + > + switch (opcode) { > + default: > + return false; > + > + case OP_REM_PROV_SCAN_CAP_GET: > + if (size != 0) > + return true; > + > + /* Compose Scan Info Status */ > + n = > mesh_model_opcode_set(OP_REM_PROV_SCAN_CAP_STATUS, msg); > + msg[n++] = PB_REMOTE_MAX_SCAN_QUEUE_SIZE; > + msg[n++] = 1; /* Active Scanning Supported */ > + break; > + > + case OP_REM_PROV_EXT_SCAN_START: > + if (!size || !pkt[0]) > + return true; > + > + /* Size check the message */ > + if (pkt[0] + 18 == size) { > + /* Range check the Timeout */ > + if (!pkt[size - 1] || pkt[size - 1] > 5) > + return true; > + } else if (pkt[0] + 1 != size) > + return true; > + > + /* Get local device extended info */ > + if (pkt[0] + 18 != size) { > + n = mesh_model_opcode_set( > + OP_REM_PROV_EXT_SCAN_REPORT, > msg); > + msg[n++] = PB_REM_ERR_SUCCESS; > + memcpy(msg + n, node_uuid_get(node), 16); > + n += 16; > + l_put_le16(0, msg + n); > + n += 2; > + size--; > + pkt++; > + > + while (size--) { > + if (*pkt++ == BT_AD_NAME_COMPLETE) { > + msg[n] = strlen(name) + 1; > + if (msg[n] > sizeof(msg) - n > - 1) > + msg[n] = sizeof(msg) > - n - 1; > + n++; > + msg[n++] = > BT_AD_NAME_COMPLETE; > + memcpy(&msg[n], name, msg[n - > 2] - 1); > + n += msg[n - 2] - 1; > + goto send_pkt; > + } > + } > + > + /* Send internal report */ > + l_debug("Send internal extended info %d", n); > + goto send_pkt; > + } > + > + status = PB_REM_ERR_SUCCESS; > + if (scan) { > + if (scan->client != src || scan->node != node > || > + scan->ext_cnt != > pkt[0]) > + status = > PB_REM_ERR_SCANNING_CANNOT_START; > + else if (memcmp(scan->ext, pkt + 1, pkt[0])) > + status = > PB_REM_ERR_SCANNING_CANNOT_START; > + else if (memcmp(scan->uuid, pkt + 2, 16)) > + status = > PB_REM_ERR_SCANNING_CANNOT_START; > + } > + > + if (status != PB_REM_ERR_SUCCESS) { > + n = > mesh_model_opcode_set(OP_REM_PROV_EXT_SCAN_REPORT, > + > msg); > + msg[n++] = status; > + memset(msg + n, 0, 16); > + n += 16; > + segmented = true; > + break; > + } > + > + /* Ignore extended requests while already scanning */ > + if (scan) > + return true; > + > + scan = (void *) l_new(uint8_t, > + sizeof(struct rem_scan_data) > + pkt[0]); > + > + /* Validate and register Extended AD types */ > + for (n = 0; n < pkt[0]; n++) { > + if (!register_ext_ad_type(pkt[1 + n], scan)) > { > + /* Invalid AD type detected -- Undo > */ > + while (n--) > + deregister_ext_ad_type(pkt[1 > + n]); > + > + l_free(scan); > + return true; > + } > + } > + > + rpb_scan = scan; > + scan->client = src; > + scan->net_idx = net_idx; > + memcpy(scan->uuid, pkt + size - 17, 16); > + scan->ext_cnt = pkt[0]; > + memcpy(scan->ext, pkt + 1, pkt[0]); > + scan->list = l_malloc(EXT_LIST_SIZE); > + scan->list[0] = 0; > + > + mesh_io_register_recv_cb(NULL, prvb, sizeof(prvb), > + scan_ > pkt, scan); > + > + scan->timeout = l_timeout_create(pkt[size-1], > + remprv_scan_cancel, > scan, NULL); > + return true; > + > + case OP_REM_PROV_SCAN_START: > + if (size != 2 && size != 18) > + return true; > + > + /* Reject Timeout of Zero */ > + if (!pkt[1]) > + return true; > + > + status = PB_REM_ERR_SUCCESS; > + if (scan) { > + if (scan->ext_cnt || scan->client != src || > + scan->node != > node) > + status = > PB_REM_ERR_SCANNING_CANNOT_START; > + else if (!!(scan->fltr) != !!(size != 18)) > + status = > PB_REM_ERR_SCANNING_CANNOT_START; > + else if (scan->fltr && memcmp(scan->uuid, pkt > + 2, 16)) > + status = > PB_REM_ERR_SCANNING_CANNOT_START; > + } > + > + if (status != PB_REM_ERR_SUCCESS) { > + n = > mesh_model_opcode_set(OP_REM_PROV_SCAN_STATUS, msg); > + msg[n++] = status; > + msg[n++] = scan ? scan->state : 0; > + msg[n++] = scan ? scan->scanned_limit : > + PB_REMOTE_MAX_SCAN_QU > EUE_SIZE; > + msg[n++] = scan ? scan->to_secs : 0; > + break; > + } > + > + if (!scan) > + scan = l_new(struct rem_scan_data, 1); > + > + rpb_scan = scan; > + > + if (size == 18) { > + memcpy(scan->uuid, pkt + 2, 16); > + scan->fltr = true; > + scan->state = 0x02; /* Limited */ > + } else { > + memset(scan->uuid, 0, 16); > + scan->fltr = false; > + scan->state = 0x01; /* Unlimited */ > + } > + > + scan->client = src; > + scan->net_idx = net_idx; > + scan->node = node; > + > + if (!scan->list) > + scan->list = l_new(uint8_t, > + 23 * > PB_REMOTE_MAX_SCAN_QUEUE_SIZE); > + > + mesh_io_register_recv_cb(NULL, prvb, 2, scan_pkt, > scan); > + > + scan->to_secs = pkt[1]; > + > + if (pkt[0]) > + scan->scanned_limit = pkt[0]; > + else > + scan->scanned_limit = > PB_REMOTE_MAX_SCAN_QUEUE_SIZE; > + > + scan->timeout = l_timeout_create(pkt[1], > + remprv_scan_cancel, scan, > NULL); > + > + /* fall through */ > + > + case OP_REM_PROV_SCAN_GET: > + /* Compose Scan Status */ > + n = mesh_model_opcode_set(OP_REM_PROV_SCAN_STATUS, > msg); > + msg[n++] = PB_REM_ERR_SUCCESS; > + msg[n++] = scan ? scan->state : 0; > + msg[n++] = scan ? scan->scanned_limit : > + PB_REMOTE_MAX_SCAN_QU > EUE_SIZE; > + msg[n++] = scan ? scan->to_secs : 0; > + break; > + > + case OP_REM_PROV_SCAN_STOP: > + if (size != 0 || !scan) > + return true; > + > + remprv_scan_cancel(NULL, scan); > + return true; > + > + case OP_REM_PROV_LINK_GET: > + if (size != 0 || !prov) > + return true; > + > + send_prov_status(prov, PB_REM_ERR_SUCCESS); > + return true; > + > + case OP_REM_PROV_LINK_OPEN: > + /* Sanity check args */ > + if (size != 16 && size != 17 && size != 1) > + return true; > + > + if (size == 17 && (pkt[16] == 0 || pkt[16] > 0x3c)) > + return true; > + > + if (size == 1 && pkt[0] > 0x02) > + return true; > + > + if (prov) { > + if (prov->client != src || prov->node != node > || > + (size == 1 && prov->nppi_proc != > pkt[0]) || > + (size >= 16 && (prov->nppi_proc != > RPR_ADV || > + memcmp(prov->u.adv.uuid, pkt, > 16)))) { > + > + /* Send Reject (in progress) */ > + send_prov_status(prov, > PB_REM_ERR_CANNOT_OPEN); > + n = mesh_model_opcode_set( > + OP_REM_PROV_LINK_STAT > US, msg); > + msg[n++] = PB_REM_ERR_CANNOT_OPEN; > + msg[n++] = > PB_REMOTE_STATE_LINK_ACTIVE; > + break; > + } > + > + /* Send redundant Success */ > + send_prov_status(prov, PB_REM_ERR_SUCCESS); > + return true; > + } > + > + if (scan && scan->client != src && scan->node != > node) { > + n = > mesh_model_opcode_set(OP_REM_PROV_LINK_STATUS, msg); > + msg[n++] = PB_REM_ERR_CANNOT_OPEN; > + msg[n++] = PB_REMOTE_STATE_LINK_ACTIVE; > + break; > + } > + > + print_packet("Remote Prov Link Open", pkt, size); > + > + remprv_scan_cancel(NULL, scan); > + > + rpb_prov = prov = l_new(struct rem_prov_data, 1); > + prov->client = src; > + prov->net_idx = net_idx; > + prov->node = node; > + prov->state = PB_REMOTE_STATE_LINK_OPENING; > + > + if (size == 1) { > + status = start_dev_key_refresh(node, pkt[0], > prov); > + > + } else { > + if (size == 17) > + prov->timeout = > l_timeout_create(pkt[16], > + remprv_prov_cancel, > prov, NULL); > + > + > + prov->nppi_proc = RPR_ADV; > + memcpy(prov->u.adv.uuid, pkt, 16); > + status = pb_adv_reg(true, srv_open, > srv_close, srv_rx, > + srv_ack, pkt, > prov); > + } > + > + if (status) > + send_prov_status(prov, PB_REM_ERR_SUCCESS); > + else { > + n = > mesh_model_opcode_set(OP_REM_PROV_LINK_STATUS, msg); > + msg[n++] = PB_REM_ERR_CANNOT_OPEN; > + msg[n++] = PB_REMOTE_STATE_IDLE; > + remprv_prov_cancel(NULL, prov); > + } > + > + return true; > + > + case OP_REM_PROV_LINK_CLOSE: > + if (size != 1) > + return true; > + > + if (!prov || prov->node != node || prov->client != > src) > + return true; > + > + prov->state = PB_REMOTE_STATE_LINK_CLOSING; > + mesh_io_send_cancel(NULL, &pkt_filter, > sizeof(pkt_filter)); > + send_prov_status(prov, PB_REM_ERR_SUCCESS); > + if (pkt[0] == 0x02) { > + msg[0] = PROV_FAILED; > + msg[1] = PROV_ERR_CANT_ASSIGN_ADDR; > + if (prov->nppi_proc == RPR_ADV) > + prov->u.adv.tx(prov->trans_data, msg, > 2); > + else > + prov->u.nppi.rx_cb(prov->trans_data, > msg, 2); > + } > + > + if (prov->nppi_proc == RPR_ADV) > + pb_adv_unreg(prov); > + > + else if (prov->nppi_proc <= RPR_COMP) { > + /* Hard or Soft refresh of local node, based > on NPPI */ > + node_refresh(prov->node, (prov->nppi_proc == > RPR_ADDR), > + &prov- > >u.nppi.info); > + } > + > + remprv_prov_cancel(NULL, prov); > + > + return true; > + > + case OP_REM_PROV_PDU_SEND: > + if (!prov || prov->node != node || prov->client != > src) > + return true; > + > + if (size < 2) > + return true; > + > + > + prov->cli_pdu_num = *pkt++; > + size--; > + prov->state = PB_REMOTE_STATE_OB_PKT_TX; > + > + if (prov->nppi_proc == RPR_ADV) > + prov->u.adv.tx(prov->trans_data, pkt, size); > + else { > + srv_ack(prov, prov->cli_pdu_num); > + prov->u.nppi.rx_cb(prov->trans_data, pkt, > size); > + } > + > + return true; > + } > + > +send_pkt: > + l_info("PB-SVR: src %4.4x dst %4.4x", unicast, src); > + print_packet("App Tx", msg, n); > + mesh_model_send(node, 0, src, APP_IDX_DEV_LOCAL, > + net_idx, DEFAULT_TTL, segmented, n, > msg); > + > + return true; > +} > + > +static void remprv_srv_unregister(void *user_data) > +{ > +} > + > +static const struct mesh_model_ops ops = { > + .unregister = remprv_srv_unregister, > + .recv = remprv_srv_pkt, > + .bind = NULL, > + .sub = NULL, > + .pub = NULL > +}; > + > +void remote_prov_server_init(struct mesh_node *node, uint8_t > ele_idx) > +{ > + mesh_model_register(node, ele_idx, REM_PROV_SRV_MODEL, &ops, > node); > +} > diff --git a/mesh/remprv.h b/mesh/remprv.h > new file mode 100644 > index 000000000..49b4e2c7c > --- /dev/null > +++ b/mesh/remprv.h > @@ -0,0 +1,78 @@ > +/* > + * > + * BlueZ - Bluetooth protocol stack for Linux > + * > + * Copyright (C) 2020 Intel Corporation. All rights reserved. > + * > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later > version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > GNU > + * Lesser General Public License for more details. > + * > + */ > + > +#define REM_PROV_SRV_MODEL SET_ID(SIG_VENDOR, 0x0004) > +#define REM_PROV_CLI_MODEL SET_ID(SIG_VENDOR, 0x0005) > + > +#define PB_REMOTE_MAX_SCAN_QUEUE_SIZE 5 > + > +#define PB_REMOTE_STATE_IDLE 0x00 > +#define PB_REMOTE_STATE_LINK_OPENING 0x01 > +#define PB_REMOTE_STATE_LINK_ACTIVE 0x02 > +#define PB_REMOTE_STATE_OB_PKT_TX 0x03 > +#define PB_REMOTE_STATE_LINK_CLOSING 0x04 > + > +#define PB_REMOTE_TYPE_LOCAL 0x01 > +#define PB_REMOTE_TYPE_ADV 0x02 > +#define PB_REMOTE_TYPE_GATT 0x04 > + > +#define PB_REMOTE_SCAN_TYPE_NONE 0x00 > +#define PB_REMOTE_SCAN_TYPE_UNLIMITED 0x01 > +#define PB_REMOTE_SCAN_TYPE_LIMITED 0x02 > +#define PB_REMOTE_SCAN_TYPE_DETAILED 0x03 > + > +/* Remote Provisioning Opcode List */ > +#define OP_REM_PROV_SCAN_CAP_GET 0x804F > +#define OP_REM_PROV_SCAN_CAP_STATUS 0x8050 > +#define OP_REM_PROV_SCAN_GET 0x8051 > +#define OP_REM_PROV_SCAN_START 0x8052 > +#define OP_REM_PROV_SCAN_STOP 0x8053 > +#define OP_REM_PROV_SCAN_STATUS 0x8054 > +#define OP_REM_PROV_SCAN_REPORT 0x8055 > +#define OP_REM_PROV_EXT_SCAN_START 0x8056 > +#define OP_REM_PROV_EXT_SCAN_REPORT 0x8057 > +#define OP_REM_PROV_LINK_GET 0x8058 > +#define OP_REM_PROV_LINK_OPEN 0x8059 > +#define OP_REM_PROV_LINK_CLOSE 0x805A > +#define OP_REM_PROV_LINK_STATUS 0x805B > +#define OP_REM_PROV_LINK_REPORT 0x805C > +#define OP_REM_PROV_PDU_SEND 0x805D > +#define OP_REM_PROV_PDU_OB_REPORT 0x805E > +#define OP_REM_PROV_PDU_REPORT 0x805F > + > +/* Remote Provisioning Errors */ > +#define PB_REM_ERR_SUCCESS 0x00 > +#define PB_REM_ERR_SCANNING_CANNOT_START 0x01 > +#define PB_REM_ERR_INVALID_STATE 0x02 > +#define PB_REM_ERR_LIMITED_RESOURCES 0x03 > +#define PB_REM_ERR_CANNOT_OPEN 0x04 > +#define PB_REM_ERR_OPEN_FAILED 0x05 > +#define PB_REM_ERR_CLOSED_BY_DEVICE 0x06 > +#define PB_REM_ERR_CLOSED_BY_SERVER 0x07 > +#define PB_REM_ERR_CLOSED_BY_CLIENT 0x08 > +#define PB_REM_ERR_CLOSED_CANNOT_RX_PDU 0x09 > +#define PB_REM_ERR_CLOSED_CANNOT_TX_PDU 0x0A > + > +void remote_prov_server_init(struct mesh_node *node, uint8_t > ele_idx); > +void remote_prov_client_init(struct mesh_node *node, uint8_t > ele_idx); > +bool register_nppi_acceptor(mesh_prov_open_func_t open_cb, > + mesh_prov_close_func_t > close_cb, > + mesh_prov_receive_func_t > rx_cb, > + mesh_prov_ack_func_t ack_cb, > + void *user_data);
diff --git a/Makefile.mesh b/Makefile.mesh index 3047f362b..e18a169eb 100644 --- a/Makefile.mesh +++ b/Makefile.mesh @@ -26,6 +26,7 @@ mesh_sources = mesh/mesh.h mesh/mesh.c \ mesh/provision.h mesh/prov.h \ mesh/model.h mesh/model.c \ mesh/cfgmod.h mesh/cfgmod-server.c \ + mesh/remprv.h mesh/remprv-server.c \ mesh/mesh-config.h mesh/mesh-config-json.c \ mesh/util.h mesh/util.c \ mesh/dbus.h mesh/dbus.c \ diff --git a/mesh/cfgmod-server.c b/mesh/cfgmod-server.c index be90ef8c5..3d7efc44b 100644 --- a/mesh/cfgmod-server.c +++ b/mesh/cfgmod-server.c @@ -30,8 +30,8 @@ (SET_ID(SIG_VENDOR, l_get_le16(pkt)))) /* Supported composition pages, sorted high to low */ -/* Only page 0 is currently supported */ static const uint8_t supported_pages[] = { + 128, 0 }; diff --git a/mesh/keyring.c b/mesh/keyring.c index 995a4b88f..894fb14fa 100644 --- a/mesh/keyring.c +++ b/mesh/keyring.c @@ -30,9 +30,9 @@ #include "mesh/node.h" #include "mesh/keyring.h" -const char *dev_key_dir = "/dev_keys"; -const char *app_key_dir = "/app_keys"; -const char *net_key_dir = "/net_keys"; +static const char *dev_key_dir = "/dev_keys"; +static const char *app_key_dir = "/app_keys"; +static const char *net_key_dir = "/net_keys"; static int open_key_file(struct mesh_node *node, const char *key_dir, uint16_t idx, int flags) @@ -295,6 +295,7 @@ bool keyring_get_remote_dev_key(struct mesh_node *node, uint16_t unicast, close(fd); } + return result; } @@ -371,6 +372,28 @@ bool keyring_del_remote_dev_key(struct mesh_node *node, uint16_t unicast, return true; } +bool keyring_del_remote_dev_key_all(struct mesh_node *node, uint16_t unicast) +{ + uint8_t dev_key[16]; + uint8_t test_key[16]; + uint8_t cnt = 1; + + if (!keyring_get_remote_dev_key(node, unicast, dev_key)) + return false; + + while (keyring_get_remote_dev_key(node, unicast + cnt, test_key)) { + if (memcmp(dev_key, test_key, sizeof(dev_key))) + break; + + cnt++; + } + + if (cnt > 1) + return keyring_del_remote_dev_key(node, unicast + 1, cnt - 1); + + return true; +} + static DIR *open_key_dir(const char *node_path, const char *key_dir_name) { char dir_path[PATH_MAX]; diff --git a/mesh/keyring.h b/mesh/keyring.h index ecf62cbc1..efc499ac2 100644 --- a/mesh/keyring.h +++ b/mesh/keyring.h @@ -39,5 +39,6 @@ bool keyring_put_remote_dev_key(struct mesh_node *node, uint16_t unicast, uint8_t count, uint8_t dev_key[16]); bool keyring_del_remote_dev_key(struct mesh_node *node, uint16_t unicast, uint8_t count); +bool keyring_del_remote_dev_key_all(struct mesh_node *node, uint16_t unicast); bool keyring_build_export_keys_reply(struct mesh_node *node, struct l_dbus_message_builder *builder); diff --git a/mesh/manager.c b/mesh/manager.c index e66b1a45b..e16dbc513 100644 --- a/mesh/manager.c +++ b/mesh/manager.c @@ -21,75 +21,137 @@ #include "mesh/mesh.h" #include "mesh/mesh-io.h" #include "mesh/node.h" +#include "mesh/model.h" #include "mesh/net.h" #include "mesh/keyring.h" #include "mesh/agent.h" #include "mesh/provision.h" +#include "mesh/prov.h" +#include "mesh/remprv.h" #include "mesh/manager.h" -struct add_data{ +struct prov_remote_data { struct l_dbus_message *msg; struct mesh_agent *agent; struct mesh_node *node; uint32_t disc_watch; + uint16_t original; uint16_t primary; uint16_t net_idx; + uint8_t transport; 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; +struct scan_req { + struct mesh_node *node; + struct l_timeout *timeout; + uint16_t server; + uint16_t net_idx; + uint8_t uuid[16]; + int8_t rssi; + bool ext; +}; + +static struct l_queue *scans; +static struct prov_remote_data *prov_pending; static const uint8_t prvb[2] = {MESH_AD_TYPE_BEACON, 0x00}; +static bool by_scan(const void *a, const void *b) +{ + return a == b; +} + +static bool by_node(const void *a, const void *b) +{ + const struct scan_req *req = a; + const struct mesh_node *node = b; + + return req->node == node; +} + +static bool by_node_svr(const void *a, const void *b) +{ + const struct scan_req *req = a; + const struct scan_req *test = b; + + return req->node == test->node && req->server == test->server; +} + static void scan_cancel(struct l_timeout *timeout, void *user_data) { - struct mesh_node *node = user_data; + struct scan_req *req = user_data; struct mesh_io *io; struct mesh_net *net; + uint8_t msg[4]; + int n; l_debug(""); - if (scan_timeout) - l_timeout_remove(scan_timeout); + req = l_queue_remove_if(scans, by_scan, req); + + if (!req) + return; + + l_timeout_remove(req->timeout); + + if (req->server) { + n = mesh_model_opcode_set(OP_REM_PROV_SCAN_STOP, msg); + mesh_model_send(req->node, 0, req->server, APP_IDX_DEV_REMOTE, + req->net_idx, DEFAULT_TTL, + true, n, msg); + } else { + net = node_get_net(req->node); + io = mesh_net_get_io(net); + mesh_io_deregister_recv_cb(io, prvb, sizeof(prvb)); + } - 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; + initiator_scan_unreg(req->node); + l_free(req); } -static void free_pending_add_call() +static void free_pending_add_call(void) { - if (!add_pending) + if (!prov_pending) return; - if (add_pending->disc_watch) + if (prov_pending->disc_watch) l_dbus_remove_watch(dbus_get_bus(), - add_pending->disc_watch); + prov_pending->disc_watch); - if (add_pending->msg) - l_dbus_message_unref(add_pending->msg); + if (prov_pending->msg) + l_dbus_message_unref(prov_pending->msg); - l_free(add_pending); - add_pending = NULL; + l_free(prov_pending); + prov_pending = NULL; } static void prov_disc_cb(struct l_dbus *bus, void *user_data) { - if (!add_pending) + if (!prov_pending) return; - initiator_cancel(add_pending); - add_pending->disc_watch = 0; + initiator_cancel(prov_pending); + prov_pending->disc_watch = 0; free_pending_add_call(); } +static void append_dict_entry_basic(struct l_dbus_message_builder *builder, + const char *key, const char *signature, + const void *data) +{ + if (!builder) + return; + + l_dbus_message_builder_enter_dict(builder, "sv"); + l_dbus_message_builder_append_basic(builder, 's', key); + l_dbus_message_builder_enter_variant(builder, signature); + l_dbus_message_builder_append_basic(builder, signature[0], data); + l_dbus_message_builder_leave_variant(builder); + l_dbus_message_builder_leave_dict(builder); +} + static void send_add_failed(const char *owner, const char *path, uint8_t status) { @@ -102,7 +164,7 @@ static void send_add_failed(const char *owner, const char *path, "AddNodeFailed"); builder = l_dbus_message_builder_new(msg); - dbus_append_byte_array(builder, add_pending->uuid, 16); + dbus_append_byte_array(builder, prov_pending->uuid, 16); l_dbus_message_builder_append_basic(builder, 's', mesh_prov_status_str(status)); l_dbus_message_builder_finalize(builder); @@ -115,14 +177,14 @@ static void send_add_failed(const char *owner, const char *path, static bool add_cmplt(void *user_data, uint8_t status, struct mesh_prov_node_info *info) { - struct add_data *pending = user_data; + struct prov_remote_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) + if (pending != prov_pending) return false; if (status != PROV_ERR_SUCCESS) { @@ -131,7 +193,12 @@ static bool add_cmplt(void *user_data, uint8_t status, return false; } - result = keyring_put_remote_dev_key(add_pending->node, info->unicast, + /* If Unicast address changing, delete old dev key */ + if (pending->transport == PB_NPPI_01) + keyring_del_remote_dev_key_all(pending->node, + pending->original); + + result = keyring_put_remote_dev_key(pending->node, info->unicast, info->num_ele, info->device_key); if (!result) { @@ -140,13 +207,29 @@ static bool add_cmplt(void *user_data, uint8_t status, return false; } - msg = l_dbus_message_new_method_call(dbus, node_get_owner(node), + if (pending->transport > PB_NPPI_02) + msg = l_dbus_message_new_method_call(dbus, node_get_owner(node), node_get_app_path(node), MESH_PROVISIONER_INTERFACE, "AddNodeComplete"); + else + msg = l_dbus_message_new_method_call(dbus, node_get_owner(node), + node_get_app_path(node), + MESH_PROVISIONER_INTERFACE, + "ReprovComplete"); builder = l_dbus_message_builder_new(msg); - dbus_append_byte_array(builder, add_pending->uuid, 16); + + if (pending->transport > PB_NPPI_02) + dbus_append_byte_array(builder, pending->uuid, 16); + else { + uint8_t nppi = (uint8_t) pending->transport; + + l_dbus_message_builder_append_basic(builder, 'q', + &pending->original); + l_dbus_message_builder_append_basic(builder, 'y', &nppi); + } + 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); @@ -161,47 +244,66 @@ static bool add_cmplt(void *user_data, uint8_t status, static void mgr_prov_data (struct l_dbus_message *reply, void *user_data) { - struct add_data *pending = user_data; + struct prov_remote_data *pending = user_data; uint16_t net_idx; uint16_t primary; - if (pending != add_pending) + if (pending != prov_pending) return; if (l_dbus_message_is_error(reply)) return; - if (!l_dbus_message_get_arguments(reply, "qq", &net_idx, &primary)) + if (pending->transport == PB_NPPI_01) { + /* If performing NPPI, we only get new primary unicast here */ + if (!l_dbus_message_get_arguments(reply, "q", &primary)) + return; + + net_idx = pending->net_idx; + + } else 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); + pending->primary = primary; + pending->net_idx = net_idx; + initiator_prov_data(net_idx, primary, pending); } static bool add_data_get(void *user_data, uint8_t num_ele) { - struct add_data *pending = user_data; + struct prov_remote_data *pending = user_data; struct l_dbus_message *msg; struct l_dbus *dbus; const char *app_path; const char *sender; - if (pending != add_pending) + if (pending != prov_pending) return false; dbus = dbus_get_bus(); - app_path = node_get_app_path(add_pending->node); - sender = node_get_owner(add_pending->node); + app_path = node_get_app_path(pending->node); + sender = node_get_owner(pending->node); - msg = l_dbus_message_new_method_call(dbus, sender, app_path, + if (pending->transport > PB_NPPI_02) { + 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); + l_dbus_message_set_arguments(msg, "y", num_ele); + } else if (pending->transport == PB_NPPI_01) { + msg = l_dbus_message_new_method_call(dbus, sender, app_path, + MESH_PROVISIONER_INTERFACE, + "RequestReprovData"); + + l_dbus_message_set_arguments(msg, "qy", pending->original, + num_ele); + } else + return false; - add_pending->num_ele = num_ele; + l_dbus_send_with_reply(dbus, msg, mgr_prov_data, pending, NULL); + + pending->num_ele = num_ele; return true; } @@ -213,15 +315,95 @@ static void add_start(void *user_data, int err) l_debug("Start callback"); if (err == MESH_ERROR_NONE) - reply = l_dbus_message_new_method_return(add_pending->msg); + reply = l_dbus_message_new_method_return(prov_pending->msg); else - reply = dbus_error(add_pending->msg, MESH_ERROR_FAILED, + reply = dbus_error(prov_pending->msg, MESH_ERROR_FAILED, "Failed to start provisioning initiator"); l_dbus_send(dbus_get_bus(), reply); - l_dbus_message_unref(add_pending->msg); + l_dbus_message_unref(prov_pending->msg); + + prov_pending->msg = NULL; +} + +static struct l_dbus_message *reprovision_call(struct l_dbus *dbus, + struct l_dbus_message *msg, + void *user_data) +{ + struct mesh_node *node = user_data; + struct l_dbus_message_iter options, var; + struct l_dbus_message *reply; + struct mesh_net *net = node_get_net(node); + const char *key; + uint16_t subidx; + uint16_t server = 0; + uint8_t nppi = 0; + + l_debug("Reprovision request"); + + if (!l_dbus_message_get_arguments(msg, "qa{sv}", &server, &options)) + return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL); + + if (!IS_UNICAST(server)) + return dbus_error(msg, MESH_ERROR_INVALID_ARGS, "Bad Unicast"); + + /* Default to nodes primary subnet index */ + subidx = mesh_net_get_primary_idx(net); + + /* Get Provisioning Options */ + while (l_dbus_message_iter_next_entry(&options, &key, &var)) { + bool failed = true; + + if (!strcmp(key, "NPPI")) { + if (l_dbus_message_iter_get_variant(&var, "y", &nppi)) { + if (nppi <= 2) + failed = false; + } + } else if (!strcmp(key, "Subnet")) { + if (l_dbus_message_iter_get_variant(&var, "q", + &subidx)) { + if (subidx <= MAX_KEY_IDX) + failed = false; + } + } + + if (failed) + return dbus_error(msg, MESH_ERROR_INVALID_ARGS, + "Invalid options"); + } + + /* AddNode cancels all outstanding Scanning from node */ + manager_scan_cancel(node); - add_pending->msg = NULL; + /* Invoke Prov Initiator */ + prov_pending = l_new(struct prov_remote_data, 1); + + prov_pending->transport = nppi; + prov_pending->node = node; + prov_pending->original = server; + prov_pending->agent = node_get_agent(node); + + if (!node_is_provisioner(node) || (prov_pending->agent == NULL)) { + reply = dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, + "Missing Interfaces"); + goto fail; + } + + prov_pending->msg = l_dbus_message_ref(msg); + initiator_start(prov_pending->transport, server, subidx, NULL, 99, 60, + prov_pending->agent, add_start, + add_data_get, add_cmplt, node, + prov_pending); + + prov_pending->disc_watch = l_dbus_add_disconnect_watch(dbus, + node_get_owner(node), + prov_disc_cb, NULL, NULL); + + return NULL; +fail: + l_free(prov_pending); + prov_pending = NULL; + return reply; } static struct l_dbus_message *add_node_call(struct l_dbus *dbus, @@ -229,55 +411,101 @@ static struct l_dbus_message *add_node_call(struct l_dbus *dbus, void *user_data) { struct mesh_node *node = user_data; - struct l_dbus_message_iter iter_uuid, options; + struct l_dbus_message_iter iter_uuid, options, var; struct l_dbus_message *reply; + struct mesh_net *net = node_get_net(node); + const char *key; uint8_t *uuid; - uint32_t n = 22; + uint32_t n = 0; + uint16_t subidx; + uint16_t sec = 60; + uint16_t server = 0; 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) + 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); + /* Default to nodes primary subnet index */ + subidx = mesh_net_get_primary_idx(net); - scan_cancel(NULL, node); + /* Get Provisioning Options */ + 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", &sec)) + failed = false; + } else if (!strcmp(key, "Server")) { + if (l_dbus_message_iter_get_variant(&var, "q", + &server)) { + if (server < 0x8000) + failed = false; + } + } else if (!strcmp(key, "Subnet")) { + if (l_dbus_message_iter_get_variant(&var, "q", + &subidx)) { + if (subidx <= MAX_KEY_IDX) + failed = false; + } + } + + if (failed) + return dbus_error(msg, MESH_ERROR_INVALID_ARGS, + "Invalid options"); } + /* Device Key update/Composition update requires remote server */ + if (!n && !server) + return dbus_error(msg, MESH_ERROR_INVALID_ARGS, + "Invalid options"); + + /* If no server specified, use local */ + if (!server) + server = node_get_primary(node); + + /* AddNode cancels all outstanding Scanning from node */ + manager_scan_cancel(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); + prov_pending = l_new(struct prov_remote_data, 1); + + if (n) + memcpy(prov_pending->uuid, uuid, 16); + else + uuid = NULL; - if (!node_is_provisioner(node) || (add_pending->agent == NULL)) { + prov_pending->transport = PB_ADV; + prov_pending->node = node; + prov_pending->agent = node_get_agent(node); + + if (!node_is_provisioner(node) || (prov_pending->agent == NULL)) { l_debug("Provisioner: %d", node_is_provisioner(node)); - l_debug("Agent: %p", add_pending->agent); + l_debug("Agent: %p", prov_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); + prov_pending->msg = l_dbus_message_ref(msg); + initiator_start(PB_ADV, server, subidx, uuid, 99, sec, + prov_pending->agent, add_start, + add_data_get, add_cmplt, node, + prov_pending); - add_pending->disc_watch = l_dbus_add_disconnect_watch(dbus, + prov_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; + l_free(prov_pending); + prov_pending = NULL; return reply; } @@ -337,38 +565,50 @@ static struct l_dbus_message *delete_node_call(struct l_dbus *dbus, return l_dbus_message_new_method_return(msg); } -static void prov_beacon_recv(void *user_data, struct mesh_io_recv_info *info, +static void manager_scan_result(void *user_data, uint16_t server, bool ext, const uint8_t *data, uint16_t len) { - struct mesh_node *node = user_data; + struct scan_req node_svr = { + .node = user_data, + .server = server, + }; + struct scan_req *req; 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) + l_debug("scan_result %4.4x %p", server, user_data); + req = l_queue_find(scans, by_node_svr, &node_svr); + if (!req) { + l_debug("No scan_result req"); return; + } - if (!memcmp(data + 2, scan_uuid, sizeof(scan_uuid))) { - if (info->rssi <= scan_rssi) + /* Filter repeats with weaker signal */ + if (!memcmp(data + 1, req->uuid, sizeof(req->uuid))) { + if (!ext && ((int8_t) data[0] <= req->rssi)) { + l_debug("Already Seen"); return; + } } - memcpy(scan_uuid, data + 2, sizeof(scan_uuid)); - scan_rssi = info->rssi; - rssi = info->rssi; + if (!ext && ((int8_t) data[0] > req->rssi)) + req->rssi = (int8_t) data[0]; + rssi = req->rssi; + memcpy(req->uuid, data + 1, sizeof(req->uuid)); dbus = dbus_get_bus(); - msg = l_dbus_message_new_method_call(dbus, node_get_owner(node), - node_get_app_path(node), + msg = l_dbus_message_new_method_call(dbus, node_get_owner(req->node), + node_get_app_path(req->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); + dbus_append_byte_array(builder, data + 1, len - 1); l_dbus_message_builder_enter_array(builder, "{sv}"); - /* TODO: populate with options when defined */ + append_dict_entry_basic(builder, "Server", "q", &server); l_dbus_message_builder_leave_array(builder); l_dbus_message_builder_finalize(builder); l_dbus_message_builder_destroy(builder); @@ -380,27 +620,71 @@ 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 scan_req new_req = { + .node = user_data, + .server = 0, + .timeout = NULL, + .ext = false, + }; + struct scan_req *req; struct mesh_net *net; + uint8_t *uuid, *ext = NULL; + uint8_t scan_req[21]; + int n; + uint32_t ext_len; + uint32_t flen = 0; + uint16_t sec = 60; 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))) + if (strcmp(sender, node_get_owner(new_req.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); + if (!node_is_provisioner(new_req.node)) + return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL); + + net = node_get_net(new_req.node); + new_req.net_idx = mesh_net_get_primary_idx(net); + memset(new_req.uuid, 0, sizeof(new_req.uuid)); + 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)) { + if (l_dbus_message_iter_get_variant(&var, "q", &sec)) failed = false; + } else if (!strcmp(key, "Subnet")) { + if (l_dbus_message_iter_get_variant(&var, "q", + &new_req.net_idx)) { + if (new_req.net_idx <= MAX_KEY_IDX) + failed = false; + } + } else if (!strcmp(key, "Server")) { + if (l_dbus_message_iter_get_variant(&var, "q", + &new_req.server)) { + if (new_req.server < 0x8000) + failed = false; + } + } else if (!strcmp(key, "Filter")) { + if (l_dbus_message_iter_get_variant(&var, "ay", &var)) { + if (l_dbus_message_iter_get_fixed_array(&var, + &uuid, &flen)) { + if (flen == 16) { + memcpy(new_req.uuid, uuid, + flen); + failed = false; + } + } + } + } else if (!strcmp(key, "Extended")) { + if (l_dbus_message_iter_get_variant(&var, "ay", &var)) { + if (l_dbus_message_iter_get_fixed_array(&var, + &ext, &ext_len)) + failed = false; } } @@ -409,27 +693,51 @@ static struct l_dbus_message *start_scan_call(struct l_dbus *dbus, "Invalid options"); } - if (scan_node && scan_node != node) - return dbus_error(msg, MESH_ERROR_BUSY, NULL); + if (!scans) + scans = l_queue_new(); - if (!node_is_provisioner(node)) - return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL); + if (new_req.server) { + if (!sec || sec > 60) + return dbus_error(msg, MESH_ERROR_INVALID_ARGS, + "Invalid options"); + } else { + new_req.server = node_get_primary(new_req.node); + if (!sec || sec > 60) + sec = 60; + } + + req = l_queue_remove_if(scans, by_node_svr, &new_req); + + if (!req) + req = l_malloc(sizeof(new_req)); + + if (req->timeout) { + l_timeout_remove(req->timeout); + req->timeout = NULL; + } + + *req = new_req; + req->rssi = -128; + + if (sec) + req->timeout = l_timeout_create(sec, scan_cancel, req, 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); + n = mesh_model_opcode_set(OP_REM_PROV_SCAN_START, scan_req); + scan_req[n++] = 5; + scan_req[n++] = sec; + if (flen) { + memcpy(scan_req + n, req->uuid, flen); + n += flen; + } + + mesh_model_send(req->node, 0, req->server, APP_IDX_DEV_REMOTE, + req->net_idx, DEFAULT_TTL, + true, n, scan_req); - if (duration) - scan_timeout = l_timeout_create(duration, scan_cancel, - node, NULL); + initiator_scan_reg(manager_scan_result, req->node); + + l_queue_push_tail(scans, req); return l_dbus_message_new_method_return(msg); } @@ -444,12 +752,7 @@ static struct l_dbus_message *cancel_scan_call(struct l_dbus *dbus, 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); - } + manager_scan_cancel(node); return l_dbus_message_new_method_return(msg); } @@ -814,6 +1117,8 @@ static void setup_management_interface(struct l_dbus_interface *iface) "aya{sv}", "uuid", "options"); l_dbus_interface_method(iface, "ImportRemoteNode", 0, import_node_call, "", "qyay", "primary", "count", "dev_key"); + l_dbus_interface_method(iface, "Reprovision", 0, reprovision_call, + "", "qa{sv}", "unicast", "options"); l_dbus_interface_method(iface, "DeleteRemoteNode", 0, delete_node_call, "", "qy", "primary", "count"); l_dbus_interface_method(iface, "UnprovisionedScan", 0, start_scan_call, @@ -849,7 +1154,7 @@ 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", + l_debug("Unable to register %s interface", MESH_MANAGEMENT_INTERFACE); return false; } @@ -859,8 +1164,8 @@ bool manager_dbus_init(struct l_dbus *bus) void manager_scan_cancel(struct mesh_node *node) { - if (scan_node != node) - return; + struct scan_req *req; - scan_cancel(NULL, node); + while ((req = l_queue_find(scans, by_node, node))) + scan_cancel(NULL, req); } diff --git a/mesh/mesh-config-json.c b/mesh/mesh-config-json.c index 7f46c8582..8f321a731 100644 --- a/mesh/mesh-config-json.c +++ b/mesh/mesh-config-json.c @@ -58,6 +58,33 @@ static const char *cfgnode_name = "/node.json"; static const char *bak_ext = ".bak"; static const char *tmp_ext = ".tmp"; +/* JSON key words */ +static const char *unicastAddress = "unicastAddress"; +static const char *deviceCan = "deviceCan"; +static const char *deviceKey = "deviceKey"; +static const char *defaultTTL = "defaultTTL"; +static const char *sequenceNumber = "sequenceNumber"; +static const char *netKeys = "netKeys"; +static const char *appKeys = "appKeys"; +static const char *elements = "elements"; +static const char *models = "models"; +static const char *modelId = "modelId"; +static const char *address = "address"; +static const char *bind = "bind"; +static const char *publish = "publish"; +static const char *subscribe = "subscribe"; +static const char *boundNetKey = "boundNetKey"; +static const char *keyRefresh = "keyRefresh"; +static const char *subEnabled = "subEnabled"; +static const char *pubEnabled = "pubEnabled"; +static const char *retransmit = "retransmit"; + +/* Common JSON values */ +static const char *enabled = "enabled"; +static const char *disabled = "disabled"; +static const char *unsupported = "unsupported"; + + static bool save_config(json_object *jnode, const char *fname) { FILE *outfile; @@ -134,14 +161,14 @@ static int get_element_index(json_object *jnode, uint16_t ele_addr) uint16_t addr, num_ele; char *str; - if (!json_object_object_get_ex(jnode, "unicastAddress", &jvalue)) + if (!json_object_object_get_ex(jnode, unicastAddress, &jvalue)) return -1; str = (char *)json_object_get_string(jvalue); if (sscanf(str, "%04hx", &addr) != 1) return -1; - if (!json_object_object_get_ex(jnode, "elements", &jelements)) + if (!json_object_object_get_ex(jnode, elements, &jelements)) return -1; num_ele = json_object_array_length(jelements); @@ -160,14 +187,14 @@ static json_object *get_element_model(json_object *jnode, int ele_idx, size_t len; char buf[9]; - if (!json_object_object_get_ex(jnode, "elements", &jelements)) + if (!json_object_object_get_ex(jnode, elements, &jelements)) return NULL; jelement = json_object_array_get_idx(jelements, ele_idx); if (!jelement) return NULL; - if (!json_object_object_get_ex(jelement, "models", &jmodels)) + if (!json_object_object_get_ex(jelement, models, &jmodels)) return NULL; num_mods = json_object_array_length(jmodels); @@ -189,7 +216,7 @@ static json_object *get_element_model(json_object *jnode, int ele_idx, char *str; jmodel = json_object_array_get_idx(jmodels, i); - if (!json_object_object_get_ex(jmodel, "modelId", &jvalue)) + if (!json_object_object_get_ex(jmodel, modelId, &jvalue)) return NULL; str = (char *)json_object_get_string(jvalue); @@ -298,7 +325,7 @@ static bool read_unicast_address(json_object *jobj, uint16_t *unicast) json_object *jvalue; char *str; - if (!json_object_object_get_ex(jobj, "unicastAddress", &jvalue)) + if (!json_object_object_get_ex(jobj, unicastAddress, &jvalue)) return false; str = (char *)json_object_get_string(jvalue); @@ -314,7 +341,7 @@ static bool read_default_ttl(json_object *jobj, uint8_t *ttl) int val; /* defaultTTL is optional */ - if (!json_object_object_get_ex(jobj, "defaultTTL", &jvalue)) + if (!json_object_object_get_ex(jobj, defaultTTL, &jvalue)) return true; val = json_object_get_int(jvalue); @@ -336,7 +363,7 @@ static bool read_seq_number(json_object *jobj, uint32_t *seq_number) int val; /* sequenceNumber is optional */ - if (!json_object_object_get_ex(jobj, "sequenceNumber", &jvalue)) + if (!json_object_object_get_ex(jobj, sequenceNumber, &jvalue)) return true; val = json_object_get_int(jvalue); @@ -396,7 +423,25 @@ static bool read_device_key(json_object *jobj, uint8_t key_buf[16]) if (!key_buf) return false; - if (!json_object_object_get_ex(jobj, "deviceKey", &jvalue)) + if (!json_object_object_get_ex(jobj, deviceKey, &jvalue)) + return false; + + str = (char *)json_object_get_string(jvalue); + if (!str2hex(str, strlen(str), key_buf, 16)) + return false; + + return true; +} + +static bool read_candidate(json_object *jobj, uint8_t key_buf[16]) +{ + json_object *jvalue; + char *str; + + if (!key_buf) + return false; + + if (!json_object_object_get_ex(jobj, deviceCan, &jvalue)) return false; str = (char *)json_object_get_string(jvalue); @@ -460,7 +505,7 @@ static bool read_app_keys(json_object *jobj, struct mesh_config_node *node) int len; int i; - if (!json_object_object_get_ex(jobj, "appKeys", &jarray)) + if (!json_object_object_get_ex(jobj, appKeys, &jarray)) return true; if (json_object_get_type(jarray) != json_type_array) @@ -484,7 +529,7 @@ static bool read_app_keys(json_object *jobj, struct mesh_config_node *node) if (!get_key_index(jtemp, "index", &appkey->app_idx)) goto fail; - if (!get_key_index(jtemp, "boundNetKey", &appkey->net_idx)) + if (!get_key_index(jtemp, boundNetKey, &appkey->net_idx)) goto fail; if (!json_object_object_get_ex(jtemp, "key", &jvalue)) @@ -516,7 +561,7 @@ static bool read_net_keys(json_object *jobj, struct mesh_config_node *node) int i; /* At least one NetKey must be present for a provisioned node */ - if (!json_object_object_get_ex(jobj, "netKeys", &jarray)) + if (!json_object_object_get_ex(jobj, netKeys, &jarray)) return false; if (json_object_get_type(jarray) != json_type_array) @@ -547,7 +592,7 @@ static bool read_net_keys(json_object *jobj, struct mesh_config_node *node) if (!str2hex(str, strlen(str), netkey->new_key, 16)) goto fail; - if (!json_object_object_get_ex(jtemp, "keyRefresh", &jvalue)) + if (!json_object_object_get_ex(jtemp, keyRefresh, &jvalue)) netkey->phase = KEY_REFRESH_PHASE_NONE; else netkey->phase = (uint8_t) json_object_get_int(jvalue); @@ -598,7 +643,7 @@ bool mesh_config_net_key_add(struct mesh_config *cfg, uint16_t idx, jnode = cfg->jnode; l_debug("netKey %4.4x", idx); - json_object_object_get_ex(jnode, "netKeys", &jarray); + json_object_object_get_ex(jnode, netKeys, &jarray); if (jarray) jentry = get_key_object(jarray, idx); @@ -616,14 +661,14 @@ bool mesh_config_net_key_add(struct mesh_config *cfg, uint16_t idx, if (!add_key_value(jentry, "key", key)) goto fail; - json_object_object_add(jentry, "keyRefresh", + json_object_object_add(jentry, keyRefresh, json_object_new_int(KEY_REFRESH_PHASE_NONE)); if (!jarray) { jarray = json_object_new_array(); if (!jarray) goto fail; - json_object_object_add(jnode, "netKeys", jarray); + json_object_object_add(jnode, netKeys, jarray); } json_object_array_add(jarray, jentry); @@ -648,7 +693,7 @@ bool mesh_config_net_key_update(struct mesh_config *cfg, uint16_t idx, jnode = cfg->jnode; - if (!json_object_object_get_ex(jnode, "netKeys", &jarray)) + if (!json_object_object_get_ex(jnode, netKeys, &jarray)) return false; jentry = get_key_object(jarray, idx); @@ -667,7 +712,7 @@ bool mesh_config_net_key_update(struct mesh_config *cfg, uint16_t idx, if (!add_key_value(jentry, "key", key)) return false; - json_object_object_add(jentry, "keyRefresh", + json_object_object_add(jentry, keyRefresh, json_object_new_int(KEY_REFRESH_PHASE_ONE)); return save_config(jnode, cfg->node_dir_path); @@ -682,20 +727,55 @@ bool mesh_config_net_key_del(struct mesh_config *cfg, uint16_t idx) jnode = cfg->jnode; - if (!json_object_object_get_ex(jnode, "netKeys", &jarray)) + if (!json_object_object_get_ex(jnode, netKeys, &jarray)) return true; jarray_key_del(jarray, idx); if (!json_object_array_length(jarray)) - json_object_object_del(jnode, "netKeys"); + json_object_object_del(jnode, netKeys); return save_config(jnode, cfg->node_dir_path); } bool mesh_config_write_device_key(struct mesh_config *cfg, uint8_t *key) { - if (!cfg || !add_key_value(cfg->jnode, "deviceKey", key)) + if (!cfg || !add_key_value(cfg->jnode, deviceKey, key)) + return false; + + return save_config(cfg->jnode, cfg->node_dir_path); +} + +bool mesh_config_write_candidate(struct mesh_config *cfg, uint8_t *key) +{ + if (!cfg || !add_key_value(cfg->jnode, deviceCan, key)) + return false; + + return save_config(cfg->jnode, cfg->node_dir_path); +} + +bool mesh_config_read_candidate(struct mesh_config *cfg, uint8_t *key) +{ + if (!cfg) + return false; + + return read_candidate(cfg->jnode, key); +} + +bool mesh_config_finalize_candidate(struct mesh_config *cfg) +{ + uint8_t key[16]; + + if (!cfg) + return false; + + if (!read_candidate(cfg->jnode, key)) + return false; + + json_object_object_del(cfg->jnode, deviceCan); + json_object_object_del(cfg->jnode, deviceKey); + + if (!add_key_value(cfg->jnode, deviceKey, key)) return false; return save_config(cfg->jnode, cfg->node_dir_path); @@ -719,7 +799,7 @@ bool mesh_config_app_key_add(struct mesh_config *cfg, uint16_t net_idx, jnode = cfg->jnode; - json_object_object_get_ex(jnode, "appKeys", &jarray); + json_object_object_get_ex(jnode, appKeys, &jarray); if (jarray) jentry = get_key_object(jarray, app_idx); @@ -734,7 +814,7 @@ bool mesh_config_app_key_add(struct mesh_config *cfg, uint16_t net_idx, if (!write_int(jentry, "index", app_idx)) goto fail; - if (!write_int(jentry, "boundNetKey", net_idx)) + if (!write_int(jentry, boundNetKey, net_idx)) goto fail; if (!add_key_value(jentry, "key", key)) @@ -744,7 +824,7 @@ bool mesh_config_app_key_add(struct mesh_config *cfg, uint16_t net_idx, jarray = json_object_new_array(); if (!jarray) goto fail; - json_object_object_add(jnode, "appKeys", jarray); + json_object_object_add(jnode, appKeys, jarray); } json_object_array_add(jarray, jentry); @@ -770,7 +850,7 @@ bool mesh_config_app_key_update(struct mesh_config *cfg, uint16_t app_idx, jnode = cfg->jnode; - if (!json_object_object_get_ex(jnode, "appKeys", &jarray)) + if (!json_object_object_get_ex(jnode, appKeys, &jarray)) return false; /* The key entry should exist if the key is updated */ @@ -804,13 +884,13 @@ bool mesh_config_app_key_del(struct mesh_config *cfg, uint16_t net_idx, jnode = cfg->jnode; - if (!json_object_object_get_ex(jnode, "appKeys", &jarray)) + if (!json_object_object_get_ex(jnode, appKeys, &jarray)) return true; jarray_key_del(jarray, idx); if (!json_object_array_length(jarray)) - json_object_object_del(jnode, "appKeys"); + json_object_object_del(jnode, appKeys); return save_config(jnode, cfg->node_dir_path); } @@ -840,7 +920,7 @@ bool mesh_config_model_binding_add(struct mesh_config *cfg, uint16_t ele_addr, if (!jmodel) return false; - json_object_object_get_ex(jmodel, "bind", &jarray); + json_object_object_get_ex(jmodel, bind, &jarray); if (jarray && jarray_has_string(jarray, buf, 4)) return true; @@ -854,7 +934,7 @@ bool mesh_config_model_binding_add(struct mesh_config *cfg, uint16_t ele_addr, json_object_put(jstring); return false; } - json_object_object_add(jmodel, "bind", jarray); + json_object_object_add(jmodel, bind, jarray); } json_object_array_add(jarray, jstring); @@ -887,13 +967,13 @@ bool mesh_config_model_binding_del(struct mesh_config *cfg, uint16_t ele_addr, if (!jmodel) return false; - if (!json_object_object_get_ex(jmodel, "bind", &jarray)) + if (!json_object_object_get_ex(jmodel, bind, &jarray)) return true; jarray_string_del(jarray, buf, 4); if (!json_object_array_length(jarray)) - json_object_object_del(jmodel, "bind"); + json_object_object_del(jmodel, bind); return save_config(jnode, cfg->node_dir_path); } @@ -963,7 +1043,7 @@ static struct mesh_config_pub *parse_model_publication(json_object *jpub) int len, value; char *str; - if (!json_object_object_get_ex(jpub, "address", &jvalue)) + if (!json_object_object_get_ex(jpub, address, &jvalue)) return NULL; str = (char *)json_object_get_string(jvalue); @@ -998,9 +1078,10 @@ static struct mesh_config_pub *parse_model_publication(json_object *jpub) if (!get_int(jpub, "credentials", &value)) goto fail; + pub->credential = (uint8_t) value; - if (!json_object_object_get_ex(jpub, "retransmit", &jvalue)) + if (!json_object_object_get_ex(jpub, retransmit, &jvalue)) goto fail; if (!get_int(jvalue, "count", &value)) @@ -1093,7 +1174,7 @@ static bool parse_models(json_object *jmodels, struct mesh_config_element *ele) l_queue_push_tail(ele->models, mod); - if (!json_object_object_get_ex(jmodel, "modelId", &jvalue)) + if (!json_object_object_get_ex(jmodel, modelId, &jvalue)) goto fail; str = (char *)json_object_get_string(jvalue); @@ -1112,29 +1193,32 @@ static bool parse_models(json_object *jmodels, struct mesh_config_element *ele) mod->id = id; - if (json_object_object_get_ex(jmodel, "bind", &jarray)) { + if (len == 8) + mod->vendor = true; + + if (json_object_object_get_ex(jmodel, bind, &jarray)) { if (json_object_get_type(jarray) != json_type_array || !parse_bindings(jarray, mod)) goto fail; } - if (json_object_object_get_ex(jmodel, "pubEnabled", &jvalue)) + if (json_object_object_get_ex(jmodel, pubEnabled, &jvalue)) mod->pub_enabled = json_object_get_boolean(jvalue); else mod->pub_enabled = true; - if (json_object_object_get_ex(jmodel, "subEnabled", &jvalue)) + if (json_object_object_get_ex(jmodel, subEnabled, &jvalue)) mod->sub_enabled = json_object_get_boolean(jvalue); else mod->sub_enabled = true; - if (json_object_object_get_ex(jmodel, "publish", &jvalue)) { + if (json_object_object_get_ex(jmodel, publish, &jvalue)) { mod->pub = parse_model_publication(jvalue); if (!mod->pub) goto fail; } - if (json_object_object_get_ex(jmodel, "subscribe", &jarray)) { + if (json_object_object_get_ex(jmodel, subscribe, &jarray)) { if (!parse_model_subscriptions(jarray, mod)) goto fail; } @@ -1187,7 +1271,7 @@ static bool parse_elements(json_object *jelems, struct mesh_config_node *node) if (sscanf(str, "%04hx", &(ele->location)) != 1) goto fail; - if (json_object_object_get_ex(jelement, "models", &jmodels)) { + if (json_object_object_get_ex(jelement, models, &jmodels)) { if (json_object_get_type(jmodels) != json_type_array || !parse_models(jmodels, ele)) goto fail; @@ -1211,13 +1295,13 @@ static int get_mode(json_object *jvalue) if (!str) return 0xffffffff; - if (!strncasecmp(str, "disabled", strlen("disabled"))) + if (!strncasecmp(str, disabled, strlen(disabled))) return MESH_MODE_DISABLED; - if (!strncasecmp(str, "enabled", strlen("enabled"))) + if (!strncasecmp(str, enabled, strlen(enabled))) return MESH_MODE_ENABLED; - if (!strncasecmp(str, "unsupported", strlen("unsupported"))) + if (!strncasecmp(str, unsupported, strlen(unsupported))) return MESH_MODE_UNSUPPORTED; return 0xffffffff; @@ -1323,7 +1407,7 @@ static bool read_net_transmit(json_object *jobj, struct mesh_config_node *node) uint16_t interval; uint8_t cnt; - if (!json_object_object_get_ex(jobj, "retransmit", &jrtx)) + if (!json_object_object_get_ex(jobj, retransmit, &jrtx)) return true; if (!json_object_object_get_ex(jrtx, "count", &jvalue)) @@ -1386,7 +1470,7 @@ static bool read_node(json_object *jnode, struct mesh_config_node *node) } /* Check for required "elements" property */ - if (!json_object_object_get_ex(jnode, "elements", &jvalue)) + if (!json_object_object_get_ex(jnode, elements, &jvalue)) return false; if (!read_net_transmit(jnode, node)) { @@ -1460,11 +1544,11 @@ static const char *mode_to_string(int mode) { switch (mode) { case MESH_MODE_DISABLED: - return "disabled"; + return disabled; case MESH_MODE_ENABLED: - return "enabled"; + return enabled; default: - return "unsupported"; + return unsupported; } } @@ -1522,7 +1606,7 @@ fail: bool mesh_config_write_unicast(struct mesh_config *cfg, uint16_t unicast) { - if (!cfg || !write_uint16_hex(cfg->jnode, "unicastAddress", unicast)) + if (!cfg || !write_uint16_hex(cfg->jnode, unicastAddress, unicast)) return false; return save_config(cfg->jnode, cfg->node_dir_path); @@ -1558,8 +1642,8 @@ bool mesh_config_write_net_transmit(struct mesh_config *cfg, uint8_t cnt, if (!write_int(jrtx, "interval", interval)) goto fail; - json_object_object_del(jnode, "retransmit"); - json_object_object_add(jnode, "retransmit", jrtx); + json_object_object_del(jnode, retransmit); + json_object_object_add(jnode, retransmit, jrtx); return save_config(cfg->jnode, cfg->node_dir_path); @@ -1599,8 +1683,8 @@ static void add_model(void *a, void *b) if (!jmodel) return; - result = (mod->vendor) ? write_uint32_hex(jmodel, "modelId", mod->id) : - write_uint16_hex(jmodel, "modelId", (uint16_t) mod->id); + result = (mod->vendor) ? write_uint32_hex(jmodel, modelId, mod->id) : + write_uint16_hex(jmodel, modelId, (uint16_t) mod->id); if (!result) { json_object_put(jmodel); @@ -1608,10 +1692,10 @@ static void add_model(void *a, void *b) } jval = json_object_new_boolean(mod->sub_enabled); - json_object_object_add(jmodel, "subEnabled", jval); + json_object_object_add(jmodel, subEnabled, jval); jval = json_object_new_boolean(mod->pub_enabled); - json_object_object_add(jmodel, "pubEnabled", jval); + json_object_object_add(jmodel, pubEnabled, jval); json_object_array_add(jmodels, jmodel); } @@ -1663,11 +1747,11 @@ static struct mesh_config *create_config(const char *cfg_path, return NULL; /* Sequence number */ - json_object_object_add(jnode, "sequenceNumber", + json_object_object_add(jnode, sequenceNumber, json_object_new_int(node->seq_number)); /* Default TTL */ - json_object_object_add(jnode, "defaultTTL", + json_object_object_add(jnode, defaultTTL, json_object_new_int(node->ttl)); /* Elements */ @@ -1702,11 +1786,11 @@ static struct mesh_config *create_config(const char *cfg_path, if (!jmodels) goto fail; - json_object_object_add(jelement, "models", jmodels); + json_object_object_add(jelement, models, jmodels); l_queue_foreach(ele->models, add_model, jmodels); } - json_object_object_add(jnode, "elements", jelems); + json_object_object_add(jnode, elements, jelems); cfg = l_new(struct mesh_config, 1); @@ -1724,6 +1808,55 @@ fail: return NULL; } +void mesh_config_reset(struct mesh_config *cfg, struct mesh_config_node *node) +{ + json_object *jelems; + const struct l_queue_entry *entry; + + if (!cfg || !cfg->jnode) + return; + + /* TODO: Recreate Element Array */ + jelems = json_object_new_array(); + if (!jelems) + return; + + entry = l_queue_get_entries(node->elements); + + for (; entry; entry = entry->next) { + struct mesh_config_element *ele = entry->data; + json_object *jelement, *jmodels; + + jelement = json_object_new_object(); + + if (!jelement) { + json_object_put(jelems); + return; + } + + write_int(jelement, "elementIndex", ele->index); + write_uint16_hex(jelement, "location", ele->location); + json_object_array_add(jelems, jelement); + + /* Models */ + if (l_queue_isempty(ele->models)) + continue; + + jmodels = json_object_new_array(); + if (!jmodels) { + json_object_put(jelems); + return; + } + + json_object_object_add(jelement, models, jmodels); + l_queue_foreach(ele->models, add_model, jmodels); + } + + /* Replace element array */ + json_object_object_del(cfg->jnode, elements); + json_object_object_add(cfg->jnode, elements, jelems); +} + struct mesh_config *mesh_config_create(const char *cfgdir_name, const uint8_t uuid[16], struct mesh_config_node *db_node) { @@ -1768,7 +1901,7 @@ static void finish_key_refresh(json_object *jobj, uint16_t net_idx) int i, len; /* Clean up all the bound appkeys */ - if (!json_object_object_get_ex(jobj, "appKeys", &jarray)) + if (!json_object_object_get_ex(jobj, appKeys, &jarray)) return; len = json_object_array_length(jarray); @@ -1779,7 +1912,7 @@ static void finish_key_refresh(json_object *jobj, uint16_t net_idx) jentry = json_object_array_get_idx(jarray, i); - if (!get_key_index(jentry, "boundNetKey", &idx)) + if (!get_key_index(jentry, boundNetKey, &idx)) continue; if (idx != net_idx) @@ -1803,14 +1936,14 @@ bool mesh_config_net_key_set_phase(struct mesh_config *cfg, uint16_t idx, jnode = cfg->jnode; - if (json_object_object_get_ex(jnode, "netKeys", &jarray)) + if (json_object_object_get_ex(jnode, netKeys, &jarray)) jentry = get_key_object(jarray, idx); if (!jentry) return false; - json_object_object_del(jentry, "keyRefresh"); - json_object_object_add(jentry, "keyRefresh", + json_object_object_del(jentry, keyRefresh); + json_object_object_add(jentry, keyRefresh, json_object_new_int(phase)); if (phase == KEY_REFRESH_PHASE_NONE) { @@ -1842,16 +1975,16 @@ bool mesh_config_model_pub_add(struct mesh_config *cfg, uint16_t ele_addr, if (!jmodel) return false; - json_object_object_del(jmodel, "publish"); + json_object_object_del(jmodel, publish); jpub = json_object_new_object(); if (!jpub) return false; if (pub->virt) - res = add_key_value(jpub, "address", pub->virt_addr); + res = add_key_value(jpub, address, pub->virt_addr); else - res = write_uint16_hex(jpub, "address", pub->addr); + res = write_uint16_hex(jpub, address, pub->addr); if (!res) goto fail; @@ -1878,8 +2011,8 @@ bool mesh_config_model_pub_add(struct mesh_config *cfg, uint16_t ele_addr, if (!write_int(jrtx, "interval", pub->interval)) goto fail; - json_object_object_add(jpub, "retransmit", jrtx); - json_object_object_add(jmodel, "publish", jpub); + json_object_object_add(jpub, retransmit, jrtx); + json_object_object_add(jmodel, publish, jpub); return save_config(jnode, cfg->node_dir_path); @@ -1911,23 +2044,23 @@ bool mesh_config_model_pub_del(struct mesh_config *cfg, uint16_t addr, uint32_t mod_id, bool vendor) { if (!cfg || !delete_model_property(cfg->jnode, addr, mod_id, vendor, - "publish")) + publish)) return false; return save_config(cfg->jnode, cfg->node_dir_path); } -static void del_page(json_object *jarray, uint8_t page) +static bool del_page(json_object *jarray, uint8_t page) { char buf[3]; int i, len, ret; if (!jarray) - return; + return false; ret = snprintf(buf, 3, "%2.2x", page); if (ret < 0) - return; + return false; len = json_object_array_length(jarray); @@ -1938,10 +2071,29 @@ static void del_page(json_object *jarray, uint8_t page) jentry = json_object_array_get_idx(jarray, i); str = (char *)json_object_get_string(jentry); - /* Delete matching page(s) */ - if (!memcmp(str, buf, 2)) + /* Delete matching page */ + if (!memcmp(str, buf, 2)) { json_object_array_del_idx(jarray, i, 1); + break; + } } + + return true; +} + +void mesh_config_comp_page_del(struct mesh_config *cfg, uint8_t page) +{ + json_object *jnode, *jarray = NULL; + + if (!cfg) + return; + + jnode = cfg->jnode; + + json_object_object_get_ex(jnode, "pages", &jarray); + + if (del_page(jarray, page)) + save_config(jnode, cfg->node_dir_path); } bool mesh_config_comp_page_add(struct mesh_config *cfg, uint8_t page, @@ -1984,56 +2136,6 @@ bool mesh_config_comp_page_add(struct mesh_config *cfg, uint8_t page, return save_config(jnode, cfg->node_dir_path); } -bool mesh_config_comp_page_mv(struct mesh_config *cfg, uint8_t old, uint8_t nw) -{ - json_object *jnode, *jarray = NULL; - uint8_t *data; - char *str; - char old_buf[3]; - int i, len, ret, dlen = 0; - bool status = true; - - if (!cfg || old == nw) - return false; - - ret = snprintf(old_buf, 3, "%2.2x", old); - if (ret < 0) - return false; - - jnode = cfg->jnode; - - json_object_object_get_ex(jnode, "pages", &jarray); - - if (!jarray) - return false; - - data = l_malloc(MAX_MSG_LEN); - - len = json_object_array_length(jarray); - - for (i = 0; i < len; i++) { - json_object *jentry; - - jentry = json_object_array_get_idx(jarray, i); - str = (char *)json_object_get_string(jentry); - - /* Delete matching page(s) but save data*/ - if (!memcmp(str, old_buf, 2)) { - dlen = strlen(str + 2); - str2hex(str + 2, dlen, data, MAX_MSG_LEN); - dlen /= 2; - json_object_array_del_idx(jarray, i, 1); - } - } - - if (dlen) - status = mesh_config_comp_page_add(cfg, nw, data, dlen); - - l_free(data); - - return status; -} - bool mesh_config_model_sub_add(struct mesh_config *cfg, uint16_t ele_addr, uint32_t mod_id, bool vendor, struct mesh_config_sub *sub) @@ -2064,7 +2166,7 @@ bool mesh_config_model_sub_add(struct mesh_config *cfg, uint16_t ele_addr, len = 32; } - json_object_object_get_ex(jmodel, "subscribe", &jarray); + json_object_object_get_ex(jmodel, subscribe, &jarray); if (jarray && jarray_has_string(jarray, buf, len)) return true; @@ -2078,7 +2180,7 @@ bool mesh_config_model_sub_add(struct mesh_config *cfg, uint16_t ele_addr, json_object_put(jstring); return false; } - json_object_object_add(jmodel, "subscribe", jarray); + json_object_object_add(jmodel, subscribe, jarray); } json_object_array_add(jarray, jstring); @@ -2107,7 +2209,7 @@ bool mesh_config_model_sub_del(struct mesh_config *cfg, uint16_t ele_addr, if (!jmodel) return false; - if (!json_object_object_get_ex(jmodel, "subscribe", &jarray)) + if (!json_object_object_get_ex(jmodel, subscribe, &jarray)) return true; if (!sub->virt) { @@ -2122,7 +2224,7 @@ bool mesh_config_model_sub_del(struct mesh_config *cfg, uint16_t ele_addr, jarray_string_del(jarray, buf, len); if (!json_object_array_length(jarray)) - json_object_object_del(jmodel, "subscribe"); + json_object_object_del(jmodel, subscribe); return save_config(jnode, cfg->node_dir_path); } @@ -2131,7 +2233,7 @@ bool mesh_config_model_sub_del_all(struct mesh_config *cfg, uint16_t addr, uint32_t mod_id, bool vendor) { if (!cfg || !delete_model_property(cfg->jnode, addr, mod_id, vendor, - "subscribe")) + subscribe)) return false; return save_config(cfg->jnode, cfg->node_dir_path); @@ -2161,7 +2263,7 @@ bool mesh_config_model_pub_enable(struct mesh_config *cfg, uint16_t ele_addr, json_object_object_add(jmodel, "pubDisabled", jval); if (!enable) - json_object_object_del(jmodel, "publish"); + json_object_object_del(jmodel, publish); return save_config(cfg->jnode, cfg->node_dir_path); } @@ -2184,13 +2286,13 @@ bool mesh_config_model_sub_enable(struct mesh_config *cfg, uint16_t ele_addr, if (!jmodel) return false; - json_object_object_del(jmodel, "subEnabled"); + json_object_object_del(jmodel, subEnabled); jval = json_object_new_boolean(enable); - json_object_object_add(jmodel, "subEnabled", jval); + json_object_object_add(jmodel, subEnabled, jval); if (!enable) - json_object_object_del(jmodel, "subscribe"); + json_object_object_del(jmodel, subscribe); return save_config(cfg->jnode, cfg->node_dir_path); } @@ -2205,14 +2307,14 @@ bool mesh_config_write_seq_number(struct mesh_config *cfg, uint32_t seq, return false; if (!cache) { - if (!write_int(cfg->jnode, "sequenceNumber", seq)) + if (!write_int(cfg->jnode, sequenceNumber, seq)) return false; return mesh_config_save(cfg, true, NULL, NULL); } /* If resetting seq to Zero, make sure cached value reset as well */ - if (seq && get_int(cfg->jnode, "sequenceNumber", &value)) + if (seq && get_int(cfg->jnode, sequenceNumber, &value)) cached = (uint32_t)value; /* @@ -2262,8 +2364,8 @@ bool mesh_config_write_seq_number(struct mesh_config *cfg, uint32_t seq, l_debug("Seq Cache: %d -> %d", seq, cached); - if (!write_int(cfg->jnode, "sequenceNumber", cached)) - return false; + if (!write_int(cfg->jnode, sequenceNumber, cached)) + return false; return mesh_config_save(cfg, false, NULL, NULL); } @@ -2273,7 +2375,7 @@ bool mesh_config_write_seq_number(struct mesh_config *cfg, uint32_t seq, bool mesh_config_write_ttl(struct mesh_config *cfg, uint8_t ttl) { - if (!cfg || !write_int(cfg->jnode, "defaultTTL", ttl)) + if (!cfg || !write_int(cfg->jnode, defaultTTL, ttl)) return false; return save_config(cfg->jnode, cfg->node_dir_path); diff --git a/mesh/mesh-config.h b/mesh/mesh-config.h index 420775829..ed1b610de 100644 --- a/mesh/mesh-config.h +++ b/mesh/mesh-config.h @@ -119,6 +119,7 @@ void mesh_config_release(struct mesh_config *cfg); void mesh_config_destroy_nvm(struct mesh_config *cfg); bool mesh_config_save(struct mesh_config *cfg, bool no_wait, mesh_config_status_func_t cb, void *user_data); +void mesh_config_reset(struct mesh_config *cfg, struct mesh_config_node *node); struct mesh_config *mesh_config_create(const char *cfgdir_name, const uint8_t uuid[16], struct mesh_config_node *node); @@ -126,6 +127,9 @@ struct mesh_config *mesh_config_create(const char *cfgdir_name, bool mesh_config_write_net_transmit(struct mesh_config *cfg, uint8_t cnt, uint16_t interval); bool mesh_config_write_device_key(struct mesh_config *cfg, uint8_t *key); +bool mesh_config_write_candidate(struct mesh_config *cfg, uint8_t *key); +bool mesh_config_read_candidate(struct mesh_config *cfg, uint8_t *key); +bool mesh_config_finalize_candidate(struct mesh_config *cfg); bool mesh_config_write_token(struct mesh_config *cfg, uint8_t *token); bool mesh_config_write_network_key(struct mesh_config *cfg, uint16_t idx, uint8_t *key, uint8_t *new_key, int phase); @@ -141,7 +145,7 @@ bool mesh_config_write_mode(struct mesh_config *cfg, const char *keyword, int value); bool mesh_config_comp_page_add(struct mesh_config *cfg, uint8_t page, uint8_t *data, uint16_t size); -bool mesh_config_comp_page_mv(struct mesh_config *cfg, uint8_t old, uint8_t nw); +void mesh_config_comp_page_del(struct mesh_config *cfg, uint8_t page); bool mesh_config_model_binding_add(struct mesh_config *cfg, uint16_t ele_addr, uint32_t mod_id, bool vendor, uint16_t app_idx); diff --git a/mesh/model.c b/mesh/model.c index d48e6ef12..e2babea10 100644 --- a/mesh/model.c +++ b/mesh/model.c @@ -24,6 +24,8 @@ #include "mesh/net.h" #include "mesh/appkey.h" #include "mesh/cfgmod.h" +#include "mesh/prov.h" +#include "mesh/remprv.h" #include "mesh/error.h" #include "mesh/dbus.h" #include "mesh/util.h" @@ -76,6 +78,9 @@ static bool is_internal(uint32_t id) if (id == CONFIG_SRV_MODEL || id == CONFIG_CLI_MODEL) return true; + if (id == REM_PROV_SRV_MODEL || id == REM_PROV_CLI_MODEL) + return true; + return false; } @@ -457,13 +462,25 @@ static int dev_packet_decrypt(struct mesh_node *node, const uint8_t *data, dst, key_aid, seq, iv_idx, out, key)) return APP_IDX_DEV_LOCAL; - if (!keyring_get_remote_dev_key(node, src, dev_key)) + key = dev_key; + + if (keyring_get_remote_dev_key(node, src, dev_key)) { + if (mesh_crypto_payload_decrypt(NULL, 0, data, size, szmict, + src, dst, key_aid, seq, iv_idx, out, key)) + return APP_IDX_DEV_REMOTE; + } + + /* See if there is a local Device Key Candidate as last resort */ + if (!node_get_device_key_candidate(node, dev_key)) return -1; - key = dev_key; - if (mesh_crypto_payload_decrypt(NULL, 0, data, size, szmict, src, - dst, key_aid, seq, iv_idx, out, key)) - return APP_IDX_DEV_REMOTE; + if (mesh_crypto_payload_decrypt(NULL, 0, data, size, szmict, + src, dst, key_aid, seq, iv_idx, out, key)) { + + /* If candidate dev_key worked, it is considered finalized */ + node_finalize_candidate(node); + return APP_IDX_DEV_LOCAL; + } return -1; } diff --git a/mesh/node.c b/mesh/node.c index cf4ed140e..5150a085a 100644 --- a/mesh/node.c +++ b/mesh/node.c @@ -27,9 +27,11 @@ #include "mesh/appkey.h" #include "mesh/mesh-config.h" #include "mesh/provision.h" +#include "mesh/prov.h" #include "mesh/keyring.h" #include "mesh/model.h" #include "mesh/cfgmod.h" +#include "mesh/remprv.h" #include "mesh/util.h" #include "mesh/error.h" #include "mesh/dbus.h" @@ -347,6 +349,15 @@ static bool add_elements_from_storage(struct mesh_node *node, if (!add_element_from_storage(node, entry->data)) return false; + /* Add configuration server model on the primary element */ + mesh_model_add(node, PRIMARY_ELE_IDX, CONFIG_SRV_MODEL, NULL); + + /* Add remote provisioning models on the primary element */ + mesh_model_add(node, PRIMARY_ELE_IDX, REM_PROV_SRV_MODEL, NULL); + + if (node->provisioner) + mesh_model_add(node, PRIMARY_ELE_IDX, REM_PROV_CLI_MODEL, NULL); + return true; } @@ -489,6 +500,10 @@ static bool init_from_storage(struct mesh_config_node *db_node, /* Initialize configuration server model */ cfgmod_server_init(node, PRIMARY_ELE_IDX); + /* Initialize remote provisioning models */ + remote_prov_server_init(node, PRIMARY_ELE_IDX); + remote_prov_client_init(node, PRIMARY_ELE_IDX); + node->cfg = cfg; return true; @@ -550,12 +565,78 @@ uint16_t node_get_primary(struct mesh_node *node) return node->primary; } +bool node_refresh(struct mesh_node *node, bool hard, void *prov_info) +{ + struct mesh_prov_node_info *info = prov_info; + bool res = true; + + if (!node || !info) + return false; + + if (!IS_UNICAST(info->unicast)) + return false; + + /* Changing Unicast addresses requires a hard node reset */ + if (!hard && info->unicast != node->primary) + return false; + + /* + * Hard refresh results in immediate use of new Device Key. + * Soft refresh saves new device key as Candidate until we + * successfully receive new incoming message on that key. + */ + if (hard) { + if (!mesh_config_write_device_key(node->cfg, info->device_key)) + return false; + + memcpy(node->dev_key, info->device_key, sizeof(node->dev_key)); + + } else if (!mesh_config_write_candidate(node->cfg, info->device_key)) + return false; + + /* Replace Primary Unicast address if it has changed */ + if (node->primary != info->unicast) { + res = mesh_config_write_unicast(node->cfg, info->unicast); + if (res) { + node->primary = info->unicast; + node->num_ele = info->num_ele; + mesh_net_register_unicast(node->net, node->primary, + node->num_ele); + } + } + + /* Replace Page 0 with Page 128 if it exists */ + if (res) { + if (node_replace_comp(node, 0, 128)) + return true; + } + + return res; +} + const uint8_t *node_get_device_key(struct mesh_node *node) { if (!node) return NULL; - else - return node->dev_key; + + return node->dev_key; +} + +bool node_get_device_key_candidate(struct mesh_node *node, uint8_t *key) +{ + if (!node) + return false; + + return mesh_config_read_candidate(node->cfg, key); +} + +void node_finalize_candidate(struct mesh_node *node) +{ + if (!node) + return; + + if (mesh_config_read_candidate(node->cfg, node->dev_key)) + mesh_config_finalize_candidate(node->cfg); } void node_set_token(struct mesh_node *node, uint8_t token[8]) @@ -785,7 +866,7 @@ uint8_t node_friend_mode_get(struct mesh_node *node) return node->friend; } -static uint16_t generate_node_comp(struct mesh_node *node, uint8_t *buf, +static uint16_t node_generate_comp(struct mesh_node *node, uint8_t *buf, uint16_t sz) { uint16_t n, features, num_ele = 0; @@ -895,6 +976,21 @@ static void convert_node_to_storage(struct mesh_node *node, } +static void free_db_storage(struct mesh_config_node *db_node) +{ + const struct l_queue_entry *entry; + + /* Free temporarily allocated resources */ + entry = l_queue_get_entries(db_node->elements); + for (; entry; entry = entry->next) { + struct mesh_config_element *db_ele = entry->data; + + l_queue_destroy(db_ele->models, l_free); + } + + l_queue_destroy(db_node->elements, l_free); +} + static bool create_node_config(struct mesh_node *node, const uint8_t uuid[16]) { struct mesh_config_node db_node; @@ -922,7 +1018,22 @@ static bool create_node_config(struct mesh_node *node, const uint8_t uuid[16]) return node->cfg != NULL; } -static bool set_node_comp(struct mesh_node *node, uint8_t page_num, +static void node_del_comp(struct mesh_node *node, uint8_t page_num) +{ + struct mesh_config_comp_page *page; + + if (!node) + return; + + page = l_queue_remove_if(node->pages, match_page, + L_UINT_TO_PTR(page_num)); + + l_free(page); + + mesh_config_comp_page_del(node->cfg, page_num); +} + +static bool node_set_comp(struct mesh_node *node, uint8_t page_num, const uint8_t *data, uint16_t len) { struct mesh_config_comp_page *page; @@ -944,16 +1055,6 @@ static bool set_node_comp(struct mesh_node *node, uint8_t page_num, return mesh_config_comp_page_add(node->cfg, page_num, page->data, len); } -static bool create_node_comp(struct mesh_node *node) -{ - uint16_t len; - uint8_t comp[MAX_MSG_LEN - 2]; - - len = generate_node_comp(node, comp, sizeof(comp)); - - return set_node_comp(node, 0, comp, len); -} - const uint8_t *node_get_comp(struct mesh_node *node, uint8_t page_num, uint16_t *len) { @@ -975,6 +1076,7 @@ const uint8_t *node_get_comp(struct mesh_node *node, uint8_t page_num, bool node_replace_comp(struct mesh_node *node, uint8_t retire, uint8_t with) { struct mesh_config_comp_page *old_page, *keep; + bool status; if (!node) return false; @@ -989,9 +1091,13 @@ bool node_replace_comp(struct mesh_node *node, uint8_t retire, uint8_t with) l_free(old_page); keep->page_num = retire; - mesh_config_comp_page_mv(node->cfg, with, retire); + status = mesh_config_comp_page_add(node->cfg, keep->page_num, + keep->data, keep->len); - return true; + if (with != retire) + mesh_config_comp_page_del(node->cfg, with); + + return status; } static void attach_io(void *a, void *b) @@ -1170,8 +1276,13 @@ static bool get_element_properties(struct mesh_node *node, const char *path, * daemon. If the model is present in the application properties, * the operation below will be a "no-op". */ - if (ele->idx == PRIMARY_ELE_IDX) + if (ele->idx == PRIMARY_ELE_IDX) { mesh_model_add(node, ele->models, CONFIG_SRV_MODEL, NULL); + mesh_model_add(node, ele->models, REM_PROV_SRV_MODEL, NULL); + if (node->provisioner) + mesh_model_add(node, ele->models, REM_PROV_CLI_MODEL, + NULL); + } return true; fail: @@ -1232,6 +1343,15 @@ static bool get_app_properties(struct mesh_node *node, const char *path, return true; } +static void save_pages(void *data, void *user_data) +{ + struct mesh_config_comp_page *page = data; + struct mesh_node *node = user_data; + + mesh_config_comp_page_add(node->cfg, page->page_num, page->data, + page->len); +} + static bool add_local_node(struct mesh_node *node, uint16_t unicast, bool kr, bool ivu, uint32_t iv_idx, uint8_t dev_key[16], uint16_t net_key_idx, uint8_t net_key[16]) @@ -1275,10 +1395,14 @@ static bool add_local_node(struct mesh_node *node, uint16_t unicast, bool kr, return false; } + l_queue_foreach(node->pages, save_pages, node); + update_net_settings(node); - /* Initialize configuration server model */ + /* Initialize internal server models */ cfgmod_server_init(node, PRIMARY_ELE_IDX); + remote_prov_server_init(node, PRIMARY_ELE_IDX); + remote_prov_client_init(node, PRIMARY_ELE_IDX); node->busy = true; @@ -1326,39 +1450,59 @@ static void update_model_options(struct mesh_node *node, static bool check_req_node(struct managed_obj_request *req) { + struct mesh_node *node; const int offset = 8; uint16_t node_len, len; uint8_t comp[MAX_MSG_LEN - 2]; const uint8_t *node_comp; - len = generate_node_comp(req->node, comp, sizeof(comp)); + if (req->type != REQUEST_TYPE_ATTACH) { + node = req->node; - if (len < MIN_COMP_SIZE) - return false; + if (!create_node_config(node, node->uuid)) + return false; + } else + node = req->attach; - node_comp = node_get_comp(req->attach, 0, &node_len); + node_comp = node_get_comp(node, 0, &node_len); + len = node_generate_comp(req->node, comp, sizeof(comp)); - /* If no page 0 exists, create it and accept */ - if (!node_len || !node_comp) - return set_node_comp(req->attach, 0, comp, len); + /* If no page 0 exists, then current composition as valid */ + if (req->type != REQUEST_TYPE_ATTACH || !node_len) + goto page_zero_valid; - /* Test Element/Model part of composition and reject if changed */ + /* + * If composition has materially changed, save new composition + * in page 128 until next NPPI procedure. But we do allow + * for CID, PID, VID and/or CRPL to freely change without + * requiring a NPPI procedure. + */ if (node_len != len || memcmp(&node_comp[offset], &comp[offset], node_len - offset)) - return false; + return node_set_comp(node, 128, comp, len); - /* If comp has changed, but not Element/Models, resave and accept */ - else if (memcmp(node_comp, comp, node_len)) - return set_node_comp(req->attach, 0, comp, len); +page_zero_valid: + /* If page 0 represents current App, ensure page 128 doesn't exist */ + node_del_comp(node, 128); - /* Nothing has changed */ - return true; + if (len == node_len && !memcmp(node_comp, comp, len)) + return true; + + return node_set_comp(node, 0, comp, len); +} + +static bool is_zero(const void *a, const void *b) +{ + const struct node_element *element = a; + + return !element->idx; } static bool attach_req_node(struct mesh_node *attach, struct mesh_node *node) { const struct l_queue_entry *attach_entry; const struct l_queue_entry *node_entry; + bool comp_changed = false; attach->obj_path = node->obj_path; node->obj_path = NULL; @@ -1368,6 +1512,34 @@ static bool attach_req_node(struct mesh_node *attach, struct mesh_node *node) return false; } + if (attach->num_ele != node->num_ele) { + struct mesh_config_node db_node; + struct node_element *old_ele, *new_ele; + + convert_node_to_storage(node, &db_node); + + /* + * If composition has materially changed, we need to discard + * everything we knew about elements in the old application, + * and start from what they are telling us now. + */ + old_ele = l_queue_remove_if(attach->elements, is_zero, NULL); + new_ele = l_queue_remove_if(node->elements, is_zero, NULL); + element_free(new_ele); + + l_queue_destroy(attach->elements, element_free); + attach->elements = node->elements; + attach->num_ele = node->num_ele; + + /* Restore primary elements */ + l_queue_push_head(attach->elements, old_ele); + + comp_changed = true; + + mesh_config_reset(attach->cfg, &db_node); + free_db_storage(&db_node); + } + attach_entry = l_queue_get_entries(attach->elements); node_entry = l_queue_get_entries(node->elements); @@ -1384,6 +1556,10 @@ static bool attach_req_node(struct mesh_node *attach, struct mesh_node *node) attach_entry = attach_entry->next; node_entry = node_entry->next; + + /* Only need the Primary element during Composition change */ + if (comp_changed) + break; } mesh_agent_remove(attach->agent); @@ -1399,8 +1575,12 @@ static bool attach_req_node(struct mesh_node *attach, struct mesh_node *node) node->owner = NULL; update_composition(node, attach); + update_model_options(node, attach); + if (comp_changed) + node->elements = NULL; + node_remove(node); return true; @@ -1499,16 +1679,7 @@ static void get_managed_objects_cb(struct l_dbus_message *msg, void *user_data) node->num_ele = num_ele; - if (req->type != REQUEST_TYPE_ATTACH) { - /* Generate node configuration for a brand new node */ - if (!create_node_config(node, node->uuid)) - goto fail; - - /* Create node composition */ - if (!create_node_comp(node)) - goto fail; - } else if (!check_req_node(req)) - /* Check the integrity of the node composition */ + if (!check_req_node(req)) goto fail; switch (req->type) { diff --git a/mesh/node.h b/mesh/node.h index 2e3d89812..a98945223 100644 --- a/mesh/node.h +++ b/mesh/node.h @@ -38,6 +38,8 @@ uint16_t node_get_primary_net_idx(struct mesh_node *node); void node_set_token(struct mesh_node *node, uint8_t token[8]); const uint8_t *node_get_token(struct mesh_node *node); const uint8_t *node_get_device_key(struct mesh_node *node); +bool node_get_device_key_candidate(struct mesh_node *node, uint8_t *key); +void node_finalize_candidate(struct mesh_node *node); void node_set_num_elements(struct mesh_node *node, uint8_t num_ele); uint8_t node_get_num_elements(struct mesh_node *node); uint8_t node_default_ttl_get(struct mesh_node *node); @@ -89,3 +91,4 @@ const char *node_get_storage_dir(struct mesh_node *node); bool node_load_from_storage(const char *storage_dir); void node_finalize_new_node(struct mesh_node *node, struct mesh_io *io); void node_property_changed(struct mesh_node *node, const char *property); +bool node_refresh(struct mesh_node *node, bool hard, void *prov_info); diff --git a/mesh/pb-adv.c b/mesh/pb-adv.c index 180b16258..385d81d65 100644 --- a/mesh/pb-adv.c +++ b/mesh/pb-adv.c @@ -219,7 +219,7 @@ static void tx_timeout(struct l_timeout *timeout, void *user_data) cb(user_data, 1); } -static void pb_adv_tx(void *user_data, void *data, uint16_t len) +static void pb_adv_tx(void *user_data, const void *data, uint16_t len) { struct pb_adv_session *session = user_data; @@ -478,7 +478,7 @@ static void pb_adv_packet(void *user_data, const uint8_t *pkt, uint16_t len) bool pb_adv_reg(bool initiator, mesh_prov_open_func_t open_cb, mesh_prov_close_func_t close_cb, mesh_prov_receive_func_t rx_cb, mesh_prov_ack_func_t ack_cb, - uint8_t uuid[16], void *user_data) + const uint8_t *uuid, void *user_data) { struct pb_adv_session *session, *old_session; diff --git a/mesh/pb-adv.h b/mesh/pb-adv.h index 5b1e03dae..e33ba8e35 100644 --- a/mesh/pb-adv.h +++ b/mesh/pb-adv.h @@ -11,5 +11,5 @@ bool pb_adv_reg(bool initiator, mesh_prov_open_func_t open_cb, mesh_prov_close_func_t close_cb, mesh_prov_receive_func_t rx_cb, mesh_prov_ack_func_t ack_cb, - uint8_t uuid[16], void *user_data); + const uint8_t *uuid, void *user_data); void pb_adv_unreg(void *user_data); diff --git a/mesh/prov-acceptor.c b/mesh/prov-acceptor.c index bf8c573da..fd9d4cd5d 100644 --- a/mesh/prov-acceptor.c +++ b/mesh/prov-acceptor.c @@ -22,6 +22,7 @@ #include "mesh/net.h" #include "mesh/prov.h" #include "mesh/provision.h" +#include "mesh/remprv.h" #include "mesh/pb-adv.h" #include "mesh/mesh.h" #include "mesh/agent.h" @@ -169,9 +170,6 @@ static void acp_prov_open(void *user_data, prov_trans_tx_t trans_tx, prov->transport != transport) return; - if (transport != PB_ADV) - return; - prov->trans_tx = trans_tx; prov->transport = transport; prov->trans_data = trans_data; @@ -425,9 +423,10 @@ static bool prov_start_check(struct prov_start *start, return true; } -static void acp_prov_rx(void *user_data, const uint8_t *data, uint16_t len) +static void acp_prov_rx(void *user_data, const void *dptr, uint16_t len) { struct mesh_prov_acceptor *rx_prov = user_data; + const uint8_t *data = dptr; struct mesh_prov_node_info *info; struct prov_fail_msg fail; uint8_t type = *data++; @@ -654,14 +653,19 @@ static void acp_prov_rx(void *user_data, const uint8_t *data, uint16_t len) info->flags = prov->rand_auth_workspace[18]; info->iv_index = l_get_be32(prov->rand_auth_workspace + 19); info->unicast = l_get_be16(prov->rand_auth_workspace + 23); + info->num_ele = prov->conf_inputs.caps.num_ele; + + /* Send prov complete */ + prov->rand_auth_workspace[0] = PROV_COMPLETE; + prov->trans_tx(prov->trans_data, + prov->rand_auth_workspace, 1); result = prov->cmplt(prov->caller_data, PROV_ERR_SUCCESS, info); prov->cmplt = NULL; l_free(info); if (result) { - prov->rand_auth_workspace[0] = PROV_COMPLETE; - prov_send(prov, prov->rand_auth_workspace, 1); + l_debug("PROV_COMPLETE"); goto cleanup; } else { fail.reason = PROV_ERR_UNEXPECTED_ERR; @@ -721,7 +725,7 @@ static void acp_prov_ack(void *user_data, uint8_t msg_num) /* This starts unprovisioned device beacon */ -bool acceptor_start(uint8_t num_ele, uint8_t uuid[16], +bool acceptor_start(uint8_t num_ele, uint8_t *uuid, uint16_t algorithms, uint32_t timeout, struct mesh_agent *agent, mesh_prov_acceptor_complete_func_t complete_cb, @@ -733,8 +737,10 @@ bool acceptor_start(uint8_t num_ele, uint8_t uuid[16], uint8_t len = sizeof(beacon) - sizeof(uint32_t); bool result; - /* Invoked from Join() method in mesh-api.txt, to join a - * remote mesh network. + /* + * Invoked from Join() method in mesh-api.txt, to join a + * remote mesh network. May also be invoked with a NULL + * uuid to perform a Device Key Refresh procedure. */ if (prov) @@ -752,37 +758,50 @@ bool acceptor_start(uint8_t num_ele, uint8_t uuid[16], caps = mesh_agent_get_caps(agent); - /* TODO: Should we sanity check values here or elsewhere? */ prov->conf_inputs.caps.num_ele = num_ele; - prov->conf_inputs.caps.pub_type = caps->pub_type; - prov->conf_inputs.caps.static_type = caps->static_type; - prov->conf_inputs.caps.output_size = caps->output_size; - prov->conf_inputs.caps.input_size = caps->input_size; - - /* Store UINT16 values in Over-the-Air order, in packed structure - * for crypto inputs - */ l_put_be16(algorithms, &prov->conf_inputs.caps.algorithms); - l_put_be16(caps->output_action, &prov->conf_inputs.caps.output_action); - l_put_be16(caps->input_action, &prov->conf_inputs.caps.input_action); - - /* Compose Unprovisioned Beacon */ - memcpy(beacon + 2, uuid, 16); - l_put_be16(caps->oob_info, beacon + 18); - if (caps->oob_info & OOB_INFO_URI_HASH){ - l_put_be32(caps->uri_hash, beacon + 20); - len += sizeof(uint32_t); + + if (caps) { + /* TODO: Should we sanity check values here or elsewhere? */ + prov->conf_inputs.caps.pub_type = caps->pub_type; + prov->conf_inputs.caps.static_type = caps->static_type; + prov->conf_inputs.caps.output_size = caps->output_size; + prov->conf_inputs.caps.input_size = caps->input_size; + + /* Store UINT16 values in Over-the-Air order, in packed + * structure for crypto inputs + */ + l_put_be16(caps->output_action, + &prov->conf_inputs.caps.output_action); + l_put_be16(caps->input_action, + &prov->conf_inputs.caps.input_action); + + /* Populate Caps fields of beacon */ + l_put_be16(caps->oob_info, beacon + 18); + if (caps->oob_info & OOB_INFO_URI_HASH) { + l_put_be32(caps->uri_hash, beacon + 20); + len += sizeof(uint32_t); + } } - /* Infinitely Beacon until Canceled, or Provisioning Starts */ - result = mesh_send_pkt(0, 500, beacon, len); + if (uuid) { + /* Compose Unprovisioned Beacon */ + memcpy(beacon + 2, uuid, 16); + + /* Infinitely Beacon until Canceled, or Provisioning Starts */ + result = mesh_send_pkt(0, 500, beacon, len); - if (!result) - goto error_fail; + if (!result) + goto error_fail; - /* Always register for PB-ADV */ - result = pb_adv_reg(false, acp_prov_open, acp_prov_close, acp_prov_rx, - acp_prov_ack, uuid, prov); + /* Always register for PB-ADV */ + result = pb_adv_reg(false, acp_prov_open, acp_prov_close, + acp_prov_rx, acp_prov_ack, uuid, prov); + } else { + /* Run Device Key Refresh Procedure */ + result = register_nppi_acceptor(acp_prov_open, acp_prov_close, + acp_prov_rx, acp_prov_ack, prov); + } if (result) return true; diff --git a/mesh/prov-initiator.c b/mesh/prov-initiator.c index c62577523..653f3ae3e 100644 --- a/mesh/prov-initiator.c +++ b/mesh/prov-initiator.c @@ -21,10 +21,12 @@ #include "mesh/crypto.h" #include "mesh/net.h" #include "mesh/node.h" +#include "mesh/model.h" #include "mesh/keyring.h" #include "mesh/prov.h" #include "mesh/provision.h" #include "mesh/pb-adv.h" +#include "mesh/remprv.h" #include "mesh/mesh.h" #include "mesh/agent.h" #include "mesh/error.h" @@ -82,12 +84,16 @@ struct mesh_prov_initiator { struct l_timeout *timeout; uint32_t to_secs; enum int_state state; - enum trans_type transport; uint16_t net_idx; + uint16_t svr_idx; uint16_t unicast; + uint16_t server; + uint8_t transport; uint8_t material; uint8_t expected; int8_t previous; + uint8_t out_num; + uint8_t rpr_state; struct conf_input conf_inputs; uint8_t calc_key[16]; uint8_t salt[16]; @@ -100,14 +106,23 @@ struct mesh_prov_initiator { uint8_t uuid[16]; }; +struct scan_req { + mesh_prov_initiator_scan_result_t scan_result; + struct mesh_node *node; + int count; +}; + static struct mesh_prov_initiator *prov = NULL; +static struct l_queue *scans; static void initiator_free(void) { - if (prov) + if (prov) { l_timeout_remove(prov->timeout); - mesh_send_cancel(&pkt_filter, sizeof(pkt_filter)); + if (!prov->server) + mesh_send_cancel(&pkt_filter, sizeof(pkt_filter)); + } pb_adv_unreg(prov); @@ -119,6 +134,15 @@ static void int_prov_close(void *user_data, uint8_t reason) { struct mesh_prov_initiator *prov = user_data; struct mesh_prov_node_info info; + uint8_t msg[4]; + int n; + + if (prov->server) { + n = mesh_model_opcode_set(OP_REM_PROV_LINK_CLOSE, msg); + msg[n++] = reason == PROV_ERR_SUCCESS ? 0x00 : 0x02; + mesh_model_send(prov->node, 0, prov->server, APP_IDX_DEV_REMOTE, + prov->svr_idx, DEFAULT_TTL, true, n, msg); + } if (reason != PROV_ERR_SUCCESS) { prov->complete_cb(prov->caller_data, reason, NULL); @@ -626,9 +650,10 @@ static void int_prov_start_auth(const struct mesh_agent_prov_caps *prov_caps, } } -static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len) +static void int_prov_rx(void *user_data, const void *dptr, uint16_t len) { struct mesh_prov_initiator *rx_prov = user_data; + const uint8_t *data = dptr; uint8_t *out; uint8_t type = *data++; uint8_t fail_code[2]; @@ -651,7 +676,7 @@ static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len) if (type >= L_ARRAY_SIZE(expected_pdu_size) || len != expected_pdu_size[type]) { l_error("Expected PDU size %d, Got %d (type: %2.2x)", - len, expected_pdu_size[type], type); + expected_pdu_size[type], len, type); fail_code[1] = PROV_ERR_INVALID_FORMAT; goto failure; } @@ -773,7 +798,12 @@ static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len) goto failure; } - if (!prov->data_req_cb(prov->caller_data, + if (prov->transport == PB_NPPI_00 || + prov->transport == PB_NPPI_02) { + /* No App data needed */ + initiator_prov_data(prov->svr_idx, prov->server, + prov->caller_data); + } else if (!prov->data_req_cb(prov->caller_data, prov->conf_inputs.caps.num_ele)) { l_error("Provisioning Failed-Data Get"); fail_code[1] = PROV_ERR_CANT_ASSIGN_ADDR; @@ -851,6 +881,8 @@ static void int_prov_ack(void *user_data, uint8_t msg_num) static void initiator_open_cb(void *user_data, int err) { + uint8_t msg[20]; + int n; bool result; if (!prov) @@ -859,18 +891,30 @@ static void initiator_open_cb(void *user_data, int err) if (err != MESH_ERROR_NONE) goto fail; - /* Always register for PB-ADV */ - result = pb_adv_reg(true, int_prov_open, int_prov_close, int_prov_rx, - int_prov_ack, prov->uuid, prov); + if (prov->server) { + n = mesh_model_opcode_set(OP_REM_PROV_LINK_OPEN, msg); + + if (prov->transport <= PB_NPPI_02) { + msg[n++] = prov->transport; + } else { + memcpy(msg + n, prov->uuid, 16); + n += 16; + } + + result = mesh_model_send(prov->node, 0, prov->server, + APP_IDX_DEV_REMOTE, prov->svr_idx, + DEFAULT_TTL, true, n, msg); + } else { + /* Always register for PB-ADV */ + result = pb_adv_reg(true, int_prov_open, int_prov_close, + int_prov_rx, int_prov_ack, prov->uuid, prov); + } if (!result) { err = MESH_ERROR_FAILED; goto fail; } - if (!prov) - return; - prov->start_cb(prov->caller_data, MESH_ERROR_NONE); return; fail: @@ -878,10 +922,20 @@ fail: initiator_free(); } -bool initiator_start(enum trans_type transport, - uint8_t uuid[16], - uint16_t max_ele, - uint32_t timeout, /* in seconds from mesh.conf */ +static void initiate_to(struct l_timeout *timeout, void *user_data) +{ + struct mesh_prov_initiator *rx_prov = user_data; + + if (rx_prov != prov) { + l_timeout_remove(timeout); + return; + } + + int_prov_close(user_data, PROV_ERR_TIMEOUT); +} + +bool initiator_start(uint8_t transport, uint16_t server, uint16_t svr_idx, + uint8_t uuid[16], uint16_t max_ele, uint32_t timeout, struct mesh_agent *agent, mesh_prov_initiator_start_func_t start_cb, mesh_prov_initiator_data_req_func_t data_req_cb, @@ -904,6 +958,10 @@ bool initiator_start(enum trans_type transport, prov->data_req_cb = data_req_cb; prov->caller_data = caller_data; prov->previous = -1; + prov->server = server; + prov->svr_idx = svr_idx; + prov->transport = transport; + prov->timeout = l_timeout_create(timeout, initiate_to, prov, NULL); memcpy(prov->uuid, uuid, 16); mesh_agent_refresh(prov->agent, initiator_open_cb, prov); @@ -915,3 +973,182 @@ void initiator_cancel(void *user_data) { initiator_free(); } + +static void rpr_tx(void *user_data, const void *data, uint16_t len) +{ + struct mesh_prov_initiator *prov = user_data; + uint8_t msg[72]; + int n; + + n = mesh_model_opcode_set(OP_REM_PROV_PDU_SEND, msg); + msg[n++] = ++prov->out_num; + memcpy(msg + n, data, len); + l_debug("Send OB %2.2x, with packet type %d", msg[n], prov->out_num); + n += len; + + prov->rpr_state = PB_REMOTE_STATE_OB_PKT_TX; + mesh_model_send(prov->node, 0, prov->server, APP_IDX_DEV_REMOTE, + prov->svr_idx, DEFAULT_TTL, true, n, msg); +} + +static bool match_req_node(const void *a, const void *b) +{ + const struct scan_req *req = a; + const struct mesh_node *node = b; + + return req->node == node; +} + +static bool remprv_cli_pkt(uint16_t src, uint16_t unicast, uint16_t app_idx, + uint16_t net_idx, const uint8_t *data, + uint16_t size, const void *user_data) +{ + struct mesh_node *node = (struct mesh_node *) user_data; + const uint8_t *pkt = data; + struct scan_req *req; + uint32_t opcode; + uint16_t n; + + if (mesh_model_opcode_get(pkt, size, &opcode, &n)) { + size -= n; + pkt += n; + } else + return false; + + if (opcode < OP_REM_PROV_SCAN_CAP_GET || + opcode > OP_REM_PROV_PDU_REPORT) + return false; + + if (app_idx != APP_IDX_DEV_REMOTE && app_idx != APP_IDX_DEV_LOCAL) + return true; + + /* Local Dev key only allowed for Loop-backs */ + if (app_idx == APP_IDX_DEV_LOCAL && unicast != src) + return true; + + if (prov && (prov->server != src || prov->node != node)) + return true; + + n = 0; + + switch (opcode) { + default: + return false; + + /* Provisioning Opcodes */ + case OP_REM_PROV_LINK_STATUS: + if (size != 2 || !prov) + break; + + if (pkt[0] == PB_REM_ERR_SUCCESS) + prov->rpr_state = pkt[1]; + + break; + + case OP_REM_PROV_LINK_REPORT: + if (size != 2 || !prov) + return true; + + if (pkt[0] != PB_REM_ERR_SUCCESS) { + if (pkt[0] == PB_REM_ERR_CLOSED_BY_DEVICE || + pkt[0] == PB_REM_ERR_CLOSED_BY_SERVER) + int_prov_close(prov, pkt[1]); + + break; + } + + + if (prov->rpr_state == PB_REMOTE_STATE_LINK_OPENING) + int_prov_open(prov, rpr_tx, prov, prov->transport); + else if (prov->rpr_state == PB_REMOTE_STATE_LINK_CLOSING) { + prov->rpr_state = PB_REMOTE_STATE_IDLE; + int_prov_close(prov, pkt[1]); + break; + } + + prov->rpr_state = pkt[1]; + + break; + + case OP_REM_PROV_PDU_REPORT: + int_prov_rx(prov, pkt + 1, size - 1); + break; + + case OP_REM_PROV_PDU_OB_REPORT: + if (size != 1 || !prov) + break; + + l_debug("Got Ack for OB %d", pkt[0]); + if (prov->rpr_state == PB_REMOTE_STATE_OB_PKT_TX && + pkt[0] == prov->out_num) + int_prov_ack(prov, pkt[0]); + + break; + + /* Scan Opcodes */ + case OP_REM_PROV_SCAN_CAP_STATUS: + case OP_REM_PROV_SCAN_STATUS: + break; + + case OP_REM_PROV_SCAN_REPORT: + case OP_REM_PROV_EXT_SCAN_REPORT: + req = l_queue_find(scans, match_req_node, node); + if (req) { + req->scan_result(node, src, + opcode == OP_REM_PROV_EXT_SCAN_REPORT, + pkt, size); + } + } + + return true; +} + +void initiator_scan_reg(mesh_prov_initiator_scan_result_t scan_result, + void *user_data) +{ + struct scan_req *req; + + if (!scans) + scans = l_queue_new(); + + req = l_queue_find(scans, match_req_node, user_data); + if (!req) { + req = l_new(struct scan_req, 1); + l_queue_push_head(scans, req); + } + + req->scan_result = scan_result; + req->node = user_data; + req->count++; +} + +void initiator_scan_unreg(void *user_data) +{ + struct scan_req *req; + + req = l_queue_find(scans, match_req_node, user_data); + if (req) { + req->count--; + if (!req->count) { + l_queue_remove(scans, req); + l_free(req); + } + } +} + +static void remprv_cli_unregister(void *user_data) +{ +} + +static const struct mesh_model_ops ops = { + .unregister = remprv_cli_unregister, + .recv = remprv_cli_pkt, + .bind = NULL, + .sub = NULL, + .pub = NULL +}; + +void remote_prov_client_init(struct mesh_node *node, uint8_t ele_idx) +{ + mesh_model_register(node, ele_idx, REM_PROV_CLI_MODEL, &ops, node); +} diff --git a/mesh/prov.h b/mesh/prov.h index 99e864c50..e86668fe4 100644 --- a/mesh/prov.h +++ b/mesh/prov.h @@ -39,14 +39,14 @@ enum mesh_prov_mode { struct mesh_prov; -typedef void (*prov_trans_tx_t)(void *trans_data, void *data, uint16_t len); +typedef void (*prov_trans_tx_t)(void *tx_data, const void *data, uint16_t len); typedef void (*mesh_prov_open_func_t)(void *user_data, prov_trans_tx_t trans_tx, void *trans_data, uint8_t trans_type); typedef void (*mesh_prov_close_func_t)(void *user_data, uint8_t reason); typedef void (*mesh_prov_send_func_t)(bool success, struct mesh_prov *prov); typedef void (*mesh_prov_ack_func_t)(void *user_data, uint8_t msg_num); -typedef void (*mesh_prov_receive_func_t)(void *user_data, const uint8_t *data, +typedef void (*mesh_prov_receive_func_t)(void *user_data, const void *data, uint16_t size); diff --git a/mesh/provision.h b/mesh/provision.h index 1634c4d40..cfeb6deba 100644 --- a/mesh/provision.h +++ b/mesh/provision.h @@ -70,10 +70,11 @@ struct mesh_agent; #define OOB_INFO_URI_HASH 0x0002 /* PB_REMOTE not supported from unprovisioned state */ -enum trans_type { - PB_ADV = 0, - PB_GATT, -}; +#define PB_NPPI_00 0x00 +#define PB_NPPI_01 0x01 +#define PB_NPPI_02 0x02 +#define PB_ADV 0x03 /* Internal only, and may be reassigned */ +#define PB_GATT 0x04 /* Internal only, and may be reassigned */ #define PROV_FLAG_KR 0x01 #define PROV_FLAG_IVU 0x02 @@ -101,15 +102,21 @@ typedef bool (*mesh_prov_initiator_complete_func_t)(void *user_data, uint8_t status, struct mesh_prov_node_info *info); +typedef void (*mesh_prov_initiator_scan_result_t)(void *user_data, + uint16_t server, bool extended, + const uint8_t *data, uint16_t len); + /* This starts unprovisioned device beacon */ -bool acceptor_start(uint8_t num_ele, uint8_t uuid[16], +bool acceptor_start(uint8_t num_ele, uint8_t *uuid, uint16_t algorithms, uint32_t timeout, struct mesh_agent *agent, mesh_prov_acceptor_complete_func_t complete_cb, void *caller_data); void acceptor_cancel(void *user_data); -bool initiator_start(enum trans_type transport, +bool initiator_start(uint8_t transport, + uint16_t server, + uint16_t svr_idx, uint8_t uuid[16], uint16_t max_ele, uint32_t timeout, /* in seconds from mesh.conf */ @@ -120,3 +127,7 @@ bool initiator_start(enum trans_type transport, void *node, void *caller_data); void initiator_prov_data(uint16_t net_idx, uint16_t primary, void *caller_data); void initiator_cancel(void *caller_data); + +void initiator_scan_reg(mesh_prov_initiator_scan_result_t scan_result, + void *user_data); +void initiator_scan_unreg(void *caller_data); diff --git a/mesh/remprv-server.c b/mesh/remprv-server.c new file mode 100644 index 000000000..e24758093 --- /dev/null +++ b/mesh/remprv-server.c @@ -0,0 +1,907 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2020 Intel Corporation. All rights reserved. + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/time.h> +#include <ell/ell.h> + +#include "src/shared/ad.h" + +#include "mesh/mesh-defs.h" +#include "mesh/mesh-io.h" +#include "mesh/util.h" +#include "mesh/node.h" +#include "mesh/net.h" +#include "mesh/appkey.h" +#include "mesh/model.h" +#include "mesh/prov.h" +#include "mesh/provision.h" +#include "mesh/pb-adv.h" +#include "mesh/remprv.h" + +#define EXT_LIST_SIZE 60 + +#define RPR_DEV_KEY 0x00 +#define RPR_ADDR 0x01 +#define RPR_COMP 0x02 +#define RPR_ADV 0xFF /* Internal use only*/ + +struct rem_scan_data { + struct mesh_node *node; + struct l_timeout *timeout; + uint8_t *list; + uint16_t client; + uint16_t oob_info; + uint16_t net_idx; + uint8_t state; + uint8_t scanned_limit; + uint8_t addr[6]; + uint8_t uuid[16]; + uint8_t to_secs; + uint8_t rxed_ads; + uint8_t ext_cnt; + bool fltr; + uint8_t ext[0]; +}; + +static struct rem_scan_data *rpb_scan; + +struct rem_prov_data { + struct mesh_node *node; + struct l_timeout *timeout; + void *trans_data; + uint16_t client; + uint16_t net_idx; + uint8_t svr_pdu_num; + uint8_t cli_pdu_num; + uint8_t state; + uint8_t nppi_proc; + union { + struct { + mesh_prov_open_func_t open_cb; + mesh_prov_close_func_t close_cb; + mesh_prov_receive_func_t rx_cb; + mesh_prov_ack_func_t ack_cb; + struct mesh_prov_node_info info; + } nppi; + struct { + uint8_t uuid[17]; + prov_trans_tx_t tx; + } adv; + } u; +}; + +static struct rem_prov_data *rpb_prov; + +static const uint8_t prvb[2] = {BT_AD_MESH_BEACON, 0x00}; +static const uint8_t pkt_filter = BT_AD_MESH_PROV; +static const char *name = "Test Name"; + +static const uint8_t zero[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +static void srv_open(void *user_data, prov_trans_tx_t adv_tx, + void *trans_data, uint8_t nppi_proc) +{ + struct rem_prov_data *prov = user_data; + uint8_t msg[5]; + int n; + + if (prov != rpb_prov || prov->state != PB_REMOTE_STATE_LINK_OPENING) + return; + + l_debug("Remote Link open confirmed"); + prov->u.adv.tx = adv_tx; + prov->trans_data = trans_data; + prov->state = PB_REMOTE_STATE_LINK_ACTIVE; + + n = mesh_model_opcode_set(OP_REM_PROV_LINK_REPORT, msg); + msg[n++] = PB_REM_ERR_SUCCESS; + msg[n++] = prov->state; + + mesh_model_send(prov->node, 0, prov->client, APP_IDX_DEV_LOCAL, + prov->net_idx, DEFAULT_TTL, true, n, msg); +} + +static void srv_rx(void *user_data, const void *dptr, uint16_t len) +{ + struct rem_prov_data *prov = user_data; + const uint8_t *data = dptr; + uint8_t msg[69]; + int n; + + if (prov != rpb_prov || prov->state < PB_REMOTE_STATE_LINK_ACTIVE || + len > 65) + return; + + l_debug("Remote PB IB-PDU"); + + prov->svr_pdu_num++; + n = mesh_model_opcode_set(OP_REM_PROV_PDU_REPORT, msg); + msg[n++] = prov->svr_pdu_num; + memcpy(msg + n, data, len); + n += len; + + mesh_model_send(prov->node, 0, prov->client, APP_IDX_DEV_LOCAL, + prov->net_idx, DEFAULT_TTL, true, n, msg); +} + +static void srv_ack(void *user_data, uint8_t msg_num) +{ + struct rem_prov_data *prov = user_data; + uint8_t msg[4]; + int n; + + if (prov != rpb_prov || prov->state != PB_REMOTE_STATE_OB_PKT_TX) + return; + + l_debug("Remote PB ACK"); + + prov->state = PB_REMOTE_STATE_LINK_ACTIVE; + n = mesh_model_opcode_set(OP_REM_PROV_PDU_OB_REPORT, msg); + msg[n++] = prov->cli_pdu_num; + + mesh_model_send(prov->node, 0, prov->client, APP_IDX_DEV_LOCAL, + prov->net_idx, DEFAULT_TTL, true, n, msg); +} + +static void srv_close(void *user_data, uint8_t reason) +{ + struct rem_prov_data *prov = user_data; + uint8_t msg[4]; + int n; + + if (prov != rpb_prov || prov->state < PB_REMOTE_STATE_LINK_ACTIVE) + return; + + l_debug("Remote PB Close"); + + prov->state = PB_REMOTE_STATE_LINK_CLOSING; + n = mesh_model_opcode_set(OP_REM_PROV_LINK_REPORT, msg); + msg[n++] = prov->state; + msg[n++] = reason; + + mesh_model_send(prov->node, 0, prov->client, APP_IDX_DEV_LOCAL, + prov->net_idx, DEFAULT_TTL, true, n, msg); +} + +static void send_prov_status(struct rem_prov_data *prov, uint8_t status) +{ + uint16_t n; + uint8_t msg[5]; + bool segmented = prov->state == PB_REMOTE_STATE_LINK_CLOSING ? + true : false; + + n = mesh_model_opcode_set(OP_REM_PROV_LINK_STATUS, msg); + msg[n++] = status; + msg[n++] = prov->state; + + l_info("RPB-Link Status(%d): dst %4.4x", prov->state, prov->client); + + mesh_model_send(prov->node, 0, prov->client, APP_IDX_DEV_LOCAL, + prov->net_idx, DEFAULT_TTL, segmented, n, msg); +} + +static void remprv_prov_cancel(struct l_timeout *timeout, + void *user_data) +{ + struct rem_prov_data *prov = user_data; + + if (prov != rpb_prov) + return; + + l_timeout_remove(prov->timeout); + l_free(prov); + rpb_prov = NULL; +} + +static void deregister_ext_ad_type(uint8_t ad_type) +{ + uint8_t short_ad; + + switch (ad_type) { + case BT_AD_MESH_BEACON: + case BT_AD_MESH_DATA: + case BT_AD_MESH_PROV: + case BT_AD_UUID16_SOME: + case BT_AD_UUID32_SOME: + case BT_AD_UUID128_SOME: + case BT_AD_NAME_SHORT: + return; + + case BT_AD_UUID16_ALL: + case BT_AD_UUID32_ALL: + case BT_AD_UUID128_ALL: + case BT_AD_NAME_COMPLETE: + /* Automatically get short versions */ + short_ad = ad_type - 1; + mesh_io_deregister_recv_cb(NULL, &short_ad, 1); + + /* fall through */ + default: + mesh_io_deregister_recv_cb(NULL, &ad_type, 1); + break; + } +} + +static void remprv_scan_cancel(struct l_timeout *timeout, + void *user_data) +{ + struct rem_scan_data *scan = user_data; + uint8_t msg[22 + EXT_LIST_SIZE]; + uint16_t i, n; + + if (!scan || scan != rpb_scan) + return; + + for (n = 0; n < scan->ext_cnt; n++) + deregister_ext_ad_type(scan->ext[n]); + + if (scan->timeout == timeout) { + /* Return Extended Results */ + if (scan->ext_cnt) { + /* Return Extended Result */ + n = mesh_model_opcode_set( + OP_REM_PROV_EXT_SCAN_REPORT, msg); + msg[n++] = PB_REM_ERR_SUCCESS; + memcpy(msg + n, scan->uuid, 16); + n += 16; + + if (scan->oob_info) { + l_put_le16(0, msg + n); + n += 2; + } + + i = 0; + while (scan->list[i]) { + msg[n++] = scan->list[i]; + memcpy(msg + n, &scan->list[i + 1], + scan->list[i]); + n += scan->list[i]; + i += scan->list[i] + 1; + } + } + } + + l_timeout_remove(scan->timeout); + l_free(scan->list); + l_free(scan); + rpb_scan = NULL; +} + +static void scan_pkt(void *user_data, struct mesh_io_recv_info *info, + const uint8_t *data, uint16_t len) +{ + struct rem_scan_data *scan = user_data; + uint8_t msg[22 + EXT_LIST_SIZE]; + uint16_t i, n; + uint8_t filled = 0; + bool report = false; + + if (scan != rpb_scan) + return; + + if (scan->ext_cnt) + goto extended_scan; + + /* RX Unprovisioned Beacon */ + if (data[0] != BT_AD_MESH_BEACON || data[1] || + (len != 18 && len != 20 && len != 24)) + return; + + data += 2; + len -= 2; + + for (n = 0; !report && n < scan->scanned_limit; n++) { + if (!memcmp(&scan->list[n * 17 + 1], data, 16)) { + + /* Repeat UUID, check RSSI */ + if ((int8_t) scan->list[n * 17] < info->rssi) { + report = true; + scan->list[n * 17] = (uint8_t) info->rssi; + } + + } else if (!memcmp(&scan->list[n * 17 + 1], zero, 16)) { + + /* Found Empty slot */ + report = true; + scan->list[n * 17] = (uint8_t) info->rssi; + memcpy(&scan->list[n * 17 + 1], data, 16); + } + + filled++; + } + + if (!report) + return; + + n = mesh_model_opcode_set(OP_REM_PROV_SCAN_REPORT, msg); + msg[n++] = (uint8_t) info->rssi; + memcpy(msg + n, data, len); + n += len; + + /* Always return oob_info, even if it wasn't in beacon */ + if (len == 16) { + l_put_le16(0, msg + n); + n += 2; + } + + goto send_report; + +extended_scan: + if (data[0] == BT_AD_MESH_BEACON && !data[1]) { + if (len != 18 && len != 20 && len != 24) + return; + + /* Check UUID */ + if (memcmp(data + 2, scan->uuid, 16)) + return; + + /* Zero AD list if prior data RXed from different bd_addr */ + if (memcmp(scan->addr, info->addr, 6)) { + scan->list[0] = 0; + scan->rxed_ads = 0; + } + + memcpy(scan->addr, info->addr, 6); + scan->fltr = true; + + if (len >= 20) + scan->oob_info = l_get_le16(data + 18); + + if (scan->rxed_ads != scan->ext_cnt) + return; + + + } else if (data[0] != BT_AD_MESH_BEACON) { + if (!scan->fltr || !memcmp(scan->addr, info->addr, 6)) { + i = 0; + while (scan->list[i]) { + /* check if seen */ + if (scan->list[i + 1] == data[0]) + return; + + i += scan->list[i] + 1; + } + + /* Overflow Protection */ + if (i + len + 1 > EXT_LIST_SIZE) + return; + + scan->list[i] = len; + scan->list[i + len + 1] = 0; + memcpy(scan->list + i + 1, data, len); + scan->rxed_ads++; + } + + if (scan->rxed_ads != scan->ext_cnt) + return; + + } else + return; + + n = mesh_model_opcode_set(OP_REM_PROV_EXT_SCAN_REPORT, msg); + msg[n++] = PB_REM_ERR_SUCCESS; + memcpy(msg + n, scan->uuid, 16); + n += 16; + l_put_le16(scan->oob_info, msg + n); + n += 2; + + i = 0; + while (scan->list[i]) { + msg[n++] = scan->list[i]; + memcpy(msg + n, &scan->list[i + 1], scan->list[i]); + n += scan->list[i]; + i += scan->list[i]; + } + +send_report: + print_packet("App Tx", msg, n); + mesh_model_send(scan->node, 0, scan->client, APP_IDX_DEV_LOCAL, + scan->net_idx, DEFAULT_TTL, true, n, msg); + + /* Clean-up if we are done reporting*/ + if (filled == scan->scanned_limit || scan->ext_cnt) + remprv_scan_cancel(NULL, scan); +} + +static bool register_ext_ad_type(uint8_t ad_type, struct rem_scan_data *scan) +{ + uint8_t short_ad; + + switch (ad_type) { + case BT_AD_MESH_PROV: + case BT_AD_UUID16_SOME: + case BT_AD_UUID32_SOME: + case BT_AD_UUID128_SOME: + case BT_AD_NAME_SHORT: + /* Illegal Requests */ + return false; + + case BT_AD_UUID16_ALL: + case BT_AD_UUID32_ALL: + case BT_AD_UUID128_ALL: + case BT_AD_NAME_COMPLETE: + /* Automatically get short versions */ + short_ad = ad_type - 1; + mesh_io_register_recv_cb(NULL, &short_ad, 1, scan_pkt, scan); + + /* fall through */ + default: + mesh_io_register_recv_cb(NULL, &ad_type, 1, scan_pkt, scan); + + /* fall through */ + + case BT_AD_MESH_BEACON: + /* Ignored/auto request */ + break; + } + + return true; +} + +static void link_active(void *user_data) +{ + struct rem_prov_data *prov = user_data; + uint8_t msg[5]; + int n; + + if (prov != rpb_prov || prov->state != PB_REMOTE_STATE_LINK_OPENING) + return; + + l_debug("Remote Link open confirmed"); + prov->state = PB_REMOTE_STATE_LINK_ACTIVE; + + n = mesh_model_opcode_set(OP_REM_PROV_LINK_REPORT, msg); + msg[n++] = PB_REM_ERR_SUCCESS; + msg[n++] = PB_REMOTE_STATE_LINK_ACTIVE; + + mesh_model_send(prov->node, 0, prov->client, APP_IDX_DEV_LOCAL, + prov->net_idx, DEFAULT_TTL, true, n, msg); +} + +bool register_nppi_acceptor(mesh_prov_open_func_t open_cb, + mesh_prov_close_func_t close_cb, + mesh_prov_receive_func_t rx_cb, + mesh_prov_ack_func_t ack_cb, + void *user_data) +{ + struct rem_prov_data *prov = rpb_prov; + + if (!prov || prov->nppi_proc == RPR_ADV) + return false; + + prov->u.nppi.open_cb = open_cb; + prov->u.nppi.close_cb = close_cb; + prov->u.nppi.rx_cb = rx_cb; + prov->u.nppi.ack_cb = ack_cb; + prov->trans_data = user_data; + + open_cb(user_data, srv_rx, prov, prov->nppi_proc); + + l_idle_oneshot(link_active, prov, NULL); + + return true; +} + +static bool nppi_cmplt(void *user_data, uint8_t status, + struct mesh_prov_node_info *info) +{ + struct rem_prov_data *prov = user_data; + + if (prov != rpb_prov) + return false; + + /* Save new info to apply on Link Close */ + prov->u.nppi.info = *info; + return true; +} + +static bool start_dev_key_refresh(struct mesh_node *node, uint8_t nppi_proc, + struct rem_prov_data *prov) +{ + uint8_t num_ele = node_get_num_elements(node); + + prov->nppi_proc = nppi_proc; + return acceptor_start(num_ele, NULL, 0x0001, 60, NULL, nppi_cmplt, + prov); +} + +static bool remprv_srv_pkt(uint16_t src, uint16_t unicast, uint16_t app_idx, + uint16_t net_idx, const uint8_t *data, + uint16_t size, const void *user_data) +{ + struct rem_prov_data *prov = rpb_prov; + struct rem_scan_data *scan = rpb_scan; + struct mesh_node *node = (struct mesh_node *) user_data; + const uint8_t *pkt = data; + bool segmented = false; + uint32_t opcode; + uint8_t msg[69]; + uint8_t status; + uint16_t n; + + if (app_idx != APP_IDX_DEV_LOCAL) + return false; + + if (mesh_model_opcode_get(pkt, size, &opcode, &n)) { + size -= n; + pkt += n; + } else + return false; + + n = 0; + + switch (opcode) { + default: + return false; + + case OP_REM_PROV_SCAN_CAP_GET: + if (size != 0) + return true; + + /* Compose Scan Info Status */ + n = mesh_model_opcode_set(OP_REM_PROV_SCAN_CAP_STATUS, msg); + msg[n++] = PB_REMOTE_MAX_SCAN_QUEUE_SIZE; + msg[n++] = 1; /* Active Scanning Supported */ + break; + + case OP_REM_PROV_EXT_SCAN_START: + if (!size || !pkt[0]) + return true; + + /* Size check the message */ + if (pkt[0] + 18 == size) { + /* Range check the Timeout */ + if (!pkt[size - 1] || pkt[size - 1] > 5) + return true; + } else if (pkt[0] + 1 != size) + return true; + + /* Get local device extended info */ + if (pkt[0] + 18 != size) { + n = mesh_model_opcode_set( + OP_REM_PROV_EXT_SCAN_REPORT, msg); + msg[n++] = PB_REM_ERR_SUCCESS; + memcpy(msg + n, node_uuid_get(node), 16); + n += 16; + l_put_le16(0, msg + n); + n += 2; + size--; + pkt++; + + while (size--) { + if (*pkt++ == BT_AD_NAME_COMPLETE) { + msg[n] = strlen(name) + 1; + if (msg[n] > sizeof(msg) - n - 1) + msg[n] = sizeof(msg) - n - 1; + n++; + msg[n++] = BT_AD_NAME_COMPLETE; + memcpy(&msg[n], name, msg[n - 2] - 1); + n += msg[n - 2] - 1; + goto send_pkt; + } + } + + /* Send internal report */ + l_debug("Send internal extended info %d", n); + goto send_pkt; + } + + status = PB_REM_ERR_SUCCESS; + if (scan) { + if (scan->client != src || scan->node != node || + scan->ext_cnt != pkt[0]) + status = PB_REM_ERR_SCANNING_CANNOT_START; + else if (memcmp(scan->ext, pkt + 1, pkt[0])) + status = PB_REM_ERR_SCANNING_CANNOT_START; + else if (memcmp(scan->uuid, pkt + 2, 16)) + status = PB_REM_ERR_SCANNING_CANNOT_START; + } + + if (status != PB_REM_ERR_SUCCESS) { + n = mesh_model_opcode_set(OP_REM_PROV_EXT_SCAN_REPORT, + msg); + msg[n++] = status; + memset(msg + n, 0, 16); + n += 16; + segmented = true; + break; + } + + /* Ignore extended requests while already scanning */ + if (scan) + return true; + + scan = (void *) l_new(uint8_t, + sizeof(struct rem_scan_data) + pkt[0]); + + /* Validate and register Extended AD types */ + for (n = 0; n < pkt[0]; n++) { + if (!register_ext_ad_type(pkt[1 + n], scan)) { + /* Invalid AD type detected -- Undo */ + while (n--) + deregister_ext_ad_type(pkt[1 + n]); + + l_free(scan); + return true; + } + } + + rpb_scan = scan; + scan->client = src; + scan->net_idx = net_idx; + memcpy(scan->uuid, pkt + size - 17, 16); + scan->ext_cnt = pkt[0]; + memcpy(scan->ext, pkt + 1, pkt[0]); + scan->list = l_malloc(EXT_LIST_SIZE); + scan->list[0] = 0; + + mesh_io_register_recv_cb(NULL, prvb, sizeof(prvb), + scan_pkt, scan); + + scan->timeout = l_timeout_create(pkt[size-1], + remprv_scan_cancel, scan, NULL); + return true; + + case OP_REM_PROV_SCAN_START: + if (size != 2 && size != 18) + return true; + + /* Reject Timeout of Zero */ + if (!pkt[1]) + return true; + + status = PB_REM_ERR_SUCCESS; + if (scan) { + if (scan->ext_cnt || scan->client != src || + scan->node != node) + status = PB_REM_ERR_SCANNING_CANNOT_START; + else if (!!(scan->fltr) != !!(size != 18)) + status = PB_REM_ERR_SCANNING_CANNOT_START; + else if (scan->fltr && memcmp(scan->uuid, pkt + 2, 16)) + status = PB_REM_ERR_SCANNING_CANNOT_START; + } + + if (status != PB_REM_ERR_SUCCESS) { + n = mesh_model_opcode_set(OP_REM_PROV_SCAN_STATUS, msg); + msg[n++] = status; + msg[n++] = scan ? scan->state : 0; + msg[n++] = scan ? scan->scanned_limit : + PB_REMOTE_MAX_SCAN_QUEUE_SIZE; + msg[n++] = scan ? scan->to_secs : 0; + break; + } + + if (!scan) + scan = l_new(struct rem_scan_data, 1); + + rpb_scan = scan; + + if (size == 18) { + memcpy(scan->uuid, pkt + 2, 16); + scan->fltr = true; + scan->state = 0x02; /* Limited */ + } else { + memset(scan->uuid, 0, 16); + scan->fltr = false; + scan->state = 0x01; /* Unlimited */ + } + + scan->client = src; + scan->net_idx = net_idx; + scan->node = node; + + if (!scan->list) + scan->list = l_new(uint8_t, + 23 * PB_REMOTE_MAX_SCAN_QUEUE_SIZE); + + mesh_io_register_recv_cb(NULL, prvb, 2, scan_pkt, scan); + + scan->to_secs = pkt[1]; + + if (pkt[0]) + scan->scanned_limit = pkt[0]; + else + scan->scanned_limit = PB_REMOTE_MAX_SCAN_QUEUE_SIZE; + + scan->timeout = l_timeout_create(pkt[1], + remprv_scan_cancel, scan, NULL); + + /* fall through */ + + case OP_REM_PROV_SCAN_GET: + /* Compose Scan Status */ + n = mesh_model_opcode_set(OP_REM_PROV_SCAN_STATUS, msg); + msg[n++] = PB_REM_ERR_SUCCESS; + msg[n++] = scan ? scan->state : 0; + msg[n++] = scan ? scan->scanned_limit : + PB_REMOTE_MAX_SCAN_QUEUE_SIZE; + msg[n++] = scan ? scan->to_secs : 0; + break; + + case OP_REM_PROV_SCAN_STOP: + if (size != 0 || !scan) + return true; + + remprv_scan_cancel(NULL, scan); + return true; + + case OP_REM_PROV_LINK_GET: + if (size != 0 || !prov) + return true; + + send_prov_status(prov, PB_REM_ERR_SUCCESS); + return true; + + case OP_REM_PROV_LINK_OPEN: + /* Sanity check args */ + if (size != 16 && size != 17 && size != 1) + return true; + + if (size == 17 && (pkt[16] == 0 || pkt[16] > 0x3c)) + return true; + + if (size == 1 && pkt[0] > 0x02) + return true; + + if (prov) { + if (prov->client != src || prov->node != node || + (size == 1 && prov->nppi_proc != pkt[0]) || + (size >= 16 && (prov->nppi_proc != RPR_ADV || + memcmp(prov->u.adv.uuid, pkt, 16)))) { + + /* Send Reject (in progress) */ + send_prov_status(prov, PB_REM_ERR_CANNOT_OPEN); + n = mesh_model_opcode_set( + OP_REM_PROV_LINK_STATUS, msg); + msg[n++] = PB_REM_ERR_CANNOT_OPEN; + msg[n++] = PB_REMOTE_STATE_LINK_ACTIVE; + break; + } + + /* Send redundant Success */ + send_prov_status(prov, PB_REM_ERR_SUCCESS); + return true; + } + + if (scan && scan->client != src && scan->node != node) { + n = mesh_model_opcode_set(OP_REM_PROV_LINK_STATUS, msg); + msg[n++] = PB_REM_ERR_CANNOT_OPEN; + msg[n++] = PB_REMOTE_STATE_LINK_ACTIVE; + break; + } + + print_packet("Remote Prov Link Open", pkt, size); + + remprv_scan_cancel(NULL, scan); + + rpb_prov = prov = l_new(struct rem_prov_data, 1); + prov->client = src; + prov->net_idx = net_idx; + prov->node = node; + prov->state = PB_REMOTE_STATE_LINK_OPENING; + + if (size == 1) { + status = start_dev_key_refresh(node, pkt[0], prov); + + } else { + if (size == 17) + prov->timeout = l_timeout_create(pkt[16], + remprv_prov_cancel, prov, NULL); + + + prov->nppi_proc = RPR_ADV; + memcpy(prov->u.adv.uuid, pkt, 16); + status = pb_adv_reg(true, srv_open, srv_close, srv_rx, + srv_ack, pkt, prov); + } + + if (status) + send_prov_status(prov, PB_REM_ERR_SUCCESS); + else { + n = mesh_model_opcode_set(OP_REM_PROV_LINK_STATUS, msg); + msg[n++] = PB_REM_ERR_CANNOT_OPEN; + msg[n++] = PB_REMOTE_STATE_IDLE; + remprv_prov_cancel(NULL, prov); + } + + return true; + + case OP_REM_PROV_LINK_CLOSE: + if (size != 1) + return true; + + if (!prov || prov->node != node || prov->client != src) + return true; + + prov->state = PB_REMOTE_STATE_LINK_CLOSING; + mesh_io_send_cancel(NULL, &pkt_filter, sizeof(pkt_filter)); + send_prov_status(prov, PB_REM_ERR_SUCCESS); + if (pkt[0] == 0x02) { + msg[0] = PROV_FAILED; + msg[1] = PROV_ERR_CANT_ASSIGN_ADDR; + if (prov->nppi_proc == RPR_ADV) + prov->u.adv.tx(prov->trans_data, msg, 2); + else + prov->u.nppi.rx_cb(prov->trans_data, msg, 2); + } + + if (prov->nppi_proc == RPR_ADV) + pb_adv_unreg(prov); + + else if (prov->nppi_proc <= RPR_COMP) { + /* Hard or Soft refresh of local node, based on NPPI */ + node_refresh(prov->node, (prov->nppi_proc == RPR_ADDR), + &prov->u.nppi.info); + } + + remprv_prov_cancel(NULL, prov); + + return true; + + case OP_REM_PROV_PDU_SEND: + if (!prov || prov->node != node || prov->client != src) + return true; + + if (size < 2) + return true; + + + prov->cli_pdu_num = *pkt++; + size--; + prov->state = PB_REMOTE_STATE_OB_PKT_TX; + + if (prov->nppi_proc == RPR_ADV) + prov->u.adv.tx(prov->trans_data, pkt, size); + else { + srv_ack(prov, prov->cli_pdu_num); + prov->u.nppi.rx_cb(prov->trans_data, pkt, size); + } + + return true; + } + +send_pkt: + l_info("PB-SVR: src %4.4x dst %4.4x", unicast, src); + print_packet("App Tx", msg, n); + mesh_model_send(node, 0, src, APP_IDX_DEV_LOCAL, + net_idx, DEFAULT_TTL, segmented, n, msg); + + return true; +} + +static void remprv_srv_unregister(void *user_data) +{ +} + +static const struct mesh_model_ops ops = { + .unregister = remprv_srv_unregister, + .recv = remprv_srv_pkt, + .bind = NULL, + .sub = NULL, + .pub = NULL +}; + +void remote_prov_server_init(struct mesh_node *node, uint8_t ele_idx) +{ + mesh_model_register(node, ele_idx, REM_PROV_SRV_MODEL, &ops, node); +} diff --git a/mesh/remprv.h b/mesh/remprv.h new file mode 100644 index 000000000..49b4e2c7c --- /dev/null +++ b/mesh/remprv.h @@ -0,0 +1,78 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2020 Intel Corporation. All rights reserved. + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + */ + +#define REM_PROV_SRV_MODEL SET_ID(SIG_VENDOR, 0x0004) +#define REM_PROV_CLI_MODEL SET_ID(SIG_VENDOR, 0x0005) + +#define PB_REMOTE_MAX_SCAN_QUEUE_SIZE 5 + +#define PB_REMOTE_STATE_IDLE 0x00 +#define PB_REMOTE_STATE_LINK_OPENING 0x01 +#define PB_REMOTE_STATE_LINK_ACTIVE 0x02 +#define PB_REMOTE_STATE_OB_PKT_TX 0x03 +#define PB_REMOTE_STATE_LINK_CLOSING 0x04 + +#define PB_REMOTE_TYPE_LOCAL 0x01 +#define PB_REMOTE_TYPE_ADV 0x02 +#define PB_REMOTE_TYPE_GATT 0x04 + +#define PB_REMOTE_SCAN_TYPE_NONE 0x00 +#define PB_REMOTE_SCAN_TYPE_UNLIMITED 0x01 +#define PB_REMOTE_SCAN_TYPE_LIMITED 0x02 +#define PB_REMOTE_SCAN_TYPE_DETAILED 0x03 + +/* Remote Provisioning Opcode List */ +#define OP_REM_PROV_SCAN_CAP_GET 0x804F +#define OP_REM_PROV_SCAN_CAP_STATUS 0x8050 +#define OP_REM_PROV_SCAN_GET 0x8051 +#define OP_REM_PROV_SCAN_START 0x8052 +#define OP_REM_PROV_SCAN_STOP 0x8053 +#define OP_REM_PROV_SCAN_STATUS 0x8054 +#define OP_REM_PROV_SCAN_REPORT 0x8055 +#define OP_REM_PROV_EXT_SCAN_START 0x8056 +#define OP_REM_PROV_EXT_SCAN_REPORT 0x8057 +#define OP_REM_PROV_LINK_GET 0x8058 +#define OP_REM_PROV_LINK_OPEN 0x8059 +#define OP_REM_PROV_LINK_CLOSE 0x805A +#define OP_REM_PROV_LINK_STATUS 0x805B +#define OP_REM_PROV_LINK_REPORT 0x805C +#define OP_REM_PROV_PDU_SEND 0x805D +#define OP_REM_PROV_PDU_OB_REPORT 0x805E +#define OP_REM_PROV_PDU_REPORT 0x805F + +/* Remote Provisioning Errors */ +#define PB_REM_ERR_SUCCESS 0x00 +#define PB_REM_ERR_SCANNING_CANNOT_START 0x01 +#define PB_REM_ERR_INVALID_STATE 0x02 +#define PB_REM_ERR_LIMITED_RESOURCES 0x03 +#define PB_REM_ERR_CANNOT_OPEN 0x04 +#define PB_REM_ERR_OPEN_FAILED 0x05 +#define PB_REM_ERR_CLOSED_BY_DEVICE 0x06 +#define PB_REM_ERR_CLOSED_BY_SERVER 0x07 +#define PB_REM_ERR_CLOSED_BY_CLIENT 0x08 +#define PB_REM_ERR_CLOSED_CANNOT_RX_PDU 0x09 +#define PB_REM_ERR_CLOSED_CANNOT_TX_PDU 0x0A + +void remote_prov_server_init(struct mesh_node *node, uint8_t ele_idx); +void remote_prov_client_init(struct mesh_node *node, uint8_t ele_idx); +bool register_nppi_acceptor(mesh_prov_open_func_t open_cb, + mesh_prov_close_func_t close_cb, + mesh_prov_receive_func_t rx_cb, + mesh_prov_ack_func_t ack_cb, + void *user_data);
From: Brian Gix <brian.gix@intel.com> Add Remote Provisioning Server Add Remote Provisioning Client Remove local scanning/provisioning Add delete-all dev key function Add NPPI procedures --- Makefile.mesh | 1 + mesh/cfgmod-server.c | 2 +- mesh/keyring.c | 29 +- mesh/keyring.h | 1 + mesh/manager.c | 535 +++++++++++++++++++----- mesh/mesh-config-json.c | 380 +++++++++++------ mesh/mesh-config.h | 6 +- mesh/model.c | 27 +- mesh/node.c | 255 +++++++++-- mesh/node.h | 3 + mesh/pb-adv.c | 4 +- mesh/pb-adv.h | 2 +- mesh/prov-acceptor.c | 87 ++-- mesh/prov-initiator.c | 269 +++++++++++- mesh/prov.h | 4 +- mesh/provision.h | 23 +- mesh/remprv-server.c | 907 ++++++++++++++++++++++++++++++++++++++++ mesh/remprv.h | 78 ++++ 18 files changed, 2246 insertions(+), 367 deletions(-) create mode 100644 mesh/remprv-server.c create mode 100644 mesh/remprv.h