| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888 |
- // SPDX-License-Identifier: LGPL-2.1-or-later
- /*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2017 Intel Corporation. All rights reserved.
- *
- *
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #include <stdio.h>
- #include <errno.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdbool.h>
- #include <sys/uio.h>
- #include <wordexp.h>
- #include <inttypes.h>
- #include <glib.h>
- #include "src/shared/util.h"
- #include "src/shared/shell.h"
- #include "gdbus/gdbus.h"
- #include "tools/mesh/config-model.h"
- #include "tools/mesh-gatt/mesh-net.h"
- #include "tools/mesh-gatt/node.h"
- #include "tools/mesh-gatt/keys.h"
- #include "tools/mesh-gatt/gatt.h"
- #include "tools/mesh-gatt/net.h"
- #include "tools/mesh-gatt/prov-db.h"
- #include "tools/mesh-gatt/util.h"
- struct mesh_model {
- struct mesh_model_ops cbs;
- void *user_data;
- GList *bindings;
- GList *subscriptions;
- uint32_t id;
- struct mesh_publication *pub;
- };
- struct mesh_element {
- GList *models;
- uint16_t loc;
- uint8_t index;
- };
- struct mesh_node {
- const char *name;
- GList *net_keys;
- GList *app_keys;
- void *prov;
- GList *elements;
- uint32_t iv_index;
- uint32_t seq_number;
- uint16_t primary_net_idx;
- uint16_t primary;
- uint16_t oob;
- uint16_t features;
- uint8_t dev_uuid[16];
- uint8_t dev_key[16];
- uint8_t num_ele;
- uint8_t ttl;
- bool provisioner;
- struct mesh_node_composition *comp;
- };
- static GList *nodes;
- static struct mesh_node *local_node;
- static int match_node_unicast(const void *a, const void *b)
- {
- const struct mesh_node *node = a;
- uint16_t dst = GPOINTER_TO_UINT(b);
- if (dst >= node->primary &&
- dst <= (node->primary + node->num_ele - 1))
- return 0;
- return -1;
- }
- static int match_device_uuid(const void *a, const void *b)
- {
- const struct mesh_node *node = a;
- const uint8_t *uuid = b;
- return memcmp(node->dev_uuid, uuid, 16);
- }
- static int match_element_idx(const void *a, const void *b)
- {
- const struct mesh_element *element = a;
- uint32_t index = GPOINTER_TO_UINT(b);
- return (element->index == index) ? 0 : -1;
- }
- static int match_model_id(const void *a, const void *b)
- {
- const struct mesh_model *model = a;
- uint32_t id = GPOINTER_TO_UINT(b);
- return (model->id == id) ? 0 : -1;
- }
- struct mesh_node *node_find_by_addr(uint16_t addr)
- {
- GList *l;
- if (!IS_UNICAST(addr))
- return NULL;
- l = g_list_find_custom(nodes, GUINT_TO_POINTER(addr),
- match_node_unicast);
- if (l)
- return l->data;
- else
- return NULL;
- }
- struct mesh_node *node_find_by_uuid(uint8_t uuid[16])
- {
- GList *l;
- l = g_list_find_custom(nodes, uuid, match_device_uuid);
- if (l)
- return l->data;
- else
- return NULL;
- }
- struct mesh_node *node_create_new(struct prov_svc_data *prov)
- {
- struct mesh_node *node;
- if (node_find_by_uuid(prov->dev_uuid))
- return NULL;
- node = g_malloc0(sizeof(struct mesh_node));
- if (!node)
- return NULL;
- memcpy(node->dev_uuid, prov->dev_uuid, 16);
- node->oob = prov->oob;
- nodes = g_list_append(nodes, node);
- return node;
- }
- struct mesh_node *node_new(void)
- {
- struct mesh_node *node;
- node = g_malloc0(sizeof(struct mesh_node));
- if (!node)
- return NULL;
- nodes = g_list_append(nodes, node);
- return node;
- }
- static void model_free(void *data)
- {
- struct mesh_model *model = data;
- g_list_free(model->bindings);
- g_list_free(model->subscriptions);
- g_free(model->pub);
- g_free(model);
- }
- static void element_free(void *data)
- {
- struct mesh_element *element = data;
- g_list_free_full(element->models, model_free);
- g_free(element);
- }
- static void free_node_resources(void *data)
- {
- struct mesh_node *node = data;
- g_list_free(node->net_keys);
- g_list_free(node->app_keys);
- g_list_free_full(node->elements, element_free);
- if(node->comp)
- g_free(node->comp);
- g_free(node);
- }
- void node_free(struct mesh_node *node)
- {
- if (!node)
- return;
- nodes = g_list_remove(nodes, node);
- free_node_resources(node);
- }
- void node_cleanup(void)
- {
- g_list_free_full(nodes, free_node_resources);
- local_node = NULL;
- }
- bool node_is_provisioned(struct mesh_node *node)
- {
- return (!IS_UNASSIGNED(node->primary));
- }
- void *node_get_prov(struct mesh_node *node)
- {
- return node->prov;
- }
- void node_set_prov(struct mesh_node *node, void *prov)
- {
- node->prov = prov;
- }
- bool node_app_key_add(struct mesh_node *node, uint16_t idx)
- {
- uint32_t index;
- uint16_t net_idx;
- if (!node)
- return false;
- net_idx = keys_app_key_get_bound(idx);
- if (net_idx == NET_IDX_INVALID)
- return false;
- if (!g_list_find(node->net_keys, GUINT_TO_POINTER(net_idx)))
- return false;
- index = (net_idx << 16) + idx;
- if (g_list_find(node->app_keys, GUINT_TO_POINTER(index)))
- return false;
- node->app_keys = g_list_append(node->app_keys, GUINT_TO_POINTER(index));
- return true;
- }
- bool node_net_key_add(struct mesh_node *node, uint16_t index)
- {
- if(!node)
- return false;
- if (g_list_find(node->net_keys, GUINT_TO_POINTER(index)))
- return false;
- node->net_keys = g_list_append(node->net_keys, GUINT_TO_POINTER(index));
- return true;
- }
- bool node_net_key_delete(struct mesh_node *node, uint16_t index)
- {
- GList *l;
- if(!node)
- return false;
- l = g_list_find(node->net_keys, GUINT_TO_POINTER(index));
- if (!l)
- return false;
- node->net_keys = g_list_remove(node->net_keys,
- GUINT_TO_POINTER(index));
- /* TODO: remove all associated app keys and bindings */
- return true;
- }
- bool node_app_key_delete(struct mesh_node *node, uint16_t net_idx,
- uint16_t idx)
- {
- GList *l;
- uint32_t index;
- if(!node)
- return false;
- index = (net_idx << 16) + idx;
- l = g_list_find(node->app_keys, GUINT_TO_POINTER(index));
- if (!l)
- return false;
- node->app_keys = g_list_remove(node->app_keys,
- GUINT_TO_POINTER(index));
- /* TODO: remove all associated bindings */
- return true;
- }
- void node_set_primary(struct mesh_node *node, uint16_t unicast)
- {
- node->primary = unicast;
- }
- uint16_t node_get_primary(struct mesh_node *node)
- {
- if (!node)
- return UNASSIGNED_ADDRESS;
- else
- return node->primary;
- }
- void node_set_device_key(struct mesh_node *node, uint8_t *key)
- {
- if (!node || !key)
- return;
- memcpy(node->dev_key, key, 16);
- }
- uint8_t *node_get_device_key(struct mesh_node *node)
- {
- if (!node)
- return NULL;
- else
- return node->dev_key;
- }
- void node_set_num_elements(struct mesh_node *node, uint8_t num_ele)
- {
- node->num_ele = num_ele;
- }
- uint8_t node_get_num_elements(struct mesh_node *node)
- {
- return node->num_ele;
- }
- GList *node_get_net_keys(struct mesh_node *node)
- {
- if (!node)
- return NULL;
- else
- return node->net_keys;
- }
- GList *node_get_app_keys(struct mesh_node *node)
- {
- if (!node)
- return NULL;
- else
- return node->app_keys;
- }
- bool node_parse_composition(struct mesh_node *node, uint8_t *data, uint16_t len)
- {
- struct mesh_node_composition *comp;
- uint16_t features;
- int i;
- comp = g_malloc0(sizeof(struct mesh_node_composition));
- if (!comp)
- return false;
- /* skip page -- We only support Page Zero */
- data++;
- len--;
- comp->cid = get_le16(&data[0]);
- comp->pid = get_le16(&data[2]);
- comp->vid = get_le16(&data[4]);
- comp->crpl = get_le16(&data[6]);
- features = get_le16(&data[8]);
- data += 10;
- len -= 10;
- comp->relay = !!(features & MESH_FEATURE_RELAY);
- comp->proxy = !!(features & MESH_FEATURE_PROXY);
- comp->friend = !!(features & MESH_FEATURE_FRIEND);
- comp->lpn = !!(features & MESH_FEATURE_LPN);
- for (i = 0; i< node->num_ele; i++) {
- uint8_t m, v;
- uint32_t mod_id;
- uint16_t vendor_id;
- struct mesh_element *ele;
- ele = g_malloc0(sizeof(struct mesh_element));
- if (!ele) {
- g_free(comp);
- return false;
- }
- ele->index = i;
- ele->loc = get_le16(data);
- data += 2;
- node->elements = g_list_append(node->elements, ele);
- m = *data++;
- v = *data++;
- len -= 2;
- while (len >= 2 && m--) {
- mod_id = get_le16(data);
- /* initialize uppper 16 bits to 0xffff for SIG models */
- mod_id |= 0xffff0000;
- if (!node_set_model(node, ele->index, mod_id)) {
- g_free(comp);
- return false;
- }
- data += 2;
- len -= 2;
- }
- while (len >= 4 && v--) {
- mod_id = get_le16(data + 2);
- vendor_id = get_le16(data);
- mod_id |= (vendor_id << 16);
- if (!node_set_model(node, ele->index, mod_id)) {
- g_free(comp);
- return false;
- }
- data += 4;
- len -= 4;
- }
- }
- node->comp = comp;
- return true;
- }
- bool node_set_local_node(struct mesh_node *node)
- {
- if (local_node) {
- bt_shell_printf("Local node already registered\n");
- return false;
- }
- net_register_unicast(node->primary, node->num_ele);
- local_node = node;
- local_node->provisioner = true;
- return true;
- }
- struct mesh_node *node_get_local_node()
- {
- return local_node;
- }
- uint16_t node_get_primary_net_idx(struct mesh_node *node)
- {
- if (node == NULL)
- return NET_IDX_INVALID;
- return node->primary_net_idx;
- }
- static bool deliver_model_data(struct mesh_element* element, uint16_t src,
- uint16_t app_idx, uint8_t *data, uint16_t len)
- {
- GList *l;
- for(l = element->models; l; l = l->next) {
- struct mesh_model *model = l->data;
- if (!g_list_find(model->bindings, GUINT_TO_POINTER(app_idx)))
- continue;
- if (model->cbs.recv &&
- model->cbs.recv(src, data, len, model->user_data))
- return true;
- }
- return false;
- }
- void node_local_data_handler(uint16_t src, uint32_t dst,
- uint32_t iv_index, uint32_t seq_num,
- uint16_t app_idx, uint8_t *data, uint16_t len)
- {
- GList *l;
- bool res;
- uint64_t iv_seq;
- uint64_t iv_seq_remote;
- uint8_t ele_idx;
- struct mesh_element *element;
- struct mesh_node *remote;
- bool loopback;
- if (!local_node || seq_num > 0xffffff)
- return;
- iv_seq = iv_index << 24;
- iv_seq |= seq_num;
- remote = node_find_by_addr(src);
- if (!remote) {
- if (local_node->provisioner) {
- bt_shell_printf("Remote node unknown (%4.4x)\n", src);
- return;
- }
- remote = g_new0(struct mesh_node, 1);
- if (!remote)
- return;
- /* Not Provisioner; Assume all SRC elements stand alone */
- remote->primary = src;
- remote->num_ele = 1;
- nodes = g_list_append(nodes, remote);
- }
- loopback = (src < (local_node->primary + local_node->num_ele) &&
- src >= local_node->primary);
- if (!loopback) {
- iv_seq_remote = remote->iv_index << 24;
- iv_seq |= remote->seq_number;
- if (iv_seq_remote >= iv_seq) {
- bt_shell_printf("Replayed message detected "
- "(%016" PRIx64 " >= %016" PRIx64 ")\n",
- iv_seq_remote, iv_seq);
- return;
- }
- }
- if (IS_GROUP(dst) || IS_VIRTUAL(dst)) {
- /* TODO: if subscription address, deliver to subscribers */
- return;
- }
- if (IS_ALL_NODES(dst)) {
- ele_idx = 0;
- } else {
- if (dst >= (local_node->primary + local_node->num_ele) ||
- dst < local_node->primary)
- return;
- ele_idx = dst - local_node->primary;
- }
- l = g_list_find_custom(local_node->elements,
- GUINT_TO_POINTER(ele_idx), match_element_idx);
- /* This should not happen */
- if (!l)
- return;
- element = l->data;
- res = deliver_model_data(element, src, app_idx, data, len);
- if (res && !loopback) {
- /* TODO: Save remote in Replay Protection db */
- remote->iv_index = iv_index;
- remote->seq_number = seq_num;
- prov_db_node_set_iv_seq(remote, iv_index, seq_num);
- }
- }
- static gboolean restore_model_state(gpointer data)
- {
- struct mesh_model *model = data;
- GList *l;
- struct mesh_model_ops *ops;
- ops = &model->cbs;
- if (model->bindings && ops->bind) {
- for (l = model->bindings; l; l = l->next) {
- if (ops->bind(GPOINTER_TO_UINT(l->data), ACTION_ADD) !=
- MESH_STATUS_SUCCESS)
- break;
- }
- }
- if (model->pub && ops->pub)
- ops->pub(model->pub);
- g_idle_remove_by_data(data);
- return true;
- }
- bool node_local_model_register(uint8_t ele_idx, uint16_t model_id,
- struct mesh_model_ops *ops, void *user_data)
- {
- uint32_t id = 0xffff0000 | model_id;
- return node_local_vendor_model_register(ele_idx, id, ops, user_data);
- }
- bool node_local_vendor_model_register(uint8_t ele_idx, uint32_t model_id,
- struct mesh_model_ops *ops, void *user_data)
- {
- struct mesh_element *ele;
- struct mesh_model *model;
- GList *l;
- if (!local_node)
- return false;
- l = g_list_find_custom(local_node->elements, GUINT_TO_POINTER(ele_idx),
- match_element_idx);
- if (!l)
- return false;
- ele = l->data;
- l = g_list_find_custom(ele->models, GUINT_TO_POINTER(model_id),
- match_model_id);
- if (!l)
- return false;
- model = l->data;
- model->cbs = *ops;
- model->user_data = user_data;
- if (model_id >= 0xffff0000)
- model_id = model_id & 0xffff;
- /* Silently assign device key binding to configuration models */
- if (model_id == CONFIG_SERVER_MODEL_ID ||
- model_id == CONFIG_CLIENT_MODEL_ID) {
- model->bindings = g_list_append(model->bindings,
- GUINT_TO_POINTER(APP_IDX_DEV));
- } else {
- g_idle_add(restore_model_state, model);
- }
- return true;
- }
- bool node_set_element(struct mesh_node *node, uint8_t ele_idx)
- {
- struct mesh_element *ele;
- GList *l;
- if (!node)
- return false;
- l = g_list_find_custom(node->elements, GUINT_TO_POINTER(ele_idx),
- match_element_idx);
- if (l)
- return false;
- ele = g_malloc0(sizeof(struct mesh_element));
- if (!ele)
- return false;
- ele->index = ele_idx;
- node->elements = g_list_append(node->elements, ele);
- return true;
- }
- bool node_set_model(struct mesh_node *node, uint8_t ele_idx, uint32_t id)
- {
- struct mesh_element *ele;
- struct mesh_model *model;
- GList *l;
- if (!node)
- return false;
- l = g_list_find_custom(node->elements, GUINT_TO_POINTER(ele_idx),
- match_element_idx);
- if (!l)
- return false;
- ele = l->data;
- l = g_list_find_custom(ele->models, GUINT_TO_POINTER(id),
- match_model_id);
- if (l)
- return true;
- model = g_malloc0(sizeof(struct mesh_model));
- if (!model)
- return false;
- model->id = id;
- ele->models = g_list_append(ele->models, model);
- return true;
- }
- bool node_set_composition(struct mesh_node *node,
- struct mesh_node_composition *comp)
- {
- if (!node || !comp || node->comp)
- return false;
- node->comp = g_malloc0(sizeof(struct mesh_node_composition));
- if (!node->comp)
- return false;
- *(node->comp) = *comp;
- return true;
- }
- struct mesh_node_composition *node_get_composition(struct mesh_node *node)
- {
- if (!node)
- return NULL;
- return node->comp;
- }
- static struct mesh_model *get_model(struct mesh_node *node, uint8_t ele_idx,
- uint32_t model_id)
- {
- struct mesh_element *ele;
- GList *l;
- if (!node)
- return NULL;
- l = g_list_find_custom(node->elements, GUINT_TO_POINTER(ele_idx),
- match_element_idx);
- if (!l)
- return NULL;
- ele = l->data;
- l = g_list_find_custom(ele->models, GUINT_TO_POINTER(model_id),
- match_model_id);
- if (!l)
- return NULL;
- return l->data;
- }
- bool node_add_binding(struct mesh_node *node, uint8_t ele_idx,
- uint32_t model_id, uint16_t app_idx)
- {
- struct mesh_model *model;
- GList *l;
- model = get_model(node, ele_idx, model_id);
- if (!model)
- return false;
- l = g_list_find(model->bindings, GUINT_TO_POINTER(app_idx));
- if (l)
- return false;
- if ((node == local_node) && model->cbs.bind) {
- if (!model->cbs.bind(app_idx, ACTION_ADD))
- return false;
- }
- model->bindings = g_list_append(model->bindings,
- GUINT_TO_POINTER(app_idx));
- return true;
- }
- bool node_add_subscription(struct mesh_node *node, uint8_t ele_idx,
- uint32_t model_id, uint16_t addr)
- {
- struct mesh_model *model;
- GList *l;
- model = get_model(node, ele_idx, model_id);
- if (!model)
- return false;
- l = g_list_find(model->subscriptions, GUINT_TO_POINTER(addr));
- if (l)
- return false;
- model->subscriptions = g_list_append(model->subscriptions,
- GUINT_TO_POINTER(addr));
- return true;
- }
- uint8_t node_get_default_ttl(struct mesh_node *node)
- {
- if (!node)
- return DEFAULT_TTL;
- else if (node == local_node)
- return net_get_default_ttl();
- else
- return node->ttl;
- }
- bool node_set_default_ttl(struct mesh_node *node, uint8_t ttl)
- {
- if (!node)
- return false;
- node->ttl = ttl;
- if (node == local_node || local_node == NULL)
- return net_set_default_ttl(ttl);
- return true;
- }
- bool node_set_sequence_number(struct mesh_node *node, uint32_t seq)
- {
- if (!node)
- return false;
- node->seq_number = seq;
- if (node == local_node || local_node == NULL)
- return net_set_seq_num(seq);
- return true;
- }
- uint32_t node_get_sequence_number(struct mesh_node *node)
- {
- if (!node)
- return 0xffffffff;
- else if (node == local_node)
- return net_get_seq_num();
- return node->seq_number;
- }
- bool node_set_iv_index(struct mesh_node *node, uint32_t iv_index)
- {
- if (!node)
- return false;
- node->iv_index = iv_index;
- return true;
- }
- uint32_t node_get_iv_index(struct mesh_node *node)
- {
- bool update;
- if (!node)
- return 0xffffffff;
- else if (node == local_node)
- return net_get_iv_index(&update);
- return node->iv_index;
- }
- bool node_model_pub_set(struct mesh_node *node, uint8_t ele, uint32_t model_id,
- struct mesh_publication *pub)
- {
- struct mesh_model *model;
- model = get_model(node, ele, model_id);
- if(!model)
- return false;
- if (!model->pub)
- model->pub = g_malloc0(sizeof(struct mesh_publication));
- if (!model)
- return false;
- memcpy(model->pub, pub, (sizeof(struct mesh_publication)));
- if((node == local_node) && model->cbs.pub)
- model->cbs.pub(pub);
- return true;
- }
- struct mesh_publication *node_model_pub_get(struct mesh_node *node, uint8_t ele,
- uint32_t model_id)
- {
- struct mesh_model *model;
- model = get_model(node, ele, model_id);
- if(!model)
- return NULL;
- else
- return model->pub;
- }
|